package com.ftinc.si.assist.test.gui.plugins;

import java.util.HashMap;

import javax.swing.JMenuItem;
import javax.swing.JOptionPane;

import com.ftinc.si.assist.run.Messages;
import com.ftinc.si.assist.test.ArgumentIF;
import com.ftinc.si.assist.test.AssertIF;
import com.ftinc.si.assist.test.AssertRecord;
import com.ftinc.si.assist.test.ObjectRecord;
import com.ftinc.si.assist.test.TestCaseIF;
import com.ftinc.si.assist.test.TestCommandIF;
import com.ftinc.si.assist.test.TestCommandRecord;
import com.ftinc.si.assist.test.Tool;
import com.ftinc.si.assist.test.gui.ArgumentEditor;
import com.ftinc.si.assist.test.gui.AssertEditor;
import com.ftinc.si.assist.test.gui.ClassReadDialog;
import com.ftinc.si.assist.test.gui.Plugin;
import com.ftinc.si.assist.test.gui.TestCaseEditor;

public class DefaultPlugin implements Plugin{

	private boolean isStatic;
	private String className;
	private int v_argpos;//第一引数が可変の場合0とする。
	private String[] argTypes;

	@Override
	public JMenuItem getMenuItem(String s) {
		if (s.equals("addCommand")) { //$NON-NLS-1$
			return TestCaseEditor.getMenuItem(s, Messages.getString("DefaultPlugin.2"), null, this); //$NON-NLS-1$
		} else if (s.equals("editArg")) { //$NON-NLS-1$
			return TestCaseEditor.getMenuItem(s, Messages.getString("DefaultPlugin.1"), null, this); //$NON-NLS-1$
		} else if (s.equals("addArg")) { //$NON-NLS-1$
			return TestCaseEditor.getMenuItem(s, Messages.getString("DefaultPlugin.0"), null, this); //$NON-NLS-1$
		} else if (s.equals("editAssert")) { //$NON-NLS-1$
			return TestCaseEditor.getMenuItem(s, Messages.getString("DefaultPlugin.3"), null, this); //$NON-NLS-1$
		}
		return null;
	}

	@Override
	public int getPriority(TestCaseIF cs, TestCommandIF rec, String stack) {
		if (rec != null && stack != null) {
			return 1;//編集：他のメニューを排除しない。
		} else if (stack == null) {
			//TestCaseの上もしくは空白
			return 1;//追加
		}
		return 0;
	}

	@Override
	public int initCommand(TestCommandIF cmd) {
		ClassReadDialog m_dial = new ClassReadDialog(null, Tool.target_dirs, (TestCommandRecord)cmd); //$NON-NLS-1$
		m_dial.setVisible(true);

		//cancelの時にはclassName=nullになっている。
		if (m_dial.className != null && m_dial.methodName != null) {
			cmd.setClassName(m_dial.className);
			className = m_dial.className;

			//m_info：①static ②メソッド名 ③可変引数の位置
			//①③は省略可能
			String[] m_info = m_dial.methodName.split(" "); //$NON-NLS-1$
			isStatic = false;
			v_argpos = -1;
			String mName = ""; //$NON-NLS-1$
			if (m_info.length == 1) {
				//メソッド名のみ
				mName = m_info[0];
			} else if (m_info.length == 2) {
				if (m_info[0].matches("^.*static")) { //$NON-NLS-1$
					//可変引数ではない
					isStatic = true;
					mName = m_info[1];
				} else if (m_info[0].equals("^final")) { //$NON-NLS-1$
					//可変引数ではない
					mName = m_info[1];
				} else {
					//可変引数
					mName = m_info[0];
				}
			} else if (m_info.length == 3) {
				//staticであり可変引数
				if (m_info[0].matches("^.*static")) { //$NON-NLS-1$
					isStatic = true;
				}
				mName = m_info[1];
				v_argpos = Integer.valueOf(m_info[2]);
			} else {
				return -1;
			}
			cmd.setMethod(mName, isStatic, v_argpos);//static の場合、先頭に「static 」が来る。

			int a_size = m_dial.objs.length;
			int count = 0;

			//initArgumentsのために情報を格納する。
			argTypes = new String[a_size];
			for (int i = 0; a_size > i; i++) {
				String obj_rep = m_dial.objs[i];   // オブジェクト表現はDialogから取る。$n=ClassName
				if (obj_rep.startsWith("$_")) { //$NON-NLS-1$
					//返却値の型を設定
					cmd.setReturnType(obj_rep.replaceAll("\\$_=", "")); //$NON-NLS-1$ //$NON-NLS-2$
				} else if (obj_rep.startsWith("$0")) { //$NON-NLS-1$
					//$0がある場合に記入。但し、staticやコンストラクタの場合、t_dial.objs[]に$0はない。
					argTypes[0] = m_dial.className;
					count++;
				} else {
					//$[1-9]+の場合
					String num = obj_rep.replaceAll("^\\$([0-9]+)=.*$", "$1"); //$NON-NLS-1$ //$NON-NLS-2$
					Integer n = Integer.valueOf(num);

					if (v_argpos + 1 == n) {
						//ちょうど可変引数
					} else {
						argTypes[n] = obj_rep.replaceAll("^\\$[0-9]+=(.*)$", "$1"); //$NON-NLS-1$ //$NON-NLS-2$
					}
					count++;
				}
			}
			return count;//$0を含めた引数の数を返す。
		}
		return -2;//エラーを伝えるため。
	}

