<?php

require_once 'abstract.form.php';
require_once 'class.eforms.php';
require_once 'class.field_factory.php';

define("CLASS_NAME_PREFIX", "WPToolset_Field_");

/**
 * FormFactory
 * Creation Form Class
 * @author onTheGo System
 *
 *
 *
 */
class FormFactory extends FormAbstract {

    private $field_count = 0;
    private $form = array();
    private $nameForm;
    private $theForm;
    protected $_validation, $_conditional, $_repetitive, $_use_bootstrap;

    public function __construct( $nameForm = 'default' )
    {
        if ( !isset($GLOBALS[ 'formFactories' ]) ) {
            $GLOBALS[ 'formFactories' ] = array();
        }

        $this->nameForm = $nameForm;
        $this->field_count = 0;
        $this->theForm = new Enlimbo_Forms($nameForm);
		$this->_use_bootstrap = false;

        wp_register_script( 'wptoolset-forms', WPTOOLSET_FORMS_RELPATH . '/js/main.js', array('jquery', 'underscore', 'suggest'), WPTOOLSET_FORMS_VERSION, true );
        wp_enqueue_script( 'wptoolset-forms' );
        $wptoolset_forms_localization = array(
            'ajaxurl' => admin_url( 'admin-ajax.php', null )
        );
        wp_localize_script( 'wptoolset-forms', 'wptoolset_forms_local', $wptoolset_forms_localization );

        if ( Toolset_Utils::is_real_admin() ) {
            wp_register_style( 'wptoolset-forms-admin', WPTOOLSET_FORMS_RELPATH . '/css/wpt-toolset-backend.css', array(), WPTOOLSET_FORMS_VERSION );
            wp_enqueue_style( 'wptoolset-forms-admin' );
        } else {

            /**
             * get cred form settings
             */
            $cred_cred_settings = get_option('cred_cred_settings');
            /**
             * Check loading of CRED front-end stylesheet and legacy one
			 *
			 * @note CRED < 1.9 stores the 'dont_load_cred_css' setting as a zero integer, while CRED >= 1.9 stores it as a zero string
             */
            $load_cred_legacy_css = false;
            $load_cred_bootstrap_css = true;

            if ( is_array( $cred_cred_settings ) ) {
                if ( 
					array_key_exists( 'dont_load_cred_css', $cred_cred_settings ) 
					&& $cred_cred_settings['dont_load_cred_css'] == "0" 
				) {
                    $load_cred_legacy_css = true;
                }
                if ( 
					array_key_exists( 'dont_load_bootstrap_cred_css', $cred_cred_settings ) 
					&& $cred_cred_settings['dont_load_bootstrap_cred_css'] === "1" 
				) {
                    $load_cred_bootstrap_css = false;
                }
				if (
		            array_key_exists( 'use_bootstrap', $cred_cred_settings )
		            && $cred_cred_settings['use_bootstrap']
	            ) {
		            $this->_use_bootstrap = true;
	            }
            }

            /**
             * register
             */
            $bootstrap_dependencies = array();

            if ( $load_cred_legacy_css ) {
                $bootstrap_dependencies[] = "wptoolset-forms-cred-legacy";
            }

            wp_register_style(
                'wptoolset-forms-cred-legacy',
                WPTOOLSET_FORMS_RELPATH . '/css/wpt-toolset-frontend-legacy.css',
                array(),
                WPTOOLSET_FORMS_VERSION
            );

            wp_register_style(
                'wptoolset-forms-cred',
                WPTOOLSET_FORMS_RELPATH . '/css/wpt-toolset-frontend.css',
                $bootstrap_dependencies,
                WPTOOLSET_FORMS_VERSION
            );

            if ( $load_cred_bootstrap_css ) {
                wp_enqueue_style('wptoolset-forms-cred');
            }

        }
    }

    /**
     * (non-PHPdoc)
     * @see classes/FormAbstract::formNameExists()
     */
    public function formNameExists( &$nameForm )
    {
        if ( !in_array($nameForm, $GLOBALS[ 'formFactories' ]) ) {
            $GLOBALS[ 'formFactories' ][] = $nameForm;
            return false;
        } else {
            echo "Form name already exists!";
            return true;
        }
    }

