/**
 * License Agreement.
 *
 * JBoss RichFaces - Ajax4jsf Component Library
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */ 
package org.richfaces.testng;

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

/**
 * a4j:repeat component selenium test
 * 
 * @author Alexandr Levkovsky
 * 
 */
public class AjaxRepeatTest extends SeleniumTestBase {

    private final static Integer DEFAULT_ROWS_COUNT = 5;

    private final static String FORM1_ID = "form1:";

    private final static String FORM2_ID = "form2:";

    private final static String FIRST_INPUT_ID = "first_input";

    private final static String ROWS_INPUT_ID = "rows_input";

    private final static String RESET_BUTTON_ID = "reset";

    private final static String ROWS_COUNT_INPUT_ID = "rows_count_input";

    private final static String TABLE_ID = "repeat_table";

    private final static String REPEAT_ID = "repeat";

    private final static String INPUT_ID = "input";

    private final static String OUTPUT_ID = "output";

    private final static String APPLY_BUTTON_ID = "apply";

    private final static String RENDERED_CHECKBOX_ID = "rendered_checkbox";

    private final static String LINK_ID = "link";

    private final static String BUTTON_ID = "button";

    private final static String RERENDERED_COUNTER_ID = "rerendered_change_counter";

    private final static String NOT_RERENDERED_COUNTER_ID = "not_rerendered_change_counter";

    private final static String INPUT_VALUE_OUTPUT_ID = "input_output";

    @Override
    public String getTestUrl() {
	return "pages/ajaxRepeat/ajaxRepeatTest.xhtml";
    }

    @Test
    public void testRerenderingRowsWithAjaxKeysAttribute(Template template) throws Exception {
	renderPage(template);
	writeStatus("Testing rerendering rows with ajaxKeys attribute...");
	// link action update counter fields in all rows but add only current
	// row number to ajaxKeys so only current row counter should be
	// rerendered
	clickReset();
	AssertRendered(TABLE_ID);
	assertRowsCount(DEFAULT_ROWS_COUNT, TABLE_ID);

	for (int i = 0; i < DEFAULT_ROWS_COUNT; i++) {
	    for (int j = 0; j < DEFAULT_ROWS_COUNT; j++) {
		if (j < i) {
		    assertOutputText(j, RERENDERED_COUNTER_ID, new Integer(j + 1).toString());
		} else {
		    assertOutputText(j, RERENDERED_COUNTER_ID, "0");
		}
		assertOutputText(j, NOT_RERENDERED_COUNTER_ID, "0");
	    }

	    writeStatus("click link " + i);
	    String linkId = getFullTableElementId(i, LINK_ID);
	    clickAjaxCommandAndWait(linkId);

	    for (int j = 0; j < DEFAULT_ROWS_COUNT; j++) {
		if (j < i) {
		    assertOutputText(j, RERENDERED_COUNTER_ID, new Integer(j + 1).toString());
		} else if (j == i) {
		    assertOutputText(j, RERENDERED_COUNTER_ID, new Integer(j + 1).toString());
		} else {
		    assertOutputText(j, RERENDERED_COUNTER_ID, "0");
		}
		assertOutputText(i, NOT_RERENDERED_COUNTER_ID, "0");
	    }
	}
    }

    @Test
    public void testRerenderingRowsWithoutAjaxKeysAttribute(Template template) throws Exception {
	renderPage(template);
	writeStatus("Testing rerendering rows without ajaxKeys attribute...");
	// button action update counter fields in all rows and sets ajaxKeys to
	// null so counters in all rows should be rerendered.
	clickReset();
	AssertRendered(TABLE_ID);
	assertRowsCount(DEFAULT_ROWS_COUNT, TABLE_ID);

	for (int i = 0; i < DEFAULT_ROWS_COUNT; i++) {
	    for (int j = 0; j < DEFAULT_ROWS_COUNT; j++) {
		assertOutputText(j, RERENDERED_COUNTER_ID, new Integer(i).toString());
		assertOutputText(j, NOT_RERENDERED_COUNTER_ID, "0");
	    }

	    writeStatus("click button " + i);
	    String buttonId = getFullTableElementId(i, BUTTON_ID);
	    clickAjaxCommandAndWait(buttonId);

	    for (int j = 0; j < DEFAULT_ROWS_COUNT; j++) {
		assertOutputText(j, RERENDERED_COUNTER_ID, new Integer(i + 1).toString());
		assertOutputText(j, NOT_RERENDERED_COUNTER_ID, "0");
	    }
	}
    }

