<?php
define ('FORM_SUBMIT_BTN_NAME', 'submit_button');

/**
 * Base class for form controls.
 * This class implements basic funcionality of all forms (registering/rendering of fields/buttons/validators without a box 
    and rendering of errors/info prompts).
 */
class MBaseForm extends MContainerControl
{
/**
 * Attribute Description.
 */
    protected $action;

/**
 * Attribute Description.
 */
    public $method;

/**
 * Attribute Description.
 */
    public $buttons;

/**
 * Attribute Description.
 */
    public $fields = array();

/**
 * Attribute Description.
 */
    public $return;

/**
 * Attribute Description.
 */
    public $reset;

/**
 * Attribute Description.
 */
    public $styles;

/**
 * Attribute Description.
 */
    public $width;

/**
 * Attribute Description.
 */
    public $showHints = true;

/**
 * Attribute Description.
 */
    public $enctype;

/**
 * Attribute Description.
 */
    public $validations;

/**
 * Attribute Description.
 */
    public $defaultButton;

/**
 * Attribute Description.
 */
    public $errors;

/**
 * Attribute Description.
 */
    public $infos;

/**
 * Attribute Description.
 */
    static $fieldNum = 0;

/**
 * Attribute Description.
 */
    public $layout;

/**
 * Attribute Description.
 */
    public $zebra = false;

/**
 * Attribute Description.
 */
    public $labelWidth = NULL;

/**
 * Attribute Description.
 */
    public $focus = '';

/**
 * Attribute Description.
 */
    public $ajax;

/**
 * Attribute Description.
 */
    public $cp; // compatibility -> $cp = $ajax;

/**
 * Attribute Description.
 */
    public $box; // compatibility -> $box = a dummy control

/**
 * Attribute Description.
 */
    public $cssForm = false;
    public $cssButtons;
    
    /**
     * This is the constructor of the MBaseForm class. It takes an 
     * action url as optional parameter. The action URL is typically 
     * obtained by calling the <code>MIOLO->getActionURL()</code> method.
     *
     * @param $action (string) the URL for the forms <code>ACTION</code>
     *                attribute.
     */
    public function __construct($action='')
    {
        parent::__construct();
        $this->box = new MFormControl(); // compatibility (a dummy control)
        $this->setId('frm' . uniqid()); 
        $this->method = 'post';
        $this->return = false;
        $this->width  = '95%';
        $this->defaultButton = true;
        $this->fields = array();
        $this->validations = array();
        $this->ajax = $this->manager->ajax;
        $this->cp = $this->ajax;
        $this->createFields();
        if ($this->isSubmitted())
//        if ($this->page->isPostBack)
        { 
            $this->getFormFields(); // set the fields array with form post/get values
        }
        $this->onLoad();
    }
    
/**
 * Brief Description.
 * Complete Description.
 *
 * @param $name (tipo) desc
 * @param $value (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
    public function __set($name, $value)
    {
        if ($name == 'form') return;
        $this->addControl($value);
        $this->fields[$name] = $value;
    }

    
/**
 * Brief Description.
 * Complete Description.
 *
 * @param $name (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
    public function __get($name)
    {
        return $this->fields[$name];
    }

    
/**
 * Brief Description.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
    public function onLoad()
    {
    }

    
/**
 * Brief Description.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
    public function createFields()
    {
    }

/**
 * Brief Description.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
    public function isAjaxCall()
    {
		return ($this->manager->getIsAjaxCall());
    }
    
/**
 * Deprecated; only for compatibility with olf MFormAjax.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
    public function registerMethod()
    {
    }
    

/**
 * Brief Description.
 * Complete Description.
 *
 * @param $validator (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
    public function addValidator($validator)
    {
        $field = $this->{$validator->field};
        $name = '_validator_' . $this->name . '_' . $validator->id . '_' . $validator->field;
        $validator->name  = $name;
        $validator->form  = $this->name;
        $validator->label = ($validator->label == '') ? $field->label : $validator->label;
        $validator->max = $validator->max ? $validator->max : $field->size;
        $this->validations[] = $validator;
        return $name;
    }

/**
 * Brief Description.
 * Complete Description.
 *
 * @param $validator (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
    public function delValidator($field)
    {
        if ($n = count($this->validations))
        {
            for($i = 0; $i < $n; $i++)
            {
                if ($this->validations[$i]->field == $field)
                {
                    $this->validations[$i] = NULL;
                }
            }
        }
    }

    
/**
 * Brief Description.
 * Complete Description.
 *
 * @param $validators (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
    public function setValidators($validators)
    {
       if (is_array($validators))
       {
          foreach($validators as $v)
          {
             $this->addValidator($v);
          }
       }
       elseif (is_subclass_of($validators,'validator'))
       {
             $this->addValidator($validators);
       }
    }

    
    /**
     * Detects if a form has been submitted.
     * 
     * @return (boolean) true if the form has been submitted otherwise false
     */
    public function isSubmitted()
    {   
        $isSubmitted = $this->defaultButton && MForm::getFormValue(FORM_SUBMIT_BTN_NAME);
        if (isset($this->fields))
        {        
            $form = $this->manager->formSubmit;
            $event = MIOLO::_REQUEST($form.'__EVENTTARGETVALUE');
            $eventTokens = explode(':', $event);
            foreach($this->fields as $b)
            {
                $isSubmitted = $isSubmitted || (($b instanceof MButton) && MForm::getFormValue($b->name)) || ($b->name == $eventTokens[0]);
            }
        }
        return $isSubmitted;
    }
    
    
    /**
     * Detects if a form has been submitted.
     * 
     * @return (boolean) true if the form has been submitted otherwise false
     */
    public function setAlternate($color0, $color1)
    {
        $this->zebra = array($color0, $color1);
    }

    
    public function setFocus($fieldName)
    {
        $this->focus = $fieldName;
    }
    
