<?php

class AdminUserTest extends WebTestCase
{

    private $testQueues = array();
    private $queueCount = null;
    private $modalWindowXPath = "//div[@id='user-grid_Modal']";
    private $scenario;
    private $userNameOnCreate = "zerg";
    private $userNameOnUpdate = "zerg_updated";
    private $defaultSpeed;

    private function scenarioIs($scenario)
    {
        return $this->scenario == $scenario ? true : false;
    }

    private function waitForAjaxResponse()
    {
        sleep(1);
    }

    public function testCreateUserForm()
    {
        $this->prepareTestbed("create");

        $this->login();
        $this->openForm();

        // validate all Tabs :
        $this->validateTabs();
        // create testUser
        $this->click("//button[@id='user-grid_Modal_saveBtn']");
        $this->waitForAjaxResponse();
        $this->checkUserExists($this->userNameOnCreate);
    }

    public function testUpdateUserForm()
    {
        $this->prepareTestbed("update");
        $this->login();
        $this->openForm();

        $this->validateTabs();

        // update testUser
        $this->click("//button[@id='user-grid_Modal_saveBtn']");
        $this->waitForAjaxResponse();
        $this->checkUserExists($this->userNameOnUpdate);
    }

    public function testUserDelete()
    {
        $this->login();
        $this->checkUserExists($this->userNameOnUpdate);

        $this->chooseCancelOnNextConfirmation();
        $this->click("//div[@id='user-grid']//tbody/tr[1]//i[@class='icon-trash']");
        $this->assertConfirmation(Yii::t('zii', 'Are you sure you want to delete this item?'));
        $this->checkUserExists($this->userNameOnUpdate);

        $this->click("//div[@id='user-grid']//tbody/tr[1]//i[@class='icon-trash']");
        $this->assertConfirmation(Yii::t('zii', 'Are you sure you want to delete this item?'));

        $this->checkUserNotExists($this->userNameOnUpdate);
        $this->waitForAjaxResponse();
    }

    private function validateTabs()
    {
        $this->checkValidationAdvancedTab();
        $this->checkValidationCallThrougTab();
        $this->checkValidationSecretaryTab();
        $this->checkValidationQueueTab();
        $this->checkValidationGeneralTab();
    }

    private function prepareTestbed($scenario)
    {
        app()->language = cfg("GUI_LANGS");
        $this->defaultSpeed = $this->getSpeed();
        $this->testQueues = $this->generateTestQueues();
        $this->queueCount = Queue::model()->count();
        $this->scenario = $scenario;
    }

    private function login()
    {
        $this->open('?r=adminUsers');
        $this->assertElementPresent('name=LoginForm[username]');
        $this->type('name=LoginForm[username]', 'admin');
        $this->type('name=LoginForm[password]', 'demo');
        $this->clickAndWait("//input[@value='Login']");
        $this->assertTextPresent(__('DASHBOARD_MODULE_LABEL'));
    }

    private function openForm()
    {
        if ($this->scenarioIs("create")) {
            $formOpenerSelector = "//div[@id='content']//a[@id='user-gridCreateBtn']";
            $this->assertElementPresent($formOpenerSelector);
            $this->click($formOpenerSelector);
            $this->waitForAjaxResponse();
            $this->assertElementPresent("//button[@id='user-grid_Modal_saveBtn']");
        } elseif ($this->scenarioIs("update")) {
            $this->checkUserExists($this->userNameOnCreate);
            $this->click("//div[@id='user-grid']/table/tbody/tr/td[last()]/a[@class='update']");
            $this->waitForAjaxResponse();
        }
    }

    private function searchForUserName($userName = null)
    {
        $this->click("//div[@id='content']//a[@id='user-gridSearchBtn']");
        $this->type("//div[@class='filter-container']/input[@name='User[name]']", $userName);
        $this->click("//div[@id='content']//a[@id='user-gridSearchBtn']");
        $this->waitForAjaxResponse();
    }

    private function checkUserExists($userName = null)
    {
        // check if user is in Grid and ready for the update Test.
        $this->searchForUserName($userName);
        $this->assertElementPresent("//div[@id='user-grid']/table/tbody/tr[1]/td[.='" . $userName . "']");
    }

