/*******************************************************************************
 * Copyright (c) 2007 Exadel, Inc. and Red Hat, Inc.
 * Distributed under license by Red Hat, Inc. All rights reserved.
 * This program is made available under the terms of the
 * Eclipse Public License v1.0 which accompanies this distribution,
 * and is available at http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Exadel, Inc. and Red Hat, Inc. - initial API and implementation
 ******************************************************************************/ 
package org.jboss.tools.jsf.vpe.richfaces.template;

import static org.jboss.tools.vpe.xulrunner.util.XPCOM.queryInterface;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.jboss.tools.jsf.vpe.richfaces.ComponentUtil;
import org.jboss.tools.vpe.editor.context.VpePageContext;
import org.jboss.tools.vpe.editor.template.VpeChildrenInfo;
import org.jboss.tools.vpe.editor.template.VpeCreationData;
import org.jboss.tools.vpe.editor.util.Constants;
import org.jboss.tools.vpe.editor.util.HTML;
import org.jboss.tools.vpe.editor.util.SourceDomUtil;
import org.jboss.tools.vpe.editor.util.VisualDomUtil;
import org.mozilla.interfaces.nsIDOMDocument;
import org.mozilla.interfaces.nsIDOMElement;
import org.mozilla.interfaces.nsIDOMNode;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

public class RichFacesDataGridTemplate extends RichFacesDataTableTemplate {

    	/*
    	 * https://jira.jboss.org/jira/browse/JBIDE-3491
    	 * Set default table size when no attributes are specified.
    	 */
	private int defaultRows = 3;
	private int defaultColumns = 1;
	private String[] rowClasses;
	private String[] columnClasses;

	public VpeCreationData create(VpePageContext pageContext, Node sourceNode, nsIDOMDocument visualDocument) {

		Element sourceElement = (Element)sourceNode;

		initStyleClasses(sourceElement);

		nsIDOMElement table = visualDocument.createElement(HTML.TAG_TABLE);
		VisualDomUtil.copyAttributes(sourceNode, table);

		VpeCreationData creationData = new VpeCreationData(table);
		creationData.addChildrenInfo(new VpeChildrenInfo(null));

		ComponentUtil.setCSSLink(pageContext, "dataTable/dataTable.css", "richFacesDataGrid"); //$NON-NLS-1$ //$NON-NLS-2$
		String tableClass = "dr-table rich-table"; //$NON-NLS-1$
		if(sourceElement.hasAttribute(RichFaces.ATTR_STYLE_CLASS)) {
			tableClass += " " + sourceElement.getAttribute(RichFaces.ATTR_STYLE_CLASS); //$NON-NLS-1$
		}
		table.setAttribute(HTML.ATTR_CLASS, tableClass);

		/*
		 * Encode colgroup definition.
		 */
		int columnsLength = getColumnsCount(sourceElement);
		nsIDOMElement colgroup = visualDocument.createElement(HTML.TAG_COLGROUP);
		colgroup.setAttribute(HTML.ATTR_SPAN, String.valueOf(columnsLength));
		table.appendChild(colgroup);
		
		/*
		 * Encode Caption
		 */
		Element caption = SourceDomUtil.getFacetByName(pageContext,
				sourceElement, RichFaces.NAME_FACET_CAPTION);
		Map<String, List<Node>> captionFacetChildren = VisualDomUtil.findFacetElements(caption, pageContext);
		Node captionBody = ComponentUtil.getFacetBody(captionFacetChildren);
		encodeCaption(pageContext, creationData, sourceElement, visualDocument, table, captionBody);

		/*
		 * Encode Header
		 */
		Element header = SourceDomUtil.getFacetByName(pageContext,
				sourceElement, RichFaces.NAME_FACET_HEADER);
		Map<String, List<Node>> headerFacetChildren = VisualDomUtil.findFacetElements(header, pageContext);
		Node headerBody = ComponentUtil.getFacetBody(headerFacetChildren);
		if (headerBody != null) {
			nsIDOMElement thead = visualDocument.createElement(HTML.TAG_THEAD);
			table.appendChild(thead);
			String headerClass = sourceElement.hasAttribute(RichFaces.ATTR_HEADER_CLASS) ? sourceElement.getAttribute(RichFaces.ATTR_HEADER_CLASS) : null;
			encodeTableHeaderOrFooterFacet(pageContext, creationData, thead, columnsLength, visualDocument, headerBody,
					"dr-table-header rich-table-header", //$NON-NLS-1$
					"dr-table-header-continue rich-table-header-continue", //$NON-NLS-1$
					"dr-table-headercell rich-table-headercell", //$NON-NLS-1$
					headerClass, HTML.TAG_TD);
		}

		/*
		 * Encode Footer
		 */
		Element footer = SourceDomUtil.getFacetByName(pageContext,
				sourceElement, RichFaces.NAME_FACET_FOOTER);
		Map<String, List<Node>> footerFacetChildren = VisualDomUtil.findFacetElements(footer, pageContext);
		Node footerBody = ComponentUtil.getFacetBody(footerFacetChildren);
		if (footerBody != null) {
			nsIDOMElement tfoot = visualDocument.createElement(HTML.TAG_TFOOT);
			table.appendChild(tfoot);
			String footerClass = sourceElement.hasAttribute(RichFaces.ATTR_FOOTER_CLASS) ? sourceElement.getAttribute(RichFaces.ATTR_FOOTER_CLASS) : null;
			encodeTableHeaderOrFooterFacet(pageContext, creationData, tfoot, columnsLength, visualDocument, footerBody,
					"dr-table-footer rich-table-footer", //$NON-NLS-1$
					"dr-table-footer-continue rich-table-footer-continue", //$NON-NLS-1$
					"dr-table-footercell rich-table-footercell", //$NON-NLS-1$
					footerClass, HTML.TAG_TD);
		}

		nsIDOMElement tbody = visualDocument.createElement(HTML.TAG_TBODY);
		table.appendChild(tbody);

		/*
		 * https://jira.jboss.org/jira/browse/JBIDE-3491
		 * Encode body.
		 * Add text nodes to children list too.
		 */
		List<Node> children = ComponentUtil.getChildren(sourceElement, true);
		sourceElement.getAttribute(RichFaces.ATTR_ELEMENTS);

		int elementsCount = getElementsCount(sourceElement, columnsLength);
		
		if(columnsLength>0) {
			int rowIndex = 0;
			for(int elementIndex = 0; elementIndex<elementsCount; rowIndex++) {
				nsIDOMElement tr = visualDocument.createElement(HTML.TAG_TR);
				tbody.appendChild(tr);
				tr.setAttribute(HTML.ATTR_CLASS, "dr-table-row rich-table-row " + getRowClass(rowIndex)); //$NON-NLS-1$
				for(int columnIndex = 0; columnIndex<columnsLength && elementIndex<elementsCount; columnIndex++) {
					nsIDOMElement td = visualDocument.createElement(HTML.TAG_TD);
					tr.appendChild(td);
					td.setAttribute(HTML.ATTR_CLASS, "dr-table-cell rich-table-cell " + getColumnClass(columnIndex)); //$NON-NLS-1$
					/*
					 * Add HTML elements from caption, header and footer. 
					 */
					VpeChildrenInfo childInfo = null;
					if (captionFacetChildren.get(VisualDomUtil.FACET_HTML_TAGS).size() > 0) {
						childInfo = new VpeChildrenInfo(td);
						for (Node child : captionFacetChildren.get(VisualDomUtil.FACET_HTML_TAGS)) {
						    childInfo.addSourceChild(child);
						}
						creationData.addChildrenInfo(childInfo);
					}
					if (headerFacetChildren.get(VisualDomUtil.FACET_HTML_TAGS).size() > 0) {
						childInfo = new VpeChildrenInfo(td);
						for (Node child : headerFacetChildren.get(VisualDomUtil.FACET_HTML_TAGS)) {
							childInfo.addSourceChild(child);
						}
						creationData.addChildrenInfo(childInfo);
					}
					if (footerFacetChildren.get(VisualDomUtil.FACET_HTML_TAGS).size() > 0) {
						childInfo = new VpeChildrenInfo(td);
						for (Node child : footerFacetChildren.get(VisualDomUtil.FACET_HTML_TAGS)) {
							childInfo.addSourceChild(child);
						}
						creationData.addChildrenInfo(childInfo);
					}
					if(!children.isEmpty()) {
						childInfo = new VpeChildrenInfo(td);
						for (Node child : children) {
						    childInfo.addSourceChild(child);
						}
						creationData.addChildrenInfo(childInfo);
					}
					elementIndex++;
				}
			}
		}

		return creationData;
	}