    /**
     * Obtains a submitted form fields's values and sets the array fields
     * Uses $page->request
     */
    public function getFormFields()
    {   
       $this->_getFormFieldValue($this->fields);
    }

    /**
     * Brief Description.
     * Complete Description.
     *
     * @param $field (tipo) desc    
     *
     * @returns (tipo) desc
     *
     */
    protected function _getFormFieldValue($field)
    {   
        if ( is_array($field) )
        {
            foreach($field as $f)
            {
                $this->_getFormFieldValue($f);
            }
        }
        else
        {
            if ($field instanceof MFormControl)
            {
                if ( $field->name )
                {
                    $field->setSubmittedValue();
                }
            }
        }
    }
    
    /**
     * Obtains a submitted form field's value. This is a static function.
     *
     * @param (string) $name
     * @param (string) $value
     * @return (mixed) value of field contained in <code>$HTTP_POST_VARS</code>
     */
    public function getFormValue($name, $value = NULL)
    { 
        $result = '';
        if ( ($name != '') && ((strpos($name,'[')) === false))
        {
           $result = $_REQUEST[$name];
        }

        if (! isset($result))
        {
            $result = $value;
        }
        return $result;
    }

       
    /**
     * Sets the content of a form field to the specified value. The 
     * function does this by setting both, the field's value member and the
     * global <code>$_POST</code> to remain consistency between the values.
     *
     * @param (string) $name Field name 
     * @param (string) $value Value to set to the field
     */
    public function setFormValue($name, $value)
    {   
        $value = MForm::escapeValue($value);
        if (isset($this->$name))
        {
            $this->$name->setValue($value);
        }
        
        // If the fields 
        if (isset($this->fields))
        {
            if ($this->fields[$name])
            {
                $this->fields[$name]= $value;        
            }
        }
        
        $_REQUEST[$name] = $value;
    }
    
    
    /**
     * Used to escapes special characters contained in a form field's value
     * Currently, only simple and double quote characters are subsituted
     * with their corresponding HTML entities.
     *
     * This function is used internally by some of the form's methods.
     *
     * @param (string) $value 
     * @return 
     */
    private function /* PRIVATE */ escapeValue($value)
    {
        if ( is_array($value) )
        {
            for ( $i=0, $n = count($value); $i < $n; $i++ )
            {
                $value[$i] = $this->escapeValue($value[$i]);
            }
        }
        else
        {
            $value = str_replace('\"','&quot;',$value);
            $value = str_replace('"','&quot;',$value);
        }
        return $value;
    }

    
    /**
     * Adds JavaScript code which is to be executed, when the form is submitted.
     * When the form is generated, and any JS code has been registered using
     * this function, an <code>OnSubmit</code> handler is dynamically generated 
     * where the code is placed.
     * 
     * The generated code looks like the following where stmt stands for the
     * registered statments
     *
     * @param (string) $jscode Javascript code
     */
    public function onSubmit($jscode)
    {
        $this->page->onSubmit($jscode);
    }

    
/**
 * Brief Description.
 * Complete Description.
 *
 * @param $jscode (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
    public function addJsCode($jscode)
    {
        $this->page->addJsCode($jscode);
    }
    
    
    /**
     * Sets the action URL for this form. This is the URL to which the
     * form data will be submitted. Usually, the URL is obtained by the
     * GetActionURL of the MIOLO class.
     *
     * @param (string) $action URL of the action
     */
    public function setAction($action)
    {
        $this->action = $action;
    }
    
   
    /**
     * Obtain the list of form fields.
     *
     * @deprecated this function will be changed in the near future, so
     * don't use it anymore and keep in touch with the development team
     * to figure out, what will be the replacement. 
     *
     * @return (array) the list of form fields 
     */
    private function /*PRIVATE*/ getFields()
    {
        return $this->fields;
    }
    
    
    /**
     * This function is used to set an array of fields for the form.
     *
     * @param (array) $fields Fields array
     */
    public function setFields($fields)
    {
        $this->fields = array();
        if (!is_array($fields))
        {
            $fields = array($fields);
        }
        $this->layout = $fields;
        $this->_registerField($fields);
    }
    
    
    /**
     * This function is used internally of the form framework to 
     * <i>prepare</i> the form fields for the usage within the form
     * framework.
     *
     * The function basically renames all fields to 'frm_' + name and
     * assigns the value from the global array <code>$HTTP_POST_VARS</code>
     * if the field has no value (null) assigned.
     *
     * @param $field (reference) to a single field or an array of fields
     *               If an array of fields is passed, the function is called
     *               recursively for each of the contained fields.
     * 
     * @return (nothing)
     */
    private function /*PRIVATE*/ _registerField($field)
    {   
        if ( is_array($field) )
        {
            for ( $i=0, $n = count($field); $i < $n; $i++ )
            {
                $this->_RegisterField($field[$i]);
            }
        }
        else
        {
            if ($field instanceof MFormControl)
            {
                $field->form = $this;
            }
            $className = $field->className;
            if ($field instanceof MFileField)
            {
                $this->enctype='multipart/form-data';
                $this->page->setEnctype($this->enctype);
            }
            $namefield = ($field->name == $field->id) ? $field->name : $field->id;
    	    if ($namefield)
	        {
                $this->manager->assert(!isset($this->$namefield), _M("Err: property [$namefield] already in use in the form [$this->title]! Choose another name to [$namefield]."));
                $this->$namefield = $field;
	        }
            $value = $this->page->request($field->name);
            if ($field instanceof MFormControl)
            {
                if ( ($field instanceof MCheckBox) || ($field instanceof MRadioButton) )
                {
                    // set checked flag of checkbox or radiobutton if the value matches
                    $field->checked = $this->page->isPostBack() ? (isset($value) ? ($value == $field->value) : $field->checked) : $field->checked;
                }
                elseif ( ($field instanceof MIndexedControl) )
                {
                    $this->addFields($field->controls);
                    $field->setValue($value);
                }
                elseif (($field instanceof MInputGrid))
                {
                    $field->setValue($value);
                }
//                else
//                {
//                    $field->setValue($this->escapeValue($field->value));
//                }
                elseif ($field instanceof MInputControl) 
                {
                    if( $field->value == '' )
                    {
                        $field->setValue($value);
                    }
                }
//                else
//                {
//                    $field->setValue($field->value);
//                }
            }
            elseif ($field instanceof MContainer)
            {
                $this->_registerField($field->getControls());
                if ($field instanceof MRadioButtonGroup)
                {
                    $field->setValue($value);
                }
        
            }
            elseif ($field instanceof MDiv)
            {
                $this->_registerField($field->getInner());
            }
        }
    }
    