	//メソッドに指定されている引数の型をセットする。
	@Override
	public void initArguments(ArgumentIF[] a) {
		for (int i = 0; i < a.length; i++) {
			if (i == 0) {
				if (!isStatic) {
					a[i].setClassName(className);
					a[i].setStack("$0"); //$NON-NLS-1$
				}
			} else {
				a[i].setClassName(argTypes[i]);

				String t_stack = "$" + Integer.toString(i); //$NON-NLS-1$
				a[i].setStack(t_stack);
			}
		}
	}

	//引数追加の場合。
	@Override
	public void initArgument(ArgumentIF a, String opt) {
		//追加の場合、最後尾の引数と同じ型である。
		String t_cname = argTypes[argTypes.length - 1];
		a.setClassName(t_cname);
	}

	@Override
	public int varArgsPos() {
		return v_argpos;
	}

	@Override
	public boolean hasSubject() {
		return !isStatic;
	}

	@Override
	public boolean hasAssert() {
		return true;
	}

	@Override
	public void editArgument(ArgumentIF a, AssertIF ast, String opt) {
		ObjectRecord xa = ((ObjectRecord)a);
		String id = a.getId().replaceFirst("^[0-9]+(\\$.*$)", "$1"); //$NON-NLS-1$ //$NON-NLS-2$
		if ("$_".equals(id)) { //$NON-NLS-1$
			//返却値のクラスを編集する。実装変更に対応するため。
			String t_data = JOptionPane.showInputDialog(ArgumentEditor.s_owner, Messages.getString("DefaultPlugin.5"), xa.getClassName()); //$NON-NLS-1$
			if (t_data != null && !xa.getClassName().equals(t_data)) {
				//変更有。
				xa.className = t_data;
				xa.changed();
			}
		} else {
			//引数を編集する。
			ArgumentEditor t_ae = new ArgumentEditor(ArgumentEditor.s_owner, xa, id); //$NON-NLS-1$ //$NON-NLS-2$
			t_ae.setVisible(true);
		}
	}

	//nullは何もしない
	@Override
	public TestCommandIF extendCommand(TestCommandIF a) {
		return null;
	}

	//Assertの内容を設定する。
	public void initAssert(AssertIF ast) {
	}

	@Override
	public void editProperties(HashMap<String, String> map) {
	}

	@Override
	public void initProperties(HashMap<String, String> map) {
	}

	@Override
	public void editAssert(AssertIF ast, TestCommandIF atd) {
		AssertEditor a_edit = null;
		try {
			a_edit = new AssertEditor(ArgumentEditor.s_owner, (AssertRecord)ast, (TestCommandRecord)atd);
			a_edit.setVisible(true);
		} catch (Exception e) {
			Tool.alertMSG(null, Messages.getString("TestCaseEditor.44") + e.getMessage() + "\n" + Tool.getStackMessage(e, 0, 10)); //$NON-NLS-1$ //$NON-NLS-2$
			return;
		}
	}

	@Override
	public void destroy() {
	}

}
