<?php

/**
 * The get repeat box snippet.
 *
 * @author     Time.ly Network Inc.
 * @since      2.0
 *
 * @package    AI1EC
 * @subpackage AI1EC.View
 */
class Ai1ec_View_Admin_Get_repeat_Box extends Ai1ec_Base {
    /**
     * get_repeat_box function
     *
     * @return string
     **/
    public function get_repeat_box() {
        $time_system = $this->_registry->get( 'date.system' );
        $loader = $this->_registry->get( 'theme.loader' );
        $repeat  = (int) $_REQUEST["repeat"];
        $repeat  = $repeat == 1 ? 1 : 0;
        $post_id = (int) $_REQUEST["post_id"];
        $count   = 100;
        $end     = 0;
        $until   = $time_system->current_time( true );

        // try getting the event
        try {
            $event = $this->_registry->get( 'model.event', $post_id );
            $rule = '';

            if ( $repeat ) {
                $rule = $event->get( 'recurrence_rules' )
                    ? $event->get( 'recurrence_rules' )
                    : '';
            } else {
                $rule = $event->get( 'exception_rules' ) ?
                    $event->get( 'exception_rules' )
                    : '';
            }

            $rule = $this->_registry->get( 'recurrence.rule' )->filter_rule( $rule );

            $rc = new SG_iCal_Recurrence(
                new SG_iCal_Line( 'RRULE:' . $rule )
            );

            if ( $until = $rc->getUntil() ) {
                $until = ( is_numeric( $until ) )
                ? $until
                : strtotime( $until );
                $end = 2;
            } elseif ( $count = $rc->getCount() ) {
                $count = ( is_numeric( $count ) ) ? $count : 100;
                $end = 1;
            }
        } catch( Ai1ec_Event_Not_Found_Exception $e ) {
            $rule = '';
            $rc   = new SG_iCal_Recurrence(
                new SG_iCal_Line( 'RRULE:' )
            );
        }

        $args = array(
            'row_daily'       => $this->row_daily(
                false,
                $rc->getInterval() ? $rc->getInterval() : 1
            ),
            'row_weekly'      => $this->row_weekly(
                false,
                $rc->getInterval() ? $rc->getInterval() : 1,
                is_array( $rc->getByDay() ) ? $rc->getByDay() : array()
            ),
            'row_monthly'     => $this->row_monthly(
                false,
                $rc->getInterval() ? $rc->getInterval() : 1,
                ! $this->_is_monthday_empty( $rc ),
                $rc->getByMonthDay() ? $rc->getByMonthDay() : array(),
                $rc->getByDay() ? $rc->getByDay() : array()
            ),
            'row_yearly'      => $this->row_yearly(
                false,
                $rc->getInterval() ? $rc->getInterval() : 1,
                is_array( $rc->getByMonth() ) ? $rc->getByMonth() : array()
            ),
            'row_custom'      => $this->row_custom(
                false,
                $this->get_date_array_from_rule( $rule )
            ),
            'count'           => $this->create_count_input(
                'ai1ec_count',
                $count
            ) . Ai1ec_I18n::__( 'times' ),
            'end'             => $this->create_end_dropdown( $end ),
            'until'           => $until,
            'repeat'          => $repeat,
            'ending_type'     => $end,
            'selected_tab'    => $rc->getFreq()
                ? strtolower( $rc->getFreq() )
                : 'custom',
        );
        $output = array(
            'error'   => false,
            'message' => $loader->get_file(
                'box_repeat.php',
                $args,
                true
            )->get_content(),
            'repeat'  => $repeat,
        );
        $json_strategy = $this->_registry->get( 'http.response.render.strategy.json' );
        $json_strategy->render( array( 'data' => $output ) );
    }

