package com.ampiere.util.ajax;

import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;

import com.ampiere.dto.Item;

/**
 * Helper class to build valid XML typically returned in a response to the client.
 *
 * @author Bato
 * @version $Revision: 1.1 $ $Date: 2010/01/13 11:52:48 $
 */
public class AjaxXmlItemBuilder {

	private String encoding = "UTF-8";

	private Map<String,String> targetInfo = new HashMap<String,String>();

	private List<Item> items = new ArrayList<Item>();

	public String getEncoding() {
		return encoding;
	}

	public void setEncoding(String encoding) {
		this.encoding = encoding;
	}

	/**
	 * Add root property.
	 *
	 * @param name The name of the item
	 * @param value The value of the item
	 * @return
	 */
	public AjaxXmlItemBuilder putInfo(String name, String value) {
		targetInfo.put(name,value);
		return this;
	}

	/**
	 * Add item to XML.
	 *
	 * @param name The name of the item
	 * @param value The value of the item
	 * @return
	 */
	public AjaxXmlItemBuilder addItem(String name, String value) {
		items.add(new Item(name, value, false));
		return this;
	}

	/**
	 * Add item wrapped with inside a CDATA element.
	 *
	 * @param name The name of the item
	 * @param value The value of the item
	 * @return
	 */
	public AjaxXmlItemBuilder addItemAsCData(String name, String value) {
		items.add(new Item(name, value, true));
		return this;
	}

	/**
	 * Add items from a collection.
	 *
	 * @param collection
	 * @param nameProperty
	 * @param valueProperty
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public AjaxXmlItemBuilder addItems(Collection collection,
			String nameProperty, String valueProperty)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		return addItems(collection, nameProperty, valueProperty, false);
	}

	/**
	 * Add items from a collection.
	 *
	 * @param collection
	 * @param nameProperty
	 * @param valueProperty
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public AjaxXmlItemBuilder addItems(Collection collection,
			String nameProperty, String valueProperty, boolean asCData)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		for (Iterator iter = collection.iterator(); iter.hasNext();) {
			Object element = (Object) iter.next();
			String name = BeanUtils.getProperty(element, nameProperty);
			String value = BeanUtils.getProperty(element, valueProperty);
			if (asCData) {
				items.add(new Item(name, value, false));
			} else {
				items.add(new Item(name, value, true));

			}
		}
		return this;
	}

	/**
	 * Add items from a collection as CDATA element.
	 *
	 * @param collection
	 * @param nameProperty
	 * @param valueProperty
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public AjaxXmlItemBuilder addItemsAsCData(Collection collection,
			String nameProperty, String valueProperty)
			throws IllegalAccessException, InvocationTargetException,
			NoSuchMethodException {
		return addItems(collection, nameProperty, valueProperty, true);
	}

	/**
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		StringBuffer xml = new StringBuffer().append("<?xml version=\"1.0\"");
		if (encoding != null) {
			xml.append(" encoding=\"");
			xml.append(encoding);
			xml.append("\"");
		}
		xml.append(" ?>");

		xml.append("<ajax-response>");
		xml.append("<response>");
		xml.append(toStringItems(false));
		xml.append("</response>");
		xml.append("</ajax-response>");

		return xml.toString();

	}

	/**
	 * make name-value pair xml block.
	 */
	public String toStringItems(boolean hasTargetInfo){
		
		StringBuffer xml = new StringBuffer();
		
		if (hasTargetInfo){
			xml.append("<target ");
			for (Iterator iter = targetInfo.keySet().iterator(); iter.hasNext();) {
				Object keyObj = iter.next();
				xml.append(keyObj + "=\"" + targetInfo.get(keyObj) + "\" " );
			}
			xml.append(">");
		}
		
		for (Iterator iter = items.iterator(); iter.hasNext();) {
			Item item = (Item) iter.next();
			xml.append("<item>");
			xml.append("<name>");
			if (item.isAsCData()) {
				xml.append("<![CDATA[");
			}
			xml.append(item.getName());
			if (item.isAsCData()) {
				xml.append("]]>");
			}
			xml.append("</name>");
			xml.append("<value>");
			if (item.isAsCData()) {
				xml.append("<![CDATA[");
			}
			xml.append(item.getValue());
			if (item.isAsCData()) {
				xml.append("]]>");
			}
			xml.append("</value>");
			xml.append("</item>");
		}
		
		if (hasTargetInfo) xml.append("</target>");

		return xml.toString();
	}
	
	/* ------------------ private functions ---------------------- */

}