    /**
     * Adds a single field to the list of form fields and optionally adds
     * a hint text for the field.
     * 
     * @param (object) $field Form field object
     * @param (string) $hint Optional hinto for the form field
     */
    public function addField($field,$hint=false)
    {
        if ( $hint )
        {
            $field->setHint($hint);
        }
        $this->_RegisterField($field);
        $this->layout[] = $field;
    }


    public function addFields($fields)
    {
        if ( is_array($fields) )
        {
           foreach($fields as $f)
           {
              $this->addField($f);
           }
        }
    }
    
    
    /**
     * Add button to the form.
     * This method adds a button to the form. Existing buttons will remaing unchanged.
     *
     * @see setButtons()
     * @see MButton
     * 
     * @param (MButton) $btn Button object
     */
    public function addButton($button)
    {
        if (strtoupper($button->action == 'REPORT'))
        {
           $this->page->hasReport = true;
        }
        $button->form = $this;
        $this->buttons[] = $this->{$button->getId()} = $button;
    }

    
    /**
     * Sets the form buttons.
     * This method adds buttons to the form, but first removes existing ones.
     *
     * @see addButton() 
     * 
     * @param (mixed) $buttons MButton object or array of MButtons
     */
    public function setButtons($buttons)
    {
        $this->clearButtons();
        
        if ( is_array($buttons) )
        {
            for ( $i=0, $n = count($buttons); $i < $n; $i++ )
            {
                $this->addButton($buttons[$i]);
            }
        }
        else
        {
           $this->addButton($buttons);
        }
    }

