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

import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.sip.address.URI;

import jp.ac.naka.ec.EventDispatcher;
import jp.ac.naka.ec.entity.Entity;
import jp.ac.naka.ec.entity.EntityEvent;
import jp.ac.naka.ec.entity.EntityEventDispatcher;
import jp.ac.naka.ec.entity.EntityListener;
import jp.ac.naka.ec.entity.EntityType;
import jp.ac.naka.ec.entity.EntityEvent.EventType;

/**
 * @author kasuya
 * 
 */
public class TupleSpaceAdapter implements EventDispatcher {

	private EventDispatcher dispatcher;

	private static TupleSpaceAdapter tuple = new TupleSpaceAdapter();

	private DatabaseConnector con;

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

	private TupleSpaceAdapter() {
		dispatcher = EntityEventDispatcher.getInstance();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jp.ac.naka.ec.EventDispatcher#addEntityListener(jp.ac.naka.ec.entity.EntityListener)
	 */
	public void addEntityListener(EntityListener listener) {
		dispatcher.addEntityListener(listener);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see jp.ac.naka.ec.EventDispatcher#dispatchEvent(jp.ac.naka.ec.entity.EntityEvent)
	 */
	public void dispatchEvent(EntityEvent evt) {
		if (con != null && evt.getSource() instanceof Entity
				&& evt.getEventType() == EventType.MESSAGE) {
			storeData(evt);
		}
		if (evt.getMessage() != null && evt.getSource() instanceof Entity
				&& evt.getEventType() == EventType.MESSAGE) {
			Entity source = (Entity) evt.getSource();
			URI uri = source.getURI();
			if (uri != null) {
				String key = uri.toString();
				EventData temp = new EventData();
				temp.name = source.getName();
				temp.value = evt.getMessage();
				if (evt.getMessage().equals("")) {
					// store sdp
					temp.value = evt.getSessionDescription().toString();
				}
				SimpleDateFormat formatter = new SimpleDateFormat(
						"yyyy.MM.dd 'at' hh:mm:ss");
				Date currentTime_1 = new Date();
				String dateString = formatter.format(currentTime_1);
				temp.date = dateString;
				if (source.getLocation() != null)
					temp.location = source.getLocation();
				map.put(key, temp);
			}
		}
		dispatcher.dispatchEvent(evt);
	}

	/**
	 * 最新データのみ配信
	 * 
	 * @param uri
	 * @return
	 */
	public String getDataByXML(String uri) {
		String ret = "";
		StringBuilder builder = new StringBuilder();
		builder.append("<event>");
		if (uri == null) {
			// Retrieve all current data
			Set<String> set = map.keySet();

			for (String key : set) {
				EventData data = map.get(key);
				builder.append("<data uri=\"" + key + "\">");
				builder.append("<values>");
				String value;
				if (data.location != null)
					value = "<value name=\"" + data.name + "\" time=\""
							+ data.date + "\" location=\""
							+ data.location.getName() + "\" latitude=\""
							+ data.location.getLatitude() + "\" longitude=\""
							+ data.location.getLongitude() + "\">" + data.value
							+ "</value>";
				else
					value = "<value name=\"" + data.name + "\" time=\""
							+ data.date + "\">" + data.value + "</value>";
				builder.append(value);
				builder.append("</values>");

				builder.append("</data>");
			}

		} else {
			EventData data = map.get(uri);
			if (data != null) {
				builder.append("<data uri=\"" + uri + ">");
				builder.append("<values>");
				String value;
				if (data.location != null)
					value = "<value name=\"" + data.name + "\" time=\""
							+ data.date + "\" location=\""
							+ data.location.getName() + "\" latitude=\""
							+ data.location.getLatitude() + "\" longitude=\""
							+ data.location.getLongitude() + "\">" + data.value
							+ "</value>";
				else
					value = "<value name=\"" + data.name + "\" time=\""
							+ data.date + "\">" + data.value + "</value>";
				builder.append(value);
				builder.append("</values>");

				builder.append("</data>");
			}
		}
		builder.append("</event>");
		ret = builder.toString();
		return ret;
	}

	/**
	 * 
	 * @param uri
	 * @param num
	 * @return
	 * @throws SQLException
	 */
	public String getDataByXML(String uri, int num) throws SQLException {
		String ret = "";
		if (uri == null) {
			// TODO
		} else {
			StringBuilder builder = new StringBuilder();

			if (con == null) {
				return "";
			}
			builder.append("<event>");
			EventData[] data = con.getData(uri, num);
			builder.append("<data uri=\"" + uri + "\">");

			int count = 0;
			if (data.length != 0) {
				// 現状では全て一緒に帰ってくる
				/*
				 * if (data[0].location != null) { builder.append("<location
				 * name=\"" + data[0].location.getName() + "\">");
				 * builder.append(makeXML("latitude", data[0].location
				 * .getLatitude())); builder.append(makeXML("longitude",
				 * data[0].location .getLongitude())); builder.append("</location>"); }
				 */
				builder.append("<values>");
				for (EventData d : data) {
					if (d == null)
						break;
					String value = "";
					if (d.location != null)
						value = "<value seq=\"" + count++ + "\" name=\""
								+ d.name + "\" time=\"" + d.date
								+ "\" location=\"" + d.location.getName()
								+ "\" latitude=\"" + d.location.getLatitude()
								+ "\" longitude=\"" + d.location.getLongitude()
								+ "\">" + d.value + "</value>";
					else
						value = "<value seq=\"" + count++ + "\" name=\""
								+ d.name + "\" time=\"" + d.date + "\">"
								+ d.value + "</value>";
					builder.append(value);
				}
				builder.append("</values>");
			}
			builder.append("</data>");
			builder.append("</event>");
			ret = builder.toString();
		}
		return ret;
	}

	public static TupleSpaceAdapter getInstance() {
		return tuple;
	}

	public void setDatabaseConnector(DatabaseConnector con) {
		this.con = con;
	}

	public void storeData(EntityEvent evt) {
		if (con == null) {
			return;
		}
		try {
			Entity source = (Entity) evt.getSource();
			EntityType type = source.getEntityType();
			Entity target = (Entity) evt.getTarget();
			String data = evt.getMessage();
			if (data != null) {
				DataObject obj = new DataObjectImpl(type, evt.getMessage(),
						source, target, source.getLocation());
				con.store(obj);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

	private String makeXML(String key, String data) {
		return "<" + key + ">" + data + "</" + key + ">";
	}
}