    private function checkUserNotExists($userName = null)
    {
        $this->searchForUserName($userName);
        $this->assertElementNotPresent("//div[@id='user-grid']/table/tbody/tr[1]/td[.='" . $userName . "']");
    }

    private function checkValidationGeneralTab()
    {
        // go To General tab :
        $this->click($this->modalWindowXPath . "//a[.='" . __("USER_MODEL_TAB_MENU_GENERAL_DATA") . "']");

        $userDataInputs = array();
        // add Username Field to generic validation.
        $userDataInputs[] = array(
            'selector' => "//input[@id='User_name']",
            'rules' => array('required'),
            'translationKey' => 'USERS_MODEL_NAME',
            'defaultValue' => 'admin' //invalid value to check unique validator after client validation
        );

        // add Password Field to generic validation.
        $userDataInputs[] = array(
            'selector' => "//input[@id='User_password']",
            'rules' => $this->scenarioIs("create") ? array('required') : null,
            'translationKey' => 'USERS_MODEL_PASSWORD',
            'defaultValue' => 'demo'
        );

        // add Firstname Field to generic validation.
        $userDataInputs[] = array(
            'selector' => "//input[@id='User_firstname']",
            'translationKey' => 'USERS_MODEL_FIRSTNAME',
            'defaultValue' => 'Zerg'
        );

        // add Lastname Field to generic validation.
        $userDataInputs[] = array(
            'selector' => "//input[@id='User_lastname']",
            'translationKey' => 'USERS_MODEL_LASTNAME',
            'defaultValue' => 'Zimmermann'
        );

        // add Extension Field to generic validation.
        $userDataInputs[] = array(
            'selector' => "//input[@id='User_extension']",
            'translationKey' => 'USERS_MODEL_EXTENSION',
            'rules' => array(
                'required',
                'numerical' => array(
                    'integerOnly' => true,
                ),
                'length'=>array(
                    'min' => 2,
                    'max' => 10,
                ),
            ),
            'defaultValue' => '777' //invalid value to check unique validator after client validation
        );

        // add e-mail Field to generic validation.
        $userDataInputs[] = array(
            'selector' => "//input[@id='User_email']",
            'rules' => array('email'),
            'translationKey' => 'USERS_MODEL_EMAIL',
            'defaultValue' => 'jens.guenther@aerea.de'
        );

        // add PIN Field to generic validation.
        $userDataInputs[] = array(
            'selector' => "//input[@id='User_pin']",
            'rules' => array(
                'required',
                'numerical' => array(
                    'integerOnly' => true,
                ),
                'length'=>array(
                    'min' => 3,
                    'max' => 10,
                )
            ),
            'translationKey' => 'USERS_MODEL_PIN',
            'defaultValue' => '1234'
        );

        $this->checkInputValidation(
            $userDataInputs,
            "//button[@id='user-grid_Modal_saveBtn']"
        );

        $this->waitForAjaxResponse();
        // check custom messages (is Unique validators ) :
        $this->waitForTextPresent(__('USER_MODEL_IS_UNIQUE_ERROR_MESSAGE')); // user name exists error message
        $this->waitForTextPresent(__('EXTENSION_IS_UNIQUE_ERROR_MESSAGE')); // extension exists error message
        //
        // set available values for user name and extension :
        $username = $this->scenarioIs("create") ? $this->userNameOnCreate : $this->userNameOnUpdate;
        $this->type("//input[@id='User_name']", $username);
        $this->type("//input[@id='User_extension']", "998");
    }

