/**
 * 
 */
package org.richfaces.testng;

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

/**
 * @author Andrey Markavstov
 * 
 */
public class ListShuttleTest extends SeleniumTestBase {

    String parentId;

    String availebleListId;

    String targetListId;

    String copyAllId;

    String copyId;

    String removeId;

    String removeAllId;

    String firstId;

    String upId;

    String downId;

    String lastId;

    String submitId;

    String resetId;

    String hideId;

    private void init() {
        parentId = getParentId() + "_form:";
        availebleListId = parentId + "lstbody";
        targetListId = parentId + "lstlTbody";
        copyAllId = parentId + "lscopyAll";
        copyId = parentId + "lscopy";
        removeId = parentId + "lsremove";
        removeAllId = parentId + "lsremoveAll";
        firstId = parentId + "lsfirst";
        upId = parentId + "lsup";
        downId = parentId + "lsdown";
        lastId = parentId + "lslast";
        submitId = parentId + "submit";
        resetId = parentId + "reset";
        hideId = parentId + "hide";

    }

    @Test
    public void testListShuttleComponent(Template template) {
        renderPage(template);
        init();
        reset();

        _checkVisibility(true);

        // Check count
        _assertTableRowsCount(availebleListId, 5);
        _assertTableRowsCount(targetListId, 0);

        // Copy all and check count
        try {
            clickById(copyAllId);
            _assertTableRowsCount(availebleListId, 0);
            _assertTableRowsCount(targetListId, 5);
        } catch (Exception e) {
            writeStatus("Test failed. Copy all does not work. Cause: " + e, true);
            Assert.fail("Test failed. Copy all does not work. Cause: " + e);
        }

        // Remove all and check count
        try {
            clickById(removeAllId);
            _assertTableRowsCount(availebleListId, 5);
            _assertTableRowsCount(targetListId, 0);
        } catch (Exception e) {
            writeStatus("Test failed. Remove all does not work. Cause: " + e, true);
            Assert.fail("Test failed. Remove all does not work. Cause: " + e);
        }

        try {
            // Copy 1st & 2nd item
            _doItemAction(parentId + "ls:0", copyId, "Copy");
            _doItemAction(parentId + "ls:1", copyId, "Copy");
            _doItemAction(parentId + "ls:2", copyId, "Copy");

            // Check count
            _assertTableRowsCount(availebleListId, 2);
            _assertTableRowsCount(targetListId, 3);
        } catch (Exception e) {
            writeStatus("Test failed. Copy does not work. Cause: " + e, true);
            Assert.fail("Test failed. Copy does not work. cause: " + e);
        }

        // Check posting to server
        _checkDataPost2Server(2, 3);

        // Check ordering
        _checkOrdering(targetListId, "1Item1", "2Item2", "3Item3", "");

        // Move the first to to the last
        _doItemAction(parentId + "ls:t0", downId, "Down");
        _checkOrdering(targetListId, "2Item2", "1Item1", "3Item3", "Test failed. Down control does not work");

        _doItemAction(parentId + "ls:t0", lastId, "Last");
        _checkOrdering(targetListId, "2Item2", "3Item3", "1Item1", "Test failed. Last control does not work");

        _doItemAction(parentId + "ls:t2", firstId, "first");
        _checkOrdering(targetListId, "3Item3", "2Item2", "1Item1", "Test failed. First control does not work");

        _doItemAction(parentId + "ls:t0", upId, "Up");
        _checkOrdering(targetListId, "3Item3", "1Item1", "2Item2", "Test failed. Up control does not work");

        _doItemAction(parentId + "ls:t1", removeId, "Remove");
        _checkOrdering(targetListId, "3Item3", "1Item1", null, "Test failed. Remove control does not work");

        _assertTableRowsCount(targetListId, 2);

        hideControls();
        _checkVisibility(false);

    }

    private void hideControls() {
        clickAjaxCommandAndWait(hideId);
    }

    private void _checkVisibility(boolean isVisible) {
        if (isVisible) {
            AssertVisible(copyAllId);
            AssertVisible(parentId + "lsdisremoveAll");
            AssertVisible(parentId + "lsdisremove");
            AssertVisible(parentId + "lsdisremove");

            AssertVisible(parentId + "lsdisfirst");
            AssertVisible(parentId + "lsdisup");
            AssertVisible(parentId + "lsdisdown");
            AssertVisible(parentId + "lsdislast");
        } else {
            AssertNotRendered(copyAllId);
            AssertNotRendered(removeAllId);
            AssertNotRendered(copyId);
            AssertNotRendered(removeId);
            AssertNotRendered(firstId);
            AssertNotRendered(lastId);
            AssertNotRendered(downId);
            AssertNotRendered(upId);
        }
    }

    private void _checkOrdering(String listId, String first, String second, String fird, String errorMessage) {
        try {
            if (first != null)
                _checkItemText(first, listId, 0);
            if (second != null) {
                _checkItemText(second, listId, 1);
            }
            if (fird != null) {
                _checkItemText(fird, listId, 2);
            }
        } catch (Exception e) {
            writeStatus(errorMessage, true);
            Assert.fail(errorMessage + e.getMessage());
        }
    }

    private void reset() {
        clickAjaxCommandAndWait(resetId);
    }

    private void _assertTableRowsCount(String tbId, int rows) {
        writeStatus("Check items count for list id : " + tbId);
        StringBuffer b = new StringBuffer("$('");
        b.append(tbId);
        b.append("').rows.length");
        String l = runScript(b.toString());
        int r;
        try {
            r = Integer.parseInt(l);
            if (r != rows) {
                writeStatus("Incorrect list item count in table id: " + tbId, true);
                Assert.fail("Incorrect list item count in table id: " + tbId);
            }
        } catch (Exception e) {
            writeStatus("List shuttle test failed. Cause: " + e.getMessage(), true);
            Assert.fail("List shuttle test failed. Cause: " + e);
        }
    }

    private void _doItemAction(String itemId, String actionId, String actionName) {
        writeStatus(actionName + " the item id: " + itemId);
        _selectItem(itemId);
        clickById(actionId);
    }

    private void _checkDataPost2Server(int availableCount, int targetCount) {
        writeStatus("Rerender form. List items should be changed.");
        clickAjaxCommandAndWait(submitId);

        try {
            _assertTableRowsCount(availebleListId, availableCount);
            _assertTableRowsCount(targetListId, targetCount);
        } catch (Exception e) {
            writeStatus("Data was post to server incorrectly. List data before rerendering does not match after", true);
            Assert
                    .fail("Data was post to server incorrectly. List data before rerendering does not match after. Cause: "
                            + e);
        }
    }

    private void _selectItem(String itemId) {
        writeStatus("Select item id:  " + itemId);
        try {
       		fireMouseEvent(itemId, "click", 0, 0, false);
        } catch (Exception e) {
            writeStatus("Selection item id: " + itemId + " failed.");
            Assert.fail("No item was found. Item id: " + itemId + e);
        }
    }

    private void _checkItemText(String text, String listId, int i) {
        StringBuffer b = new StringBuffer("$('");
        b.append(listId);
        b.append("').rows[");
        b.append(i);
        b.append("].id");

        String id = null;
        try {
            id = runScript(b.toString());
            AssertTextEquals(id, text, "Invalid item's text");
        } catch (Exception e) {
            writeStatus("Invalid item text. Item id: " + id);
            Assert.fail("Invalid item text. Item id: " + id);
        }
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.richfaces.SeleniumTestBase#getTestUrl()
     */
    @Override
    public String getTestUrl() {
        return "pages/listShuttle/listShuttleTest.xhtml";
    }

}