    /**
     * getClassFromType
     * Return the class name from a type
	 * @note Multiselect fields use the Select fields class
     * @param unknown_type $type
     */
    protected function getClassFromType( $type )
    {
		if ( 'multiselect' === strtolower( $type ) ) {
			$type = 'select';
		}
        return CLASS_NAME_PREFIX . ucfirst($type);
    }

    /**
     * (non-PHPdoc)
     * @see classes/FormAbstract::getFieldObject()
     */
    public function getFieldObject( $data, $global_name_field, $value )
    {
        if ( $class = $this->loadFieldClass($data[ 'type' ]) ) {
            return new $class($data, $global_name_field, $value);
        }
        return null;
    }

    /**
     * (non-PHPdoc)
     * @see classes/FormAbstract::addFormField()
     */
    public function addFormField( $data )
    {
        //check mandatory info in data like type and name field
        $global_name_field = $this->nameForm . '_field_' . $this->field_count;
        $obj = $this->getFieldObject($data, $global_name_field);
        $this->form[ $global_name_field ] = $obj->metaform();
        $this->field_count++;
    }

    /**
     * (non-PHPdoc)
     * @see classes/FormAbstract::createForm()
     */
    public function createForm( $nameForm /*= 'default'*/ )
    {
        if ( $this->formNameExists($nameForm) ) {
            return;
        }
        $this->theForm->autoHandle($nameForm, $this->form);

        $out = "";
        $out .= '<form method="post" action="" id="' . $nameForm . '">';
        $out .= $this->theForm->renderElements($this->form);
        //$out .= $this->theForm->renderForm();
        $out .= '</form>';

        return $out;
    }

    /**
     * (non-PHPdoc)
     * @see classes/FormAbstract::displayForm()
     */
    public function displayForm( $nameForm /*= 'default'*/ )
    {
        if ( $this->formNameExists($nameForm) ) {
            return;
        }
        $myform = $this->theForm;
        $this->theForm->autoHandle($nameForm, $this->form);

        echo '<form method="post" action="" id="' . $nameForm . '">';
        echo $this->theForm->renderForm();
        echo '</form>';
    }