    /**
     * get_weekday_by_id function
     *
     * Returns weekday name in English
     *
     * @param int $day_id Day ID
     *
     * @return string
     **/
    public function get_weekday_by_id( $day_id, $by_value = false ) {
        // do not translate this !!!
        $week_days = array(
            0 => 'SU',
            1 => 'MO',
            2 => 'TU',
            3 => 'WE',
            4 => 'TH',
            5 => 'FR',
            6 => 'SA',
        );

        if ( $by_value ) {
            while ( $_name = current( $week_days ) ) {
                if ( $_name == $day_id ) {
                    return key( $week_days );
                }
                next( $week_days );
            }
            return false;
        }
        return $week_days[$day_id];
    }

    /**
     * convert_rrule_to_text method
     *
     * Convert a `recurrence rule' to text to display it on screen
     *
     * @return void
     **/
    public function convert_rrule_to_text() {
        $error   = false;
        $message = '';
        // check to see if RRULE is set
        if ( isset( $_REQUEST['rrule'] ) ) {
            // check to see if rrule is empty
            if ( empty( $_REQUEST['rrule'] ) ) {
                $error   = true;
                $message = Ai1ec_I18n::__(
                    'Recurrence rule cannot be empty.'
                );
            } else {
                //list( $rule, $value ) = explode( '=', $_REQUEST['rrule'], 2 );
                //if ( in_array( array(), $rule ) ) {
                //    $message = $this->_registry->get( 'recurrence.date' );
                //
                //} else {
                    $rrule = $this->_registry->get( 'recurrence.rule' );
                    // convert rrule to text
                    $message = ucfirst(
                        $rrule->rrule_to_text( $_REQUEST['rrule'] )
                    );
                    //}
            }
        } else {
            $error   = true;
            $message = Ai1ec_I18n::__(
                'Recurrence rule was not provided.'
            );
        }
        $output = array(
            'error'   => $error,
            'message' => ( version_compare( phpversion(), '7.4.0', '<' ) && function_exists( 'get_magic_quotes_gpc' ) && get_magic_quotes_gpc() )
            ? stripslashes( $message )
            : $message,
        );

        $json_strategy = $this->_registry->get( 'http.response.render.strategy.json' );
        $json_strategy->render( array( 'data' => $output ) );
    }

    /**
     * create_end_dropdown function
     *
     * Outputs the dropdown list for the recurrence end option.
     *
     * @param int $selected The index of the selected option, if any
     * @return void
     **/
    protected function create_end_dropdown( $selected = NULL ) {
        ob_start();

        $options = array(
            0 => Ai1ec_I18n::__( 'Never' ),
            1 => Ai1ec_I18n::__( 'After' ),
            2 => Ai1ec_I18n::__( 'On date' ),
        );

        ?>
        <select name="ai1ec_end" id="ai1ec_end">
                    <?php foreach( $options as $key => $val ): ?>
                        <option value="<?php echo $key ?>"
                <?php if( $key === $selected ) echo 'selected="selected"' ?>>
                            <?php echo $val ?>
                        </option>
                    <?php endforeach ?>
                </select>
        <?php

                $output = ob_get_contents();
                ob_end_clean();

                return $output;
    }

    /**
     * row_daily function
     *
     * Returns daily selector
     *
     * @return void
     **/
    protected function row_daily( $visible = false, $selected = 1 ) {
        $loader = $this->_registry->get( 'theme.loader' );

        $args = array(
            'visible'  => $visible,
            'count'    => $this->create_count_input(
                'ai1ec_daily_count',
                $selected,
                365
            ) . Ai1ec_I18n::__( 'day(s)' ),
        );
        return $loader->get_file( 'row_daily.php', $args, true )
            ->get_content();
    }

    /**
     * row_custom function
     *
     * Returns custom dates selector
     *
     * @return void
     **/
    protected function row_custom( $visible = false, $dates = array() ) {
        $loader = $this->_registry->get( 'theme.loader' );

        $args = array(
            'visible'        => $visible,
            'selected_dates' => implode( ',', $dates )
        );
        return $loader->get_file( 'row_custom.php', $args, true )
            ->get_content();
    }

