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

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.Timer;
import java.util.TimerTask;

import javax.sip.RequestEvent;
import javax.sip.address.Address;
import javax.sip.address.SipURI;
import javax.sip.header.ContactHeader;
import javax.sip.header.ExpiresHeader;
import javax.sip.header.ToHeader;
import javax.sip.message.Request;
import javax.sip.message.Response;

import jp.ac.naka.ec.EntityCollaborator;
import jp.ac.naka.ec.entity.AbstractEntity;
import jp.ac.naka.ec.entity.Entity;
import jp.ac.naka.ec.entity.EntityEvent;
import jp.ac.naka.ec.entity.EntityType;
import jp.ac.naka.ec.entity.test.ButtonEntity;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * @author Takashi Kasuya
 * 
 */
class RegisterDelegate implements MethodDelegate {

	private static Log logger = LogFactory.getLog(RegisterDelegate.class);
	private static SipCore core;

	private HashMap<String, Timer> clients = new HashMap<String, Timer>();

	public RegisterDelegate() {
		core = SipCore.getInstance();
	}

	public boolean forward(RequestEvent evt) {
		Request req = evt.getRequest();

		// FromHeader from = (FromHeader) req.getHeader(FromHeader.NAME);
		ToHeader to = (ToHeader) req.getHeader(ToHeader.NAME);
		ContactHeader contact = (ContactHeader) req
				.getHeader(ContactHeader.NAME);

		// AoRの値
		Address target = to.getAddress();
		SipURI targetURI = (SipURI) target.getURI();
		SipURI contactURI = (SipURI) contact.getAddress().getURI();

		// 更新の確認
		SipClient temp = (SipClient) clients.get(targetURI.toString());
		if (temp != null) {
			logger.info("Reflesh : " + targetURI);
			temp.reflesh();
			try {
				core.sendResponse(Response.OK, evt, contactURI.toString());
			} catch (Exception e) {
				e.printStackTrace();
			}
			return true;
		}

		// Expiresの処理
		ExpiresHeader expiresHeader = (ExpiresHeader) req
				.getHeader(ExpiresHeader.NAME);

		final int expires = expiresHeader.getExpires();

		// ダミーのEntityを作成
		Entity source = new AbstractEntity(targetURI) {
			@Override
			public void receiveMessage(EntityEvent e) {
			}
		};
		source.setLocal(false);
		source.setContactURI(contactURI);
		
		// Display Nameをキーワードにする
		source.addKeyword(target.getDisplayName());
		if (expiresHeader == null) {
			expiresOut(source);
			return true;
		}
		source.setEntityType(EntityType.SOUND);
		// Chord.getInstance().insertEntity(target.getDisplayName(), source);
		EntityCollaborator.getInstance().addEntity(source);
		clients.put(contactURI.toString(), new SipClient(source, expires));
		try {
			// 100 Trying
			// core.sendResponse(Response.TRYING, evt, contactURI.toString());
			// 200 OK
			core.sendResponse(Response.OK, evt, target.toString());
		} catch (Exception e) {
			e.printStackTrace();
		}

		return true;
	}

	private void expiresOut(Entity entity) {
		SipURI uri = entity.getURI();
		if (clients.containsKey(uri.toString())) {
			
			clients.remove(uri);
			EntityCollaborator.getInstance().removeEntity(entity);
			entity = null;
			logger.info("Remove Client :" + uri);
		} else {
			throw new NullPointerException("SipClient : " + uri + " is null.");
		}
	}

	private class SipClient extends Timer {

		int expires = 3600;
		TimerTask task;

		public SipClient(final Entity source, int expires) {
			this.expires = expires;
			task = new TimerTask() {
				public void run() {
					expiresOut(source);
				}
			};
			start();
		}

		public void start() {
			schedule(task, expires * 1000);
		}

		public void reflesh() {
			cancel();
			start();
		}
	}

	public static void main(String[] args) {
		String str = "REGISTER sip:10.0.1.221 SIP/2.0\r\n"
				+ "Via: SIP/2.0/UDP 10.0.1.221:20510;branch=z9hG4bK-d87543-6d9b272834735003-1--d87543-;rport=20510;received=10.0.1.221\r\n"
				+ "Max-Forwards: 70\r\n"
				+ "Contact: <sip:201@192.168.0.20:20510;rinstance=204379f79bef1d2c>"
				+ "To: \"201\" <sip:201@192.168.0.20>\r\n"
				+ "From: \"201\" <sip:201@192.168.0.20>;tag=5e8e37ab\r\n"
				+ "Call-ID: NTg0MGE4Njk3MmJmOTk3YWZiNzc3NWZlMmM1MTc5OTk.\r\n"
				+ "CSeq: 1 REGISTER\r\n"
				+ "Expires: 60\r\n"
				+ "Allow: INVITE,ACK,CANCEL,OPTIONS,BYE,REFER,NOTIFY,MESSAGE,SUBSCRIBE,INFO\r\n"
				+ "User-Agent: X-Lite/release/1011b/stamp/39984\r\n"
				+ "Content-Length: 0\r\n\r\n";
		try {
			EntityCollaborator ec  = EntityCollaborator.getInstance("lo0");
			ec.initiateSipCore();
			ec.initiateDHT();
			ec.addEntity(new ButtonEntity());
			Thread.sleep(1000);
			byte buf[] = str.getBytes();
			/** データを受信 * */
			// データグラムソケットを作成(引数にポート番号を指定)
			 DatagramSocket socket = new DatagramSocket();
			DatagramPacket packet = new DatagramPacket(buf, buf.length,
					InetAddress.getByName("10.0.1.221"), 5060);
			// データを送信します。
			socket.send(packet);
			System.out.println("\"" + new String(buf) + "\"を送信しました");
			
			
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