    /**
     * Set the buttons labels.
     * This function is mainly used, to change the labels of the form's
     * default buttons for submit and return.
     *
     * @param (integer) $index The 0 based index of the button
     * @param (string) $label The new button label
     */
    public function setButtonLabel( $index, $label )
    {
        $this->buttons[$index]->label = $label;
    }

    /**
     * @deprecated This method is deprecated, use setShowReturnButton instead.
     */
    public function showReturn( $state )
    {
        $this->setShowReturnButton( $state );
    }

    /**
     * Return button visibility.
     * Use this function to set the visibility of the form's return button.
     *
     * @param (boolean) $state True to show, false to not show.
     */
    public function setShowReturnButton( $state )
    {
        $this->return = $state;
    }

    /**
     * Post button visibility.
     * Use this method to set the visibility of the Post Button.
     *
     * @param (boolean) $state The visible state of the Post Button
     */
    public function setShowPostButton( $state )
    {
        $this->defaultButton = $state;
    }

    /**
     * @deprecated This method is deprecated, use setShowResetButton instead.
     */
    public function showReset( $state )
    {
        $this->setShowResetButton( $state );
    }

    /**
    * Reset button visibility.
    * This function can be used to show or hide the form's reset button.
    *
    * @param (boolean) $state The visible state of the reset button
    */
    public function setShowResetButton( $state )
    {
        $this->reset = $state;
    }

    /**
     * Form's hints visibility.
     * This function returns the visibility of the form's hint texts.
     *
     * @see ShowHints
     */
    public function getShowHints()
    {
        return $this->showHints;
    }

    /**
     * Set form's hints visibility.
     * This function can be used to show or hide the form's hint texts.
     * Each form element may have a hint text associated with it. Using
     * this method, one can enable/disable the display of the texts. This
     * may be useful for implementing kind of an beginner/expert mode.
     *
     * @param (boolean) $state The visible state of the hint texts
     */
    public function setShowHints( $state )
    {
        $this->showHints = $state;
    }

    /**
     * @deprecated This method is deprecated, use setShowHints instead.
     */
    public function showHints( $state )
    {
        $this->setShowHints ( $state );
    }


    /**
     * Returns form fields list.
     * This is a placeholder function to bu the form's field list. It
     * is excpected, that the form returns a scalar list of all defined 
     * fields which carry a form field value. Thus, form elements of 
     * decorative purpose only should be omitted.
     * <br><br>
     * Derived classes such as <code>TabbedForm</code> override this
     * function to provide the list of fields independently of the form's
     * layout.
     *
     * @returns (array) a scalar array of form fields
     */
    public function getFieldList()
    {
        return $this->_getFieldList($this->fields);
    }

    /**
     * Returns field list.
     * Internal function which takes a list of form elements possibly
     * consisting of single fields as well as arrays and returns a scalar
     * the list of fields filtering out some known decorative form fields.
     *
     * @param  (array) $allfields An array of form fields
     * @return (array) A scalar array of form fields
     */
    private function _getFieldList($allfields)
    {
        $fields = array();
        foreach ($allfields as $f )
        {
            if ( is_array($f) )
            {
                foreach ( $f as $a )
                {
                    if (is_a($a,'MBaseLabel')) continue;
                    $fields[] = $a;
                }
            }
            else
            {
                if ( is_a($f,'MBaseLabel') || is_null($f->value) ) continue;
                $fields[] = $f;
            }
        }
        return $fields;
    }

    public function clearFields()
    {
        $this->fields = NULL;
        $this->layout = NULL;
    }

    public function clearField($name)
    {
        $f = $this->fields[$name];
        $f->addStyle('display','none');
    }


