<?php

defined( 'ABSPATH' ) or exit;   // show a blank page if try to access this file directly

require_once( EWZ_PLUGIN_DIR . "classes/ewz-layout.php" );
require_once( EWZ_PLUGIN_DIR . "classes/validation/ewz-field-input.php" );
require_once( EWZ_PLUGIN_DIR . "classes/validation/ewz-input.php" );

/* Validation for the Layouts page */

class Ewz_Layout_Input extends Ewz_Input {

    /**
     * @param array<mixed> $form_data
     *
     * @return void
     */
    function __construct( $form_data ) {
        parent::__construct( $form_data );
        $customvars = array_keys( Ewz_Custom_Data::$data );
        $xcols = array_merge( array( 'att','aat','aae','aac','atg', 'add','dlc', 'dtu', 'iid', 'wft',
                                     'wid', 'wfm', 'nam', 'fnm', 'lnm', 'mnm', 'mem', 'mid', 'mli' ),
                             $customvars );
        if(!isset($form_data['fields'])){
            $form_data['fields'] = array();
        }
        /* rules('type') specifies the function called to validate, defined either here or in ewz-input.php */
        /* rules('val') defines extra args to pass */
        $this->rules = array(
            'fields'        => array( 'type' => 'v_fields',       'req' => true,  'val' => ['len' => 10] ),
            'forder'        => array( 'type' => 'v_forder',       'req' => true,  'val' => ['len' => 35] ),   //forder_f147_c504_
            'layout_id'     => array( 'type' => 'to_seq',         'req' => false, 'val' => ['len' => 10]),
            'layout_name'   => array( 'type' => 'to_string',      'req' => true,  'val' => ['len' => 60]),
            'max_num_items' => array( 'type' => 'to_seq',         'req' => true,  'val' => ['len' =>  4] ),
            'override'      => array( 'type' => 'to_bool',        'req' => false, 'val' => '' ),
            'notes'         => array( 'type' => 'to_string',      'req' => false, 'val' => ['len' => 500]),
            'ewzmode'       => array( 'type' => 'fixed',          'req' => true,  'val' => 'layout' ),
            'ewznonce'      => array( 'type' => 'anonce',         'req' => true,  'val' => '' ),
            'restrictions'  => array( 'type' => 'v_restrictions', 'req' => false, 'val' => $form_data['fields'] ),
            '_wp_http_referer' => array( 'type' => 'to_string',   'req' => false, 'val' => '' ),
            'extra_cols'    => array( 'type' => 'v_extra_cols',   'req' => false, 'val' => $xcols ),
            'copy_restr_from'=>array( 'type' => 'to_seq',         'req' => false, 'val' => ['len' => 10] ),
        );

        $this->validate();
    }

    /**
     * @return boolean  true on success
     */
    function validate(){
        parent::validate();
        if ( !array_key_exists( 'override', $this->input_data ) ) {
            $this->input_data['override'] = 0;
        }

        foreach ( $this->input_data['forder'] as $col => $value ) {
            $mat = array( );
            preg_match( '/forder_fX?(\d+)_c(X?\d+)_/', $value, $mat );
            // assert( 3 == count( $mat ) );
            $field = $mat[2];
            $this->input_data['fields'][$field]['pg_column'] = $col;

            if( !array_key_exists( 'append', $this->input_data['fields'][$field] ) ){
                $this->input_data['fields'][$field]['append'] = false;
            }
            // ignore "append" in first column
            if( $col == 0 ){
                $this->input_data['fields'][$field]['append'] = false;
            }
        }

        // create empty values for 'restrictions' and 'extra_cols' if they dont exist
        if ( !array_key_exists( 'restrictions', $this->input_data ) ) {
            $this->input_data['restrictions'] = array( );
        }
        if ( !array_key_exists( 'extra_cols', $this->input_data ) ) {
            $this->input_data['extra_cols'] = array( );
        }

        return true;
   }

