/* $Id: TransitionalActivityInspector.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.inspector;

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

import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;

import jp.co.argo21.nautica.commons.swing.DialogUtilities;
import jp.co.argo21.nautica.commons.util.ResourceManager;
import jp.co.argo21.nautica.tool.wfd.ConditionDialog;
import jp.co.argo21.nautica.tool.wfd.DesktopPane;
import jp.co.argo21.nautica.tool.wfd.ProcessDesignFrame;
import jp.co.argo21.nautica.tool.wfd.WorkflowDesignerManager;
import jp.co.argo21.nautica.tool.wfd.element.ActivityElement;
import jp.co.argo21.nautica.tool.wfd.element.Element;
import jp.co.argo21.nautica.tool.wfd.element.ProcessElement;
import jp.co.argo21.nautica.tool.wfd.element.TransitionElement;
import jp.co.argo21.nautica.tool.wfd.element.VariableElement;
import jp.co.argo21.nautica.tool.wfd.expression.ExceptionExpression;
import jp.co.argo21.nautica.tool.wfd.expression.Expression;
import jp.co.argo21.nautica.tool.wfd.expression.OtherwiseExpression;

/**
 * 遷移情報付アクティビティ用のインスペクタ画面
 * 
 * @author  Norihiro Itoh(ARGO 21 Corp.)
 * @version $Revision: 1.2 $
 * @since   Nautica Workflow 1.0
 */
public class TransitionalActivityInspector extends BasicActivityInspector
{
	/** シリアルバージョンID */
	private static final long serialVersionUID = 1L;

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

	/** 遷移条件のタイプ名 */
	private static String[] conditionTypes;

	/** 遷移テーブル */
	private JTable transitionTable;

	/** 条件表示エリア */
	private JTextArea conditionArea;
	
	/** 遷移一覧 */
	private List<TransitionElement> transitions = new ArrayList<TransitionElement>();

	/**
	 * 変数初期化
	 */
	static
	{
		ResourceManager rm = WorkflowDesignerManager.getResourceManager();

		columnNames = new String[2];
		columnNames[0] = rm.getResource("TransitionTableModel.columnName.0");
		columnNames[1] = rm.getResource("TransitionTableModel.columnName.1");

		conditionTypes = new String[5];
		conditionTypes[0] = rm.getResource("TransitionTableModel.conditionType.0");
		conditionTypes[1] = rm.getResource("TransitionTableModel.conditionType.1");
		conditionTypes[2] = rm.getResource("TransitionTableModel.conditionType.2");
		conditionTypes[3] = rm.getResource("TransitionTableModel.conditionType.3");
		conditionTypes[4] = rm.getResource("TransitionTableModel.conditionType.4");
	}

	/**
	 * 遷移情報付アクティビティ用のインスペクタ画面を生成する。
	 */
	public TransitionalActivityInspector()
	{
		super();
		
		ResourceManager rm = WorkflowDesignerManager.getResourceManager();

		JPanel panel = createTransitionInfoPanel(rm);
		addTab(rm.getResource("TransitionalActivityInspector.tab.0"), panel);

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

		transitionTable = new JTable(new TransitionTableModel());
		transitionTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		ListSelectionModel tlsm = transitionTable.getSelectionModel();
		tlsm.addListSelectionListener(new TransitionSelectAction());
		JScrollPane sp1 = new JScrollPane();
		sp1.setViewportView(transitionTable);
		
		conditionArea = new JTextArea();
		conditionArea.setLineWrap(true);
		conditionArea.setEditable(false);
		JScrollPane sp2 = new JScrollPane();
		sp2.setViewportView(conditionArea);

		JButton editButton = new JButton(rm.getResource("JButton.label.edit"));

		editButton.addActionListener(new EditTransitionAction());
		
		panel.add(locate(l0,          10,  10, 100,  25));
		panel.add(locate(sp1,         10,  40, 360, 155));
		panel.add(locate(l1,          10, 200, 100,  25));
		panel.add(locate(sp2,         10, 230, 270, 105));
		panel.add(locate(editButton, 290, 230,  80,  25));

		validate();

		return panel;
	}