    /**
     * metaform
     * @param type $name
     * @param type $type
     * @param type $config
     * @param type $global_name_field
     * @param type $value
     * @return type
     */
    public function metaform($config, $global_name_field, $value) {
        /**
         * add bootstrap, media and Toolset buttons config to every field
         */
		$config['use_bootstrap'] = $this->theForm->form_settings['use_bootstrap'];
        $config['has_media_button'] = isset( $this->theForm->form_settings[ 'has_media_button' ] )
            ? $this->theForm->form_settings[ 'has_media_button' ]
            : false;
        $config['has_toolset_buttons'] = isset( $this->theForm->form_settings[ 'has_toolset_buttons' ] )
            ? $this->theForm->form_settings[ 'has_toolset_buttons' ]
            : false;

        /**
         * WMPL configuration
         */
        $config[ 'wpml_action' ] = $this->get_wpml_action($config[ 'id' ]);

        /**
         * Change config options.
         *
         * This filter allow to chenge value of key 'options' for field config..
         *
         * @since 1.8.0
         *
         * @param array $options Array options for field.
         * @param string $slug Field slug.
         * @param string $type field type
         */
        if (
            isset($config[ 'type' ])
            && isset($config[ 'slug' ])
            && isset($config[ 'options' ])
        ) {
            $config[ 'options' ] = apply_filters(
                'wpcf_config_options_' . $config[ 'type' ],
                $config[ 'options' ],
                $config[ 'slug' ],
                $config[ 'type' ]
            );
        }

        $htmlArray = array();
        $_gnf = $global_name_field;
        $_cfg = $config;
        if ( empty( $value ) )
            $value = array(null);
        elseif ( !is_array( $value ) )
            $value = array($value);
        $count = 0;

        //Fix if i get skype i receive skype i have 2 elements array in $value !!
        if ( $config['type'] == 'skype' ) {
            if ( isset( $value['style'] ) )
                unset( $value['style'] );
            if ( isset( $value['button_style'] ) )
                unset( $value['button_style'] );
        }

        foreach ( $value as $val ) {
            if ( !empty( $config['repetitive'] ) ) {
                $_gnf = $_cfg['name'] = "{$global_name_field}[{$count}]";
            }
            //CHECKGEN			
            if ( isset( $_cfg['validation'] ) &&
                    is_array( $_cfg['validation'] ) &&
                    count( $_cfg['validation'] ) > 0 &&
                    !Toolset_Utils::is_real_admin() && $_SERVER['REQUEST_METHOD'] == 'POST' &&
                    isset( $_GET['_tt'] ) &&
                    !isset( $_GET['_success'] ) &&
                    !isset( $_GET['_success_message'] ) ) {
                $_cfg['validate'] = 1;
            }
            if ( !is_wp_error($field = $this->loadField($_cfg, $_gnf, $val)) ) {
                $form = $field->metaform();
                // Set $config['validate'] to trigger PHP validation
                // when rendering metaform
                if ( !empty($_cfg[ 'validate' ]) &&
                    is_wp_error($valid = $this->validateField($field, $val))
                ) {
                    $key = key($form);
                    $error = $valid->get_error_data();
                    if ( is_array($error) ) {
                        $error = array_shift($error);
                    }
                    $form[ $key ][ '#error' ] = $error;
                }

                if ( isset($_cfg[ 'validation_error' ]) ) {
                    $key = key($form);
                    $form[ $key ][ '#error' ] = $_cfg[ 'validation_error' ];
                }
                $this->form[ $global_name_field ] = $form;
                $this->field_count++;
                $htmlArray[] = $this->theForm->renderElements($form);
                if ( empty($config[ 'repetitive' ]) ) {
                    break;
                }
                $count++;
            } else {
                if ( current_user_can( 'manage_options' ) ) {
                    $htmlArray[] = sprintf(
                        '<div id="message" class="error"><p>%s</p><p>%s</p></div>',
                        //https://icanlocalize.basecamphq.com/projects/7393061-toolset/todo_items/196628627/comments#310360880
                        //changed render to rendering
                        sprintf(
                            __('There is a problem rendering field <strong>%s (%s)</strong>.', 'wpv-views'),
                            $_cfg[ 'title' ],
                            $_cfg[ 'type' ]
                        ),
                        $field->get_error_message()
                    );
                }
            }
        }
        if ( !empty($htmlArray) && isset($config[ 'repetitive' ]) && $config[ 'repetitive' ] ) {
            $_gnf = $_cfg[ 'name' ] = "{$global_name_field}[%%{$count}%%]";
            if ( !is_wp_error($field = $this->loadField($_cfg, $_gnf, null)) ) {
                $tpl = $this->_tplItem($config,
                    $this->theForm->renderElements($field->metaform()));
                $this->_repetitive()->add($config, $tpl);
            }
        }

        return !empty($htmlArray) ? $this->_tpl($config, $htmlArray) : '';
    }

    /**
     *
     * @staticvar array $loaded
     * @param type $config
     * @param string $global_name_field
     * @param type $value
     * @return \WP_Error|\class
     */
    public function loadField( $config, $global_name_field, $value )
    {
        global $wp_version;
        static $loaded = array();
        $type = $config[ 'type' ];
        $global_name_field = $this->nameForm . '_field_' . $this->field_count;
        $field = $this->getFieldObject($config, $global_name_field, $value);

        if ( is_null($field) ) {
            return new WP_Error('wptoolset_forms', 'wrong field type');
        }

        $settings = $field->getSettings();
        if ( isset($settings[ 'min_wp_version' ]) && version_compare($wp_version,
                $settings[ 'min_wp_version' ], '<')
        ) {
            return new WP_Error('wptoolset_forms', 'Higher WP version required');
        }

        $this->_setGlobalField($field);

        // Load/enqueue scripts
        if ( !isset($loaded[ $type ]) ) {
            $loaded[ $type ] = 1;
            // These should be performed only once
            $field->registerScripts();
            $field->registerStyles();
            $field->enqueueScripts();
            $field->enqueueStyles();
            $field->addFilters();
            $field->addActions();
        }
        $this->_checkValidation($config);
        $this->_checkConditional($config);

        return $field;
    }

    protected function _checkValidation( $config )
    {
        if ( isset($config[ 'validation' ]) && is_null($this->_validation) ) {
            require_once 'class.validation.php';
            $this->_validation = new WPToolset_Forms_Validation($this->nameForm, isset($config[ 'form_settings' ]) ? $config[ 'form_settings' ] : "");
        }
    }

    protected function _checkConditional( $config )
    {
        if ( !empty($config[ 'conditional' ]) ) {
            $this->getConditionalClass()->add($config);
        }
    }

    public function addConditional( $config )
    {
        $this->getConditionalClass()->add($config);
    }

