/* $Id: SimulatorView.java,v 1.2 2007/12/11 09:54:58 nito Exp $
 * 
 * Copyright (c)ARGO 21, Corporation. 2005, 2006.  All rights reserved.
 * 
 * This file is part of Nautica Workflow.
 * 
 *  Nautica Workflow is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 * 
 *  Nautica Workflow 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 General Public License for more details.
 * 
 *  You should have received a copy of the GNU General Public License
 *  along with Nautica Workflow; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *  
 */
package jp.co.argo21.nautica.tool.wfd.sim;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.Icon;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.text.Document;

import jp.co.argo21.nautica.commons.swing.BooleanDocument;
import jp.co.argo21.nautica.commons.swing.ByteLimitedDocument;
import jp.co.argo21.nautica.commons.swing.DialogUtilities;
import jp.co.argo21.nautica.commons.swing.NumericDocument;
import jp.co.argo21.nautica.commons.util.ResourceManager;
import jp.co.argo21.nautica.tool.wfd.IconManager;
import jp.co.argo21.nautica.tool.wfd.IconView;
import jp.co.argo21.nautica.tool.wfd.WorkflowDesignerConstants;
import jp.co.argo21.nautica.tool.wfd.WorkflowDesignerManager;
import jp.co.argo21.nautica.tool.wfd.element.ActivityElement;
import jp.co.argo21.nautica.tool.wfd.expression.ConditionalVariable;

/**
 * シミュレータ用変数設定用ダイアログに表示するビュー。
 * 
 * 
 * @author  Norihiro Itoh(ARGO 21 Corp.)
 * @version $Revision: 1.2 $
 * @since   Nautica Workflow 1.0
 */
public class SimulatorView extends JTabbedPane
{
	/** シリアルバージョンID */
	private static final long serialVersionUID = 1L;

	/** テーブルの列名 */
	private static String[] columnNames;

	/** 枠線 */
	protected static final Border border = BorderFactory.createEtchedBorder();

	/** アイコン表示エリア */
	private IconView iconView;
	/** ID表示エリア */
	private JLabel idField;
	/** 名称表示エリア */
	private JLabel nameField;
	/** 変数更新ボタン */
	private JRadioButton editVarButton;
	/** 例外発生ボタン */
	private JRadioButton raiseExButton;
	/** 変数一覧テーブル */
	private JTable varTable;
	/** 変数地編集エリア */
	private JTextField varField;
	/** 変更ボタン */
	private JButton updateButton;
	
	/** 文字列入力制御 */
	private Document strDocument = new ByteLimitedDocument(128);
	
	/** 数値入力制御 */
	private Document numDocument = new NumericDocument(9, true);
	
	/** 真理値入力制御 */
	private Document boolDocument = new BooleanDocument();
	
	/** 変数一覧 */
	private List<ConditionalVariable> vars;
	
	/**
	 * 定数初期化
	 */
	static
	{
		ResourceManager rm = WorkflowDesignerManager.getResourceManager();

		columnNames = new String[3];
		columnNames[0] = rm.getResource("SimulatorView.columnName.0");
		columnNames[1] = rm.getResource("SimulatorView.columnName.1");
	}
	
	/**
	 * ビューを生成する。
	 */
	public SimulatorView()
	{
		ResourceManager rm = WorkflowDesignerManager.getResourceManager();

		JPanel panel = createEditorPanel(rm);
		addTab(rm.getResource("SimulatorView.tab.0"), panel);

		validate();
	}
	
	/**
	 * エディタのパネルを生成する。
	 * 
	 * @param rm リソースマネージャ
	 * @return パネル
	 */
	private JPanel createEditorPanel(ResourceManager rm)
	{
		JPanel panel = new JPanel();
		panel.setLayout(null);
		panel.setBorder(border);
		Dimension size = new Dimension(380, 265);
		panel.setSize(size);
		panel.setPreferredSize(size);
		JLabel l0 = new JLabel(rm.getResource("SimulatorView.label.0"));
		JLabel l1 = new JLabel(rm.getResource("SimulatorView.label.1"));

		iconView = new IconView();
		idField = new JLabel();
		idField.setBorder(border);
		nameField = new JLabel();
		nameField.setBorder(border);

		editVarButton = new JRadioButton(rm.getResource("SimulatorView.operate.0"));
		editVarButton.addActionListener(new SelectEditVarAction());
		raiseExButton = new JRadioButton(rm.getResource("SimulatorView.operate.1"));
		raiseExButton.addActionListener(new SelectRaiseExceptionAction());

		JPanel opePane = new JPanel();
		opePane.setLayout(new GridLayout(1, 3, 5, 5));
		opePane.setBorder(border);
		opePane.add(editVarButton);
		opePane.add(raiseExButton);

		ButtonGroup opeGroup = new ButtonGroup();
		opeGroup.add(editVarButton);
		opeGroup.add(raiseExButton);

		varTable = new JTable(new VarTableModel());
		varTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		varTable.setRowHeight(35);
		varTable.getColumnModel().getColumn(0).setCellRenderer(new VarRenderer());
		ListSelectionModel vlsm = varTable.getSelectionModel();
		vlsm.addListSelectionListener(new VarSelectAction());
		JScrollPane sp0 = new JScrollPane();
		sp0.setViewportView(varTable);
		
		varField = new JTextField();
		varField.setDocument(strDocument);

		updateButton = new JButton(rm.getResource("JButton.label.update"));
		updateButton.addActionListener(new UpdateVarAction());

		panel.add(locate(iconView,      10,  10,  60,  60));
		panel.add(locate(l0,            80,  10, 100,  25));
		panel.add(locate(l1,            80,  40, 100,  25));
		panel.add(locate(idField,      180,  10, 190,  25));
		panel.add(locate(nameField,    180,  40, 190,  25));
		panel.add(locate(opePane,       10,  80, 360,  35));
		panel.add(locate(sp0,           10, 120, 360, 105));
		panel.add(locate(varField,      10, 230, 270,  25));
		panel.add(locate(updateButton, 290, 230,  80,  25));

		validate();

		return panel;
	}

