/*
 *  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.util.ArrayList;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import jp.ac.naka.ec.Location;
import jp.ac.naka.ec.Main;

import org.apache.log4j.PropertyConfigurator;
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 org.apache.log4j.Logger logger = org.apache.log4j.Logger
			.getLogger(EntityConfigParser.class);

	/**
	 * entities.xmlからEntityを読み出すためのパーサ。
	 * @param config_file
	 * @return
	 */
	public static Entity[] parse(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 " + Main.entity_config,
									e);
					System.exit(-1);
				}

				public void fatalError(SAXParseException e) throws SAXException {
					logger
							.error("Error while parsing " + Main.entity_config,
									e);
					System.exit(-1);
				}

				public void warning(SAXParseException e) throws SAXException {
					logger
							.error("Error while parsing " + Main.entity_config,
									e);
					System.exit(-1);
				}
			});
			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
	 */
	private static ArrayList<Entity> parseEntity(NodeList entities) {
		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();
			}
			Class<Entity> clazz;
			Entity instance;
			try {
				clazz = (Class<Entity>) Class.forName(cls);
				instance = 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.setName(id);
			instance.setEntityType(EntityType.valueOf(type));
			// 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;
	}

}
