<?php namespace Majestic\Form;
/**
 * @copyright NetMonsters <team@netmonsters.ru>
 * @link http://netmonsters.ru
 * @package Majestic
 * @subpackage form
 * @since 2010-04-25
 */

class FormField
{
    /**
     * @var iValidator[]
     */
    protected $validators = array();

    /**
     * @var iFilter[]
     */
    protected $filters = array();

    /**
     * Used instead message of validator if defined.
     *
     * @var string
     */
    protected $default_message = false;

    /**
     * @var string
     */
    protected $message = false;

    /**
     * @var mixed
     */
    protected $value;

    /* Flags */
    /**
     * @var bool
     */
    protected $required = true;

    /**
     * @var bool
     */
    protected $ignored = false;


    /**
     * @param bool|string $default_message
     */
    public function __construct($default_message = false)
    {
        $this->default_message = $default_message;
    }

    /**
     * @param bool $flag
     * @return FormField
     */
    public function setRequired($flag)
    {
        $this->required = (bool) $flag;
        return $this;
    }

    /**
     * @return bool
     */
    public function isRequired()
    {
        return $this->required;
    }

    /**
     * @param bool $flag
     * @return FormField
     */
    public function setIgnored($flag)
    {
        $this->ignored = (bool) $flag;
        return $this;
    }

    /**
     * @return bool
     */
    public function isIgnored()
    {
        return $this->ignored;
    }

    /**
     * @param string[]|\Majestic\Validator\iValidator[] $validators
     * @return FormField
     */
    public function addValidators($validators)
    {
        foreach ($validators as $validator) {
            $this->addValidator($validator);
        }
        return $this;
    }

    /**
     * @param string|\Majestic\Validator\iValidator $validator
     * @return FormField
     * @throws \Majestic\Exception\InitializationException
     */
    public function addValidator($validator)
    {
        if ($validator instanceof \Majestic\Validator\iValidator) {
            $name = get_class($validator);
        } elseif (is_string($validator)) {
            $name = $validator . 'Validator';
            $validator = new $name();
        } else {
            throw new \Majestic\Exception\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 \Majestic\Exception\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 \Majestic\Validator\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;
    }
}