    //****** All v_.... functions must return true or raise an exception **************/
    /**
     * @param mixed $value
     * @param array<mixed> $arg
     *
     * @return boolean
     */
    function v_extra_cols( &$value, $arg ) {

        if ( !is_array( $value ) ) {
            throw new EWZ_Exception( "Invalid format for extra columns" );
        }
        foreach ( array_keys( $value ) as $key ) {
            if ( !in_array( $key, $arg ) ) {
                throw new EWZ_Exception( "Invalid spreadsheet column type '$key'" );
            }
        }
        $used_cols = array();
        foreach ( $arg as $key ) {
            if ( isset( $value[$key] ) ) {
                if ( !( is_string( $value[$key] ) &&
                        preg_match( '/^\-?\d+$/', $value[$key] ) &&
                        ( int ) $value[$key] >= -1 &&
                        ( int ) $value[$key] <= 1000 ) ) {
                    throw new EWZ_Exception( 'Invalid spreadsheet column ' . $value[$key] );
                }
                $value[$key] = intval( $value[$key] );

                // make sure each ss column ( except -1 )  only assigned once
                if( $value[$key] >= 0  && isset( $used_cols[$value[$key]] ) ){
                    throw new EWZ_Exception( 'Spreadsheet column used twice: ' . ( $value[$key] + 1 ) );
                }
            }
            $used_cols[$value[$key]] = 1;
        }
        return true;
    }

    /**
     * @param mixed $value
     * @param array<mixed> $arg
     *
     * @return boolean
     */
    function v_forder( $value, $arg ) {
        $max = isset( $arg['len'] ) ? $arg['len'] : 50;
        if ( is_array( $value ) ) {
            foreach ( $value as $key => $nm ) {
                if ( !preg_match( '/^\d+$/', $key ) ) {
                    throw new EWZ_Exception( "Invalid key $key" );
                }
                if ( !( is_string( $nm ) && ( strlen($nm) <= $max ) &&
                        preg_match( '/^forder_fX?(\d)+_cX?(\d)+/', $nm ) ) ) {
                    throw new EWZ_Exception( "Invalid field sort order '$key' for $nm" );
                }
            }
        } else {
            throw new EWZ_Exception( "Bad input data for 'forder'" );
        }
        return true;
    }

    /**
     * @param mixed $value
     * @param array<mixed> $arg
     *
     * @return boolean
     */
    function v_fields( &$value, $arg ) {
        if ( is_array( $value ) ) {
            if( count( $value ) == 0 ){
                throw new EWZ_Exception( 'A Layout must have at least one field' );
            }
            foreach ( $value as $key => $fld ) {
                $f = new Ewz_Field_Input( $fld );
                $value[$key] = $f->get_input_data();  // changing, cant use $fld on left
            }
        } else {
            throw new EWZ_Exception( 'Invalid value for field array' );
        }
        return true;
    }

    /**
     * @param mixed $restrictions
     * @param array<mixed> $arg
     *
     * @return boolean
     */
    function v_restrictions( &$restrictions, $arg ) {
        if( !is_array($restrictions) ){
            throw new EWZ_Exception( 'Invalid value for restrictions' );
        }
        foreach ( $restrictions as &$restr ) {
            foreach ( $restr as $key => $value ) {
                if ( $key == 'msg' ) {
                    if ( $value ) {
                        if ( !self::to_string( $restr[$key], array('len' => 100) ) ) {      // also html_entity_decodes the string
                            throw new EWZ_Exception( 'Invalid message for restriction' );
                        }
                    } else {
                        throw new EWZ_Exception( 'Missing message for restriction' );
                    }
                } else {
                    $okkey = 0;
                    $okval = in_array( "$value", array( '~*~', '~-~', '~+~' ) ) ? 1 : 0;
                    foreach ( $arg as $field_id => $field ) {
                        if ( $key == $field_id ) {
                            if( ( $field['field_ident'] == 'followupQ' ) && ( $value != "~*~" ) ){
                                throw new EWZ_Exception( "Restrictions are not allowed on 'followup' fields");
                            } else {
                                $okkey = 1;
                            }
                            if ( !$okval && $field['field_type'] == 'opt' ) {
                                foreach ( $field['fdata']['options'] as $options ) {
                                    if ( $value == $options['value'] ) {
                                        $okval = 1;
                                    }
                                }
                            }
                        }
                    }
                    if ( !$okval || !$okkey ) {
                        if( isset($field['field_header']) ){
                            throw new EWZ_Exception( "Invalid value for restriction on field '" . $field['field_header'] . "'" );
                        } else {
                           throw new EWZ_Exception( "Invalid value for a restriction" );
                        }
                    }
                }
            }
        }
        unset($restr);
        $restrictions = array_values($restrictions);   // otherwise if keys not 0,1,... js reads it as an object instead of array
                                                       // this can happen if a restriction is deleted.
        return true;
    }

}
