<?php

if (! defined('ABSPATH')) {
    return;
}

    class ZnHgFw_Options
    {

        // OLD VAR...
        public $data;

        /**
         *	Will hold all registered option types
         */
        private $_optionTypes = array();

        /**
         *	Will hold all registered forms
         */
        private $_registeredForms = array();

        /**
         *	Holds all instantiated forms
         */
        private $_formInstances = array();

        private $_dataSources = array();

        public function __construct()
        {
            // Enqueue scripts
            add_action('admin_enqueue_scripts', array( $this, 'enqueue_scripts' ));
            add_action('wp_enqueue_scripts', array( $this, 'enqueue_scripts' ));

            // Form save
            // add_action( 'wp_ajax_znhgfw_html_save', array( $this, 'formSave' ) );

            // Register default option types
            $this->registerStandardOptionTypes();

            // Let others know we're in bussiness
            do_action('znhgfw_html_init', $this);
        }

        public function registerStandardOptionTypes()
        {
            //  Load base class
            require(trailingslashit(dirname(__FILE__)) . 'class-base-field.php');
            require(trailingslashit(dirname(__FILE__)) . 'class-base-form.php');
            require(trailingslashit(dirname(__FILE__)) . 'class-base-data-source.php');

            $path = trailingslashit(trailingslashit(dirname(__FILE__)) . 'fields');
            $files = glob($path . '*.php');
            if (is_array($files)) {
                foreach ($files as $file) {

                    // Load the file
                    require($file);

                    // Get the option type name
                    $optionType = str_replace('.php', '', basename($file));
                    // Get the option type class name
                    $optionClass = 'ZnHgFw_Html_' . ucwords($optionType);

                    // Register the option
                    $this->registerOptionType(new $optionClass($this));
                }
            }


            // Register data sources
            $path = trailingslashit(trailingslashit(dirname(__FILE__)) . 'data_source');
            $files = glob($path . '*.php');
            foreach ($files as $file) {
                $optionType = str_replace('.php', '', basename($file));
                $this->registerDataSource(require($file));
            }

            // Register default form type
            // TODO : Move this form to kallyas
            require(trailingslashit(dirname(__FILE__)) . 'forms/theme_form.php');
        }

        public function registerOptionType($optionClassInstance)
        {
            $this->_optionTypes[$optionClassInstance->getType()] = $optionClassInstance;
        }

        public function unregisterOptionType($optionId)
        {
            if (! empty($this->_optionTypes[$optionId])) {
                unset($this->_optionTypes[$optionId]);
            }
        }


        /**
         * Registers a data source type. For example, get all pages
         *
         * @param object $optionClass The data source type Class
         *
         * @return void
         */
        public function registerDataSource($optionClass)
        {
            if (! is_subclass_of($optionClass, 'ZnHgFw_BaseDataSource')) {
                trigger_error(__CLASS__ . 'registerDataSource accepts only a child of ZnHgFw_BaseDataSource class', E_USER_ERROR);
            }

            // Register the data source class
            $this->_dataSources[$optionClass->dataSourceType] = $optionClass;
        }


        /**
         * Will return the data source for an option
         *
         * @param [type] $dataSourceType [description]
         *
         * @return [type] [description]
         */
        public function getDataSource($dataSourceType)
        {
            if (! empty($this->_dataSources[$dataSourceType])) {
                return $this->_dataSources[$dataSourceType]->getSource();
            }

            return array();
        }

        public function addForm($formId, $config = array())
        {

            // Check to see if we got a form type instance
            if ($formId instanceof ZnHgFw_BaseFormType) {
                $formInstance = $formId;
            } else {
                $formInstance = new ZnHgFw_BaseFormType($formId, $config);
            }

            $this->_formInstances[$formInstance->id] = $formInstance;
        }

        public function renderForm($formId)
        {
            // var_dump( $this->_formInstances );
            if (! empty($this->_formInstances[$formId])) {
                return $this->_formInstances[$formId]->render();
            }
        }

        public function renderOption($optionConfig)
        {

            // Check if this is a valid option type
            if (! isset($this->_optionTypes[$optionConfig['type']])) {
                $message = '<div class="znhgfw-error-message">';
                $message .= sprintf(__('The option type (%s) is missing or we don\'t have any knowledge of this option type', 'zn_framework'), $optionConfig['type']);
                $message .= '</div>';
                return $message;
            }

            // Check to see if the option has a data source
            if (! empty($optionConfig['data-source'])) {
                $optionConfig['options'] = $this->getDataSource($optionConfig['data-source']);
            }

            return $this->_optionTypes[$optionConfig['type']]->_render($optionConfig);
        }

        public function enqueue_scripts()
        {
            // Will load all scripts
            // START OLD SCRIPTS
            do_action('znfw_scripts');

            // STYLES
            wp_enqueue_style('dashicons');
            wp_enqueue_style('wp-color-picker');
            wp_enqueue_style('zn_html_css', ZNHGFW()->getFwUrl('assets/dist/css/zn_html_css.css'));

            wp_enqueue_script('wp-color-picker-alpha', ZNHGFW()->getFwUrl('assets/dist/js/wp-color-picker-alpha.min.js'), array('wp-color-picker'), ZNHGFW()->getVersion(), true);
            $color_picker_strings = array(
                'clear'            => __('Clear', 'zn_framework'),
                'clearAriaLabel'   => __('Clear color', 'zn_framework'),
                'defaultString'    => __('Default', 'zn_framework'),
                'defaultAriaLabel' => __('Select default color', 'zn_framework'),
                'pick'             => __('Select Color', 'zn_framework'),
                'defaultLabel'     => __('Color value', 'zn_framework'),
            );
            wp_localize_script('wp-color-picker-alpha', 'wpColorPickerL10n', $color_picker_strings);


            // HTML SCRIPTS
            wp_enqueue_script('jquery-ui-slider'); // HTML
            wp_enqueue_script('jquery-ui-button'); // HTML
            wp_enqueue_script('jquery-ui-draggable'); // HTML + PB
            wp_enqueue_script('jquery-ui-sortable'); // HTML + PB
            wp_enqueue_script('jquery-ui-datepicker'); // HTML

            wp_enqueue_media();

            // Add a dummy editor so we can use functions like wplink
            add_action('wp_footer', array( $this, 'add_dummy_editor' ), 1);
            add_action('admin_footer', array( $this, 'add_dummy_editor' ), 1);

            wp_enqueue_script('zn_timepicker', ZNHGFW()->getFwUrl('assets/dist/js/jquery.timepicker.min.js'), array( 'jquery' ), ZNHGFW()->getVersion(), true);
            wp_enqueue_script('zn_modal', ZNHGFW()->getFwUrl('assets/dist/js/zn_modal.js'), array( 'jquery' ), ZNHGFW()->getVersion(), true);
            wp_enqueue_script('zn_media', ZNHGFW()->getFwUrl('assets/dist/js/zn_media.js'), array( 'jquery' ), ZNHGFW()->getVersion(), true);
            wp_enqueue_script('zn_ace', ZNHGFW()->getFwUrl('assets/dist/js/src-min-noconflict/ace.js'), array( 'jquery' ), ZNHGFW()->getVersion(), true);

            wp_enqueue_script('zn_html_script', ZNHGFW()->getFwUrl('assets/dist/js/zn_html_script.js'), array( 'jquery' ), ZNHGFW()->getVersion(), true);
            wp_localize_script('zn_html_script', 'ZnAjax', array(
                'ajaxurl' => admin_url('admin-ajax.php', 'relative'),
                'security' => wp_create_nonce('zn_framework'),
                'debug' => ZNHGFW()->isDebug(),
            ));

            // END OLD SCRIPTS
            // Load HTML styles
            wp_enqueue_style('znhgfw-html-style', ZNHGFW()->getFwUrl('assets/dist/css/html.css'), array(), ZNHGFW()->getVersion(), 'all');

            // Load all option types extra scripts
            foreach ($this->_optionTypes as $optionType) {
                $optionType->scripts();
            }

            foreach ($this->_formInstances as $formInstance) {
                $formInstance->scripts();
            }
        }

        // TODO : REMOVE THIS ?
        public function add_dummy_editor()
        {
            echo '<div class="zn_hidden">';
            wp_editor('dummy_text', 'zn_dummy_editor_id');
            echo '</div>';
        }

        // function formSave(){
        //
        // 	// check nonces and other security stuff
        // 	if ( ! is_user_logged_in() ) {
        // 		wp_send_json_error( 'unauthenticated' );
        // 	}
        //
        // 	do_action( 'znhgfw_html_form_save' );
        //
        // 	// Perform save action on all forms
        // 	$formId = ! empty( $_POST['formId'] ) ? $_POST['formId'] : false;
        //
        // 	// Bail if we don't have a form id
        // 	if( ! $formId ){
        // 		wp_send_json_error('form_id_missing');
        // 	}
        //
        // 	// Let others hook into this save form
        // 	do_action( 'znhgfw_html_form_save_'. $formId );
        // 	die();
        // }
        // OLD CODE

        public function zn_render_single_option($option)
        {
            $defaults = array(
                'class' => '',
                'placeholder' => '',
                'std' => '',
                'supports' => '',
                'show_blank' => false,
            );

            // Check if we can render this option
            if (isset($option['can_show']) && ! $option['can_show']) {
                return;
            }

            // Sanitize fields
            $option = wp_parse_args($option, $defaults);

            $dynamic_start = (! isset($option['dynamic'])) ? $this->zn_render_option_start($option) : '';
            $dynamic_end = (! isset($option['dynamic'])) ? $this->zn_render_option_end($option) : '';

            if (method_exists($this, $option['type'])) {

                //[[Fixes: #763
                $result = call_user_func(array($this, $option['type']), $option);
                return sprintf('%s%s%s', $dynamic_start, $result, $dynamic_end);
            } else {
                return sprintf('%s%s%s', $dynamic_start, $this->renderOption($option), $dynamic_end);
            }
        }

        public function zn_render_option_start($option)
        {
            $output = '';
            $class = '';
            // SHOW THE TITLE
            if ('group' == $option['type']) {
                $class = 'zn_group_container zn_full';
            }

            $data_atts = '';
            if (isset($option['dependency'])) {
                $dependencies = array();



                // Special case when we only have one dependency
                // This is for old options when multiple dependencies were not available
                if (! empty($option['dependency']['element'])) {

                    // Set the proper dependency element name
                    if (! empty($option['is_in_group'])) {
                        foreach ($option['dependency'] as $key => &$value) {
                            if ('element' === $key) {
                                $value = $option['dependency_id'] . '[' . $value . ']';
                            }
                        }
                    }

                    $dependencies[] = $option['dependency'];
                } else {

                    // Set the proper dependency element name
                    if (! empty($option['is_in_group'])) {
                        foreach ($option['dependency'] as $key => &$dependency) {
                            foreach ($dependency as $key => &$value) {
                                if ('element' === $key) {
                                    $value = $option['dependency_id'] . '[' . $value . ']';
                                }
                            }
                        }
                    }

                    $dependencies = $option['dependency'];
                }

                $config = json_encode($dependencies);
                $data_atts = " data-dependency='{$config}' ";
            }

            /*
             * Check if the options change needs to be done live
             * TYPE : CSS , CLASS
             */
            if (isset($option['live'])) {
                if (! empty($option['is_in_group'])) {
                    $option['live']['is_in_group'] = true;
                }

                $live_config = json_encode($option['live']);
                $data_atts .= " data-live_setup='{$live_config}'";
                $class .= ' zn_live_change ';
            }

            $output .= '<div class="zn_option_container ' . $option['class'] . ' ' . $class . ' clearfix" data-optionid="' . $option['id'] . '" ' . $data_atts . '>';

            if ('hidden' != $option['type'] && ! $option['show_blank']) {
                // Add a label for livechanging options
                $live_text = '';
                if (isset($option['live']) && ! empty($option['name'])) {
                    $live_text = '<span class="zn_live_label">live</span>';
                }
                if (isset($option['deprecated']) && ! empty($option['name'])) {
                    $live_text = '<span class="zn_live_label zn_live_label--deprecated">deprecated</span>';
                }
                if (! empty($option['name'])) {
                    $output .= '<h4>' . $option['name'] . ' ' . $live_text . '</h4>';
                }
            }

            if (! empty($option['description']) && ! $option['show_blank']) {
                $output .= '<p class="zn_option_desc">';
                $output .= $option['description'];
                $output .= '</p>';
            }

            $output .= '<div class="zn_option_content zn_class_' . $option['type'] . '">';

            return $output;
        }

        public function zn_render_option_end($option)
        {
            return '</div></div>';
        }



        /*--------------------------------------------------------------------------------------------------
            Start custom code option
        --------------------------------------------------------------------------------------------------*/
        public function custom_code($option, $stripslashes = true)
        {
            $editor_type = isset($option['editor_type']) ? $option['editor_type'] : 'css';
            if ($stripslashes) {
                $option['std'] = htmlspecialchars(stripslashes($option['std']));
            } else {
                $option['std'] = htmlspecialchars($option['std']);
            }

            $output = '<div class="zn_code_input" id="zn_code_editor_' . $option['id'] . '" data-editor_type="' . $editor_type . '">' . $option['std'] . '</div>';
            $output .= '<textarea class="zn_code_input_textarea zn_hidden" id="' . $option['id'] . '" name="' . $option['id'] . '">' . $option['std'] . '</textarea>';
            return $output;
        }

        /*--------------------------------------------------------------------------------------------------
            Custom HTML
        --------------------------------------------------------------------------------------------------*/
        public function custom_html($option)
        {
            // $option['std'] = htmlspecialchars( stripslashes ( $option['std'] ) );
            return $this->custom_code($option);
        }
        /*--------------------------------------------------------------------------------------------------
            Start Custom css option
        --------------------------------------------------------------------------------------------------*/
        public function custom_css($option)
        {
            $option['std'] = get_option('zn_' . ZNHGTFW()->getThemeId() . '_custom_css', '');
            return $this->custom_code($option, false);
        }

        /*--------------------------------------------------------------------------------------------------
            Start Custom css option
        --------------------------------------------------------------------------------------------------*/
        public function custom_js($option)
        {
            $option['std'] = get_option('zn_' . ZNHGTFW()->getThemeId() . '_custom_js', '');
            return $this->custom_code($option);
        }


        /*--------------------------------------------------------------------------------------------------
            Start Gallery Element
        --------------------------------------------------------------------------------------------------*/
        public function gallery($option)
        {

        // FOR GALLERY
            $defaults = array(
                'media_type' => 'image_gallery',
                'insert_title' => 'Insert gallery', // The text that will appear on the inser button from the media manager
                'button_title' => 'Add / Edit gallery', // The text that will appear as the main option button for adding images
                'title' => 'Add / Edit gallery', // The text that will appear as the main option button for adding images
                'type' => 'image', // The media type : image, video, etc
                'value_type' => 'id', // What to return - url, id
                'state' => 'gallery-library', // The media manager state
                'frame' => 'post', // The media manager frame
                'class' => 'zn-media-gallery media-frame', // The media manager state
            );

            // Set the data
            $option['data'] = ! empty($option['data']) ? wp_parse_args($option['data'], $defaults) : $defaults;
            $option['preview_holder'] = 'No video selected';

            if (! empty($option['std'])) {
                $saved_images = ! empty($option['std']) ? explode(',', $option['std']) : array();
                $option['preview_holder'] = self::get_media_preview($saved_images);
            }

            return $this->zn_media($option);
        }

        // Returns the HTML needed for the gallery type option
        public static function get_media_preview($images)
        {
            $images_holder = '';
            foreach ($images as $image) {
                $image_url = wp_get_attachment_image_src($image, 'thumbnail');
                $images_holder .= '<span class="zn-media-gallery-preview-image"><img src="' . $image_url[0] . '" /></span>';
            }

            return $images_holder;
        }


        /**
         * Generates a video element
         *
         * @param type $option
         *
         * @return string
         */
        public function video_upload($option)
        {

        // FOR Video upload
            $defaults = array(
                'media_type' => 'html5video', // The text that will appear on the inser button from the media manager
                'insert_title' => 'Select video', // The text that will appear on the inser button from the media manager
                'button_title' => 'Add / Edit video', // The text that will appear as the main option button for adding images
                'title' => 'Add / Edit video', // The text that will appear as the main option button for adding images
                'type' => 'video', // The media type : image, video, etc
                'state' => 'video-details', // The media manager state
                'frame' => 'video', // The media manager frame - can be select, post, manage, image, audio, video, edit-attachments
                'class' => 'zn-media-video media-frame', // A css class that will be applied to the modal
            );

            // Set the data
            $option['data'] = ! empty($option['data']) ? wp_parse_args($option['data'], $defaults) : $defaults;
            $option['std'] = stripslashes($option['std']);
            $saved_video_settings = json_decode($option['std'], true);
            $option['preview_holder'] = 'No video selected';

            // Build the preview holder
            if (! empty($saved_video_settings['mp4']) || ! empty($saved_video_settings['ogv']) || ! empty($saved_video_settings['webm'])) {
                $option['preview_holder'] = '<video controls>';

                // Add the mp4 string if the user selected an mp4
                if (! empty($saved_video_settings['mp4'])) {
                    $option['preview_holder'] .= '<source src="' . $saved_video_settings['mp4'] . '" type="video/mp4">';
                }

                if (! empty($saved_video_settings['ogv'])) {
                    $option['preview_holder'] .= '<source src="' . $saved_video_settings['ogv'] . '" type="video/ogg">';
                }

                if (! empty($saved_video_settings['webm'])) {
                    $option['preview_holder'] .= '<source src="' . $saved_video_settings['webm'] . '" type="video/webm">';
                }

                $option['preview_holder'] .= '</video>';
            }

            return $this->zn_media($option);
        }

        /**
         * General WP media select window
         *
         * @param type $option
         *
         * @return type
         */
        public function media_upload($option)
        {
            // FOR GENERAL UPLOADS
            $defaults = array(
                'media_type' => 'media_field_upload', // The text that will appear on the inser button from the media manager
                'insert_title' => 'Select video', // The text that will appear on the inser button from the media manager
                'button_title' => 'Add / Edit video', // The text that will appear as the main option button for adding images
                'title' => 'Add / Edit video', // The text that will appear as the main option button for adding images
                'type' => 'image', // The media type : image, video, etc
                'state' => 'library', // The media manager state
                'frame' => 'select', // The media manager frame - can be select, post, manage, image, audio, video, edit-attachments
                'class' => 'zn-media-video media-frame', // A css class that will be applied to the modal
                'value_type' => 'url', // The media manager state
            );

            $args = wp_parse_args($option['data'], $defaults);
            $data_attributes = self::set_data_attributes($args);
            $option['std'] = esc_html($option['std']);

            $output = '<input id="' . $option['id'] . '" class="zn-media-value-container zn_input zn_input_text" type="text"  name="' . $option['id'] . '" value="' . $option['std'] . '" />';

            // The main button
            $output .= '<div class="zn-main-button zn_media_upload_add zn-add-media-trigger" ' . $data_attributes . '>' . $args['button_title'] . '</div>';

            return $output;
        }

        /*--------------------------------------------------------------------------------------------------
            Main media function
        --------------------------------------------------------------------------------------------------*/
        public function zn_media($option)
        {
            $defaults = array(
                'button_title' => 'Add image',
                'preview' => 'image_holder',
                'preview_holder' => 'Nothing selected',

            );

            $args = wp_parse_args($option['data'], $defaults);
            $preview_holder_class = ! empty($option['std']) ? '' : 'zn-media-preview-holder-empty';
            $data_attributes = self::set_data_attributes($args);
            $option['std'] = esc_html($option['std']);

            $field_type = ('text' == $args['preview']) ? 'text' : 'hidden';

            // The option id where we store the values
            $output = '<input id="' . $option['id'] . '" class="zn-media-value-container zn_input zn_input_text" type="' . $field_type . '"  name="' . $option['id'] . '" value="' . $option['std'] . '" />';

            // The main button
            $output .= '<div class="zn-main-button zn_media_upload_add zn-add-media-trigger" ' . $data_attributes . '>' . $args['button_title'] . '</div>';

            // RENDER THE IMAGE HOLDER
            if ('image_holder' == $args['preview']) {
                $output .= '<div class="zn-media-preview-holder zn_preview_holder_' . $option['data']['media_type'] . ' ' . $preview_holder_class . '">' . $option['preview_holder'] . '</div>';
            }

            return $output;
        }

        // This function prepares the data attributes
        public static function set_data_attributes($data)
        {
            $data_string = "";

            foreach ($data as $key=>$value) {
                if (is_array($value)) {
                    $value = implode(", ", $value);
                }
                $data_string .= " data-$key='$value' ";
            }

            return $data_string;
        }
    }

return new ZnHgFw_Options();
