/*
 * 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.Writer;
import java.util.Iterator;
import java.util.Map;

import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;

import org.maskat.framework.BasicDef;
import org.maskat.framework.IBasicDef;
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.DescDef;
import org.maskat.framework.screendef.DivHtmlDef;
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.JavaScriptDef;
import org.maskat.framework.screendef.JavaScriptGlobal;
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.TreeNodeDef;
import org.maskat.framework.screendef.TreeViewDef;
import org.maskat.framework.screendef.customize.CustomizeDef;
import org.maskat.framework.screendef.customize.IPluginComponentDef;
import org.maskat.xml.DefXmlSerializer;

public class LayoutDefXmlSerializer extends DefXmlSerializer {

	public LayoutDefXmlSerializer(MaskatDef def, Writer writer) {
		super(def, writer);
	}

	protected void writeObj(XMLStreamWriter writer, Object def, int hierarchyLvl)
			throws XMLStreamException {

		writer.writeCharacters("\n");
		writeIndent(writer, hierarchyLvl);
		writer.writeStartElement(getElementName(def));

		// ここではnamespaceの定義をdefから取り出せます
		if (def instanceof MaskatDef) {
			Map namespaceMap = ((MaskatDef) def).getNamespaces();
			if (namespaceMap != null) {
				for (Iterator it = namespaceMap.keySet().iterator(); it != null
						&& it.hasNext();) {
					String uri = (String) it.next();
					String prefix = (String) namespaceMap.get(uri);
					writer.writeNamespace(prefix, uri);
				}
			}
		}
		if (def instanceof LayoutDef) {
			LayoutDef layoutDef = (LayoutDef) def;
			layoutDef.packRadioGroup();
		}

		// write attribute
		writeDefAttribute(writer, def);

		// write children
		if (def instanceof DescDef) {
			writer.writeCData(((DescDef) def).getComment());
		}
		if (def instanceof JavaScriptDef) {
			writer.writeCData(((JavaScriptDef) def).getContent());
		}
		if (def instanceof DivHtmlDef) {
			writer.writeCData(((DivHtmlDef) def).getHtml());
		}
		boolean hasChildren = false;
		if (def instanceof BasicDef) {
			for (Iterator it = ((IBasicDef) def).getAllChildren(); it != null
					&& it.hasNext();) {
				hasChildren = true;

				Object next = it.next();
				writeObj(writer, next, hierarchyLvl + 1);
			}
		}

		if (hasChildren) {
			writer.writeCharacters("\n");
			writeIndent(writer, hierarchyLvl);
		}

		writer.writeEndElement();

	}

	protected String getElementName(Object def) {
		if (def instanceof CustomizeDef) {
			return ((CustomizeDef) def).getQName();
		}
		if (def instanceof IPluginComponentDef) {
			return ((IPluginComponentDef) def).getProxy().getQName();
		}
		if (def instanceof MaskatDef) {
			return "layoutDef";
		}
		if (def instanceof LayoutDef) {
			return "layout";
		}
		if (def instanceof FrameDef) {
			return "frame";
		}
		if (def instanceof DescDef) {
			return "desc";
		}
		if (def instanceof JavaScriptGlobal) {
			return "javaScriptGlobal";
		}
		if (def instanceof JavaScriptDef) {
			return "javaScript";
		}
		if (def instanceof DivHtmlDef) {
			return "divHtml";
		}
		if (def instanceof SplitterDef) {
			return "splitter";
		}
		if (def instanceof DivSplitDef) {
			return "divSplit";
		}
		if (def instanceof TabFolderDef) {
			return "tabFolder";
		}
		if (def instanceof TabItemDef) {
			return "tabItem";
		}
		if (def instanceof ImageDef) {
			return "image";
		}
		if (def instanceof LabelDef) {
			return "label";
		}
		if (def instanceof TextDef) {
			return "text";
		}
		if (def instanceof CodeLibDef) {
			return "codeLib";
		}
		if (def instanceof ButtonDef) {
			return "button";
		}
		if (def instanceof RadioDef) {
			return "radio";
		}
		if (def instanceof CheckboxDef) {
			return "checkbox";
		}
		if (def instanceof ComboDef) {
			return "combo";
		}
		if (def instanceof ComboItemDef) {
			return "comboItem";
		}
		if (def instanceof GridDef) {
			return "grid";
		}
		if (def instanceof GridHeaderDef) {
			return "gridHeader";
		}
		if (def instanceof GridLineDef) {
			return "gridLine";
		}
		if (def instanceof GridCellDef) {
			return "gridCell";
		}
		if (def instanceof TreeViewDef) {
			return "treeview";
		}
		if (def instanceof TreeNodeDef) {
			return "treeNode";
		}
		if (def instanceof RadioGroupDef) {
			return "radioGroup";
		}
		if (def instanceof RadioMemberDef) {
			return "radioMember";
		}
		return "unknown";
	}

	protected void writeDefAttribute(XMLStreamWriter writer, Object def)
			throws XMLStreamException {
		if (def instanceof CustomizeDef) {
			CustomizeDef theDef = (CustomizeDef) def;
			if (theDef.getAttributes() != null) {
				for (int i = 0; i < theDef.getAttributes().size(); i++) {
					CustomizeDef.Attribute attribute = (CustomizeDef.Attribute) theDef
							.getAttributes().get(i);
					writeOneAttribute(writer, attribute.getName(), attribute.getValue());
				}
			}
			return;
		}
		if (def instanceof IPluginComponentDef) {
			IPluginComponentDef theDef = (IPluginComponentDef) def;
			Iterator it = theDef.getProxy().getAttributeNames();
			// how to write left,top,width,height property according to the
			// component's type. @see ComponentPluginConfig#defineProperty

			while (it != null && it.hasNext()) {
				String attribName = (String) it.next();
				writeOneAttribute(writer, attribName, theDef.getAttribute(attribName));
			}
			return;
		}
		if (def instanceof LayoutDef) {
			LayoutDef theDef = (LayoutDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "refParentHTML", theDef.getRefParentHTML());
			return;
		}
		if (def instanceof FrameDef) {
			FrameDef theDef = (FrameDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "width", String.valueOf(theDef.getWidth()));
			writeOneAttribute(writer, "height", String.valueOf(theDef.getHeight()));
			writeOneAttribute(writer, "title", theDef.getTitle());
			writeOneAttribute(writer, "position", theDef.getPosition());
			writeOneAttribute(writer, "draggable", theDef.getDraggable());
			writeOneAttribute(writer, "autoResizeParent", theDef.getAutoResizeParent());
			writeOneAttribute(writer, "dynamic", theDef.getDynamic());
			return;
		}
		if (def instanceof SplitterDef) {
			SplitterDef theDef = (SplitterDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "width", String.valueOf(theDef.getWidth()));
			writeOneAttribute(writer, "height", String.valueOf(theDef.getHeight()));
			writeOneAttribute(writer, "orientation", theDef.getOrientation());
			writeOneAttribute(writer, "style", theDef.getStyle());
			writeOneAttribute(writer, "prop", theDef.getProp());
			writeOneAttribute(writer, "limInf", theDef.getLimInf());
			writeOneAttribute(writer, "limSup", theDef.getLimSup());
			writeOneAttribute(writer, "withImg", theDef.getWithImg());
			writeOneAttribute(writer, "reverseClose", theDef.getReverseClose());
			writeOneAttribute(writer, "autoResizeParent", theDef.getAutoResizeParent());
			writeOneAttribute(writer, "autoResizableH", theDef.getAutoResizableH());
			writeOneAttribute(writer, "autoResizableW", theDef.getAutoResizableW());
			writeOneAttribute(writer, "tailleCurs", theDef.getTailleCurs());
			return;
		}
		if (def instanceof DivSplitDef) {
			DivSplitDef theDef = (DivSplitDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "backgroundColor", theDef.getBackgroundColor());
			return;
		}
		if (def instanceof TabFolderDef) {
			TabFolderDef theDef = (TabFolderDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "width", String.valueOf(theDef.getWidth()));
			writeOneAttribute(writer, "height", String.valueOf(theDef.getHeight()));
			writeOneAttribute(writer, "widthTabName", theDef.getWidthTabName());
			writeOneAttribute(writer, "noActiveTab", theDef.getNoActiveTab());
			writeOneAttribute(writer, "autoRedimTab", theDef.getAutoRedimTab());
			writeOneAttribute(writer, "autoResizeParent", theDef.getAutoResizeParent());
			writeOneAttribute(writer, "isClosable", theDef.getIsClosable());
			writeOneAttribute(writer, "draggableItem", theDef.getDraggableItem());
			return;
		}
		if (def instanceof TabItemDef) {
			TabItemDef theDef = (TabItemDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "title", theDef.getTitle());
			return;
		}
		if (def instanceof ImageDef) {
			ImageDef theDef = (ImageDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "imageOut", theDef.getImageOut());
			writeOneAttribute(writer, "imageOn", theDef.getImageOn());
			writeOneAttribute(writer, "alternateText", theDef.getAlternateText());
			return;
		}
		if (def instanceof LabelDef) {
			LabelDef theDef = (LabelDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "text", theDef.getText());
			writeOneAttribute(writer, "className", theDef.getClassName());
			return;
		}
		if (def instanceof TextDef) {
			TextDef theDef = (TextDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "width", String.valueOf(theDef.getWidth()));
			writeOneAttribute(writer, "datatype", theDef.getDatatype());
			writeOneAttribute(writer, "isRequired", theDef.getIsRequired());
			writeOneAttribute(writer, "disable", theDef.getDisable());
			writeOneAttribute(writer, "autoUp", theDef.getAutoUp());
			writeOneAttribute(writer, "rows", theDef.getRows());
			return;
		}
		if (def instanceof CodeLibDef) {
			CodeLibDef theDef = (CodeLibDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "width", String.valueOf(theDef.getWidth()));
			writeOneAttribute(writer, "url", theDef.getUrl());
			writeOneAttribute(writer, "boolWithLabel", theDef.getBoolWithLabel());
			return;
		}
		if (def instanceof ButtonDef) {
			ButtonDef theDef = (ButtonDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "title", theDef.getTitle());
			writeOneAttribute(writer, "alt", theDef.getAlt());
			writeOneAttribute(writer, "enable", theDef.getEnable());
			return;
		}
		if (def instanceof RadioDef) {
			RadioDef theDef = (RadioDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "text", theDef.getText());
			writeOneAttribute(writer, "className", theDef.getClassName());
			// writeOneAttribute(writer, "group", theDef.getGroup());
			// Radio component's group attribute is managed by the radioGroup
			// member.
			writeOneAttribute(writer, "checked", theDef.getChecked());
			return;
		}
		if (def instanceof CheckboxDef) {
			CheckboxDef theDef = (CheckboxDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "text", theDef.getText());
			writeOneAttribute(writer, "className", theDef.getClassName());
			writeOneAttribute(writer, "checked", theDef.getChecked());
			return;
		}
		if (def instanceof ComboDef) {
			ComboDef theDef = (ComboDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "width", String.valueOf(theDef.getWidth()));
			writeOneAttribute(writer, "enable", theDef.getEnable());
			writeOneAttribute(writer, "heightItem", theDef.getHeightItem());
			return;
		}
		if (def instanceof ComboItemDef) {
			ComboItemDef theDef = (ComboItemDef) def;
			writeOneAttribute(writer, "text", theDef.getText());
			writeOneAttribute(writer, "value", theDef.getValue());
			return;
		}
		if (def instanceof GridDef) {
			GridDef theDef = (GridDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "height", String.valueOf(theDef.getHeight()));
			writeOneAttribute(writer, "rang", theDef.getRang());
			writeOneAttribute(writer, "lineHeight", theDef.getLineHeight());
			writeOneAttribute(writer, "autoResizeParent", theDef.getAutoResizeParent());
			writeOneAttribute(writer, "multiSelect", theDef.getMultiSelect());
			writeOneAttribute(writer, "sortable", theDef.getSortable());
			writeOneAttribute(writer, "actifClic", theDef.getActifClic());
			writeOneAttribute(writer, "cellActive", theDef.getCellActive());
			writeOneAttribute(writer, "switchable", theDef.getSwitchable());
			writeOneAttribute(writer, "bNavig", theDef.getBNavig());
			writeOneAttribute(writer, "boolPrint", theDef.getBoolPrint());
			writeOneAttribute(writer, "writable", theDef.getWritable());
			writeOneAttribute(writer, "widthLastCell", theDef.getWidthLastCell());
			return;
		}
		if (def instanceof GridHeaderDef) {
			GridHeaderDef theDef = (GridHeaderDef) def;
			writeOneAttribute(writer, "width", String.valueOf(theDef.getWidth()));
			writeOneAttribute(writer, "title", theDef.getTitle());
			writeOneAttribute(writer, "type", theDef.getType());
			return;
		}
		if (def instanceof GridCellDef) {
			GridCellDef theDef = (GridCellDef) def;
			writeOneAttribute(writer, "value", theDef.getValue());
			return;
		}
		if (def instanceof TreeViewDef) {
			TreeViewDef theDef = (TreeViewDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "top", String.valueOf(theDef.getTop()));
			writeOneAttribute(writer, "left", String.valueOf(theDef.getLeft()));
			writeOneAttribute(writer, "width", String.valueOf(theDef.getWidth()));
			writeOneAttribute(writer, "height", String.valueOf(theDef.getHeight()));
			writeOneAttribute(writer, "boolSelActive", theDef.getBoolSelActive());
			writeOneAttribute(writer, "withRoot", theDef.getWithRoot());
			writeOneAttribute(writer, "rootOpen", theDef.getRootOpen());
			writeOneAttribute(writer, "withT", theDef.getWithT());
			writeOneAttribute(writer, "autoResizableH", theDef.getAutoResizableH());
			writeOneAttribute(writer, "autoResizableW", theDef.getAutoResizableW());
			writeOneAttribute(writer, "draggableNode", theDef.getDraggableNode());
			return;
		}
		if (def instanceof TreeNodeDef) {
			TreeNodeDef theDef = (TreeNodeDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
			writeOneAttribute(writer, "text", theDef.getText());
			writeOneAttribute(writer, "icon", theDef.getIcon());
			writeOneAttribute(writer, "icon2", theDef.getIcon2());
			writeOneAttribute(writer, "open", theDef.getOpen());
			writeOneAttribute(writer, "reload", theDef.getReload());
			writeOneAttribute(writer, "url", theDef.getUrl());
			writeOneAttribute(writer, "typeInfo", theDef.getTypeInfo());
			writeOneAttribute(writer, "onclick", theDef.getOnclick());
			return;
		}
		if (def instanceof RadioGroupDef) {
			RadioGroupDef theDef = (RadioGroupDef) def;
			writeOneAttribute(writer, "name", theDef.getName());
		}
		if (def instanceof RadioMemberDef) {
			RadioMemberDef theDef = (RadioMemberDef) def;
			writeOneAttribute(writer, "ref", theDef.getRef());
		}
	}

	protected void customizeWrite(XMLStreamWriter writer) throws XMLStreamException {
		writer.writeDTD("<!DOCTYPE layoutDef SYSTEM \"layoutDef.dtd\">");
	}
}