    @Test
    public void testRerenderingRowsWithValidation(Template template) throws Exception {
	renderPage(template);
	writeStatus("Testing rerendering rows with validation...");
	clickReset();
	AssertRendered(TABLE_ID);
	assertRowsCount(DEFAULT_ROWS_COUNT, TABLE_ID);

	for (Integer i = 0; i < DEFAULT_ROWS_COUNT; i++) {
	    assertInputValue(i, INPUT_ID, i.toString());
	    assertOutputText(i, INPUT_VALUE_OUTPUT_ID, i.toString());
	    assertOutputText(i, RERENDERED_COUNTER_ID, "0");

	    writeStatus("set not valid value for row " + i + " input...");
	    type(getFullTableElementId(i, INPUT_ID), "200");
	    writeStatus("click link " + i);
	    String linkId = getFullTableElementId(i, LINK_ID);
	    clickAjaxCommandAndWait(linkId);

	    assertInputValue(i, INPUT_ID, "200");
	    assertOutputText(i, INPUT_VALUE_OUTPUT_ID, i.toString());
	    assertOutputText(i, RERENDERED_COUNTER_ID, "0");

	    writeStatus("set valid value for row " + i + " input...");
	    type(getFullTableElementId(i, INPUT_ID), "99");
	    writeStatus("click link " + i);
	    clickAjaxCommandAndWait(linkId);

	    assertInputValue(i, INPUT_ID, "99");
	    assertOutputText(i, INPUT_VALUE_OUTPUT_ID, "99");
	    assertOutputText(i, RERENDERED_COUNTER_ID, new Integer(i + 1).toString());
	}
    }

    @Test
    public void testRenderedAttribute(Template template) throws Exception {
	renderPage(template);
	writeStatus("Testing rendered attribute...");
	clickReset();
	AssertRendered(TABLE_ID);
	// repeat has rendered=true and should present on page as table with
	// default 5 rows
	assertRowsCount(5, TABLE_ID);

	writeStatus("change rendered attribute to false");
	// change rendered attribute to false
	String checkboxId = getParentId() + FORM1_ID + RENDERED_CHECKBOX_ID;
	selenium.click(checkboxId);
	writeStatus("Click apply");
	clickApply();

	// repeat now has rendered=false and should not present on page as table
	// with default 0 rows
	assertRowsCount(0, TABLE_ID);
    }

    @Test
    public void testFirstAttribute(Template template) throws Exception {
	renderPage(template);
	writeStatus("Testing first attribute...");
	clickReset();
	AssertRendered(TABLE_ID);
	// repeat has rendered=true and should present on page as table with
	// default 5 rows
	assertRowsCount(5, TABLE_ID);
	// first row default value 0
	String fullInput0Id = getParentId() + FORM2_ID + REPEAT_ID + ":" + 0 + ":" + OUTPUT_ID;
	String fullInput1Id = getParentId() + FORM2_ID + REPEAT_ID + ":" + 1 + ":" + OUTPUT_ID;
	AssertPresent(fullInput0Id);
	AssertPresent(fullInput1Id);
	writeStatus("change first attribute to 1");

	String inputId = getParentId() + FORM1_ID + FIRST_INPUT_ID;
	type(inputId, "1");
	writeStatus("Click apply");
	clickApply();

	// now first row value should be 1
	AssertNotPresent(fullInput0Id);
	AssertPresent(fullInput1Id);
    }

    @Test
    public void testRowsAttribute(Template template) throws Exception {
	renderPage(template);
	writeStatus("Testing rows attribute...");
	clickReset();
	AssertRendered(TABLE_ID);
	// repeat has rows=0 and table with all default 5 rows should present on
	// page
	assertRowsCount(5, TABLE_ID);

	writeStatus("change rendered attribute to false");
	// change rows attribute to 3
	String inputId = getParentId() + FORM1_ID + ROWS_INPUT_ID;
	type(inputId, "3");
	writeStatus("Click apply");
	clickApply();

	// repeat now has rendered=false and should not present on page as table
	// with default 0 rows
	assertRowsCount(3, TABLE_ID);
	// last row should have value 2
	assertInputValue(2, INPUT_ID, "2");
    }

    @Test
    public void testRowKeyVarAttribute(Template template) throws Exception {
	renderPage(template);
	writeStatus("Testing rowKeyVar attribute...");
	clickReset();
	AssertRendered(TABLE_ID);
	String inputId = getParentId() + FORM1_ID + ROWS_COUNT_INPUT_ID;
	Integer rowsCount = new Integer(getValueById(inputId));
	// repeat has rows=0 and table with all default 5 rows should present on
	// page
	assertRowsCount(rowsCount, TABLE_ID);

	// output text has value="#{rowKey % 2 == 0 ? '0' : '1'}"
	for (int i = 0; i < rowsCount; i++) {
	    assertOutputText(i, OUTPUT_ID, i % 2 == 0 ? "0" : "1");
	}
    }

    private void clickReset() {
	String buttonId = getParentId() + FORM2_ID + RESET_BUTTON_ID;
	writeStatus("Click reset button");
	clickCommandAndWait(buttonId);
    }

    private void clickApply() {
	String buttonId = getParentId() + FORM1_ID + APPLY_BUTTON_ID;
	clickCommandAndWait(buttonId);
    }

    private void assertInputValue(int row, String inputId, String value) {
	String fullInputId = getFullTableElementId(row, inputId);
	String elementValue = getValueById(fullInputId);
	Assert.assertEquals(elementValue, value);
    }

    private void assertOutputText(int row, String outputId, String value) {
	String fullInputId = getFullTableElementId(row, outputId);
	String elementValue = getTextById(fullInputId);
	Assert.assertEquals(elementValue, value);
    }

    private String getFullTableElementId(int row, String elementId) {
	return getParentId() + FORM2_ID + REPEAT_ID + ":" + row + ":" + elementId;
    }

}
