<?php

/**
 * Routing (management) base class
 *
 * @author     Time.ly Network Inc.
 * @since      2.0
 *
 * @package    AI1EC
 * @subpackage AI1EC.Routing
 */

class Ai1ec_Router extends Ai1ec_Base {

    /**
     * @var boolean
     */
    private $at_least_one_filter_set_in_request;

    /**
     * @var string Calendar base url
     */
    protected $_calendar_base = null;

    /**
     * @var string Base URL of WP installation
     */
    protected $_site_url = NULL;

    /**
     * @var Ai1ec_Adapter_Query_Interface Query manager object
     */
    protected $_query_manager = null;

    /**
     * @var Ai1ec_Cookie_Present_Dto
     */
    protected $cookie_set_dto;

    /**
     * @var array Rewrite structure.
     */
    protected $_rewrite = null;

    /**
     * Check if at least one filter is set in the request
     *
     * @param array $view_args
     * @return boolean
     */
    public function is_at_least_one_filter_set_in_request( array $view_args ) {
        if ( null === $this->at_least_one_filter_set_in_request ) {
            $filter_set = false;
            $ai1ec_settings = $this->_registry->get( 'model.settings' );
            // check if something in the filters is set
            $types          = apply_filters(
                'ai1ec_filter_types',
                Ai1ec_Cookie_Utility::$types
            );
            foreach ( $types as $type ) {
                if (
                    ! is_array( $type ) &&
                    isset( $view_args[$type] ) &&
                    ! empty( $view_args[$type] )
                ) {
                    $filter_set = true;
                    break;
                }
            }
            // check if the default view is set
            $mode = wp_is_mobile() ? '_mobile' : '';
            $setting = 'default_calendar_view' . $mode;
            if ( $ai1ec_settings->get( $setting ) !== $view_args['action'] ) {
                $filter_set = true;
            }
            $this->at_least_one_filter_set_in_request = $filter_set;
        }
        return $this->at_least_one_filter_set_in_request;
    }

    /**
     * @return the $cookie_set_dto
     */
    public function get_cookie_set_dto() {
        $utility = $this->_registry->get( 'cookie.utility' );
        if( null === $this->cookie_set_dto ) {
            $this->cookie_set_dto =  $utility->is_cookie_set_for_current_page();
        }
        return $this->cookie_set_dto;
    }

    /**
     * @param Ai1ec_Cookie_Present_Dto $cookie_set_dto
     */
    public function set_cookie_set_dto( Ai1ec_Cookie_Present_Dto $cookie_set_dto = null ) {
        $this->cookie_set_dto = $cookie_set_dto;
    }

    /**
     * Set base (AI1EC) URI
     *
     * @param string $url Base URI (i.e. http://www.example.com/calendar)
     *
     * @return Ai1ec_Router Object itself
     */
    public function asset_base( $url ) {
        $this->_calendar_base = $url;
        return $this;
    }

    /**
     * Get base URL of WP installation
     *
     * @return string URL where WP is installed
     */
    public function get_site_url() {
        if ( null === $this->_site_url ) {
            $this->_site_url = ai1ec_site_url();
        }
        return $this->_site_url;
    }

    /**
     * Generate (update) URI
     *
     * @param array     $arguments List of arguments to inject into AI1EC group
     * @param string $page        Page URI to modify
     *
     * @return string Generated URI
     */
    public function uri( array $arguments, $page = NULL ) {
        if ( NULL === $page ) {
            $page = $this->_calendar_base;
        }
        $uri_parser = new Ai1ec_Uri();
        $parsed_url = $uri_parser->parse( $page );
        $parsed_url['ai1ec'] = array_merge(
            $parsed_url['ai1ec'],
            $arguments
        );
        $result_uri = $uri_parser->write( $parsed_url );

        return $result_uri;
    }

    /**
     * Properly capitalize encoded URL sequence.
     *
     * @param string $url Original URL to use.
     *
     * @return string Modified URL.
     */
    protected function _fix_encoded_uri( $url ) {
        $particles = preg_split(
            '|(%[a-f0-9]{2})|',
            $url,
            -1,
            PREG_SPLIT_DELIM_CAPTURE|PREG_SPLIT_NO_EMPTY
        );
        $state  = false;
        $output = '';
        foreach ( $particles as $particle ) {
            if ( '%' === $particle ) {
                $state = true;
            } else {
                if ( ! $state && '%' === $particle{0} ) {
                    $particle = strtoupper( $particle );
                }
                $state = false;
            }
            $output .= $particle;
        }
        return $output;
    }

    /**
     * Register rewrite rule to enable work with pretty URIs
     */
    public function register_rewrite( $rewrite_to ) {
        if (
            ! $this->_calendar_base &&
            ! $this->_query_manager->rewrite_enabled()
        ) {
            return $this;
        }
        $base = basename( $this->_calendar_base );
        if ( false !== strpos( $base, '?' ) ) {
            return $this;
        }
        $base       = $this->_fix_encoded_uri( $base );
        $base       = '(?:.+/)?' . $base;
        $named_args = str_replace(
            '[:DS:]',
            preg_quote( Ai1ec_Uri::DIRECTION_SEPARATOR ),
            '[a-z][a-z0-9\-_[:DS:]\/]*[:DS:][a-z0-9\-_[:DS:]\/]'
        );

        $regexp     = $base . '(\/' . $named_args . ')';
        $clean_base = trim( $this->_calendar_base, '/' );
        $clean_site = trim( $this->get_site_url(), '/' );
        if ( 0 === strcmp( $clean_base, $clean_site ) ) {
            $regexp     = '(' . $named_args . ')';
            $rewrite_to = remove_query_arg( 'pagename', $rewrite_to );
        }
        $this->_query_manager->register_rule(
            $regexp,
            $rewrite_to
        );
        $this->_rewrite = array(
            'mask'   => $regexp,
            'target' => $rewrite_to,
        );
        add_filter(
            'rewrite_rules_array',
            array( $this, 'rewrite_rules_array' )
        );
        return $this;
    }

    /**
     * Initiate internal variables
     */
    public function __construct( Ai1ec_Registry_Object $registry ) {
        parent::__construct( $registry );
        $this->_query_manager = $registry->get( 'query.helper' );
    }

    /**
     * Checks if calendar rewrite rule is registered.
     *
     * @param array $rules Rewrite rules.
     *
     * @return array Rewrite rules.
     */
    public function rewrite_rules_array( $rules ) {
        if ( null !== $this->_rewrite ) {
            $newrules[$this->_rewrite['mask']] = $this->_rewrite['target'];
            $rules = array_merge( $newrules, $rules );
        }
        return $rules;
    }

}
