/*
 *  Copyright (C) 2006  Takashi Kasuya <kasuya@sfc.keio.ac.jp>
 *
 * This library is free software; you can redistribute it and/or
 *　modify it under the terms of the GNU Lesser General Public
 *　License as published by the Free Software Foundation; either
 *　version 2.1 of the License, or (at your option) any later version.
 *　This library is distributed in the hope that it will be useful,
 *　but WITHOUT ANY WARRANTY; without even the implied warranty of
 *　MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *　Lesser General Public License for more details.
 *
 *　You should have received a copy of the GNU Lesser General Public
 *　License along with this library; if not, write to the Free Software
 *　Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

package jp.ac.naka.ec.entity;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.StringTokenizer;

import javax.sip.address.SipURI;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import jp.ac.naka.ec.Location;
import jp.ac.naka.ec.sip.SipCore;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

/**
 * Entityを生成するためのパーサ。DTDなどを作る必要あり。
 * 
 * @author Takashi Kasuya
 * 
 */
public class EntityConfigParser {

	public static Log logger = LogFactory.getLog(EntityConfigParser.class);

	/**
	 * entities.xmlからEntityを読み出すためのパーサ。
	 * 
	 * @param config_file
	 * @return
	 */
	public Entity[] parse(final String config_file) {

		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		try {
			DocumentBuilder db = dbf.newDocumentBuilder();
			db.setErrorHandler(new ErrorHandler() {
				public void error(SAXParseException e) throws SAXException {
					logger.error("Error while parsing " + config_file, e);
				}

				public void fatalError(SAXParseException e) throws SAXException {
					logger.error("Error while parsing " + config_file, e);
				}

				public void warning(SAXParseException e) throws SAXException {
					logger.error("Error while parsing " + config_file, e);
				}
			});
			Document doc = db.parse(new File(config_file));
			Element root = doc.getDocumentElement();
			NodeList entities = root.getElementsByTagName("entity");

			ArrayList<Entity> list = new ArrayList<Entity>();

			list = parseEntity(entities);
			Entity[] a = new Entity[list.size()];
			return list.toArray(a);
		} catch (Exception e) {
			logger.error("Error while initiating Entity class", e);
		}
		return new Entity[0];
	}

	/**
	 * 
	 * @param entities
	 * @return
	 * @throws IOException 
	 * @throws ParseException 
	 */
	private static ArrayList<Entity> parseEntity(NodeList entities) throws IOException, ParseException {
		String host = EntityContainerImpl.getIpAddress(EntityContainerImpl.getHostName()) +":"+SipCore.PORT;
		ArrayList<Entity> list = new ArrayList<Entity>();
		for (int i = 0; i < entities.getLength(); i++) {
			Element entity = (Element) entities.item(i);
			String id = entity.getAttribute("id");
			String cls = entity.getAttribute("class");
			// type
			Node temp = entity.getElementsByTagName("type").item(0);
			String type = "SENSOR";
			if (temp != null) {
				type = temp.getFirstChild().getNodeValue();
			}
			// Description
			String description = "";
			temp = entity.getElementsByTagName("description").item(0);
			if (temp != null) {
				description = temp.getFirstChild().getNodeValue();
			}
			// keyword
			String[] keywords = null;
			temp = entity.getElementsByTagName("keywords").item(0);
			if (temp != null) {
				String str = temp.getFirstChild().getNodeValue();
				StringTokenizer stToken = new StringTokenizer(str, ", ");
				keywords = new String[stToken.countTokens()];
				int num = 0;
				while (stToken.hasMoreTokens()) {
					keywords[num++] = stToken.nextToken();
				}
			}
			SipURI uri = EntityImpl.createSipURI(id, host);
			Class clazz;
			Entity instance;
			try {
				clazz = Class.forName(cls);
				clazz.getConstructors();
				instance = (Entity)clazz.newInstance();
			} catch (ClassNotFoundException e) {
				logger.error("Could not found class :" + cls, e);
				continue;
			} catch (Exception e) {
				logger.error("Error while initiating class :" + cls, e);
				continue;
			}
			instance.setURI(uri);
			instance.setName(id);
			instance.setDescrpition(description);
			instance.setEntityType(EntityType.valueOf(type));
			if (instance instanceof AbstractEntity) {
				//((AbstractEntity)instance).init();
			}
			if (keywords != null) {
				for (String keyword:keywords) {
					instance.addKeyword(keyword);
				}
			}
			// location
			temp = entity.getElementsByTagName("location").item(0);
			if (temp != null) {
				String location = ((Element) temp).getAttribute("name");
				temp = ((Element) temp).getElementsByTagName("latitude")
						.item(0);
				String lat = "", lon = "";
				if (temp != null) {
					lat = temp.getFirstChild().getNodeValue();
					temp = temp.getNextSibling();
					do {
						if (temp.getNodeType() != Node.TEXT_NODE
								&& temp.getNodeName().equals("longitude")) {
							lon = temp.getFirstChild().getNodeValue();
							break;
						}
						temp = temp.getNextSibling();
					} while (temp != null);
				}
				if (!lat.equals("") && !lon.equals("")) {
					instance.setLocation(new Location(location, lat, lon));
				}

			}
			list.add(instance);

		}
		return list;
	}

	
	public static void main(String[] args) {
		EntityConfigParser parser = new EntityConfigParser();
		Entity[] entities = parser.parse("config/entities.xml");
		for (Entity entity:entities) {
			System.out.println(entity);
		}
	}
}
