import com.nttdocomo.ui.*;
import com.nttdocomo.io.*;
import com.nttdocomo.net.*;
import javax.microedition.io.*;
import java.io.*;
import java.util.*;

public class A extends MApplication implements KeyListener {
	public void keyPressed(Panel panel, int key) {
	}
	public void keyReleased(Panel panel, int key)	 {
		// 待ち受けボタンで非活性化状態、休眠状態への遷移
		if (key == Display.KEY_IAPP) {
			setWakeupTimer(INTERVAL * 1000); // INTERVAL秒後に復帰
			deactive = true;
			deactivate();
			sleep();
		}
	}
	boolean deactive = true; // 非活性化状態であることを示すフラグ
	public void processSystemEvent(int type, int param) {
		if (type == FOLD_CHANGED_EVENT) {
			if (deactive) {
				// フリップイベントがきたらすぐに休眠状態へ
				sleep(); // 再び休眠状態に移行する
			}
		} else if (type == MODE_CHANGED_EVENT) {
			deactive = false;
		}
	}
	static final int INTERVAL = 10; // 10秒置きにサーバと通信
	// ------------------------------------------------------------------
	// データ構造
	// ------------------------------------------------------------------
	
	class Member {
		String name;
		String state;

		Member(String name, String state) {
			this.name = name;
			this.state = state;
		}
	}
	class Data {
		String myname = null;
		Vector member = new Vector();
		
		String[] getMemberNamesAndState() {
			String[] names = new String[member.size()];
			for (int i = 0; i < names.length; i++) {
				Member m = (Member)member.elementAt(i);
				names[i] = m.name + " [" + m.state + "]";
			}
			return names;
		}
		String[] getMemberNames() {
			String[] names = new String[member.size()];
			for (int i = 0; i < names.length; i++) {
				Member m = (Member)member.elementAt(i);
				names[i] = m.name;
			}
			return names;
		}
		int getMemberLength() {
			return member.size();
		}
	}
	Data data;

	class Message {
		String name;
		String message;

		Message(String name, String message) {
			this.name = name;
			this.message = message;
		}
	}
	
	// ------------------------------------------------------------------
	// データの永続化
	// ------------------------------------------------------------------
	