	/**
	 * 変数の編集可否を設定する。
	 * 
	 * @param b	編集可否
	 */	
	private void setVarEditable(boolean b)
	{
		varTable.clearSelection();
		varField.setText("");
		varTable.setEnabled(b);
		varField.setEditable(b);
		updateButton.setEnabled(b);
	}

	/**
	 * 例外発生を選択した同化を返す。
	 * 
	 * @return	選択した場合true
	 */
	public boolean isExceptionRaising()
	{
		return raiseExButton.isSelected();
	}

	/**
	 * 現在の変数一覧を返す。
	 * 
	 * @return	変数一覧
	 */
	public List<ConditionalVariable> getCurrentVariables()
	{
		return vars;
	}

	/**
	 * 現在のアクティビティを設定する。
	 * 
	 * @param act	アクティビティ
	 */
	public void setCurrentActivity(ActivityElement act)
	{
		iconView.setIconName(act.getActivityState().getIconName());
		idField.setText(act.getID());
		nameField.setText(act.getName());
	}

	/**
	 * 変数一覧を設定する。
	 * 
	 * @param vars	変数一覧
	 */
	public void setCurrentVariables(List<ConditionalVariable> vars)
	{
		this.vars = vars;
	}

	/**
	 * 値の編集可否を設定する。
	 * 
	 * @param b	編集可否
	 */	
	void setValueEditable(boolean b)
	{
		editVarButton.setEnabled(b);
		raiseExButton.setEnabled(b);
		varTable.setEnabled(b);
		varField.setEditable(b);
		updateButton.setEnabled(b);
		varField.setText("");
	}

	/**
	 * ビューを初期化する。
	 */
	void init()
	{
		editVarButton.setSelected(true);
		setVarEditable(true);
	}

	/**
	 * 設定値をチェックする。
	 * 
	 * @return	結果
	 */	
	public boolean check()
	{
		return true;
	}
	
	/**
	 * 設定値を確定する。
	 */
	public void commit()
	{
	}

	/**
	 * 指定されたコンポーネントの属性を指定の大きさと座標で更新する。
	 * 
	 * @param component 対象コンポーネント
	 * @param x 左上のX座標
	 * @param y 左上のY座標
	 * @param w 幅
	 * @param h 高さ
	 * @return 変更されたコンポーネント
	 */
	protected Component locate(Component component, int x, int y, int w, int h)
	{
		component.setLocation(x, y);
		component.setSize(w, h);
		return  component;
	}
	
