/**
 * License Agreement.
 *
 *  JBoss RichFaces 3.0 - 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.component;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.component.UIOutput;
import javax.faces.component.html.HtmlForm;
import javax.faces.component.html.HtmlOutputLink;
import javax.faces.component.html.HtmlOutputText;
import javax.faces.context.FacesContext;
import javax.faces.el.EvaluationException;
import javax.faces.el.PropertyNotFoundException;
import javax.faces.el.ValueBinding;
import javax.faces.model.ListDataModel;

import org.ajax4jsf.tests.AbstractAjax4JsfTestCase;
import org.apache.commons.collections.Predicate;

import com.gargoylesoftware.htmlunit.html.HtmlElement;
import com.gargoylesoftware.htmlunit.html.HtmlPage;

/**
 * Unit test for DataTable component.
 */
public class DataTableComponentTest extends AbstractAjax4JsfTestCase {

    private UIDataTable dataTable;

    private UIColumn column1;

    private UIColumn column2;

    private UIForm form = null;
    
    private UIColumnGroup columnGroup;

    /**
     * Create the test case
     * 
     * @param testName
     *            name of the test case
     */
    public DataTableComponentTest(String testName) {
        super(testName);
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.ajax4jsf.tests.AbstractAjax4JsfTestCase#setUp()
     */
    public void setUp() throws Exception {
        super.setUp();
        
        form = new HtmlForm();
        form.setId("form");
        facesContext.getViewRoot().getChildren().add(form);
        dataTable = (UIDataTable) application
                .createComponent("org.richfaces.DataTable");
        dataTable.setId("dataTable");

        List list = new ArrayList();
        for (int i = 1; i <= 5; i++) {
            list.add(new Date((long) Math.random()));
        }
        dataTable.setValue(new ListDataModel(list));

        columnGroup = (UIColumnGroup) application
                .createComponent("org.richfaces.ColumnGroup");
        dataTable.getChildren().add(columnGroup);

        column1 = (UIColumn) application
                .createComponent("org.richfaces.Column");
        UIOutput cellElement1 = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        cellElement1.setValueBinding("value", new ValueBinding() {
            public Class getType(FacesContext context)
                    throws EvaluationException, PropertyNotFoundException {
                return String.class;
            }

            public Object getValue(FacesContext context)
                    throws EvaluationException, PropertyNotFoundException {
                return Long.toString(((Date) dataTable.getValue()).getTime());
            }

            public boolean isReadOnly(FacesContext context)
                    throws EvaluationException, PropertyNotFoundException {
                return false;
            }

            public void setValue(FacesContext context, Object value)
                    throws EvaluationException, PropertyNotFoundException {
            }
        });
        column1.getChildren().add(cellElement1);
        columnGroup.getChildren().add(column1);

        column2 = (UIColumn) application
                .createComponent("org.richfaces.Column");
        UIOutput cellElement2 = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputLink.class.getName(),
                null, null, null);
        cellElement2.setValueBinding("value", new ValueBinding() {
            public Class getType(FacesContext context)
                    throws EvaluationException, PropertyNotFoundException {
                return String.class;
            }

            public Object getValue(FacesContext context)
                    throws EvaluationException, PropertyNotFoundException {
                return Long.toString(((Date) dataTable.getValue()).getTime());
            }

            public boolean isReadOnly(FacesContext context)
                    throws EvaluationException, PropertyNotFoundException {
                return false;
            }

            public void setValue(FacesContext context, Object value)
                    throws EvaluationException, PropertyNotFoundException {
            }
        });
        column2.getChildren().add(cellElement2);
        columnGroup.getChildren().add(column2);     
        
        
        form.getChildren().add(dataTable);

    }

    /*
     * (non-Javadoc)
     * 
     * @see org.ajax4jsf.tests.AbstractAjax4JsfTestCase#tearDown()
     */
    public void tearDown() throws Exception {
        super.tearDown();

        column1 = null;
        column2 = null;
        columnGroup = null;
        dataTable = null;
    }

