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

import java.io.BufferedOutputStream;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Properties;

import javax.sip.address.SipURI;

import jp.ac.naka.ec.EventDispatcher;
import jp.ac.naka.ec.EventSource;
import jp.ac.naka.ec.Location;
import jp.ac.naka.ec.db.TupleSpaceAdapter;
import jp.ac.naka.ec.entity.Entity;
import jp.ac.naka.ec.entity.EntityContainer;
import jp.ac.naka.ec.entity.EntityEvent;
import jp.ac.naka.ec.entity.EntityImpl;
import jp.ac.naka.ec.entity.EntityEvent.EventType;
import jp.ac.naka.ec.sip.SipCore;

import org.apache.log4j.Logger;
import org.mortbay.http.HttpContext;
import org.mortbay.http.HttpException;
import org.mortbay.http.HttpRequest;
import org.mortbay.http.HttpResponse;
import org.mortbay.http.HttpServer;
import org.mortbay.http.SocketListener;
import org.mortbay.http.handler.ResourceHandler;

/**
 * Webサーバとして機能し、HTTPからのイベントの入出力も管理する。
 * httpフォルダ以下の静的なWebリソースを読み込み表示する。デフォルトのWebへのアクセスポートは8080。
 * 
 * @author Takashi Kasuya
 * 
 */
public class HttpCore extends EventSource {

	private static Logger logger = Logger.getLogger(HttpCore.class);

	HttpServer server;
	EntityContainer source;

	/*
	 * Default port is 8080
	 */
	public static int DEFAULT_PORT = 8080;
	public static String VALUE_PARAM = "value";
	public static String TARGET_PARAM = "target";
	public static String AJAX_REQUEST_PATH = "event/ajax";

	/**
	 * 
	 *
	 */
	public HttpCore() {
	}

	/**
	 * 
	 * @param source
	 * @throws Exception
	 */
	@Override
	public void init(EntityContainer source, Properties prop) throws Exception {
		String t = prop.getProperty("port");
		int port = HttpCore.DEFAULT_PORT;
		if (!t.equals("") || t != null)
			port = Integer.parseInt(t);
		server = new HttpServer();
		this.source = source;
		SocketListener listener = new SocketListener();
		listener.setPort(port);
		server.addListener(listener);
	
		HttpContext context = new HttpContext();
		context.setContextPath("/");
	
		context.setResourceBase("./html");
		context.addHandler(new MyHttpHandler());
	
		server.addContext(context);
		server.start();
	}
	/**
	 * 
	 * @return
	 */
	public boolean isStarted() {
		if (server == null)
			return false;
		return server.isStarted();
	}

	/**
	 * 
	 * @throws InterruptedException
	 */
	public void stopServer() throws InterruptedException {
		server.stop();
	}

	class MyHttpHandler extends ResourceHandler {

		/**
		 * 
		 */
		private static final long serialVersionUID = -3390140933419713641L;

		/*
		 * (non-Javadoc)
		 * 
		 * @see org.mortbay.http.HttpHandler#handle(java.lang.String,
		 *      java.lang.String, org.mortbay.http.HttpRequest,
		 *      org.mortbay.http.HttpResponse)
		 */
		public void handle(String pathInContext, String pathParams,
				HttpRequest req, HttpResponse res) throws HttpException,
				IOException {
			if (!HttpRequest.__GET.equals(req.getMethod())
					&& !HttpRequest.__POST.equals(req.getMethod()))
				return;
			logger.info("Request to : " + pathInContext);
			String res_str = "YES";
			String target = req.getParameter(TARGET_PARAM);

			if (pathInContext.equals(AJAX_REQUEST_PATH)) {
				// return xml for AJAX
				int count = 0;
				String temp = req.getParameter("count");
				try {
					if (temp != null) {
						count = Integer.valueOf(temp);

						res_str = ((TupleSpaceAdapter) dispatcher)
								.getDataByXML(target, count);

					} else {

						res_str = ((TupleSpaceAdapter) dispatcher)
								.getDataByXML(target);
						if (res_str.equals("")) {
							res_str = ((TupleSpaceAdapter) dispatcher)
									.getDataByXML(target, 1);
						}
					}
				} catch (SQLException e) {
					logger.warn("Error while processing Database", e);
					res_str = "Error while processing Database";
				}
			} else {
				String value = req.getParameter(VALUE_PARAM);
				if (value == null) {
					// TODO
					super.handle(pathInContext, pathParams, req, res);
					return;
				}
				logger.info("Receive value : " + value);
				EntityEvent evt = null;

				// 位置情報がついてくる場合
				String location_name, latitude, longitude;
				Location location = null;
				if ((location_name = req.getParameter("location")) != null
						&& (latitude = req.getParameter("latitude")) != null
						&& (longitude = req.getParameter("longitude")) != null) {
					location = new Location(location_name, latitude, longitude);
					source.setLocation(location);
				}
				if (target != null) {
					SipURI target_uri = null;
					target_uri = (SipURI) SipCore.getInstance().createURI(
							target);
					if (target_uri != null) {
						Entity e = new EntityImpl(target_uri);

						evt = new EntityEvent(value, e, source,
								EventType.MESSAGE);
					} else {
						res_str = "Invalid URI :" + target;
					}
				} else {
					// Broadcast message
					evt = new EntityEvent(value, null, source);
					evt.setBroadcast(true);
				}
				if (evt != null) {
					if (evt.isBroadcast())
						logger.info("Dispatch Event by Broadcast.");
					else
						logger.info("Dispatch Event to " + target);

					dispatcher.dispatchEvent(evt);

				}
			}
			// logger.info("Return value : " + res);
			BufferedOutputStream bos = new BufferedOutputStream(res
					.getOutputStream());

			byte[] b = res_str.getBytes();
			bos.write(b, 0, b.length);
			bos.flush();
		}

	}

}