	/**
	 * インスペクタを初期化する。
	 * 
	 * @see jp.co.argo21.nautica.tool.wfd.inspector.Inspector#init()
	 */
	public void init()
	{
		super.init();

		transitions.clear();
		conditionArea.setText("");
	}
	
	/**
	 * 編集された情報をアクティビティ要素に反映する。
	 * 
	 * @see jp.co.argo21.nautica.tool.wfd.inspector.Inspector#commit()
	 */
	public void commit()
	{
		super.commit();
		Element e = getInspectable();
		if (e != null) {
			if (e instanceof ActivityElement) {
				@SuppressWarnings("unused")
				ActivityElement act = (ActivityElement)e;
			}
		}		
	}
	
	/**
	 * アクティビティ要素の情報をインスペクタに反映する。
	 * 
	 * @param elem アクティビティ要素
	 * @see jp.co.argo21.nautica.tool.wfd.inspector.Inspector#setInspectable(jp.co.argo21.nautica.tool.wfd.element.Element)
	 */
	public void setInspectable(Element elem)
	{
		super.setInspectable(elem);

		if (elem != null) {
			if (elem instanceof ActivityElement) {
				ActivityElement act = (ActivityElement)elem;
				
				DesktopPane desktop = WorkflowDesignerManager.getMainFrame().getDesktop();
				ProcessDesignFrame frame = desktop.getCurrentProcessDesignFrame();
				if (frame == null) return;
				ProcessElement proc = frame.getProcess();
				if (proc == null) return;
				for (TransitionElement t : proc.getTransitions()) {
					if (act == t.getSource()) {
						transitions.add(t);
					}
				}
			}
		}
		repaint();
	}

	/**
	 * 遷移条件の編集が呼ばれた場合の処理
	 */	
	class EditTransitionAction 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 = transitionTable.getSelectedRow();
			if (selected < 0) {
				DialogUtilities.showWarning(rm.getResource("message.warn.0004"));
				return;
			}
			TransitionElement tr = (TransitionElement)transitions.get(selected);
			Expression exp = tr.getCondition();
			Expression newExp = ConditionDialog.showDialog(TransitionalActivityInspector.this, exp);
			if (newExp == null) {
				tr.setType(TransitionElement.CONDITION);
			} else if (newExp instanceof OtherwiseExpression) {
				tr.setType(TransitionElement.OTHERWISE);
			} else if (newExp instanceof ExceptionExpression) {
				tr.setType(TransitionElement.EXCEPTION);
			} else {
				tr.setType(TransitionElement.CONDITION);
			}
			tr.setCondition(newExp);
			transitionTable.clearSelection();
			conditionArea.setText("");
		}
	}

	/**
	 * 遷移が選択された場合の処理
	 */	
	class TransitionSelectAction 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();
				Expression exp = ((TransitionElement)transitions.get(selected)).getCondition();
				if (exp != null) {
					List<VariableElement> vars = WorkflowDesignerManager.getMainFrame().getPackage().getVariables();
					conditionArea.setText(exp.getExpressionString(vars));
				} else {
					conditionArea.setText("");
				}
			}
		}
	}
	
	/**
	 * 遷移テーブル制御モデル
	 */
	class TransitionTableModel extends AbstractTableModel
	{
		/** シリアルバージョンID */
		private static final long serialVersionUID = 1L;

		/**
		 * 遷移テーブル制御モデルを生成する。
		 */
		TransitionTableModel()
		{
		}

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

		/**
		 * データソースオブジェクトが管理するレコード数を返す。
		 * JTableはこのメソッドを使って、作成および表示する必要のある行数を判断する。
		 *
		 * @return	モデルの行数
		 */
		public int getRowCount()
		{
			return transitions.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)
		{
			TransitionElement tr = (TransitionElement)transitions.get(row);
			if (col == 0) {
				return tr.getDestination().getName();
			} else {
				int type = tr.getType();
				if (type == TransitionElement.OTHERWISE) {
					return conditionTypes[1];
				} else if (type == TransitionElement.EXCEPTION) {
					return conditionTypes[2];
				} else if (type == TransitionElement.DEFAULTEXCEPTION) {
					return conditionTypes[3];
				} else {
					if (tr.getCondition() == null) {
						return conditionTypes[4];
					} else {
						return conditionTypes[0];
					}
				}
			}
		}

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

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