    /**
     * Test DataTable component rendering.
     * 
     * @throws Exception
     */
    public void testRenderDataTable() throws Exception {

        dataTable.getAttributes().put("columnsWidth", "400px,200px");

        UIColumn column3 = (UIColumn) application
                .createComponent("org.richfaces.Column");
        dataTable.getChildren().add(column3);
        UIOutput text = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        text.setValue("Column");
        column3.getChildren().add(text);
        column3.setBreakBefore(true);

        UIColumn column4 = (UIColumn) application
                .createComponent("org.richfaces.Column");
        dataTable.getChildren().add(column4);
        UIOutput text2 = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        text.setValue("Column2");
        column4.getChildren().add(text2);
        column4.setRendered(false);

        HtmlPage page = renderView();
        assertNotNull(page);
        // System.out.println(page.asXml());

        HtmlElement table = page.getHtmlElementById(dataTable
                .getClientId(facesContext));
        assertNotNull(table);
        assertEquals("table", table.getNodeName());
        String classAttr = table.getAttributeValue("class");
        assertTrue(classAttr.contains("dr-table rich-table"));

        List elements = table.getHtmlElementsByTagName("col");
        assertEquals(2, elements.size());
        classAttr = ((HtmlElement) elements.get(0)).getAttributeValue("width");
        assertTrue(classAttr.contains("400px"));
        classAttr = ((HtmlElement) elements.get(1)).getAttributeValue("width");
        assertTrue(classAttr.contains("200px"));

        List bodies = table.getHtmlElementsByTagName("tbody");
        assertEquals(1, bodies.size());
        List trs = ((HtmlElement) bodies.get(0)).getHtmlElementsByTagName("tr");
        assertTrue(trs.size() > 0);
        HtmlElement tr = (HtmlElement) trs.get(0);
        assertNotNull(tr);
        classAttr = tr.getAttributeValue("class");
        assertTrue(classAttr.contains("dr-table-firstrow rich-table-firstrow"));

        List tds = tr.getHtmlElementsByTagName("td");
        assertTrue(tds.size() > 0);
        HtmlElement td = (HtmlElement) tds.get(0);
        assertNotNull(td);
        classAttr = td.getAttributeValue("class");
        assertTrue(classAttr.contains("dr-table-cell rich-table-cell"));
    }