    private function checkValidationQueueTab()
    {
        //go to Queue Tab
        $this->click($this->modalWindowXPath . "//a[.='" . __("USER_MODEL_TAB_MENU_QUEUES") . "']");

        //check if all test-Queues are in the Dropdown.
        foreach ($this->testQueues as $index => $queue) {
            if ($this->scenarioIs("update") && $index == 0) {
                $this->assertElementNotPresent("//select[@id='queuesDropdown']//option[.='" . $queue->name . "']");
            } else {
                $this->assertElementPresent("//select[@id='queuesDropdown']//option[.='" . $queue->name . "']");
            }
        }

        // check dynamic grid functions (add, remove, preset Values) :
        $footerInputIds = array(
            'Tiers_footer_static_member',
            'Tiers_footer_level',
            'Tiers_footer_position',
        );
        $this->checkFooterInputsExists($footerInputIds);
        $this->assertElementPresent($this->modalWindowXPath . "//div[@class='icon-plus addQueueRow']");

        $addedQueueCount = 0;
        $this->checkQueueColumn($this->testQueues[2]->name, true, "3", "3");
        $addedQueueCount++;
        $this->checkQueueColumn($this->testQueues[1]->name, false, "4", "4");
        $addedQueueCount++;
        if ($this->scenarioIs("create")) {
            $this->checkQueueColumn($this->testQueues[0]->name, true, "5", "5");
            $addedQueueCount++;
        }

        $this->removeLastAddedQueues($addedQueueCount);

        if ($this->scenarioIs("create")) {
            $this->assertElementPresent(
                "//select[@id='queuesDropdown']/option[.='" . $this->testQueues[0]->name . "']"
            );
        }
        $this->assertElementPresent("//select[@id='queuesDropdown']/option[.='" . $this->testQueues[1]->name . "']");
        $this->assertElementPresent("//select[@id='queuesDropdown']/option[.='" . $this->testQueues[2]->name . "']");
        $this->addAllQueues();

        if ($this->scenarioIs("update")) {
            $this->removeLastAddedQueues($this->queueCount - 1);
        } else {
            $this->removeLastAddedQueues($this->queueCount);
        }


        //add one Queue for update form testing
        if ($this->scenarioIs("create")) {
            $this->checkQueueColumn($this->testQueues[0]->name, true, "5", "5");
        }
    }

    private function checkValidationSecretaryTab()
    {
        $firstVisibleRowIndex = 2; // default for on create scenario.
        if ($this->scenarioIs("update")) {
            $firstVisibleRowIndex = 1;
        }

        $secretaryGridXPath = "//div[@id='secretary-grid']//tbody";
        // go to secretary tab;
        $this->click($this->modalWindowXPath . "//a[.='" . __("USER_MODEL_TAB_SECRETARY") . "']");

        if ($this->scenarioIs("update")) {
            $this->setSpeed(300);
            $this->assertElementPresent("$secretaryGridXPath/tr[1]/td[1]/div[.='admin']");
            $this->assertElementPresent("$secretaryGridXPath/tr[1]/td[2]/a[@class='delete']");
            $this->click("$secretaryGridXPath/tr[1]/td[2]/a[@class='delete']");
        }

        $this->assertElementPresent("//select[@id='userDropdown']/option[.='admin']");
        $this->setSpeed($this->defaultSpeed);
        $this->select("//select[@id='userDropdown']", "admin");
        $this->assertTextPresent(__("TIERS_MODEL_FOOTER_ADD_SECRETARY_BUTTON"));
        $this->click($this->modalWindowXPath . "//div[@class='addSecretary']");

        $this->assertElementPresent("$secretaryGridXPath/tr[" . $firstVisibleRowIndex . "]/td[1]/div[.='admin']");
        //remove event
        $deleteButtonXPath = "$secretaryGridXPath/tr[$firstVisibleRowIndex]//i[@class='icon-trash']";
        $this->assertElementPresent($deleteButtonXPath);
        $this->click($deleteButtonXPath);
        $this->assertElementNotPresent("$secretaryGridXPath/tr[$firstVisibleRowIndex]/td[1]/div[.='admin']");
        // check Add-button onclick event
        $this->assertElementPresent("//select[@id='userDropdown']//option[.='admin']");
        $this->select("//select[@id='userDropdown']", "admin");
        $this->click($this->modalWindowXPath . "//div[@class='icon-plus addSecretary']");
    }

