package org.richfaces.testng;

import java.util.HashMap;
import java.util.Map;

import junit.framework.Assert;

import org.ajax4jsf.template.Template;
import org.richfaces.AutoTester;
import org.richfaces.SeleniumTestBase;
import org.testng.annotations.Test;

public class SuggestionBoxTest extends SeleniumTestBase {

    private static Map<String, String> params = new HashMap<String, String>();

    private final static String RESET_METHOD = "#{suggestionBean.reset}";

    static {
        params.put("parameter1", "value1");
        params.put("parameter2", "value2");
        params.put("parameter3", "value3");
    }

    @Test
    public void testRenderedAttribute(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test component with rendered = false is not present on the page");
        tester.testRendered();
    }

    @Test
    public void testNestedParams(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test component encodes nested f:param tags and their values are present as request parameters");
        tester.testRequestParameters(params);
    }

    @Test
    public void testReRenderAttribute(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test component re-renders another components");
        tester.testReRender();
    }

    @Test
    public void testOncomplete(Template template) {
      AutoTester tester = getAutoTester(this);
      tester.renderPage(template, RESET_METHOD);
      writeStatus("Test oncomplete attribute");
      tester.testOncomplete();
    }

    @Test
    public void testWithExternalValidationFailure(Template template) {
        AutoTester autoTester = getAutoTester(this);
        autoTester.renderPage(template, RESET_METHOD);
        writeStatus("Check component in case of external validation failure: listeners are not invoked, model is not updated");
        autoTester.testExtrenalValidationFailure();
    }

    @Test
    public void testLimitToListAttribute(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test component with limitToList = true skips ajaxRendered areas update");
        tester.testLimitToList();
    }

    @Test
    public void testBypassUpdatesAttribute(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test component with bypassUpdates = true skips update model values phase");
        tester.testBypassUpdate(false);
    }

    @Test
    public void testImmediate(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test immediate attribute");
        tester.testImmediate(false);
    }

    @Test
    public void testImmediateWithExternalValidationFailed(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test immediate attribute with external validation failed");
        tester.testImmediateWithExternalValidationFailed(false);
    }

    @Test
    public void testAjaxSingle(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test ajaxSingle attribute");
        tester.testAjaxSingle(false);
    }

    @Test
    public void testAjaxSingleWithInternalValidationFailed(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Test ajaxSingle attribute in case of invalid children state");
        tester.testAjaxSingleWithInternalValidationFailed();
    }

    @Test
    public void testAjaxSingleWithProcessExternalValidation(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        tester.testAjaxSingleWithProcesExternalValidation(false);
    }

    @Test
    public void testKeyboardNavigation(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Check keyboard navigation works for component");
        String componentId = getAutoTester(this).getClientId("suggestion");

        type(componentId, "stan");
        waitForAjaxCompletion();
        selenium.keyDown(componentId, "\\40");//down x 4 times
        selenium.keyDown(componentId, "\\40");
        selenium.keyDown(componentId, "\\40");
        selenium.keyDown(componentId, "\\40");
        selenium.keyDown(componentId, "\\13");//enter
        AssertValueEquals(componentId, "Uzbekistan");

        type(componentId, "stan");
        waitForAjaxCompletion();
        selenium.keyDown(componentId, "\\40");//down x 2 times
        selenium.keyDown(componentId, "\\40");
        selenium.keyDown(componentId, "\\38");//up
        selenium.keyDown(componentId, "\\13");//enter
        AssertValueEquals(componentId, "Kyrgyzstan");
    }

    @Test
    public void testJSAPI(Template template) {
        AutoTester tester = getAutoTester(this);
        tester.renderPage(template, RESET_METHOD);
        writeStatus("Check JS API is present and works");

        writeStatus("Check callSuggestion(ignoreMinChars) function");
        String componentId = getAutoTester(this).getClientId(AutoTester.COMPONENT_ID);
        String suggestInputId = getAutoTester(this).getClientId("suggestion");
        type(suggestInputId, "Be");
        invokeFromComponent(componentId, "callSuggestion", true);
        waitForAjaxCompletion();
        selenium.keyDown(suggestInputId, "\\13");//enter
        AssertValueEquals(suggestInputId, "Belarus");

        writeStatus("Check getSelectedItems() function");
        type(suggestInputId, "Aze");//Azerbaijan
        waitForAjaxCompletion();
        selenium.keyDown(suggestInputId, "\\13");//enter
        String capital = runScript(String.format("document.getElementById('%1$s').component.getSelectedItems()[0].capital", componentId));
        Assert.assertEquals("Baku", capital);
    }

    @Override
    public void sendAjax() {
        type(getAutoTester(this).getClientId("suggestion"), "Bel");
        waitForAjaxCompletion();
        selenium.click("//table[@id='" + getAutoTester(this).getClientId(AutoTester.COMPONENT_ID + ":suggest']/tbody/tr[1]"));
    }

    @Override
    public String getAutoTestUrl() {
        return "pages/suggestionBox/suggestionBoxAutoTest.xhtml";
    }

    @Override
    public String getTestUrl() {
        return null;
    }

}