    /**
     * Generates and returns "End after X times" input
     *
     * @param Integer|NULL $count Initial value of range input
     *
     * @return String Repeat dropdown
     */
    protected function create_count_input( $name, $count = 100, $max = 365 ) {
        ob_start();

        if ( ! $count ) {
            $count = 100;
        }
        ?>
    <input type="range" name="<?php echo $name ?>" id="<?php echo $name ?>"
        min="1" max="<?php echo $max ?>"
        <?php if ( $count ) echo 'value="' . $count . '"' ?> />
    <?php
        return ob_get_clean();
    }

    /**
     * row_weekly function
     *
     * Returns weekly selector
     *
     * @return void
     **/
    protected function row_weekly(
        $visible        = false,
        $count          = 1,
        array $selected = array()
    ) {
        global $wp_locale;
        $start_of_week = $this->_registry->get( 'model.option' )
            ->get( 'start_of_week', 1 );
        $loader = $this->_registry->get( 'theme.loader' );

        $options = array();
        // get days from start_of_week until the last day
        for ( $i = $start_of_week; $i <= 6; ++$i ) {
            $options[$this->get_weekday_by_id( $i )] = $wp_locale
                ->weekday_initial[$wp_locale->weekday[$i]];
        }

        // get days from 0 until start_of_week
        if ( $start_of_week > 0 ) {
            for ( $i = 0; $i < $start_of_week; $i++ ) {
                $options[$this->get_weekday_by_id( $i )] = $wp_locale
                    ->weekday_initial[$wp_locale->weekday[$i]];
            }
        }

        $args = array(
            'visible'    => $visible,
            'count'      => $this->create_count_input(
                'ai1ec_weekly_count',
                $count,
                52
            ) . Ai1ec_I18n::__( 'week(s)' ),
            'week_days'  => $this->create_list_element(
                'ai1ec_weekly_date_select',
                $options,
                $selected
            )
        );
        return $loader->get_file( 'row_weekly.php', $args, true )
            ->get_content();
    }

    /**
     * Creates a grid of weekday, day, or month selection buttons.
     *
     * @return string
     */
    protected function create_list_element(
        $name,
        array $options  = array(),
        array $selected = array()
    ) {
        ob_start();
        ?>
<div class="ai1ec-btn-group-grid" id="<?php echo $name; ?>">
    <?php foreach ( $options as $key => $val ) : ?>
        <div class="ai1ec-pull-left">
            <a class="ai1ec-btn ai1ec-btn-default ai1ec-btn-block
                <?php echo in_array( $key, $selected ) ? 'ai1ec-active' : ''; ?>">
                <?php echo $val; ?>
            </a>
            <input type="hidden" name="<?php echo $name . '_' . $key; ?>"
                value="<?php echo $key; ?>">
        </div class="ai1ec-pull-left">
    <?php endforeach; ?>
</div>
<input type="hidden" name="<?php echo $name; ?>"
    value="<?php echo implode( ',', $selected ) ?>">
<?php
        return ob_get_clean();
    }