    private function generateTestQueues()
    {
        // generate 3 test Queues or get them by extension
        $testQueueAttributes = array(
            'name' => 'Queue',
            "extension" => "1133"
        );
        $queues = array();
        for ($i = 1; $i <= 3; $i++) {

            $existingQueue = Queue::model()->findByAttributes(
                array(
                    "extension" => $testQueueAttributes["extension"] . $i
                )
            );

            if (!$existingQueue) {
                $queue = new Queue();
                $queue->name = $testQueueAttributes["name"] . $i;
                $queue->extension = $testQueueAttributes["extension"] . $i;
                $queue->save() ? $queues[] = $queue : Log::d("can not generate test Queue", "phonalisa-phpunit");
            } else {
                $queues[] = $existingQueue;
            }
        }
        return $queues;
    }

    private function checkValidationCallThrougTab()
    {
        //go to Call-Trough numbers tab
        $this->click($this->modalWindowXPath . "//a[.='" . __("USER_MODEL_TAB_MENU_CALL_TROUGH") . "']");

        $firstVisibleRowIndex = 1; // default value for on create scenario
        if ($this->scenarioIs("update")) {
            $firstVisibleRowIndex = 0;
        }

        $externalNumberGridXPath = "//div[@id='external-number-grid']";

        if ($this->scenarioIs("update")) {
            $this->assertElementPresent("$externalNumberGridXPath//input[@value='test1']");
            $this->assertChecked("$externalNumberGridXPath//input[@value='test1']/../../td[2]/input[@value='1']");
            $this->assertElementPresent("$externalNumberGridXPath//input[@value='test2']");
            $this->assertNotChecked("$externalNumberGridXPath//input[@value='test2']/../../td[2]/input[@value='1']");

            // remove Call-trough-numbers
            $this->click("$externalNumberGridXPath//tbody//tr[last()]//td[last()]/a");
            $this->click("$externalNumberGridXPath//tbody//tr[last()]//td[last()]/a");
        }

        // add 3 new numbers :
        $this->assertElementPresent($this->modalWindowXPath . "//div[@class='icon-plus addExternalNumber']");
        $this->click($this->modalWindowXPath . "//div[@class='icon-plus addExternalNumber']");
        $this->click($this->modalWindowXPath . "//div[@class='icon-plus addExternalNumber']");
        $this->click($this->modalWindowXPath . "//div[@class='icon-plus addExternalNumber']");

        // insert test values
        $this->assertElementPresent("//input[@id='ExternalNumber_" . $firstVisibleRowIndex . "_pattern']");
        $this->assertElementPresent("//input[@id='ExternalNumber_" . $firstVisibleRowIndex . "_callThrough']");
        $this->type("//input[@id='ExternalNumber_" . $firstVisibleRowIndex . "_pattern']", "test1");
        $this->check("//input[@id='ExternalNumber_" . $firstVisibleRowIndex . "_callThrough']");

        // insert more test values
        $this->assertElementPresent("//input[@id='ExternalNumber_" . ($firstVisibleRowIndex + 1) . "_pattern']");
        $this->assertElementPresent("//input[@id='ExternalNumber_" . ($firstVisibleRowIndex + 1) . "_callThrough']");
        $this->type("//input[@id='ExternalNumber_" . ($firstVisibleRowIndex + 1) . "_pattern']", "test2");
        $this->uncheck("//input[@id='ExternalNumber_" . ($firstVisibleRowIndex + 1) . "_callThrough']");

        $this->assertElementPresent("//input[@id='ExternalNumber_" . ($firstVisibleRowIndex + 2) . "_pattern']");

        // check if coulumn delete button works
        $this->assertElementPresent("$externalNumberGridXPath/table/tbody/tr[last()]/td[3]/a[@class='delete']");
        $this->click("$externalNumberGridXPath/table/tbody/tr[last()]/td[3]/a[@class='delete']");
        $this->assertElementNotPresent("//input[@id='ExternalNumber_3_pattern']");
    }