	/**
	 * 変数編集を選択した場合の処理。
	 */	
	class SelectEditVarAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 変数編集を可能にする。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			setVarEditable(true);
		}
	}
	
	/**
	 * 例外発生を選択した場合の処理
	 */	
	class SelectRaiseExceptionAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 変数編集を不可にする。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			setVarEditable(false);
		}
	}
	
	/**
	 * 更新処理。
	 */	
	class UpdateVarAction extends AbstractAction
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 更新処理。
		 * 
		 * @param e	イベント
		 * @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
		 */
		public void actionPerformed(ActionEvent e)
		{
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();
			int selected = varTable.getSelectedRow();
			if (selected < 0) {
				DialogUtilities.showWarning(rm.getResource("message.warn.0006"));
				return;
			}
			ConditionalVariable var = (ConditionalVariable)vars.get(selected);
			var.setValue(varField.getText());
			varTable.updateUI();
		}
	}

	/**
	 * 変数リスト選択時の処理。
	 */	
	class VarSelectAction implements ListSelectionListener
	{
		/**
		 * 変数の型に応じて入力エリアを切り替える。
		 * 
		 * @param e	イベント
		 * @see javax.swing.event.ListSelectionListener#valueChanged(javax.swing.event.ListSelectionEvent)
		 */
		public void valueChanged(ListSelectionEvent e)
		{
			if (e.getValueIsAdjusting()) return;

			ListSelectionModel lsm = (ListSelectionModel)e.getSource();
			if (lsm.isSelectionEmpty() == false) {
				int selected = lsm.getMinSelectionIndex();
				ConditionalVariable var = (ConditionalVariable)vars.get(selected);
				String v = var.getValue();
				int type = var.getType();
				if (v == null) varField.setText("");
				else varField.setText(v);
				if (type == ConditionalVariable.INTEGER) {
					varField.setDocument(numDocument);
					varField.setHorizontalAlignment(SwingUtilities.RIGHT);
				} else if (type == ConditionalVariable.BOOLEAN) {
					varField.setDocument(boolDocument);
					varField.setHorizontalAlignment(SwingUtilities.LEFT);
				} else {
					varField.setDocument(strDocument);
					varField.setHorizontalAlignment(SwingUtilities.LEFT);
				}
			}
		}
	}

	/**
	 * プロセス変数テーブル制御モデル
	 */
	class VarTableModel extends AbstractTableModel
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * プロセス変数制御モデルを生成する。
		 */
		VarTableModel()
		{
			vars = new ArrayList<ConditionalVariable>();
		}

		/**
		 * データソースオブジェクトが管理する列数を返す。
		 * JTableはこのメソッドを使って、初期化時に作成および表示する
		 * 必要のある列数を判断する。
		 *
		 * @return	モデルの列数
		 */
		public int getColumnCount()
		{
			return 2;
		}

		/**
		 * データソースオブジェクトが管理するレコード数を返す。
		 * JTableはこのメソッドを使って、作成および表示する必要のある行数を判断する。
		 *
		 * @return	モデルの行数
		 */
		public int getRowCount()
		{
			return vars.size();
		}

		/**
		 * colにある列の名前を返す。
		 * このメソッドは、テーブルの列ヘッダ名を初期化するために使われる。
		 *
		 * @param	col		列のインデックス
		 * @return	列ヘッダ名
		 */
		public String getColumnName(int col)
		{
			return columnNames[col];
		}

		/**
		 * カラムの値を返す。
		 *
		 * @param	row		値が参照される行
		 * @param	col		値が参照される列
		 * @return	指定されたセルにある値
		 */
		public Object getValueAt(int row, int col)
		{
			ConditionalVariable var = (ConditionalVariable)vars.get(row);
			if (col == 0) return var;
			else return var.getValue();
		}

		/**
		 * 列のClassを返す。
		 *
		 * @param	col		列
		 * @return	モデルのオブジェクト値の共通の上位クラス
		 */
		public Class<?> getColumnClass(int col)
		{
			if (col == 0) return ConditionalVariable.class;
			else return String.class;
		}

		/**
		 * rowとcolにあるセルが編集可能な場合はtrueを返す。
		 * そうでない場合、セルでsetValueAt()を呼び出しても、そのセルの値は変更されない。
		 *
		 * @param	row		値が参照される行
		 * @param	col		値が参照される列
		 * @return	セルが編集可能な場合はtrue
		 */
		public boolean isCellEditable(int row, int col)
		{
			return false;
		}
	}

	/**
	 * 変数テーブル用のレンダラー
	 */	
	public class VarRenderer extends DefaultTableCellRenderer
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/** アイコン */
		private Icon icon;
		
		/**
		 * レンダラーを生成する。
		 */
		VarRenderer()
		{
			String name = WorkflowDesignerConstants.EL_VARIABLE + "-cur";
			icon = IconManager.getIcon(name);
		}

		/**
		 * レンダリング処理
		 * 
		 * @param table	テーブル
		 * @param o	セル内容
		 * @param isSelected	選択状態
		 * @param hasFocus	フォーカス状態
		 * @param row	行
		 * @param column	列
		 * @return	レンダリング結果
		 * @see javax.swing.table.TableCellRenderer#getTableCellRendererComponent(javax.swing.JTable, java.lang.Object, boolean, boolean, int, int)
		 */		
		public Component getTableCellRendererComponent(
		JTable table,
		Object o,
		boolean isSelected,
		boolean hasFocus,
		int row,
		int column)
		{
			super.getTableCellRendererComponent(table, o, isSelected, hasFocus, row, column);
			ResourceManager rm = WorkflowDesignerManager.getResourceManager();

			ConditionalVariable var = (ConditionalVariable)o;
			setText(var.getName());

			if (icon != null) setIcon(icon);
			setToolTipText(var.getTooltipText(rm));
			return this;
		}
	}
}