	final int SP_DATA_POS = 0;
	void writeData(Data data) {
		try {
			OutputStream os = Connector.openOutputStream("scratchpad:///0;pos=" + SP_DATA_POS);
			writeString(os, data.myname);
			os.write(data.member.size());
			for (int i = 0; i < data.member.size(); i++) {
				Member member = (Member)data.member.elementAt(i);
				writeString(os, member.name);
				writeString(os, member.state);
			}
			os.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	void writeString(OutputStream os, String s) throws Exception {
		byte[] b = s.getBytes();
		os.write(b.length);
		os.write(b);
	}
	
	Data readData() {
		InputStream is = null;
		Data data = null;
		try {
			is = Connector.openInputStream("scratchpad:///0;pos=" + SP_DATA_POS);
			
			String myname = readString(is);
			if (myname != null) {
				data = new Data();
				data.myname = myname;
				int n = is.read();
				for (int i = 0; i < n; i++) {
					Member member = new Member(readString(is), readString(is));
					data.member.addElement(member);
				}
			}
			is.close();
		} catch (Exception e) {
			e.printStackTrace();
			try {
				if (is != null)
					is.close();
			} catch (Exception e2) {
			}
		}
		return data; // エラー時にはnullを返す
	}
	String readString(InputStream is) throws Exception {
		int len = is.read();
		if (len == 0)
			return null;
		byte[] b = new byte[len];
		int off = 0;
		for (;;) {
			int n = is.read(b, off, len);
			if (n < 0)
				return null;
			off += n;
			len -= n;
			if (len == 0)
				break;
		}
		return new String(b);
	}
	
	// ------------------------------------------------------------------
	// サーバとの通信
	// ------------------------------------------------------------------
	
	class Network {
		InputStream http(String name, String[] nameval) throws Exception {
			String res = null;
			HttpConnection conn = null;

			try {
				String url = IApplication.getCurrentApp().getSourceURL() + "servlet/BusinessIM/" + name;
				
				// パラメータをエンコードする
				if (nameval.length > 0) {
					url += "?";
					for (int i = 0; i < nameval.length / 2; i++) {
						url += nameval[i * 2] + "=" + URLEncoder.encode(nameval[i * 2 + 1]) + "&";
					}
					url = url.substring(0, url.length() - 1);
				}
				System.out.println("access to: " + url);
				
				conn = (HttpConnection)Connector.open(url, Connector.READ);
				conn.setRequestMethod(HttpConnection.GET);
				
				conn.connect();
				
				InputStream in = conn.openInputStream();
				
				int len = (int)conn.getLength();
				
				// 長さ分だけ読み込む
				byte[] buf = new byte[len];
				int off = 0;
				for (;;) {
					int n = in.read(buf, off, len);
					if (n < 0)
						throw new Exception();
					off += n;
					len -= n;
					if (len == 0)
						break;
				}
				in.close();
				conn.close();
				return new ByteArrayInputStream(buf);
			} catch (Exception e) {
				try {
					if (conn != null)
						conn.close();
				} catch (Exception e2) {
				}
				throw e;
			}
		}
		boolean sendInit(String myname) { // IDを受け取る
			try {
				InputStream is = http("sendInit", new String[] { "name", myname });
				boolean res = is.read() == 1;
				return res;
			} catch (Exception e) {
				e.printStackTrace();
			}
			return false;
		}
		Message[] update(Data data) { // 定期的に
			try {
				InputStream is = http("update", new String[] { "name", data.myname });
				
				// メンバー状態の取得
				int nmember = is.read();
				data.member.removeAllElements();
				for (int i = 0; i < nmember; i++) {
					String name = readString(is);
					String state = readString(is);
					Member member = new Member(name, state);
					data.member.addElement(member);
				}
				
				// メッセージの取得
				int nmes = is.read();
				Message[] message = new Message[nmes];
				for (int i = 0; i < nmes; i++) {
					String name = readString(is);
					String mes = readString(is);
					message[i] = new Message(name, mes);
				}
				
				return message;
			} catch (Exception e) {
				e.printStackTrace();
			}
			return new Message[0];
		}
		void sendState(String myname, String state) {
			try {
				http("sendState", new String[] { "name", myname, "state", state });
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		void sendMessage(String myname, String toname, String mes) {
			try {
				http("sendMessage", new String[] { "myname", myname, "toname", toname, "mes", mes });
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	Network network = new Network();
	
	// ------------------------------------------------------------------
	// 各パネルの実装
	// ------------------------------------------------------------------

	class InitPanel extends Panel implements SoftKeyListener {
		TextBox name;
		InitPanel() {
			setKeyListener(A.this);
			
			data = readData();
			if (data != null) {
				new StateViewPanel();
				return;
			}

			setTitle("初回登録");
			
			add(new Label("名前"));
			name = new TextBox("", 20, 1, TextBox.DISPLAY_ANY);
			add(name);
			
			setSoftLabel(Frame.SOFT_KEY_1, "ＯＫ");
			setSoftKeyListener(this);
			Display.setCurrent(this);
		}
		public void softKeyPressed(int key) {
			if (key == Frame.SOFT_KEY_1) {
				String myname = name.getText();
				network.sendInit(myname);
				data = new Data();
				data.myname = myname;
				writeData(data);
				new StateViewPanel();
			}
		}
		public void softKeyReleased(int key) {
		}
	}

	class StateViewPanel extends Panel implements SoftKeyListener, Runnable {
		ListBox memberview;
		StateViewPanel() {
			setKeyListener(A.this);

			setTitle("ビジネスＩＭ");
			
			memberview = new ListBox(ListBox.SINGLE_SELECT, 9);
			memberview.setItems(data.getMemberNamesAndState());
			add(memberview);

			// ソフトキーのラベルを設定し、ソフトキー受け取りを有効にする
			setSoftLabel(Frame.SOFT_KEY_1, "状態"); // 状態変更
			setSoftLabel(Frame.SOFT_KEY_2, "送信");  // メッセージ送信
			setSoftKeyListener(this);
			Display.setCurrent(this);
			
			// 一定時間置きに更新するスレッドを起動する
			new Thread(this).start();
		}
		public void softKeyPressed(int key) {
			if (key == Frame.SOFT_KEY_1) { // 状態変更
				new ChangeStatePanel(this);
			} else if (key == Frame.SOFT_KEY_2) { // メッセージ送信
				new SendMessagePanel(this);
			}
		}
		public void softKeyReleased(int key) {
		}
		
		// 一定時間置きに更新するスレッド処理
		public void run() {
			for (;;) {
				if (Display.getCurrent() == this) {
					Message[] message = network.update(data); // dataを更新する
					writeData(data); // dataをスクラッチパッドに書き出す
					memberview.setItems(data.getMemberNamesAndState()); // dataを画面に反映する
					new ReceiveMessagePanel(this, message);
				}
				if (deactive) {
					setWakeupTimer(INTERVAL * 1000); // INTERVAL秒後に復帰
					try {
						sleep(); // 非活性化状態なら再び休眠状態に移行する
					} catch (Exception e) {
					}
				}
				try {
					for (int i = 0; i < INTERVAL; i++) {
						if (deactive)
							break;
						Thread.sleep(1000); // 1秒待ち
					}
				} catch (Exception e) {
				}
			}
		}
	}

	class ChangeStatePanel extends Panel implements SoftKeyListener {
		Panel back;
		
		ListBox state;
		String[] STATE_LIST = { "仕事中", "休憩中", "会議中", "外出中", "帰宅" };
		ChangeStatePanel(Panel back) {
			setKeyListener(A.this);

			this.back = back;

			setTitle("状態変更");
			
			add(new Label("状態"));
			state = new ListBox(ListBox.CHOICE);
			state.setItems(STATE_LIST);
			state.select(0);
			add(state);
			
			setSoftLabel(Frame.SOFT_KEY_1, "ＯＫ");
			setSoftLabel(Frame.SOFT_KEY_2, "中止");
			setSoftKeyListener(this);
			Display.setCurrent(this);
		}
		public void softKeyPressed(int key) {
			if (key == Frame.SOFT_KEY_1) {
				String st = state.getItem(state.getSelectedIndex());
				network.sendState(data.myname, st);
			}
			Display.setCurrent(back);
		}
		public void softKeyReleased(int key) {
		}
	}
	
	class SendMessagePanel extends Panel implements SoftKeyListener {
		Panel back;
		
		ListBox to;
		ListBox mes;
		
		String[] MESSAGE_LIST = { "電話求む", "メール読め", "助けて", "いいよ", "やだね" };
		SendMessagePanel(Panel back) {
			setKeyListener(A.this);

			this.back = back;
			
			setTitle("メッセージ送信");
			
			add(new Label("送り先"));
			to = new ListBox(ListBox.CHOICE);
			String[] names = data.getMemberNames();
			if (names.length == 0) // メンバーが０なら何もせず終わる
				return;
			to.setItems(names);
			to.select(0);
			add(to);

			add(new Label("送信メッセージ"));
			mes = new ListBox(ListBox.CHOICE);
			mes.setItems(MESSAGE_LIST);
			mes.select(0);
			add(mes);
			
			setSoftLabel(Frame.SOFT_KEY_1, "ＯＫ");
			setSoftLabel(Frame.SOFT_KEY_2, "中止");
			setSoftKeyListener(this);
			Display.setCurrent(this);
		}
		
		public void softKeyPressed(int key) {
			if (key == Frame.SOFT_KEY_1) {
				String message = mes.getItem(mes.getSelectedIndex());
				String toname = to.getItem(to.getSelectedIndex());
				network.sendMessage(data.myname, toname, message);
			}
			Display.setCurrent(back);
		}
		public void softKeyReleased(int key) {
		}
	}

	class ReceiveMessagePanel extends Panel implements SoftKeyListener {
		Panel back;
		
		Message[] message;
		
		ReceiveMessagePanel(Panel back, Message[] message) {
			setKeyListener(A.this);

			this.back = back;
			this.message = message;
			if (message.length == 0)
				return;
			
			setTitle("メッセージ受信");
			
			add(new Label("送り主"));
			add(new TextBox(message[0].name, 20, 1, TextBox.DISPLAY_ANY));

			add(new Label("受信メッセージ"));
			add(new TextBox(message[0].message, 20, 1, TextBox.DISPLAY_ANY));
			
			setSoftLabel(Frame.SOFT_KEY_1, "ＯＫ");
			setSoftKeyListener(this);
			Display.setCurrent(this);
		}
		
		public void softKeyPressed(int key) {
			if (key == Frame.SOFT_KEY_1) {
				if (message.length > 1) { // 表示すべきメッセージがあれば
					Message[] m = new Message[message.length - 1];
					System.arraycopy(message, 1, m, 0, m.length);
					Display.setCurrent(new ReceiveMessagePanel(back, m));
				} else { // 表示すべきメッセージがなければ戻る
					Display.setCurrent(back);
				}
			}
		}
		public void softKeyReleased(int key) {
		}
	}
	// ------------------------------------------------------------------
	// iアプリの開始メソッド
	// ------------------------------------------------------------------
	public void start() {
		new InitPanel();
	}
}
