/**
* Kandata
* Copyright (C) 2003. Yoshinori Watanabe
* 
* 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package roomreservation.client;

import java.net.URL;
import java.text.*;
import java.util.*;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Container;
import java.awt.BorderLayout;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import kandata.client.*;
import roomreservation.common.*;

/**
 * クライアントアプリケーションのサンプル.
 */
public class RoomReservationFrame extends JFrame {

	static final String TITLE = "会議室予約";
	static final SimpleDateFormat formatter = new SimpleDateFormat("yyyy 年 MM 月 dd 日(EEE)");
	static final SimpleDateFormat yyyymmddFormatter = new SimpleDateFormat("yyyyMMdd");
	static final String[] TIME = {
		"07:00","07:15","07:30","07:45",
		"08:00","08:15","08:30","08:45",
		"09:00","09:15","09:30","09:45",
		"10:00","10:15","10:30","10:45",
		"11:00","11:15","11:30","11:45",
		"12:00","12:15","12:30","12:45",
		"13:00","13:15","13:30","13:45",
		"14:00","14:15","14:30","14:45",
		"15:00","15:15","15:30","15:45",
		"16:00","16:15","16:30","16:45",
		"17:00","17:15","17:30","17:45",
		"18:00","18:15","18:30","18:45",
		"19:00","19:15","19:30","19:45",
		"20:00","20:15","20:30","20:45",
		"21:00","21:15","21:30","21:45",
		"22:00","22:15","22:30","22:45",
		"23:00","23:15","23:30","23:45",
		"24:00"		// もう帰りなさい
	};
	KandataConnector connector;
	// モデル
	List reservationList;
	List roomList;
	Calendar date = Calendar.getInstance();
	String user = null;
	Icon icon = null;
	// コントロール群
	ReservationTableModel model = new ReservationTableModel();
	JTable table = new JTable(model);
	JLabel dateLabel = new JLabel(formatter.format(date.getTime()));
	JButton lastDateButton = new JButton(new ChangeDateAction(-1, "前の日"));
	JButton nextDateButton = new JButton(new ChangeDateAction(1, "次の日"));
	JButton registButton = new JButton(new RegistAction(this));
	JButton updateButton = new JButton(new UpdateReservationAction(this));
	JButton deleteButton = new JButton(new DeleteAction(this));
	JButton exitButton = new JButton(new ExitAction());
	JComboBox roomCombo;
	JComboBox startTimeCombo = new JComboBox(TIME);
	JComboBox endTimeCombo = new JComboBox(TIME);
	JTextField memoField = new JTextField(16);

