/*
 * Copyright 2006 Takahiro Nakamura.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package woolpack.html;

import java.util.Collection;
import java.util.Set;
import java.util.regex.Pattern;

import org.w3c.dom.Element;
import org.w3c.dom.Node;

import woolpack.bool.BoolUtils;
import woolpack.convert.ConvertUtils;
import woolpack.el.EL;
import woolpack.el.GettingEL;
import woolpack.fn.Fn;
import woolpack.fn.FnUtils;
import woolpack.xml.NodeContext;
import woolpack.xml.NodeFindable;
import woolpack.xml.NodeFindableChildNodesImpl;
import woolpack.xml.XmlUtils;

/**
 * ユーティリティです。
 * 型推論で表記を簡略するためのスタティックメソッドと変数を含みます。
 * 
 * @author nakamura
 * 
 */
public final class HtmlUtils {

	public static final SpaceCompressor COMPRESS_SPACE = new SpaceCompressor();
	public static final MergeCellAll MERGE_CELL_ALL = new MergeCellAll();
	public static final CaseNormalizer NORMALIZE_CASE = new CaseNormalizer();
	public static final CommentRemover REMOVE_COMMENT = new CommentRemover();
	public static final ThisAndTextsRemover REMOVE_THIS_AND_TEXTS = new ThisAndTextsRemover();

	static final NodeFindable TR = new NodeFindableChildNodesImpl(
	FnUtils.join(XmlUtils.GET_NODE_NAME, BoolUtils.checkEquals("TR")), false);

	static final NodeFindable TD = new NodeFindableChildNodesImpl(
			FnUtils.join(XmlUtils.GET_NODE_NAME, BoolUtils.checkEquals("TD")), false);

	private HtmlUtils() {
	}

	/**
	 * 指定された DOM ノードを削除し、さらにその後ろにあるテキストノードを全て削除します。
	 * ラジオボタン・チェックボックスを削除するために使用します。
	 * 
	 * @param node
	 */
	public static void removeThisAndText(final Node node) {
		Node nextNode = node.getNextSibling();
		while (nextNode != null && nextNode.getNodeType() == Node.TEXT_NODE) {
			XmlUtils.removeThis(nextNode);
			nextNode = node.getNextSibling();
		}
		XmlUtils.removeThis(node);
	}
	
	public static AutoUpdater updateAuto(
			final Iterable<String> attrNames,
			final GettingEL componentEL,
			final GettingEL configEL,
			final Set<Class> atomSet,
			final GettingEL errorEL) {
		return new AutoUpdater(attrNames, componentEL, configEL, atomSet, errorEL);
	}
	
	public static AutoUpdater updateAuto(
			final Iterable<String> attrNames,
			final GettingEL componentEL,
			final GettingEL configEL) {
		return new AutoUpdater(attrNames, componentEL, configEL);
	}
	
	public static <C extends NodeContext> BranchPropertyCounter<C> branchPropertyCount(
			final EL el,
			final Iterable<String> attrNames,
			final Fn<? super C, Void> firstFn,
			final Fn<? super C, Void> pluralFn) {
		return new BranchPropertyCounter<C>(el, attrNames, firstFn, pluralFn);
	}
	
	public static RowAttrConverter convertRowAttr(final String attrName, final String[] attrValueArray) {
		return new RowAttrConverter(attrName, attrValueArray);
	}
	
	public static HiddenAppender hiddenAllToChild(
			final GettingEL mapEL,
			final Collection<String> excludeProperties) {
		return new HiddenAppender(mapEL, excludeProperties);
	}
	
	public static RowIndexInserter insertRowIndex(final String headValue) {
		return new RowIndexInserter(headValue);
	}
	
	public static RadioRemaker makeRadio(final GettingEL mapEL) {
		return new RadioRemaker(mapEL);
	}
	
	public static SelectRemaker makeSelect(final GettingEL mapEL) {
		return new SelectRemaker(mapEL);
	}
	
	public static MergeCell mergeCell(final int colIndex) {
		return new MergeCell(colIndex);
	}
	
	public static SelectedValueUpdater updateToSelectedValue(
			final GettingEL valueEL,
			final GettingEL mapEL) {
		return new SelectedValueUpdater(valueEL, mapEL);
	}
	
	public static ValueUpdater updateValue(
			final GettingEL valueEL,
			final GettingEL mapEL,
			final boolean selectFlag) {
		return new ValueUpdater(valueEL, mapEL, selectFlag);
	}
	
	public static ValueUpdater updateValue(
			final GettingEL valueEL,
			final GettingEL mapEL) {
		return new ValueUpdater(valueEL, mapEL);
	}
	
	public static ValueUpdater updateValue(
			final GettingEL valueEL) {
		return new ValueUpdater(valueEL);
	}

	/**
	 * 拡張子を取り除く{@link Fn}を返します。
	 * @param elementName
	 * @param attrName
	 * @return 拡張子を取り除く{@link Fn}。
	 */
	public static Fn<NodeContext, Void> removeExtension(final String elementName, final String attrName) {
		return XmlUtils.findNode(
			new NodeFindableChildNodesImpl(
					new Fn<Node, Boolean>() {
						public Boolean exec(final Node c) {
							return c.getNodeType() == Node.ELEMENT_NODE
							&& elementName.equals(c.getNodeName())
							&& ((Element) c).hasAttribute(attrName);
						}
					}, true),
			XmlUtils.updateAttrValue(attrName,
				FnUtils.join(
						XmlUtils.getAttrValue(attrName),
						ConvertUtils.convertRegExp(Pattern.compile("^([^\\.]+)\\.[^\\.]+$"), "$1"))));
	}
}
