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

require_once dirname(__FILE__) . '/../../validator/iValidator.php';
require_once dirname(__FILE__) . '/../../validator/Validator.php';
require_once dirname(__FILE__) . '/../../validator/NotEmptyValidator.php';
require_once dirname(__FILE__) . '/../../validator/RegexValidator.php';
require_once dirname(__FILE__) . '/../../validator/EmailValidator.php';
require_once dirname(__FILE__) . '/../../form/FormField.php';
require_once dirname(__FILE__) . '/../../exception/InitializationException.php';

class FormFieldTest extends PHPUnit_Framework_TestCase
{
    public function testSetRequired()
    {
        $form_field = new FormField();

        $this->assertTrue($form_field->isRequired());
        $return_object = $form_field->setRequired(false);
        $this->assertInstanceOf('FormField', $return_object);
        $this->assertSame($form_field, $return_object);
        $this->assertFalse($form_field->isRequired());
    }

    public function testSetIgnored()
    {
        $form_field = new FormField();

        $this->assertFalse($form_field->isIgnored());
        $return_object = $form_field->setIgnored(true);
        $this->assertInstanceOf('FormField', $return_object);
        $this->assertSame($form_field, $return_object);
        $this->assertTrue($form_field->isIgnored());
    }

    public function testIsIgnored()
    {
        $class_name = 'FormField';
        $form_field = new $class_name();
        $this->assertFalse($form_field->isIgnored());
        $form_field->setIgnored(true);
        $this->assertTrue($form_field->isIgnored());
    }

    public function testIsRequired()
    {
        $class_name = 'FormField';
        $form_field = new $class_name();
        $this->assertTrue($form_field->isRequired());
        $form_field->setRequired(false);
        $this->assertFalse($form_field->isRequired());
    }

    public function testAddValidators()
    {
        $validators = array(
            'NotEmpty' => new NotEmptyValidator(),
            'Email' => new EmailValidator()
        );

        $this->assertInstanceOf('iValidator', $validators['NotEmpty']);
        $this->assertInstanceOf('iValidator', $validators['Email']);
        $form_field = new FormField();
        $return_object = $form_field->addValidators($validators);
        $array = array('NotEmptyValidator' => new NotEmptyValidator(), 'EmailValidator' => new EmailValidator());
        $this->assertAttributeEquals($array, 'validators', $form_field);
        $this->assertSame($form_field, $return_object);
    }

    public function testAddValidatorObject()
    {
        $validator = new NotEmptyValidator();
        $array = array('NotEmptyValidator' => new NotEmptyValidator());
        $form_field = new FormField();

        $return_object = $form_field->addValidator($validator);
        $this->assertAttributeEquals($array, 'validators', $form_field);
        $this->assertSame($form_field, $return_object);
    }

    public function testAddValidatorString()
    {
        $form_field = new FormField();
        $return_object = $form_field->addValidator('NotEmpty');

        $array = array('NotEmptyValidator' => new NotEmptyValidator());
        $this->assertAttributeEquals($array, 'validators', $form_field);
        $this->assertSame($form_field, $return_object);
    }

    public function testAddValidatorElse()
    {
        $validator = true;
        $tmp_form_field = new FormField();
        // @TODO Fix exception type
        $this->setExpectedException('InitializationException', 'Invalid validator provided to addValidator; must be string or iValidator'); // Text of Exception
        $tmp_form_field->addValidator($validator);
    }

    public function testAddFilters()
    {
        $array = array('loginFilter' => new loginFilter(), 'passwordFilter' => new passwordFilter());
        $this->assertInstanceOf('iFilter', $array['loginFilter']);
        $this->assertInstanceOf('iFilter', $array['passwordFilter']);

        $form_field = new FormField();
        $return_object = $form_field->addFilters($array);
        $this->assertAttributeEquals($array, 'filters', $form_field);
        $this->assertSame($form_field, $return_object);
    }

    public function testAddFilterObject()
    {
        $filter = new loginFilter();
        $array = array('loginFilter' => new loginFilter());
        $this->assertInstanceOf('iFilter', new loginFilter());
        $form_field = new FormField();
        $return_object = $form_field->addFilter($filter);

        $this->assertAttributeEquals($array, 'filters', $form_field);
        $this->assertSame($form_field, $return_object);
    }

    public function testAddFilterString()
    {
        $form_field = new FormField();
        $array = array('loginFilter' => new loginFilter());
        $this->assertInstanceOf('iFilter', new loginFilter());
        $return_object = $form_field->addFilter('login');

        $this->assertAttributeEquals($array, 'filters', $form_field);
        $this->assertSame($form_field, $return_object);
    }

    public function testAddFilterElse()
    {
        $filter = new NotEmptyValidator();
        $form_field = new FormField();
        // @TODO Fix exception type
        $this->setExpectedException('InitializationException', 'Invalid filter provided to addFilter; must be string or iFilter'); // Text of exception
        $form_field->addFilter($filter);
    }