    /**
     * Test DataTable component facets rendering.
     * 
     * @throws Exception
     */
    public void testRenderDataTableFacets() throws Exception {

        UIColumnGroup header1 = (UIColumnGroup) application
                .createComponent("org.richfaces.ColumnGroup");
        header1.getAttributes().put("columnClasses", "cola, colb");
        dataTable.getFacets().put("header", header1);

        UIColumn headerColumn1 = (UIColumn) application
                .createComponent("org.richfaces.Column");
        UIOutput headerText1 = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        headerText1.setValue("Header Column1");
        headerColumn1.getChildren().add(headerText1);
        header1.getChildren().add(headerColumn1);

        UIOutput column1header = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        column1header.setValue("Column1 Header");
        headerColumn1.getFacets().put("header", column1header);

        UIColumn headerColumn2 = (UIColumn) application
                .createComponent("org.richfaces.Column");
        UIOutput headerText2 = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        headerText2.setValue("Header Column2");
        headerColumn2.getChildren().add(headerText2);
        header1.getChildren().add(headerColumn2);

        UIOutput column2header = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        column2header.setValue("Column2 Header");
        headerColumn2.getFacets().put("header", column2header);

        UIOutput caption = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        dataTable.getFacets().put("caption", caption);
        caption.setValue("Caption");

        UIOutput footer = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        dataTable.getFacets().put("footer", footer);
        footer.setValue("Footer");

        HtmlPage page = renderView();
        assertNotNull(page);
        // System.out.println(page.asXml());

        HtmlElement table = page.getHtmlElementById(dataTable
                .getClientId(facesContext));
        assertNotNull(table);

        List captions = table.getHtmlElementsByTagName("caption");
        assertNotNull(captions);
        assertEquals(1, captions.size());
        String classAttr = ((HtmlElement) captions.get(0))
                .getAttributeValue("class");
        assertTrue(classAttr.contains("dr-table-caption rich-table-caption"));

        List headers = table.getHtmlElementsByTagName("thead");
        assertNotNull(headers);
        assertEquals(1, headers.size());
        List trs = ((HtmlElement) headers.get(0))
                .getHtmlElementsByTagName("tr");
        assertTrue(trs.size() > 0);
        HtmlElement tr = (HtmlElement) trs.get(0);
        assertNotNull(tr);
        classAttr = tr.getAttributeValue("class");
        assertTrue(classAttr.contains("dr-table-header rich-table-header"));

        List tds = tr.getHtmlElementsByTagName("th");
        assertTrue(tds.size() > 0);
        HtmlElement td = (HtmlElement) tds.get(0);
        assertNotNull(td);
        classAttr = td.getAttributeValue("class");
        assertTrue(classAttr
                .contains("dr-table-headercell rich-table-headercell"));
        assertTrue(classAttr.contains("cola"));

        List footers = table.getHtmlElementsByTagName("tfoot");
        assertNotNull(footers);
        assertEquals(1, footers.size());
        trs = ((HtmlElement) footers.get(0)).getHtmlElementsByTagName("tr");
        assertTrue(trs.size() > 0);
        tr = (HtmlElement) trs.get(0);
        assertNotNull(tr);
        classAttr = tr.getAttributeValue("class");
        //System.out.println(classAttr);
        assertTrue(classAttr.contains("dr-table-footer rich-table-footer "));
  
        tds = tr.getHtmlElementsByTagName("td");
        assertTrue(tds.size() > 0);
        td = (HtmlElement) tds.get(0);
        assertNotNull(td);
        classAttr = td.getAttributeValue("class");
        //System.out.println(classAttr);
        assertTrue(classAttr.contains("dr-table-footercell rich-table-footercell "));

        Iterator fixedChildren = dataTable.fixedChildren();
        assertNotNull(fixedChildren);
        assertTrue(fixedChildren.hasNext());
    }

    /**
     * Test DataTable component rows and columns rendering.
     * 
     * @throws Exception
     */
    public void testRenderDataTableRowsAndColumns() throws Exception {

        UIOutput caption = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        dataTable.getFacets().put("caption", caption);
        caption.setValue("Caption");
        dataTable.getAttributes().put("captionClass", "captionClass");
        dataTable.getAttributes().put("captionStyle", "captionStyle");

        dataTable.getAttributes().put("rowClasses", "row1,row2");
        dataTable.getAttributes().put("columnClasses", "column1,column2");

        column1.getAttributes().put("styleClass", "column1StyleClass");
        column2.getAttributes().put("styleClass", "");

        HtmlPage page = renderView();
        assertNotNull(page);
        // System.out.println(page.asXml());

        HtmlElement table = page.getHtmlElementById(dataTable
                .getClientId(facesContext));
        assertNotNull(table);

        List captions = table.getHtmlElementsByTagName("caption");
        assertNotNull(captions);
        assertEquals(1, captions.size());
        String classAttr = ((HtmlElement) captions.get(0))
                .getAttributeValue("class");
        assertTrue(classAttr.contains("captionClass"));
        classAttr = ((HtmlElement) captions.get(0)).getAttributeValue("style");
        assertTrue(classAttr.contains("captionStyle"));

        List bodies = table.getHtmlElementsByTagName("tbody");
        assertTrue(bodies.size() > 0);
        List trs = ((HtmlElement) bodies.get(0)).getHtmlElementsByTagName("tr");
        assertTrue(trs.size() > 0);
        HtmlElement tr = (HtmlElement) trs.get(0);
        assertNotNull(tr);
        classAttr = tr.getAttributeValue("class");
        assertTrue(classAttr.contains("row1"));

        List tds = tr.getHtmlElementsByTagName("td");
        assertTrue(tds.size() > 0);
        HtmlElement td = (HtmlElement) tds.get(0);
        assertNotNull(td);
        classAttr = td.getAttributeValue("class");
        assertTrue(classAttr.contains("column1"));
        assertTrue(classAttr.contains("column1StyleClass"));
    }