    /**
     * Remove existing buttons on the form.
     */
    public function clearButtons()
    {
        $this->buttons = NULL;
        $this->defaultButton = false;
    }

    /**
     * Validate all form fields.
     * Validates all form fields to have a non-empty content
     * 
     * @param (boolean) $assert Flag how to handle invalid fields;
     *                  if TRUE, an error message will be shown
     *                  if FALSE no error message will be shown and the
     *                  caller can provide an appropriate action based on the
     *                  return value.
     * @returns (boolean) TRUE if all fields have a value;
     *                    FALSE if any of the fields has been left empty
     */
    public function validateAll( $assert=true )
    {
        foreach ( $this->getFieldList() as $f )
        {
            if ( $f->name )
            {
                $required[] = $f->name;
            }
        }
        return $this->validate($required, $assert);
    }

    /**
     * Validates required fields
     *
     * @param (tipo) $assert
     * @return (boolean)
     */
    public function validateRequiredFields( $assert=true )
    {
        foreach ( $this->getFieldList() as $f )
        {
            if ( $f->required )
            {
                $required[] = $f->name;
            }
        }
        return $this->validate( $required, $assert );
    }

    /**
     * Validates the form input
     * Validate form data based on an array of required variable names.
     *
     * @param (array) $required Fields to be validated
     * @param (boolean) $assert Should the program stop if a error is found?
     *
     * @return (boolean) TRUE if all fields have a value;
     *                   FALSE if any of the fields has been left empty
     */
    public function validate( $required, $assert=true )
    {   
        $this->errors = array();
        // collect fields by label
        foreach ( $this->getFieldList() as $f )
        {
            $fields[$f->name] = $f->name;
        }
        foreach ( $required as $r )
        {
            $name  = $r;
            $label = $fields[$name];
            $this->manager->assert( $label,
                            _M("ERROR: Required field [<b><font color=red>$name</font></b>] is not defined in form!") );

            $value = $this->getFormValue( $name );
            if ( $value === '' || (is_null($value)) )
            {
                $this->errors[] = "<b>$label</b> " . _M("was not informed!");
            }
        }
        if ( $assert && count($this->errors) )
        {
            $theme =& $this->manager->getTheme();
            $theme->setContent( $this );
            $theme->generate();
        }
        return count( $this->errors ) == 0;
    }

    /**
     * Regiter the error
     * Registers the error related to the form
     *
     * @param $err (tipo) desc
     * @return (tipo) desc
     */
    public function error( $err )
    {   
        $this->manager->logMessage(_M("[DEPRECATED] Call method Form::error() is deprecated -- use Form::addError() instead!"));
        $this->addError( $err );
    }

    /**
     * Adds the related form error
     *
     * @param (mixed) $err Error message string or array of messages
     */
    public function addError($err)
    {
        if ( $err )
        {
            if ( is_array($err) )
            {
                if ( $this->errors )
                {
                    $this->errors = array_merge($this->errors,$err);
                }
                
                else
                {
                    $this->errors = $err;
                }
            }
            else
            {
                $this->errors[] = $err;
            }
        }
    }

    
    /**
     *  Returns the number of error messages or 0 if no errors exist
     *
     * @return (integer) Error count
     */
    public function hasErrors()
    {
        return count($this->errors);
    }
    
    
    /**
     * Register an information related to the form
     *
     * @param (mixed) $info Information message string or array of messages
     */
    public function addInfo($info)
    {
        if ( $info )
        {
            if ( is_array($info) )
            {
                if ( $this->infos )
                {
                    $this->infos = array_merge($this->infos,$info);
                }
                
                else
                {
                    $this->infos = $info;
                }
            }
            else
            {
                $this->infos[] = $info;
            }
        }
    }

    
    /**
     * Returns the number of info messages or 0, if no info exist
     *
     * @return (integer) Information messages count
     */
    public function hasInfos()
    {
        return count($this->infos);
    }
    
    
    /**
     * Get form data and put it into the classmembers
     */
    public function collectInput($data)
    {           
        foreach ( $this->getFieldList() as $f )
        {
            $field = $f->name;
            if ( $field != '' )
            {
                  $value = $this->getFormValue($field); 
                  $data->$field = $value;
            }
        }
        return $data;
    }

    /**
     * Obtains form fields in a FormData object.
     *
     * @return (Object) Form fields
     */
    public function getData()
    {
        return $this->collectInput( new FormData() );
    }

