/*
 * 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 org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

import woolpack.xml.AbstractNodeSeeker;
import woolpack.xml.NodeContext;
import woolpack.xml.XmlUtils;

/**
 * エレメント名を大文字に、属性名を小文字に変換する{@link woolpack.fn.Fn}です。
 * @author nakamura
 *
 */
public class CaseNormalizer extends AbstractNodeSeeker<NodeContext> {
	@Override
	public Void exec(final NodeContext context) {
		super.exec(context);
		if (context.getNode().getNodeType() == Node.ELEMENT_NODE) {
			final Element e = (Element) context.getNode();
			final Element newE;
			{
				final String s = e.getNodeName().toUpperCase();
				if (s.equals(e.getNodeName())) {
					newE = e;
				} else {
					newE = XmlUtils.getDocumentNode(e).createElement(s);
				}
			}

			{
				final NamedNodeMap attrs = e.getAttributes();
				final Attr[] attrArray = new Attr[attrs.getLength()];
				for (int i = 0; i < attrArray.length; i++) {
					attrArray[i] = (Attr) attrs.item(i);
				}
				for (int i = 0; i < attrArray.length; i++) {
					final Attr attr = attrArray[i];
					final String s = attr.getName().toLowerCase();
					if (e != newE || !s.equals(attr.getName())) {
						if (e == newE) {
							newE.removeAttributeNode(attr);
						}
						newE.setAttribute(s, attr.getNodeValue());
					}
				}
			}
			if (e != newE) {
				{
					Node child = null;
					while ((child = e.getFirstChild()) != null) {
						newE.appendChild(child);
					}
				}
				e.getParentNode().replaceChild(newE, e);
			}
		}
		return null;
	}
}