    public function getConditionalClass()
    {
        if ( is_null($this->_conditional) ) {
            require_once 'class.conditional.php';
            $this->_conditional = new WPToolset_Forms_Conditional($this->nameForm);
        }
        return $this->_conditional;
    }

    protected function _repetitive()
    {
        if ( is_null($this->_repetitive) ) {
            require_once 'class.repetitive.php';
            $this->_repetitive = new WPToolset_Forms_Repetitive();
        }
        return $this->_repetitive;
    }

    protected function _tpl( $cfg, $html )
    {
        ob_start();
        include WPTOOLSET_FORMS_ABSPATH . '/templates/metaform.php';
        $o = ob_get_contents();
        ob_get_clean();
        return $o;
    }

    protected function _tplItem( $cfg, $out )
    {
        ob_start();
        include WPTOOLSET_FORMS_ABSPATH . '/templates/metaform-item.php';
        $o = ob_get_contents();
        ob_get_clean();
        return $o;
    }

    static $_validate_flag = array();

    public function validateField( $field, $value )
    {
        if ( is_array($field) ) {
            $field = $this->loadField($field, $field[ 'name' ], $value);
        }

        /**
         * Temporary fixing validation for checkbox/radios/skype because _cakeValidation is not working for thats
         * https://icanlocalize.basecamphq.com/projects/7393061-toolset/todo_items/186243370/comments
         */
        if ( !Toolset_Utils::is_real_admin() ) {
            //I receive wpcf-id and wpcf[id] for the same type
            if ( $field->getId() == $field->getName() &&
                    ($field->getType() == 'checkbox' ||
                    $field->getType() == 'radios' ||
                    $field->getType() == 'skype' )
            ) {
                //https://icanlocalize.basecamphq.com/projects/7393061-toolset/todo_items/188604193/comments
                //added sanitize_text_field for sucuri warning php.backdoor.eval_POST.010
                $field_value = isset( $_POST[$field->getName()] ) ? sanitize_text_field( $_POST[$field->getName()] ) : "";
                if ( $field->getType() == 'skype' ) {
                    $field_value = isset( $_POST[$field->getName()]['skypename'] ) ? sanitize_text_field( $_POST[$field->getName()]['skypename'] ) : "";
                }
                //##########################################################################################

                $_tmp = $field->getValidationData();
                if ( isset( $_tmp['required'] ) &&
                        !isset( $field_value ) ) {
                    $mess = $field->getTitle() . ' Field is required';
                    return new WP_Error( 'wptoolset_forms', $mess, array($field->getTitle() . ' Field is required') );
                }
            }
        }
        //****************************************************************

        if ( !is_wp_error( $field ) ) {
            if ( $field->getValidationData() ) {
                return $this->_validation->validateField($field);
            }
            return true;
        }
        return new WP_Error( 'wptoolset_forms', 'Field do not exist', array('Field do not exist') );
    }

    protected function _setGlobalField($field) {
        global $wptoolset_field;
        $wptoolset_field = $field;
    }

    public function __toString()
    {
        return join("\n", $this->elements);
    }

    public function loadFieldClass($type) {
        $type = strtolower( $type );
        $class = $this->getClassFromType( $type );

        /**
         * try to load custom class
         */
        $loader = $class . '_loader';
        if ( function_exists( $loader ) ) {
            $loader();
        }

        if ( !class_exists($class) ) {
            $file = apply_filters('wptoolset_load_field_class_file', WPTOOLSET_FORMS_ABSPATH . "/classes/class.{$type}.php", $type);
            if ( file_exists($file) ) {
                require_once $file;
                return $class;
            } else {
                // third party fields array $type => __FILE__
                $third_party_fields = apply_filters( 'wptoolset_registered_fields', array() );
                if ( isset( $third_party_fields[$type] ) && file_exists( $third_party_fields[$type] ) ) {
                    require_once $third_party_fields[$type];
                    return $class;
                }
            }
        }
        return class_exists($class) ? $class : false;
    }

    private function get_wpml_action($id) {
        global $iclTranslationManagement;
        if (
                is_object( $iclTranslationManagement ) && 'TranslationManagement' == get_class( $iclTranslationManagement ) && isset( $iclTranslationManagement->settings['custom_fields_translation'][$id] )
        ) {
            return $iclTranslationManagement->settings[ 'custom_fields_translation' ][ $id ];
        }
        return 0;
    }
}