    public function testGetValueArray()
    {
        $test_array = array(
            'login' => 'login',
            'password' => 'password'
        );
        $form_field = new FormField();
        $form_field->addFilter('Login');
        $this->assertTrue($form_field->isValid($test_array));
        $this->assertAttributeInternalType('array', 'value', $form_field);
        $value = $form_field->getValue();

        $this->assertArrayHasKey('login', $value);
        $this->assertArrayHasKey('password', $value);
        $this->assertSame(array('login' => 'login',
                               'password' => ''), $value);
    }

    public function testGetValueStringCorrect()
    {
        $test_string = 'login';
        $form_field = new FormField();
        $form_field->addFilter('Login');

        $this->assertTrue($form_field->isValid($test_string));
        $this->assertAttributeNotInternalType('array', 'value', $form_field);
        $this->assertSame('login', $form_field->getValue());
    }

    public function testGetValueStringIncorrect()
    {
        $test_string = 'password';
        $form_field = new FormField();
        $form_field->addFilter('Login');

        $this->assertTrue($form_field->isValid($test_string));
        $this->assertAttributeNotInternalType('array', 'value', $form_field);
        $this->assertSame('', $form_field->getValue());
    }

    public function testGetMessageDefault()
    {
        $form_field = new FormField();
        $this->assertFalse($form_field->getMessage());
        $form_field->addValidator('NotEmpty');

        $this->assertFalse($form_field->isValid(''));
        $this->assertSame('Value is required and can\'t be empty', $form_field->getMessage());
    }

    public function testGetMessageCustom()
    {
        $message = 'Test message';
        $form_field = new FormField($message);
        $this->assertFalse($form_field->getMessage());
        $form_field->addValidator('NotEmpty');

        $this->assertFalse($form_field->isValid(''));
        $this->assertSame($message, $form_field->getMessage());
    }

    public function testIsValidArrayMissingDefaultMessage()
    {
        $test_array = array(
            'login' => '',
            'password' => ''
        );
        $form_field = new FormField();
        $form_field->addValidator('NotEmpty');
        $this->setExpectedException('InitializationException', 'Define default message for array fields');
        $form_field->isValid($test_array);
    }

    public function testIsValidArrayMissingCustomMessage()
    {
        $message = 'Test message';
        $test_array = array(
            'login' => '',
            'password' => ''
        );
        $form_field = new FormField($message);
        $return_object = $form_field->addValidator('NotEmpty');
        $array = array('NotEmptyValidator' => new NotEmptyValidator());
        $this->assertAttributeEquals($array, 'validators', $form_field);
        $this->assertSame($form_field, $return_object);
        $this->assertFalse($form_field->isValid($test_array));
        $this->assertSame($message, $form_field->getMessage());
    }

    public function testIsValidMissingNotRequired()
    {
        $form_field = new FormField();
        $form_field->setRequired(false);
        $this->assertTrue($form_field->isValid(''));
    }

    public function testIsValidArray()
    {
        $test_array = array(
            'login' => 'login',
            'password' => 'password'
        );
        $validator = new NotEmptyValidator();
        $form_field = new FormField();
        $return_object = $form_field->addValidator($validator);
        $this->assertTrue($form_field->isValid($test_array));
    }

    public function testIsValidScalar()
    {
        $test = 'password';
        $validator = new NotEmptyValidator();
        $form_field = new FormField();
        $return_object = $form_field->addValidator($validator);
        $this->assertTrue($form_field->isValid($test));
    }

    public function testGetSourceValue()
    {
        $test_array = array(
            'login' => ' login ',
            'password' => ''
        );
        $form_field = new FormField('Custom message');
        $form_field->addFilter('login');
        $form_field->addValidator('NotEmpty');
        $this->assertFalse($form_field->isValid($test_array));
        $this->assertSame(array('login' => 'login', 'password' => ''), $form_field->getValue());
        $this->assertNotSame($test_array, $form_field->getValue());
        $this->assertSame($test_array, $form_field->getSourceValue());
    }

    public function testFilterValue()
    {
        $input = ' login ';
        $form_field = new FormField();
        $form_field->isValid($input);
        $form_field->addFilter('login');
        $lf = new loginFilter();
        $this->assertSame($form_field->getValue(), $lf->filter($input));
    }
}

interface iFilter
{
    public function isValid($value, $context = null);

    public function filter($value);

    public function getMessage();
}

class loginFilter implements iFilter
{
    public function filter($value)
    {
        $value = trim($value);
        if ($value === 'login') {
            return $value;
        }
        return '';
    }

    public function isValid($value, $context = null)
    {
    }

    public function getMessage()
    {
    }
}

class passwordFilter implements iFilter
{
    public function filter($value)
    {
        return $value;
    }

    public function isValid($value, $context = null)
    {
    }

    public function getMessage()
    {
    }
}