/*
 * Copyright 2006 Mask@ Project.
 * 
 * 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 org.maskat.framework.screendef.xml;

import java.io.InputStream;
import java.util.Iterator;

import org.apache.commons.digester.RegexMatcher;
import org.apache.commons.digester.SimpleRegexMatcher;
import org.maskat.framework.screendef.ButtonDef;
import org.maskat.framework.screendef.CheckboxDef;
import org.maskat.framework.screendef.CodeLibDef;
import org.maskat.framework.screendef.ComboDef;
import org.maskat.framework.screendef.ComboItemDef;
import org.maskat.framework.screendef.DivSplitDef;
import org.maskat.framework.screendef.FrameDef;
import org.maskat.framework.screendef.GridCellDef;
import org.maskat.framework.screendef.GridDef;
import org.maskat.framework.screendef.GridHeaderDef;
import org.maskat.framework.screendef.GridLineDef;
import org.maskat.framework.screendef.ImageDef;
import org.maskat.framework.screendef.LabelDef;
import org.maskat.framework.screendef.LayoutDef;
import org.maskat.framework.screendef.MaskatDef;
import org.maskat.framework.screendef.RadioDef;
import org.maskat.framework.screendef.RadioGroupDef;
import org.maskat.framework.screendef.RadioMemberDef;
import org.maskat.framework.screendef.SplitterDef;
import org.maskat.framework.screendef.TabFolderDef;
import org.maskat.framework.screendef.TabItemDef;
import org.maskat.framework.screendef.TextDef;
import org.maskat.framework.screendef.TreeViewDef;
import org.maskat.framework.screendef.WindowDef;
import org.maskat.xml.MaskatRegexRules;
import org.maskat.xml.digester.MaskatDigester;
import org.maskat.xml.digester.rules.CustomizeComponentRule;

public class LayoutDefParser {

	public static MaskatDef parse(InputStream input) throws Exception {

		MaskatDigester digester = new MaskatDigester();

		// digester.setValidating(false);
		digester.setNamespaceAware(true);
		RegexMatcher m = new SimpleRegexMatcher();
		digester.setRules(new MaskatRegexRules(m));

		digester.addObjectCreate("layoutDef", null, MaskatDef.class);

		digester.addCallMethod("layoutDef/javaScriptGlobal", "addJavaScriptGlobal", 0);

		digester.addObjectCreate("*/layout", null, LayoutDef.class);
		digester.addSetProperties("*/layout");
		digester.addSetNext("*/layout", "addChild", Object.class.getName());

		digester.addCallMethod("*/desc", "addDesc", 0);

		digester.addCallMethod("*/divHtml", "addDivHtml", 0);

		digester.addCallMethod("*/javaScript", "addJavaScript", 0);

		digester.addCallMethod("*/layout/objs", "addObjs", 0);

		digester.addObjectCreate("*/window", null, WindowDef.class);
		digester.addSetProperties("*/window");
		digester.addSetNext("*/window", "addChild", WindowDef.class.getName());

		digester.addObjectCreate("*/frame", null, FrameDef.class);
		digester.addSetProperties("*/frame");
		digester.addSetNext("*/frame", "addChild", FrameDef.class.getName());

		// digester.addObjectCreate("*/alert", null, AlertDef.class);
		// digester.addSetProperties("*/alert");
		// digester.addSetNext("*/alert", "addChild", AlertDef.class.getName());

		digester.addObjectCreate("*/button", null, ButtonDef.class);
		digester.addSetProperties("*/button");
		digester.addSetNext("*/button", "addChild", ButtonDef.class.getName());

		digester.addObjectCreate("*/label", null, LabelDef.class);
		digester.addSetProperties("*/label");
		digester.addSetNext("*/label", "addChild", LabelDef.class.getName());

		digester.addObjectCreate("*/text", null, TextDef.class);
		digester.addSetProperties("*/text");
		digester.addSetNext("*/text", "addChild", TextDef.class.getName());

		// gridコンポーネント
		digester.addObjectCreate("*/grid", null, GridDef.class);
		digester.addSetProperties("*/grid");
		digester.addSetNext("*/grid", "addChild", GridDef.class.getName());

		digester.addObjectCreate("*/gridHeader", null, GridHeaderDef.class);
		digester.addSetProperties("*/gridHeader");
		digester.addSetNext("*/gridHeader", "addChild", GridHeaderDef.class.getName());

		digester.addObjectCreate("*/gridLine", null, GridLineDef.class);
		digester.addSetProperties("*/gridLine");
		digester.addSetNext("*/gridLine", "addChild", GridLineDef.class.getName());

		digester.addObjectCreate("*/gridCell", null, GridCellDef.class);
		digester.addSetProperties("*/gridCell");
		digester.addSetNext("*/gridCell", "addChild", GridCellDef.class.getName());
		// gridコンポーネント

		digester.addObjectCreate("*/checkbox", null, CheckboxDef.class);
		digester.addSetProperties("*/checkbox");
		digester.addSetNext("*/checkbox", "addChild", CheckboxDef.class.getName());

		digester.addObjectCreate("*/radio", null, RadioDef.class);
		digester.addSetProperties("*/radio");
		digester.addSetNext("*/radio", "addChild", RadioDef.class.getName());

		// コンボコンポーネント
		digester.addObjectCreate("*/combo", null, ComboDef.class);
		digester.addSetProperties("*/combo");
		digester.addSetNext("*/combo", "addChild", ComboDef.class.getName());

		digester.addObjectCreate("*/comboItem", null, ComboItemDef.class);
		digester.addSetProperties("*/comboItem");
		digester.addSetNext("*/comboItem", "addChild", ComboItemDef.class.getName());
		// コンボコンポーネント

		// タブコンポーネント
		digester.addObjectCreate("*/tabFolder", null, TabFolderDef.class);
		digester.addSetProperties("*/tabFolder");
		digester.addSetNext("*/tabFolder", "addChild", TabFolderDef.class.getName());

		digester.addObjectCreate("*/tabItem", null, TabItemDef.class);
		digester.addSetProperties("*/tabItem");
		digester.addSetNext("*/tabItem", "addChild", TabItemDef.class.getName());
		// タブコンポーネント

		// イメージ
		digester.addObjectCreate("*/image", null, ImageDef.class);
		digester.addSetProperties("*/image");
		digester.addSetNext("*/image", "addChild", ImageDef.class.getName());
		// イメージ

		// コードライブラリ
		digester.addObjectCreate("*/codeLib", null, CodeLibDef.class);
		digester.addSetProperties("*/codeLib");
		digester.addSetNext("*/codeLib", "addChild", CodeLibDef.class.getName());
		// コードライブラリ

		// splitter
		digester.addObjectCreate("*/splitter", null, SplitterDef.class);
		digester.addSetProperties("*/splitter");
		digester.addSetNext("*/splitter", "addChild", SplitterDef.class.getName());

		digester.addObjectCreate("*/divSplit", null, DivSplitDef.class);
		digester.addSetProperties("*/divSplit");
		digester.addSetNext("*/divSplit", "addChild", DivSplitDef.class.getName());
		// splitter

		// ツリー
		digester.addObjectCreate("*/treeview", null, TreeViewDef.class);
		digester.addSetProperties("*/treeview");
		digester.addSetNext("*/treeview", "addChild", TreeViewDef.class.getName());
		// ツリー

		// ツリーノード
		// digester.addObjectCreate("*/treeNode", null, TreeNodeDef.class);
		// digester.addSetProperties("*/treeNode");
		// digester.addSetNext("*/treeNode", "addChild",
		// TreeNodeDef.class.getName());
		// ツリーノード

		// ポップアップ
		// digester.addObjectCreate("*/pop", null, PopupDef.class);
		// digester.addSetProperties("*/pop");
		// digester.addSetNext("*/pop", "addChild", PopupDef.class.getName());
		// ポップアップ

		digester.addObjectCreate("*/layout/radioGroup", null, RadioGroupDef.class);
		digester.addSetProperties("*/layout/radioGroup");
		digester.addSetNext("*/layout/radioGroup", "addChild", RadioGroupDef.class
				.getName());

		digester.addObjectCreate("*/layout/radioGroup/radioMember", null,
				RadioMemberDef.class);
		digester.addSetProperties("*/layout/radioGroup/radioMember");
		digester.addSetNext("*/layout/radioGroup/radioMember", "addChild",
				RadioMemberDef.class.getName());

		// !! */* ルールは一番最後に定義することを注意！!
		digester.addRule("*/*", new CustomizeComponentRule());
		//digester.addSetProperties("*/*");
		digester.addSetNext("*/*", "addChild", Object.class.getName());

		MaskatDef maskatDef = (MaskatDef) digester.parse(input);

		// ここでは、digesterにprefixとnamespaceURIのマップが出来上がったので
		// MaskatDefに一時保存
		maskatDef.setNamespaces(digester.getNamespaceMap());
		// List layoutList = maskatDef.getLayoutList();
		// if (layoutList == null || layoutList.size() != 1) {
		// throw new Exception("レイアウト定義XMLにはlayout要素一個しか定義できません。");
		// }

		Iterator it = maskatDef.getTypedChildren(LayoutDef.class);
		boolean hasLayout = false;
		while (it.hasNext()) {
			hasLayout = true;
			((LayoutDef) it.next()).unpackRadioGroup();
		}
		if (!hasLayout) {
			maskatDef.addChild(new LayoutDef());
		}
		return maskatDef;
	}
}