    /**
     * Set data on the form fields.
     * Set form fields values. A subclassed form will likely override this
     * method, in order to provide a specialized processing for the passed
     * data object. <br><br>
     * This method simply calls the <code>_setData()</code> method of the
     * <code>Form</code> class.
     * @example
     * $data = new FormData();
     * $form->setData( $data );
     *
     * @param $data (MBusiness Object) object containing the field values
     */
    public function setData( MBusiness $data)
    {
        $this->_setData($data);
    }
    
    
    /**
     * This method sets the form field values in way, that it iterates
     * thru the list of fields and sets the values of all fields matching
     * the data object attribute names.
     * 
     * In short it does the following<br>
     * @example 
     * <code>$frm_name = $data->name;</code>
     * 
     * This implies that the form field names must be identical the data
     * member names.
     * 
	 * @param $data (array) Data to be assigned to formfields
 	 *
 	 * @return (void)
 	 */
    private function _setData($data)
    {
        foreach ( $this->fields as $field=>$name)
        {
            $name = $this->fields[$field]->name;
            if ( $name )
            {
                if ( ($this->fields[$field] instanceof MRadioButton) || 
                     ($this->fields[$field] instanceof MCheckBox) )
                {
                    $this->fields[$field]->checked = ( $data->$name == $this->fields[$field]->value );
                }
                else
                { 
                    $value = $data->$name;
                    
                    if ( ($this->fields[$field] instanceof MFormControl) &&
                         (isset($value)) )
                    {
                        $this->fields[$field]->setValue($value);
                        $_POST[$name] = $value;
                    }
                }
            }
        }
    }
    
    
    /**
     * Obtains a form field's value
     */
    public function getFieldValue($name,$value=false)
    {   
        $field = $this->fields[$name];
        return ($field ? $field->getValue() : NULL);
    }
    
    
    /**
     * Set a form field's value
     */
    public function setFieldValue($name,$value)
    {   
        $field = $this->fields[$name];
        $field->setValue($value);
    }
    
    
    /**
     * Set a form field's validator
     */
    public function setFieldValidator($name,$value)
    {   
        for ( $i=0, $n = count($field); $i < $n; $i++ )
        {
            if ( $name == $this->fields[$i]->name )
            {
                $this->fields[$i]->validator = $value;
                break;
            }
        }
    }
    
    
    /**
     * Get a reference for a form field
     */
    public function & getField($name)
    {
        return $this->fields[$name];
    }
    
    
    /**
     * Get a reference for a button
     */
    public function & getButton($name)
    {
        for ( $i=0, $n = count($this->buttons); $i < $n; $i++ )
        {
            if ( $name == $this->buttons[$i]->name )
            {
                return $this->buttons[$i];
            }
        }
    }
    
    
    /**
     * Get a reference for page
     */
    public function & getPage()
    {
        return $this->page;
    }
    
    
    /**
     * Set reference for page
     */
    public function setPage($page)
    {
        $this->page = $page;
    }
    
    
    /**
     * Set a form field's attribute a value
     */
    public function setFieldAttr($name,$attr,$value)
    {   
/*
        if (($attr == 'visible') && (! $value))
        {
            $this->delValidator($name);
        }
*/
        $this->fields[$name]->$attr = $value; 
    }
    
    
    /**
     * Get a form field's attribute value
     */
    public function getFieldAttr($name,$attr, $index=NULL)
    {   
        $field = $this->fields[$name];
        if ( is_array($field->$attr) )
        {
            $a = $field->$attr;
            $value = $a[$index];
        }
        else
        {
          $value = $field->$attr;
        }
        return $value;
    }
    
    
    /**
     * Set a form field's attribute a value
     */
    public function setButtonAttr($name,$attr,$value)
    {   
        $button = &$this->getButton($name);
        $button->$attr = $value;
    }
    
    /**
     * Set a Ajax response
     */
    public function setResponse($controls, $element='')
    { 
        if ($element == '')
        {
            $element = $this->manager->_request('__FORMSUBMIT') . '_content';
        }
        $this->manager->ajax->setResponseControls($controls, $element);
    }


    public function getCloseWindow()
    {
        return $this->manager->getUI()->closeWindow();
    }

   /**
    * Renderize
    *
    * @param (integer) $width
    */
   public function setLabelWidth($width)
   {
        if ( (strpos($width, '%') === false) && (strpos($width, 'px') === false) )
        {
            $width = "{$width}%";
        }
        $this->labelWidth = $width; 
   } 

