<?php
/**
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link http://netmonsters.ru 
 * @package Majestic
 * @subpackage form
 * @since 2010-04-25
 * @version SVN: $Id$
 * @filesource $URL$
 */

class FormField
{
    
    protected $validators = array();
    protected $filters = array();
    
    /**
     * Used instead message of validator if defined.
     * 
     * @var string
     */
    protected $default_message = false;
    protected $message = false;
    protected $value;
    
    /* Flags */
    protected $required = true;
    protected $ignored = false;
    
    
    public function __construct($default_message = false)
    {
        $this->default_message = $default_message;
    }
    
    public function setRequired($flag)
    {
        $this->required = (bool) $flag;
        return $this;
    }
    
    public function isRequired()
    {
        return $this->required;
    }
    
    public function setIgnored($flag)
    {
        $this->ignored = (bool) $flag;
        return $this;
    }
    
    public function isIgnored()
    {
        return $this->ignored;
    }
    
    public function addValidators($validators)
    {
        foreach ($validators as $validator) {
            $this->addValidator($validator);
        }
        return $this;
    }
    
    public function addValidator($validator)
    {
        if ($validator instanceof iValidator) {
            $name = get_class($validator);
        } elseif (is_string($validator)) {
            $name = $validator . 'Validator';
            $validator = new $name();
        } else {
            throw new InitializationException('Invalid validator provided to addValidator; must be string or iValidator');
        }
        $this->validators[$name] = $validator;
        return $this;
    }
    
    public function addFilters($filters)
    {
        foreach ($filters as $filter) {
            $this->addFilter($filter);
        }
        return $this;
    }
    
    public function addFilter($filter)
    {
       if ($filter instanceof iFilter) {
            $name = get_class($filter);
        } elseif (is_string($filter)) {
            $name = $filter . 'Filter';
            $filter = new $name();
        } else {
            throw new InitializationException('Invalid filter provided to addFilter; must be string or iFilter');
        }
        $this->filters[$name] = $filter;
        return $this;
    }
    
    public function getValue()
    {
        $value = $this->value;
        if (is_array($value)) {
            array_walk_recursive($value, array($this, 'filterValue'));
        } else {
            $this->filterValue($value, $value);
        }
        return $value;
    }
    
    /**
     * $value & $key for array_walk_recursive
     * 
     * @param mixed $value
     * @param mixed $key
     */
    protected function filterValue(&$value, &$key)
    {
        foreach ($this->filters as $filter) {
            $value = $filter->filter($value);
        }
    }
    
    public function getSourceValue()
    {
        return $this->value;
    }
    
    public function isValid($value, $context = null)
    {
        $this->value = $value;
        // filtered value here
        $value = $this->getValue();
        
        $valid = true;
        
        if ((($value === '') || ($value === null)) && !$this->isRequired()) {
            return $valid;
        }
        
        foreach ($this->validators as $validator) {
            if (is_array($value)) {
                foreach ($value as $val) {
                    if (!$validator->isValid($val, $context)) {
                        $valid = false;
                        if (!$this->default_message) {
                            throw new InitializationException('Define default message for array fields');
                        }
                        $this->message = $this->default_message;
                    }
                }
                if ($valid) {
                    continue;
                }
            } elseif ($validator->isValid($value, $context)) {
                continue;
            }
            
            $valid = false;
            $this->message = ($this->default_message) ? $this->default_message : $validator->getMessage();
            break;
        }
        return $valid;
    }
    
    public function getMessage()
    {
        return $this->message;
    }
}