	private void initStyleClasses(Element sourceElement) {
		String columnClassesString = sourceElement.getAttribute(RichFaces.ATTR_COLUMN_CLASSES);
		String rowClassesString = sourceElement.getAttribute(RichFaces.ATTR_ROW_CLASSES);
		columnClasses = parceClasses(columnClassesString);
		rowClasses = parceClasses(rowClassesString);
	}

	private String[] parceClasses(String classes) {
		if(classes==null) {
			return new String[]{Constants.EMPTY};
		}
		ArrayList<String> list = new ArrayList<String>();
		StringTokenizer st = new StringTokenizer(classes, Constants.COMMA, false);
		while(st.hasMoreElements()) {
			list.add((String)st.nextElement());
		}
		if(list.isEmpty()) {
			return new String[]{Constants.EMPTY};
		}
		return (String[])list.toArray(new String[list.size()]);
	}

	private String getColumnClass(int column) {
		return columnClasses[column%columnClasses.length];
	}

	private String getRowClass(int row) {
		return rowClasses[row%rowClasses.length];
	}

	protected int getColumnsCount(Element sourceElement) {
		int count = defaultColumns;
		// check for exact value in component
		try {
			int span = Integer.parseInt(sourceElement.getAttribute(RichFaces.ATTR_COLUMNS));
			count = span > 0 ? span : defaultColumns;
		} catch (NumberFormatException e) {
			// Ignore wrong formatted attribute 
		}
		return count;
	}

	protected int getElementsCount(Element sourceElement, int columnCount) {
		int elements = columnCount * defaultRows;
		// check for exact value in component
		try {
			int span = Integer.parseInt(sourceElement.getAttribute(RichFaces.ATTR_ELEMENTS));
			elements = span>0 ? span : columnCount * defaultRows;
		} catch (NumberFormatException e) {
			elements = columnCount * defaultRows;
		}
		return elements;
	}
	
	@Override
	public void removeAttribute(VpePageContext pageContext, Element sourceElement, nsIDOMDocument visualDocument, nsIDOMNode visualNode, Object data, String name) {
		nsIDOMElement visualElement = queryInterface(visualNode, nsIDOMElement.class); 
		visualElement.removeAttribute(name);
	}

	@Override
	public void setAttribute(VpePageContext pageContext, Element sourceElement, nsIDOMDocument visualDocument, nsIDOMNode visualNode, Object data, String name, String value) {
		nsIDOMElement visualElement = queryInterface(visualNode, nsIDOMElement.class); 
		visualElement.setAttribute(name, value);
	}

}