<?php

/**
 * Change the following URL based on your server configuration
 * Make sure the URL ends with a slash so that we can use relative URLs in test cases
 */

define('TEST_BASE_URL', 'http://localhost/ng/index-test.php');

/**
 * The base class for functional test cases.
 * In this class, we set the base URL for the test application.
 * We also provide some common methods to be used by concrete test classes.
 */
class WebTestCase extends CWebTestCase
{

    public function elementsPresented($selectors)
    {
        if (is_array($selectors)) {
            foreach ($selectors as $selector) {
                $this->elementsPresented($selector);
            }
        } else {
            $this->assertElementPresent($selectors);
        }
    }

    public function checkInputValidation($elements, $triggerSelector, $ajaxValidation = true)
    {

        // check validation for each element
        foreach ($elements as $element) {
            $selector = $element['selector'];
            $rules = isset($element['rules']) ? $element['rules'] : array();
            $translationKey = $element['translationKey'];

            $this->assertElementPresent($selector);

            foreach ($rules as $rule => $ruleParams) {
                // if rule has no params and $rule becomes array index
                if (is_integer($rule)) {
                    $rule = $ruleParams;
                    $ruleParams = null;
                }

                $this->checkValidationRule(
                    $rule,
                    $ruleParams,
                    $selector,
                    $translationKey,
                    $triggerSelector,
                    $ajaxValidation
                );
            }
        }

        // set default values for each element
        foreach ($elements as $element) {
            $selector = $element['selector'];
            $defaultValue = isset($element['defaultValue']) ? $element['defaultValue'] : '';

            $this->type($selector, $defaultValue);
        }
    }

    public function checkValidationRule(
        $rule,
        $ruleParams,
        $selector,
        $translationKey,
        $triggerSelector,
        $ajaxValidation
    ) {
        switch ($rule) {
            case "required":
                $this->checkRequiredRule($selector, $translationKey, $triggerSelector, $ajaxValidation);
                break;
            case "length":
                $this->checkLengthRule($ruleParams, $selector, $translationKey, $triggerSelector, $ajaxValidation);
                break;
            case "numerical":
                $this->checkNumericalRule($ruleParams, $selector, $translationKey, $triggerSelector, $ajaxValidation);
                break;
            case "email":
                $this->checkEmailRule($selector, $translationKey, $triggerSelector, $ajaxValidation);
                break;
            case "ip":
                $this->checkIpRule($selector, $translationKey, $triggerSelector, $ajaxValidation);
                break;
            default:
                $this->assertTrue(false, 'Unexpected validator type');
        }
    }

    public function checkLengthRule(
        $ruleParams,
        $selector,
        $translationKey,
        $triggerSelector,
        $ajaxValidation
    ) {
        foreach ($ruleParams as $paramName => $paramValue) {
            if ($paramName == "min") {
                $testValue = "";
                for ($i = 1; $i < $paramValue; $i++) {
                    $testValue .= "1";
                }

                $error = Yii::t('yii', "{attribute} is too short (minimum is {min} characters).");
                $error = strtr(
                    $error,
                    array(
                    '{min}' => $paramValue,
                    )
                );
                $this->type($selector, $testValue);
            } elseif ($paramName == "max") {

                $testValue = "";
                for ($i = 0; $i <= $paramValue; $i++) {
                    $testValue .= "1";
                }
                $this->type($selector, $testValue);
                $value = $this->getValue($selector);
                $this->assertTrue(strlen($value) == $paramValue);
                continue;
            }

            // run validation
            $this->clickTrigger(
                $triggerSelector,
                $translationKey,
                $error,
                $ajaxValidation
            );

            $this->waitForTextPresent($error);
        }
    }

    public function checkRequiredRule($selector, $translationKey, $triggerSelector, $ajaxValidation)
    {
        // clear input
        $this->type($selector, '');

        // build error message
        $error = Yii::t('yii', '{attribute} cannot be blank.');

        // run validation
        $this->clickTrigger(
            $triggerSelector,
            $translationKey,
            $error,
            $ajaxValidation
        );

        // check text
        $this->waitForTextPresent($error);
    }

    public function checkNumericalRule(
        $ruleParams,
        $selector,
        $translationKey,
        $triggerSelector,
        $ajaxValidation
    ) {
        if ($ruleParams == null) {
            $error = Yii::t('yii', '{attribute} must be a number.');

            // run validation
            $this->clickTrigger(
                $triggerSelector,
                $translationKey,
                $error,
                $ajaxValidation
            );
            $this->waitForTextPresent($error);
            return;
        }

        foreach ($ruleParams as $paramName => $paramValue) {
            $error = '';

            if ($paramName == 'integerOnly') {

                $error = Yii::t('yii', '{attribute} must be an integer.');
                $this->type($selector, $paramValue + 0.5);
            } else {
                if ($paramName == 'min') {

                    $error = Yii::t('yii', '{attribute} is too short (minimum is {min} characters).');
                    $error = strtr($error, array('{min}' => $paramValue));
//                    $this->type($selector, pow(10, $paramValue - 1) - 1);
                    $this->type($selector, ($paramValue - 1));
                } else {
                    if ($paramName == 'max') {

                        $this->type($selector, ($paramValue + 1)); // set value where value length > input maxLength
                        $inputValue = $this->getValue($selector);
                        $this->assertEquals(strlen($inputValue), $paramValue, 'Input maxlenght test');
                        continue;
                    } else {
                        $this->assertTrue(false, 'Unexpected numerical sub validator type');
                    }
                }
            }

            // run validation
            $this->clickTrigger(
                $triggerSelector,
                $translationKey,
                $error,
                $ajaxValidation
            );
            $this->waitForTextPresent($error);
        }
    }

    public function checkEmailRule($selector, $translationKey, $triggerSelector, $ajaxValidation)
    {
        // set invalid input
        $this->type($selector, "invalid.email.com");

        // build error message
        $error = Yii::t('yii', '{attribute} is not a valid email address.');

        // run validation
        $this->clickTrigger(
            $triggerSelector,
            $translationKey,
            $error,
            $ajaxValidation
        );

        // check text
        $this->waitForTextPresent($error);
    }

    public function checkIpRule($selector, $translationKey, $triggerSelector, $ajaxValidation)
    {
        // set invalid input
        $this->type($selector, "192.168.178.256");

        // build error message
        $error = __('{attribute} is not a valid IP address.');

        // run validation
        $this->clickTrigger(
            $triggerSelector,
            $translationKey,
            $error,
            $ajaxValidation
        );

        // check text
        $this->waitForTextPresent($error);
    }

    /**
     * Sets up before each test method runs.
     * This mainly sets the base URL for the test application.
     */
    protected function setUp()
    {
        parent::setUp();
        $this->setBrowser('*firefox');

        /**
         * Change the following URL based on your server configuration
         * Make sure the URL ends with a slash so that we can use relative URLs in test cases
         */
        $this->setBrowserUrl(app()->params->testBaseUrl);
    }

    protected function clickTrigger(
        $triggerSelector,
        $translationKey,
        &$error,
        $ajaxValidation = true
    ) {
        $error = strtr(
            $error,
            array(
                '{attribute}' => __($translationKey),
            )
        );

        if ($ajaxValidation) {
            $this->click($triggerSelector);
            sleep(1);
        } else {
            $this->clickAndWait($triggerSelector);
        }
    }
}
