package jp.ne.mki.wedge.rule.client.control;

import java.util.ListIterator;
import java.util.Vector;
import jp.ne.mki.wedge.rule.base.AbstractClient;
import jp.ne.mki.wedge.run.client.control.Manager;
import jp.ne.mki.wedge.run.client.data.Item;
import jp.ne.mki.wedge.run.client.event.ClientToolKit;
import jp.ne.mki.wedge.run.client.event.ExecutionInterface;
import jp.ne.mki.wedge.run.client.event.Judgement;
import jp.ne.mki.wedge.run.client.event.NextExecuteJudger;
import jp.ne.mki.wedge.run.interfaces.DataInterface;

/**
 * <h2>Inに設定されたTextアイテムに値が設定されるまでアイテムのAfterイベントを実行する(返り値 引継ぎ)</h2>
 * <p>このロジッククラスを実行すると、まず最初に「Inに設定されたTextアイテム」の値が空になります。<br />
 * その後は、Out に設定されたアイテムの After 実行リストを順番に実行し、
 * ひとつロジッククラスが実行されるタイミングで In アイテムをチェックします。<br />
 * この時 In アイテムに何か値が設定されていればを強制的を抜けます<br />
 *
 * 結果、<code>jp.ne.mki.wedge.rule.client.event.ExecuteAfterTakeOver</code>と似たような動作をしますが、
 * 「Inに設定されたTextアイテムに値が設定された」場合は、強制的に SKIP_ALL する点のみが異なります。<br>
 * </p>
 *
 * <br/>
 * <h4>[I/O RECORD]</h4>
 * <table border="1" cellpadding="3" cellspacing="0" width="100%">
 *  <tr bgcolor="#EEEEFF" class="TableSubHeadingColor">
 *      <th style="width:50%;">InputRecord</th>
 *      <th>OutputRecord</th>
 *  </tr><tr bgcolor="#EEEEFF" class="TableRowColor">
 *      <td>
 *      <!--  InputRecordの内容を記述   -->
 *		値が設定されていた場合に実行を終了するためのアイテム。(Text)
 *      <!--  ここまで   -->
 *      </td>
 *      <td>
 *      <!-- OutputRecordの内容を記述    -->
 *      Afterイベントが設定されているコンポーネント(複数指定可)
 *      <!--  ここまで   -->
 *      </td>
 *  </tr></table>
 *
 * <h4>[RULE PARAMETER]</h4>
 * <table border="1" cellpadding="3" cellspacing="0" width="100%">
 *  <tr>
 *      <th style="width:100px;" class="TableSubHeadingColor">Parameter</th>
 *      <td class="TableRowColor">
 *      <!-- Parameterの内容を記述    -->
 *      <!--ここまで   -->
 *      </td>
 *  </tr></table>
 *
 * @since 1.1.3
 * @author mki
 * @version 1.0
 * @see jp.ne.mki.wedge.rule.client.event.ExecuteAfterTakeOver
 * @see jp.ne.mki.wedge.rule.client.control.ExecuteAfterEvent
 */
public class ExecuteAfterUntilEmpty extends AbstractClient {

	private DataInterface inItem = null;

	private static final int NOT_EMPTY = -1;

	/**
	 * IOパラメータ取得。{@link #execute() execute} の前に実行される。
	 * @return int OK=処理続行、ERROR=異常終了、CANCEL=処理を中断(正常終了)
	 */
	public int getIOParameter() {
		if (getInRecordCount() < 1) {
			return IO_ERROR_IN;
		}
		inItem = getInRecord(0);
		if (inItem.getItemType() != DataInterface.TYPE_TEXT) {
			return IO_ERROR_ITEM_TYPE;
		}
		return OK;
	}

	/**
	 * 入力可に変更する処理を実行。OutputRecordに指定されているもの全てを処理する。
	 * @return int BusinessRuleの戻り値を参照
	 */
	public int execute() {
		// In アイテムを空にする。
		inItem.setString("");
		int result = OK;
		int count = 0;
		int size = outputRecord.size();
		ListIterator iterator = outputRecord.listIterator();
		Item outItem = null;
		Vector afterExecutions = null;
		try {
			while (iterator.hasNext()) {
				outItem = (Item) iterator.next();
				afterExecutions = outItem.getAfterExecutions();
				result = runExecutions(afterExecutions, getManager());
				if (result == SKIP || result == SKIP_ALL) {
					result = OK;
				}
				count++;
				if (result == NOT_EMPTY) {
					result = OK;
					break;
				}
				if (count >= size || result != OK) {
					break;
				}
			}
		} finally {
			afterExecutions = null;
			outItem = null;
			iterator = null;
		}
		return result;
	}

	/**
	 * 終了処理。保持していた変数などを開放する処理を記述します。<br/>
	 * {@link #execute() execute} の後に実行されます。<br/>正常終了・異常終了などに関わらず必ず実行されます。
	 */
	public void exit() {
		inItem = null;
	}

	/**
	 * 次の実行リストを実行するかどうかの判断オブジェクト
	 * Inのアイテムが空で無かった場合にはfalseが返ります。
	 *
	 */
	class MyNextExecuteJuder implements NextExecuteJudger {

		public Judgement getJudgemenet(int resultCode, ExecutionInterface exec) {
			boolean isNextExecute = false;
			if (resultCode == OK || resultCode == SKIP) {
				if (!"".equals(inItem.getString())) {
					// In アイテムが空でなければ break;
					resultCode = NOT_EMPTY;
					isNextExecute = false;
				} else {
					isNextExecute = true;
				}
			}
			return new Judgement(isNextExecute, resultCode);
		}
	}

	/**
	 * 実行リストの処理を実行
	 * @param executions
	 * @param manager
	 * @return
	 * @throws Throwable
	 */
	public int runExecutions(Vector executions, final Manager manager) {
		return ClientToolKit.runExecutions(executions, manager, new MyNextExecuteJuder());
	}
}