    /**
     * row_monthly function
     *
     * Returns monthly selector
     *
     * @return void
     **/
    protected function row_monthly(
        $visible    = false,
        $count      = 1,
        $bymonthday = true,
        $month      = array(),
        $day        = array()
    ) {
        global $wp_locale;
        $start_of_week = $this->_registry->get( 'model.option' )
            ->get( 'start_of_week', 1 );
        $loader = $this->_registry->get( 'theme.loader' );

        $options_wd = array();
        // get days from start_of_week until the last day
        for ( $i = $start_of_week; $i <= 6; ++$i ) {
            $options_wd[$this->get_weekday_by_id( $i )] = $wp_locale
                ->weekday[$i];
        }

        // get days from 0 until start_of_week
        if ( $start_of_week > 0 ) {
            for ( $i = 0; $i < $start_of_week; $i++ ) {
                $options_wd[$this->get_weekday_by_id( $i )] = $wp_locale
                    ->weekday[$i];
            }
        }

        // get options like 1st/2nd/3rd for "day number"
        $options_dn = array( 1 => 1, 2 => 2, 3 => 3, 4 => 4, 5 => 5 );
        foreach ( $options_dn as $_dn ) {
            $options_dn[$_dn] = $this->_registry->get(
                'date.time',
                strtotime( $_dn . '-01-1998 12:00:00' )
            )->format_i18n( 'jS' );
        }
        $options_dn['-1'] = Ai1ec_I18n::__( 'last' );

        $byday_checked       = $bymonthday ? '' : 'checked';
        $byday_expanded      = $bymonthday ? 'ai1ec-collapse' : 'ai1ec-in';
        $bymonthday_checked  = $bymonthday ? 'checked' : '';
        $bymonthday_expanded = $bymonthday ? 'ai1ec-in' : 'ai1ec-collapse';

        $args = array(
            'visible'              => $visible,
            'count'                => $this->create_count_input(
                'ai1ec_monthly_count',
                $count,
                12
            ) . Ai1ec_I18n::__( 'month(s)' ),
            'month'                => $this->create_monthly_date_select(
                $month
            ),
            'day_nums'             => $this->create_select_element(
                'ai1ec_monthly_byday_num',
                $options_dn,
                $this->_get_day_number_from_byday( $day )
            ),
            'week_days'            => $this->create_select_element(
                'ai1ec_monthly_byday_weekday',
                $options_wd,
                $this->_get_day_shortname_from_byday( $day )
            ),
            'bymonthday_checked'  => $bymonthday_checked,
            'byday_checked'       => $byday_checked,
            'bymonthday_expanded' => $bymonthday_expanded,
            'byday_expanded'      => $byday_expanded,
        );
        return $loader->get_file( 'row_monthly.php', $args, true )
            ->get_content();
    }

    /**
     * Creates selector for dates in monthly repeat tab.
     *
     * @return void
     */
    protected function create_monthly_date_select( $selected = array() ) {
        $options = array();
        for ( $i = 1; $i <= 31; ++$i ) {
            $options[$i] = $i;
        }
        return $this->create_list_element(
            'ai1ec_montly_date_select',
            $options,
            $selected
        );
    }

    /**
     * create_on_the_select function
     *
     *
     *
     * @return string
     **/
    protected function create_on_the_select(
        $f_selected = false,
        $s_selected = false
    ) {
        $ret = '';

        $first_options = array(
            '0' => Ai1ec_I18n::__( 'first' ),
            '1' => Ai1ec_I18n::__( 'second' ),
            '2' => Ai1ec_I18n::__( 'third' ),
            '3' => Ai1ec_I18n::__( 'fourth' ),
            '4' => '------',
            '5' => Ai1ec_I18n::__( 'last' )
        );
        $ret = $this->create_select_element(
            'ai1ec_monthly_each_select',
            $first_options,
            $f_selected,
            array( 4 )
        );

        $second_options = array(
            '0'   => Ai1ec_I18n::__( 'Sunday' ),
            '1'   => Ai1ec_I18n::__( 'Monday' ),
            '2'   => Ai1ec_I18n::__( 'Tuesday' ),
            '3'   => Ai1ec_I18n::__( 'Wednesday' ),
            '4'   => Ai1ec_I18n::__( 'Thursday' ),
            '5'   => Ai1ec_I18n::__( 'Friday' ),
            '6'   => Ai1ec_I18n::__( 'Saturday' ),
            '7'   => '--------',
            '8'   => Ai1ec_I18n::__( 'day' ),
            '9'   => Ai1ec_I18n::__( 'weekday' ),
            '10'  => Ai1ec_I18n::__( 'weekend day' )
        );

        return $ret . $this->create_select_element(
            'ai1ec_monthly_on_the_select',
            $second_options,
            $s_selected,
            array( 7 )
        );
    }