    /**
     * Test SubTable component rendering.
     * 
     * @throws Exception
     */
    public void testSubTable() throws Exception {

        UISubTable subTable = (UISubTable) application
                .createComponent("org.richfaces.SubTable");
        subTable.setId("subTable");
       
        UIColumnGroup subTableColumnGroup = (UIColumnGroup) application
                .createComponent("org.richfaces.ColumnGroup");

        UIColumn column3 = (UIColumn) application
                .createComponent("org.richfaces.Column");
                 
        subTableColumnGroup.getChildren().add(column3);
        UIOutput text = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        text.setValue("Column1");
        column3.getChildren().add(text);

        UIColumn column4 = (UIColumn) application
                .createComponent("org.richfaces.Column");
        subTableColumnGroup.getChildren().add(column4);
        UIOutput text2 = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        text.setValue("Column2");
        column4.getChildren().add(text2);

        UIColumn headerColumn = (UIColumn) application
                .createComponent("org.richfaces.Column");
        UIOutput header = (UIOutput) createComponent(
                HtmlOutputText.COMPONENT_TYPE, HtmlOutputText.class.getName(),
                null, null, null);
        header.setValue("Header");
        headerColumn.getChildren().add(header);
        subTable.getFacets().put("header", headerColumn);

        column3.getFacets().put(
                "header",
                (UIOutput) createComponent(HtmlOutputText.COMPONENT_TYPE,
                        HtmlOutputText.class.getName(), null, null, null));
        column4.getFacets().put(
                "header",
                (UIOutput) createComponent(HtmlOutputText.COMPONENT_TYPE,
                        HtmlOutputText.class.getName(), null, null, null));

        subTable.getAttributes().put("columnClasses", "sub1,sub2");
        dataTable.getChildren().add(subTable);
        
        assertTrue(subTable.isBreakBefore());

        try {
            subTable.setBreakBefore(false);
            assertTrue(false);
        } catch (IllegalStateException e) {

        }

        HtmlPage page = renderView();
        assertNotNull(page);
       // System.out.println(page.asXml());
              
        // System.out.println(page.asXml());

    }

    /**
     * Test for UIColumnGroup class.
     * 
     * @throws Exception
     */
    public void testUIColumnGroup() throws Exception {

        try {
            columnGroup.setBreakBefore(true);
            assertTrue(false);
        } catch (Exception e) {
            assertTrue(e instanceof IllegalStateException);
        }
    }

    /**
     * Test for Predicate classes of UIDataTable class.
     * 
     * @throws Exception
     */
    public void testPredicates() throws Exception {

        Predicate columnPredicate = UIDataTable.isColumn;
        Predicate notColumnPredicate = UIDataTable.isNotColumn;
        Predicate ajaxSupportPredicate = UIDataTable.isAjaxSupport;

        UIComponent notColumn = createComponent(HtmlOutputText.COMPONENT_TYPE,
                HtmlOutputText.class.getName(), null, null, null);
        UIComponent column = column1;
        UIComponent notAjaxSupport = notColumn;
        

        assertTrue(columnPredicate.evaluate(column));
        assertTrue(!columnPredicate.evaluate(notColumn));

        assertTrue(notColumnPredicate.evaluate(notColumn));
        assertTrue(!notColumnPredicate.evaluate(column));
      
        assertTrue(!ajaxSupportPredicate.evaluate(notAjaxSupport));
    }
}