   public function submit_button()
   {
        $this->setResponse(new stdClass,'');
   }

   /**
    * setFieldsFromXML
    *
    * @param (integer) $width
    */
    public function setFieldsFromXML( $module, $name, $data = NULL, $dir = NULL )
	{
        $controls = $this->manager->getUI()->getXMLView($module, $name, $data, $dir);
        $this->setFields($controls->get('fields'));
        $this->setButtons($controls->get('buttons'));
        $this->setValidators($controls->get('validators'));
	}

    public function setFieldsFromXMLString( $xmlString, $data = NULL)
	{
        $controls = new MXMLControls();    
        $controls->loadString($xmlString, $data);
        $this->setFields($controls->get('fields'));
        $this->setButtons($controls->get('buttons'));
        $this->setValidators($controls->get('validators'));
	}

/**
 * Brief Description.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
   public function generateErrors()
   {    
        $prompt = MPrompt::error($this->errors,'NONE',_M('Errors'));
        return $prompt;
   }
   
   
/**
 * Brief Description.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
   public function generateInfos()
   {    
        $prompt = MPrompt::information($this->infos,'NONE',_M('Information'));
        return $prompt;
   }
   
    
/**
 * Brief Description.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
   public function generateBody()
   {  
        $row = 0;
        $t = array();

        // optionally generate errors
        if ( $this->hasErrors() )
        {
            $t[] = $this->generateErrors();
        }
        if ( $this->hasInfos() )
        {
            $t[] = $this->generateInfos();
        }
        $hidden = null;
        $t = array_merge($t, $this->generateLayoutFields($hidden));
        
        if( method_exists($this->page,'getLayout') )
        {
            $layout = $this->page->theme->getLayout();
        }
        else
        {
            $layout = $this->manager->theme->getLayout();
        }
        
        if ( $layout != 'print')
        {
            $buttons = $this->generateButtons();
            if ($buttons)
            {
                $t = array_merge($t,array($buttons));
            }
        }
        if ($this->action == '')
        {
           $this->action = $this->page->action;
        } 
        $hidden[] = new MHiddenField($this->getId() . '_action',$this->action);

        if ( $hidden )
        {
           $t = array_merge($t,$this->generateHiddenFields($hidden));
        }
        $t = array_merge($t,$this->generateScript());
        $body = new MDiv('',$t);
        return $body;
   }
   
    
/**
 * Brief Description.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
   public function generateFooter()
   {
   }
   
    
/**
 * Brief Description.
 * Complete Description.
 *
 * @param &$hidden (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
   public function generateLayoutFields(&$hidden)
   {  
       $line = 0;  
       $zebra = is_array($this->zebra);
       $t = array();
       if (is_array($this->layout))
       {
           foreach ( $this->layout as $f )
           {
               if ( $f->validator != NULL)
               {
                    if ($f->validator instanceof MValidator)
                    {
                        $this->addValidator($f->validator);
                    }
               }
               else
               {
                    foreach($this->validations as $validator)
                    {
                        if($validator->field == $f->name)
                        {
                            $f->validator = $validator;
                        }
                    }
               }
               $row = $t[] = $this->generateLayoutField($f, $hidden);
               if ($zebra)
               {
                   $row->addStyle('background-color', $this->zebra[($line++) % 2]);
               }
           }
       }
       return $t;
   }

    public function getFieldValidator($name)
    {
        foreach($this->validations as $validator)
        {
            if( $validator && $validator->field == $name )
            {
                return $validator;
            }
        }
        return false;
    }
   
/**
 * Brief Description.
 * Complete Description.
 *
 * @param $f (tipo) desc
 * @param &$hidden (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
    public function generateLayoutField($f, &$hidden)
    {  
        if ( is_array($f) )
        {
            $c = array();
            foreach($f as $fld)
            {
                if ($fld->visible)
                {
                    $c[] = $fld;
                }
            }
            $f = new MHContainer('',$c);
            $f->setShowLabel(true);
        }

        if ( ! $f->visible )
        {
            return;
        }

        $rowContent = NULL;
        $label = $f->label;
        if ( ( ( ($f->className == 'textfield') || ($f->className == 'mtextfield'))  && ($f->size==0) ) || ($f instanceof  MHiddenField) )
        {
            $hidden[] = $f;
            return;
        }

        if ( ( $f->readonly || $f->maintainstate) )
        {
            $hidden[] = $f;
        }

        if ( $f->cssp )
        {
            return $f;
        }
   
        if (($f->formMode != MFormControl::FORM_MODE_SHOW_SIDE) || 
           (($f->formMode == MFormControl::FORM_MODE_SHOW_SIDE) && (! $label)))
        {
            $rowContent[] = $f;
        }
        else
        {

            if ( $label != '' && $label != '&nbsp;' )
            {
                $label .= ':';
            }
            $tf = array();
            if ($label != '') 
            {  
                if ($f->id != '')
                { 
                    $lbl = new MFieldLabel($f->id,$label);

                    if($f->validator && $f->validator->type == 'required')
                    {
                        $lbl->setClass('mCaptionRequired');
                    }
                    else
                    {
                        $lbl->setClass('mCaption');
                    }
                }
                else
                {
                    $lbl = new MSpan('',$label,'mCaption');
                }

                $slbl = $rowContent[] = new MSpan('',$lbl,'label');
                if ($this->labelWidth != NULL)
                {
                    $slbl->setWidth($this->labelWidth);
                }
            }

            $rowContent[] = new MSpan('',$f,'field');

            if ( $this->showHints && $f->hint )
            {
                $hint = new MHint($f->hint);
                $rowContent[] = new MSpan('',$hint,'hint');
            }
/*
            if ($this->labelWidth != NULL)
            {
                $sfld->addStyle('width', (95 - $this->labelWidth).'%');
            }
*/

        }