    private function checkValidationAdvancedTab()
    {
        // go to advanced tab :
        $this->click($this->modalWindowXPath . "//a[.='" . __("USER_MODEL_TAB_MENU_ADDITIONAL_DATA") . "']");
        //check the only input field with a Rule
        $userDataInputs = array();
        $userDataInputs[] = array(
            'selector' => "//input[@id='User_fax_header_number']",
            'rules' => array(
                'numerical' => array(
                    'integerOnly' => true
                )
            ),
            'translationKey' => 'USERS_MODEL_FAX_HEADER_NUMBER',
            'defaultValue' => '123456'
        );

        $userDataInputs[] = array(
            'selector' => "//input[@id='User_fax_header_text']",
            'translationKey' => 'USERS_MODEL_FAX_HEADER_TEXT',
            'defaultValue' => 'Zerg Zimmermann'
        );

        $userDataInputs[] = array(
            'selector' => "//input[@id='User_droptarget']",
            'translationKey' => 'USERS_MODEL_DROPTARGET',
            'defaultValue' => '777'
        );

        $this->checkInputValidation(
            $userDataInputs,
            "//button[@id='user-grid_Modal_saveBtn']"
        );
    }

    private function checkQueueColumn($queueName, $staticMember, $level, $position)
    {
        // set given params in Footer inputs and click the add button :
        $this->setQueueGridFooterInputs($queueName, $staticMember, $level, $position);
        $this->click($this->modalWindowXPath . "//div[@class='icon-plus addQueueRow']");

        // check if the new Row has the given values :
        $this->assertElementPresent($this->modalWindowXPath . "//td[.='" . $queueName . "']");
        if ($staticMember) {
            $this->assertChecked("//div[@id='queues-grid']/table/tbody/tr[last()]/td[2]/input[@type='checkbox']");
        } else {
            $this->assertNotChecked("//div[@id='queues-grid']/table/tbody/tr[last()]/td[2]/input[@type='checkbox']");
        }
        $this->assertSelectedValue("//div[@id='queues-grid']/table/tbody/tr[last()]/td[3]/select", $level);
        $this->assertValue("//div[@id='queues-grid']/table/tbody/tr[last()]/td[4]/input[@type='text']", $position);

        // check if footer values still like the params and dont jump back to default.
        $this->checkFooterValues($queueName, $staticMember, $level, $position);
    }

    private function setQueueGridFooterInputs($queueName, $staticMember, $level, $position)
    {
        // insert, select, check or uncheck the given values in the footer Inputs.
        $this->select("//select[@id='queuesDropdown']", $queueName);
        if ($staticMember) {

            $this->check("//input[@id='Tiers_footer_static_member']");
        } else {
            $this->uncheck("//input[@id='Tiers_footer_static_member']");
        }
        $this->select("//select[@id='Tiers_footer_level']", $level);
        $this->type("//input[@id='Tiers_footer_position']", $position);
    }

    private function removeLastAddedQueues($count)
    {
        for ($i = $count + 1; $i > 1; $i--) {
            $this->click("//div[@id='queues-grid']/table/tbody/tr[" . $i . "]/td[last()]//a[@class='delete']");
        }
        if ($this->scenarioIs("create")) {
            $this->assertElementPresent("//div[@id='queues-grid']/table/tbody/tr[last()]/td[1]/div[.='']");
        }
    }

    private function checkFooterInputsExists($ids)
    {
        foreach ($ids as $id) {
            $this->assertElementPresent("//*[@id='" . $id . "']");
        }
    }

    private function addAllQueues()
    {
        for ($i = 0; $i < $this->queueCount; $i++) {
            $this->click($this->modalWindowXPath . "//div[@class='icon-plus addQueueRow']");
        }
        $this->assertNotVisible("//div[@id='queues-grid']/table/tfoot");
    }

    private function checkFooterValues($queueName, $staticMember, $level, $position)
    {
        // checks if footer values still the same and not jump back to any default value
        $this->assertTrue($staticMember == $this->isChecked("//input[@id='Tiers_footer_static_member']"));
        $this->assertValue("//select[@id='Tiers_footer_level']", $level);
        $this->assertValue("//input[@id='Tiers_footer_position']", $position);
        $this->assertElementNotPresent("//select[@id='queuesDropdown']/option[.='" . $queueName . "']");
    }
}
