/*
 *  Copyright (C) 2007  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.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import jp.ac.naka.ec.EventDispatcher;
import jp.ac.naka.ec.entity.AbstractEntity;
import jp.ac.naka.ec.entity.EntityEvent;
import jp.ac.naka.ec.entity.EntityEventDispatcher;

/**
 * FlashのXMLSocketを用いて、イベント情報を配布するためのサーバ。デフォルトのポートは4444
 * 
 * @author 粕谷
 * 
 */
public class FlashXMLSocketServerEntity extends AbstractEntity implements Runnable {

	private List<FlashClient> clients = new ArrayList<FlashClient>();

	/*
	 * デフォルトポート
	 */
	private static int port = 5555;
	private static ServerSocket server;
	private SimpleDateFormat formatter = new SimpleDateFormat(
	"yyyy.MM.dd hh:mm:ss");
	
	List<FlashClient> errors = new ArrayList<FlashClient>();

	static {
		try {
			server = new ServerSocket(port);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public FlashXMLSocketServerEntity() {
		Thread th = new Thread(this);
		th.start();
	}
	

	@Override
	public void receiveMessage(EntityEvent evt) {
		StringBuilder sb = new StringBuilder();
		sb.append("<event><data>");
		sb.append(evt.getMessage());
		sb.append("</data>");
		// source
		sb.append("<source>");
		sb.append(evt.getSource().toString());
		sb.append("</source>");
		// timestamp
		Date currentTime_1 = new Date();
		String dateString = formatter.format(currentTime_1);
		sb.append("<time>");
		sb.append(dateString);
		sb.append("</time></event>");
		errors.clear();
		for (FlashClient fc : clients) {
			try {
				fc.sendMessage(sb.toString());
			} catch (IOException e) {
				errors.add(fc);
			}
		}
		for (FlashClient fc : errors) {
			clients.remove(fc);
			fc = null;
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see java.lang.Runnable#run()
	 */
	public void run() {
		try {
			while (true) {
				Socket sock = server.accept();
				FlashClient fc = new FlashClient(sock);
				fc.start();
				clients.add(fc);
			}
		} catch (IOException e) {
		} finally {
			try {
				server.close();
				for (FlashClient fc : clients) {
					fc.stopClient();
					fc = null;
				}
				clients.clear();
			} catch (IOException e) {
			}
		}
	}

	/**
	 * イベントの送信
	 * 
	 * @param evt
	 */
	private void dispatchEvent(String str) {
		sendMessage(str);
		
	}

	private class FlashClient extends Thread {

		BufferedReader in = null;

		PrintWriter out = null;

		Socket sock;

		/*
		 * 
		 */
		public FlashClient(Socket sock) throws IOException {
			this.sock = sock;
			in = new BufferedReader(new InputStreamReader(
					sock.getInputStream(), "UTF8"));
			out = new PrintWriter(new OutputStreamWriter(
					sock.getOutputStream(), "UTF8"));
		}

		public InetAddress getInetAddress() {
			return sock.getInetAddress();
		}

		public void sendMessage(String msg) throws IOException {
			out.print(msg + "\0");
			if (out.checkError()) {
				throw new IOException();
			}
		}

		public void run() {
			try {
				char c[] = new char[1];
				while (in.read(c, 0, 1) != -1) {
					StringBuilder sb = new StringBuilder(4096);
					// null check
					while (c[0] != '\0') {
						sb.append(c[0]);
						in.read(c, 0, 1);
					}
					String str = new String(sb.toString().getBytes(), "SJIS");
					// ポリシーファイルリクエスト
					if (str.equals("<policy-file-request/>")) {
						sendMessage("<cross-domain-policy><allow-access-from domain=\"*\" to-ports=\"5555\" /></cross-domain-policy>");
						return;
					}
					System.out.println("Message : " + str);
					if (str != null)
						dispatchEvent(str);
				}
			} catch (IOException e) {
			} finally {
				stopClient();
			}
		}

		/**
		 * Stop the Client
		 * 
		 */
		private void stopClient() {
			// TODO
			this.interrupt();
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		try {
			new FlashXMLSocketServerEntity().init();
			Thread.sleep(Integer.MAX_VALUE);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	
}