//        $rowContent[] = new MSpacer();
        $rowContent[] = new MDiv('','','clear');
        return new MDiv('',$rowContent, "mFormRow");
    }

    
/**
 * Brief Description.
 * Complete Description.
 *
 * @returns (tipo) desc
 *
 */
    public function generateButtons()
    {
        $ul = new MUnorderedList();
        if (isset($this->buttons) )
        {
            $c[] = new MHr;
            foreach ( $this->buttons as $b )
            {
                if ($b->visible) $buttons[] = $b;
            }
        }
        if ( $this->reset )
        {
            $buttons[] = new MButton('_reset',_M("Clear"),'RESET');
        }
        if ( $this->return )
        {
            $buttons[] = new MButton('_return',_M("Back"),'RETURN');
        }
        $ul->addOption(new MDiv('',$buttons));
        $d = (count($ul->options) ? new MDiv('',array($c,$ul),'mFormButtonBox') : NULL);
        return ($d ? new MDiv('',$d,'mFormRow') : NULL);
    }


/**
 * Brief Description.
 * Complete Description.
 *
 * @param $hidden (tipo) desc
 *
 * @returns (tipo) desc
 *
 */
    public function generateHiddenFields($hidden)
    {
        $f[] = "\n<!-- START OF HIDDEN FIELDS -->";
        foreach ( $hidden as $h )
        {
            $f[] = new MHiddenField($h->name,$h->value);
        }
        $f[] = "\n<!-- END OF HIDDEN FIELDS -->";
        return $f;
    }

    
    /**
     * Generate form specific script code
     */
    public function generateScript()
    {
        if ($this->focus != '')
        {
            $this->page->onLoad("miolo.getElementById('{$this->focus}').focus();");
        }
        $f = array();
        if ( $this->validations )
        {
            MValidator::generateValidators($this->validations);
        }
        return $f;
    }

    public function generateInner()
    {
        if (!isset($this->buttons))
        {
            if ($this->defaultButton)
            {
                $this->buttons[] = new MButton(FORM_SUBMIT_BTN_NAME, _M("Send"), 'SUBMIT');
            }
        }
        if ($this->cssForm)
        {
            $body = $this->generateBody();
            $this->setControls(array($body));
            $this->setClass('mFormCSS');
            return $this->generate();
        }
        else
        {
            $body = new MDiv('',$this->generateBody(),'mFormBody');
            if (!is_null($this->bgColor))
            {
                $body->addStyle('background-color',$this->bgColor);
            }
/*
            $this->formBox->setControls(array($body, $footer));
//            $id = $this->getId();
            $this->formBox->setClass("m-form-outer");
            $this->setClass("m-form-box");
//            $form = new MDiv($id, $this->formBox,"m-form-box");
//            if (!is_null($this->align)) $form->addStyle('text-align',$this->align);
            if (!is_null($this->align)) $this->addStyle('text-align',$this->align);
            $this->inner = $this->formBox;
*/
            $this->inner = $body;
        }
    }
}

class FormData
{
}

?>