	/** モデルの初期化を行い、コントロールを構築する. */
	public RoomReservationFrame(KandataConnector connector) {
		super(TITLE);
		// モデルの初期化
		this.connector = connector;
		try {
			roomList = (List) connector.invoke("getRoomList", null);
			reservationList = (List) connector.invoke("getReservationList", new Object[] {getDateStr()});
			String fname = "/symbol.png";
			byte[] imagedata = connector.getResource(fname);
			icon = new ImageIcon(imagedata);
			System.out.println("icon="+icon);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		// コントロールの初期化
		Object[] roomary = new Object[roomList.size()];
		for (int i=0; i<roomList.size(); i++) {
			Room room = (Room) roomList.get(i);
			roomary[i] = room.getName();
		}
		roomCombo = new JComboBox(roomary);
		startTimeCombo.setSelectedItem("09:00");
		endTimeCombo.setSelectedItem("18:00");
		memoField.setText("ミーティング");
		TableColumnModel colmodel = table.getColumnModel();
		colmodel.getColumn(0).setPreferredWidth(150);
		colmodel.getColumn(1).setPreferredWidth(100);
		colmodel.getColumn(2).setPreferredWidth(100);
		colmodel.getColumn(3).setPreferredWidth(250);
		table.getTableHeader().setReorderingAllowed(false);	// ドラッグさせない
		table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);	// 単一行選択
		//table.setGridColor(Color.blue);
		table.setRowHeight(table.getRowHeight()+5);

		Container pane = this.getContentPane();
		pane.setLayout(new BorderLayout());
		pane.add(new JScrollPane(table), BorderLayout.CENTER);
		
		JPanel north = new JPanel();
		north.add(new JLabel("<html><font color=\"blue\" size=\"+2\">"+TITLE+":</font></html>",
					icon, JLabel.LEFT));
		north.add(lastDateButton);
		north.add(dateLabel);
		north.add(nextDateButton);
		north.add(updateButton);
		north.add(exitButton);
		pane.add(north, BorderLayout.NORTH);

		JPanel buttons = new JPanel();
		buttons.add(new JLabel("部屋"));
		buttons.add(roomCombo);
		buttons.add(new JLabel("時間"));
		buttons.add(startTimeCombo);
		buttons.add(new JLabel("〜"));
		buttons.add(endTimeCombo);
		buttons.add(new JLabel("メモ"));
		buttons.add(memoField);
		buttons.add(registButton);
		buttons.add(deleteButton);
		pane.add(buttons, BorderLayout.SOUTH);
		pack();
//		setSize(640,480);
		setVisible(true);
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				exit();
			}
		});
		// ユーザ名を設定する
		user = JOptionPane.showInputDialog("名前を入力してください(予約するときの名前に使います)");
		System.out.println("user="+user);
		if (user == null) exit();	// cancelが押されたら終了
	}

	/** 終了処理を行う. */
	void exit() {
		System.out.println("exit() :-)");
		try {
			connector.disconnect();
		} catch (Exception e) { e.printStackTrace(); }
		System.exit(0);
	}

	/** サーバで使用する形式の日付を返す. ex"20030601" */
	private String getDateStr() { return yyyymmddFormatter.format(date.getTime()); }
	private void update() {
		try {
			reservationList = (ArrayList) connector.invoke("getReservationList", new Object[]{getDateStr()});
			for (int i=0; i<reservationList.size(); i++) {
				Reservation r = (Reservation) reservationList.get(i);
				System.out.println(r);
			}
			model.fireTableDataChanged();
		}
		catch(Exception ex) {
			ex.printStackTrace();
		}
	}

	/** 登録 */
	public class RegistAction extends AbstractAction {
		JFrame frame;
		public RegistAction(JFrame frame) {
			super("登録");
			this.frame = frame;
		}
		public void actionPerformed(ActionEvent e) {
			System.out.println("RegistAction.actionPerformed(e)");
			// 各種コントロールから値を取得
			String room = (String) roomCombo.getSelectedItem();
			String startTime = (String) startTimeCombo.getSelectedItem();
			String endTime = (String) endTimeCombo.getSelectedItem();
			String memo = memoField.getText();
			System.out.println(""+room+","+startTime+","+endTime+","+memo);
			// クライアントで可能なチェックを行う。
			if (startTime.compareTo(endTime) >= 0) {
				JOptionPane.showMessageDialog(frame, "開始時間 < 終了時間 でなければなりません", 
						TITLE, JOptionPane.INFORMATION_MESSAGE);
				return;
			}
			// サーバに対して登録する。
			Reservation reserv = new Reservation();
			reserv.setName(user);
			reserv.setRoomName(room);
			reserv.setDate(getDateStr());
			reserv.setStartTime(startTime);
			reserv.setEndTime(endTime);
			reserv.setMemo(memo);
			try {
				Boolean rc = (Boolean) connector.invoke("registReservation", new Object[]{ reserv });
				if (! rc.booleanValue()) {
					JOptionPane.showMessageDialog(frame, "登録に失敗しました", 
						TITLE, JOptionPane.INFORMATION_MESSAGE);
				}
			}
			catch (Exception ex) {
				ex.printStackTrace();
			}
			update();	// 最新の情報を取得
		}
	}

	/** 最新の情報を取得 */
	public class UpdateReservationAction extends AbstractAction {
		JFrame frame;
		public UpdateReservationAction(JFrame frame) {
			super("最新の情報を取得");
			this.frame = frame;
		}
		public void actionPerformed(ActionEvent e) {
			System.out.println("UpdateReservationAction.actionPerformed(e)");
			update();
		}
	}

	/** 次、前の日付に */
	public class ChangeDateAction extends AbstractAction {
		int addDay;
		public ChangeDateAction(int addDay, String command) {
			super(command);
			this.addDay = addDay;
		}
		public void actionPerformed(ActionEvent e) {
			System.out.println("ChangeDateAction.actionPerformed(e)");
			date.add(Calendar.DATE, addDay);	// ?日後
			dateLabel.setText(formatter.format(date.getTime()));
			update();
		}
	}

	/** 予約の削除. */
	public class DeleteAction extends AbstractAction {
		JFrame frame;
		public DeleteAction(JFrame frame) {
			super("削除");
			this.frame = frame;
		}
		public void actionPerformed(ActionEvent e) {
			System.out.println("DeleteAction.actionPerformed(e)");
			this.setEnabled(false);
			setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));    // 砂時計
			try {
			int row = table.getSelectedRow();
			if (row ==-1) {
				JOptionPane.showMessageDialog(frame, "行が選択されていません", 
						TITLE, JOptionPane.INFORMATION_MESSAGE);
				return;
			}
			Reservation reserv = (Reservation) reservationList.get(row);
			if (! user.equals(reserv.getName())) {
				JOptionPane.showMessageDialog(frame, "自分の登録した予約しか削除できません", 
						TITLE, JOptionPane.INFORMATION_MESSAGE);
				return;
			}
			try {
				connector.invoke("cancelReservation", new Object[]{ reserv });
				update();
			}
			catch (Exception ex) {
				ex.printStackTrace();
			}
			}finally {
			this.setEnabled(true);
			setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); // デフォルト
}
		}
	}

	/** 終了する. */
	public class ExitAction extends AbstractAction {
		public ExitAction() {
			super("終了");
		}
		public void actionPerformed(ActionEvent e) {
			System.out.println("ExitAction.actionPerformed(e)");
			exit();
		}
	}

	/** テーブルのモデルへのアダプタ. */
	public class ReservationTableModel extends AbstractTableModel {
		final String[] columnNames = {
			"部屋", "時間", "登録者", "メモ"
		};
		public String getColumnName(int columnIndex) {
			return columnNames[columnIndex];
		}
		public int getColumnCount() {
			return columnNames.length;
		}
		public int getRowCount() {
			return (reservationList!=null) ? reservationList.size() : 0;
		}
		public Object getValueAt(int rowIndex, int columnIndex) {
			if (reservationList==null) return "";
			Reservation reserv = (Reservation) reservationList.get(rowIndex);
			switch (columnIndex) {
			case 0: return reserv.getRoomName();
			case 1: return reserv.getStartTime()+"〜"+reserv.getEndTime();
			case 2: return reserv.getName();
			case 3: return reserv.getMemo();
			default:	return "?";
			}
		}
	}

}