    /**
     * create_select_element function
     *
     * Render HTML <select> element
     *
     * @param string $name          Name of element to be rendered
     * @param array  $options       Select <option> values as key=>value pairs
     * @param string $selected      Key to be marked as selected [optional=false]
     * @param array  $disabled_keys List of options to disable [optional=array]
     *
     * @return string Rendered <select> HTML element
     **/
    protected function create_select_element(
        $name,
        array $options       = array(),
        $selected            = false,
        array $disabled_keys = array()
    ) {
        ob_start();
        ?>
    <select name="<?php echo $name ?>" id="<?php echo $name ?>">
                <?php foreach( $options as $key => $val ): ?>
                    <option value="<?php echo $key ?>"
            <?php echo $key === $selected ? 'selected="selected"' : '' ?>
            <?php echo in_array( $key, $disabled_keys ) ? 'disabled' : '' ?>>
                        <?php echo $val ?>
                    </option>
                <?php endforeach ?>
            </select>
    <?php
            return ob_get_clean();
    }

    /**
     * row_yearly function
     *
     * Returns yearly selector
     *
     * @return void
     **/
    protected function row_yearly(
        $visible = false,
        $count   = 1,
        $year    = array(),
        $first   = false,
        $second  = false
    ) {
        $loader = $this->_registry->get( 'theme.loader' );

        $args = array(
            'visible'              => $visible,
            'count'                => $this->create_count_input(
                'ai1ec_yearly_count',
                $count,
                10
            ) . Ai1ec_I18n::__( 'year(s)' ),
            'year'                 => $this->create_yearly_date_select( $year ),
            'on_the_select'        => $this->create_on_the_select(
                $first,
                $second
            ),
        );
        return $loader->get_file( 'row_yearly.php', $args, true )
            ->get_content();
    }

    /**
     * create_yearly_date_select function
     *
     *
     *
     * @return void
     **/
    protected function create_yearly_date_select( $selected = array() ) {
        global $wp_locale;
        $options = array();
        for ( $i = 1; $i <= 12; ++$i ) {
            $options[$i] = $wp_locale->month_abbrev[
            $wp_locale->month[sprintf( '%02d', $i )]
            ];
        }
        return $this->create_list_element(
            'ai1ec_yearly_date_select',
            $options,
            $selected
        );
    }

    /**
     * Converts recurrence rule to array of string of dates.
     *
     * @param string $rule RUle.
     *
     * @return array Array of dates or empty array.
     * @throws Ai1ec_Bootstrap_Exception
     */
    protected function get_date_array_from_rule( $rule ) {
        if (
            'RDATE' !== substr( $rule, 0, 5 ) &&
            'EXDATE' !== substr( $rule, 0, 6 )
        ) {
            return array();
        }
        $line             = new SG_iCal_Line( 'RRULE:' . $rule );
        $dates            = $line->getDataAsArray();
        $dates_as_strings = array();
        foreach ( $dates as $date ) {
            $date = str_replace( array( 'RDATE=', 'EXDATE=' ), '', $date );
            $date = $this->_registry->get( 'date.time', $date )->set_preferred_timezone( 'UTC' );
            $dates_as_strings[] = $date->format( 'm/d/Y' );
        }
        return $dates_as_strings;
    }

    /**
     * Returns whether recurrence rule has non null ByMonthDay.
     *
     * @param SG_iCal_Recurrence $rc iCal class.
     *
     * @return bool True or false.
     */
    protected function _is_monthday_empty( SG_iCal_Recurrence $rc ) {
        return false === $rc->getByMonthDay();
    }

    /**
     * Returns day number from by day array.
     *
     * @param array $day
     *
     * @return bool|int Day of false if empty array.
     */
    protected function _get_day_number_from_byday( array $day ) {
        return isset( $day[0] ) ? (int) $day[0] : false;
    }

    /**
     * Returns string part from "ByDay" recurrence rule.
     *
     * @param array $day Element to parse.
     *
     * @return bool|string False if empty or not matched, otherwise short day
     *                     name.
     */
    protected function _get_day_shortname_from_byday( $day ) {
        if ( empty( $day ) ) {
            return false;
        }
        $value = $day[0];
        if ( preg_match('/[-]?\d([A-Z]+)/', $value, $matches ) ) {
            return $matches[1];
        }
        return false;
    }
}
