/*******************************************************************************
  * Copyright (c) 2007-2008 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
  *
  * Contributor:
  *     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.List;

import org.jboss.tools.vpe.editor.context.VpePageContext;
import org.jboss.tools.vpe.editor.template.VpeAbstractTemplate;
import org.jboss.tools.vpe.editor.template.VpeCreationData;
import org.jboss.tools.vpe.editor.template.expression.VpeExpression;
import org.jboss.tools.vpe.editor.template.expression.VpeExpressionException;
import org.jboss.tools.vpe.editor.util.HTML;
import org.jboss.tools.vpe.editor.util.VpeClassUtil;
import org.mozilla.interfaces.nsIDOMDocument;
import org.mozilla.interfaces.nsIDOMElement;
import org.mozilla.interfaces.nsIDOMNode;
import org.mozilla.interfaces.nsIDOMNodeList;
import org.w3c.dom.Node;

/**
 * Class {@code RichFacesDataTableStyleClassesApplier} should be used in templates
 * of tags that support attributes {@code 'rowClasses'} and {@code 'columnClasses'}.
 * <P/>
 * It expects it is used in pair with {@link RichFacesDataTableChildrenEncoder}.
 * 
 * @author yradtsevich
 */
public class RichFacesDataTableStyleClassesApplier {
	private final List<String> rowClasses;
	private final List<String> columnClasses;
	
	/**
	 * Constructs {@code RichFacesDataTableStyleClassesApplier}.
	 * 
	 * @param visualDocument an object of {@link nsIDOMDocument} 
	 * @param pageContext an object of {@link VpePageContext}
	 * @param sourceNode an object of a tag that could have
	 *        attributes {@code 'rowClasses'} and {@code 'columnClasses'}.
	 */
	public RichFacesDataTableStyleClassesApplier(final nsIDOMDocument visualDocument,
			final VpePageContext pageContext, final Node sourceNode) {
		final VpeExpression exprRowClasses = RichFaces.getExprRowClasses();
		final VpeExpression exprColumnClasses = RichFaces.getExprColumnClasses();
		
		try {
			rowClasses = VpeClassUtil.getClasses(exprRowClasses, sourceNode,
					pageContext);
			columnClasses = VpeClassUtil.getClasses(exprColumnClasses, sourceNode,
					pageContext);
		} catch (final VpeExpressionException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Applies style-classes specified in attributes {@code 'rowClasses'} and 
	 * {@code 'columnClasses'} of {@code sourceNode} to the {@code targetTable}.
	 * <P/>
	 * This method should be used in 
	 * {@link VpeAbstractTemplate#validate(VpePageContext, Node, nsIDOMDocument, VpeCreationData) validate()}
	 * method of a template after 
	 * {@link RichFacesDataTableChildrenEncoder#validateChildren(VpePageContext, Node, nsIDOMDocument, VpeCreationData) RichFacesDataTableChildrenEncoder.validateChildren()}
	 * is called. 
	 * <P/>
	 * The basic idea of the method is to add appropriate rowClasses only
	 * to the direct TR children of the table and add appropriate columnClasses
	 * only to direct TD children of that TRs. It gives us opportunity to separate
	 * TRs and TDs that created by the tag directly from TRs and TDs created
	 * by the tag's children.
	 */
	public void applyClasses(final nsIDOMElement targetTable) {
		final nsIDOMNodeList tableChildren = targetTable.getChildNodes();			
		int rowIndex = 0;
		final int tableChildrenLength = (int) tableChildren.getLength();
		for (int i = 0; i < tableChildrenLength; i++) {
			final nsIDOMNode tableChild = tableChildren.item(i);
			if (tableChild.getNodeType() == nsIDOMNode.ELEMENT_NODE 
					&& HTML.TAG_TR.equalsIgnoreCase( tableChild.getNodeName() )) {
				final nsIDOMElement row = 
					queryInterface(tableChild, nsIDOMElement.class);

				applyClass(rowClasses, row, rowIndex);

				applyClassesToCells(row);
				rowIndex++;
			}
		}
	}

	/**
	 * Applies style-classes specified in attribute {@code 'columnClasses'}
	 * of {@code sourceNode} to the {@code row}.
	 */
	private void applyClassesToCells(final nsIDOMElement row) {
		final int columnClassesSize = columnClasses.size();
		if (columnClassesSize > 0) {
			final nsIDOMNodeList rowChildren = row.getChildNodes();
			int columnIndex = 0;
			int rowChildrenLength = (int)rowChildren.getLength();
			for (int j = 0; j < rowChildrenLength; j++) {
				final nsIDOMNode rowChild = rowChildren.item(j);
				if (rowChild.getNodeType() == nsIDOMNode.ELEMENT_NODE 
						&& HTML.TAG_TD.equalsIgnoreCase( rowChild.getNodeName() )) {
					final nsIDOMElement cell = 
						queryInterface(rowChild, nsIDOMElement.class);
					
					applyClass(columnClasses, cell, columnIndex);
					
					columnIndex++;
				}
			}
		}
	}

	/**
	 * Applies appropriate style-class from the list {@code classes} to the
	 * {@code element} (a row or a cell) position of that is {@code elementIndex}.
	 */
	private static void applyClass(final List<String> classes, final nsIDOMElement element,
			int elementIndex) {
		int classesSize = classes.size();
		if (classesSize > 0) {
			final String clazz = classes.get(elementIndex % classesSize);
			String actualClass = element.hasAttribute(HTML.ATTR_CLASS) ? element.getAttribute(HTML.ATTR_CLASS) + HTML.VALUE_CLASS_DELIMITER + clazz : clazz;
			element.setAttribute(HTML.ATTR_CLASS, actualClass);
		}
	}
}
