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

import java.util.Vector;
import java.util.logging.Level;

import jp.ne.mki.wedge.rule.base.AbstractClient;
import jp.ne.mki.wedge.run.client.data.Item;
import jp.ne.mki.wedge.run.client.executer.ExecutionExecuter;

/**
 *   <h2>IfElse構造化ロジッククラス</h2>
 *   <p>
 *     入力引数のアイテムAfterを 条件、出力引数のアイテムAfter を処理 として IfElse の構造化を行います。<br>
 *     入力引数のアイテムAfterを実行し、戻り値にOKが返って来た場合のみ 出力引数の同行アイテムAfterを実行し
 *     処理を終了します。<br>
 *     入力引数のアイテムAfterの結果がいずれもOKで返らなかった場合には、入力引数の数 + 1個目の 行である
 *     出力引数のアイテムのAfterを実行します。(else としての処理)
 *   </p>
 *   <p>
 *     <table border="1">
 *      <tr><th>入力引数</th><th>出力引数</th></tr>
 *      <tr><td>アイテムA</td><td>アイテムD</td></tr>
 *      <tr><td>アイテムB</td><td>アイテムE</td></tr>
 *      <tr><td>アイテムC</td><td>アイテムF</td></tr>
 *      <tr><td></td><td>アイテムG</td></tr>
 *     <table>
 *     <br>
 *     という設定がされた場合には、以下のような処理になります。<br>
 *     <br>
 *     <pre>
 *     if( アイテムA:After == OK ){
 *        return アイテムD:After;
 *     }
 *     else if( アイテムB:After == OK ){
 *        return アイテムE:After;
 *     }
 *     else if( アイテムC:After == OK ){
 *        return アイテムF:After;
 *     }
 *     else{
 *        return アイテムG:After;
 *     }
 *     </pre>
 *     入力引数のアイテムAfterは、「条件式」として扱い、戻り値は 基本的に OK か それ以外か の
 *     判断で行います。<br>
 *     「条件式」での戻り値では、 OK 、 CANCEL(もしくは ERROR) のいずれかを返すように
 *     して、
 *     STOP,STOP_SELECT_ALL,FRAME_CLOSE などの 戻り値は使用しないようにして下さい。 <br>
 *     「条件式」にて、最後の戻り値が SKIP,SKIP_ALL などの場合は OK とみなされます。<br>
 *
 *
 *     <br>
 *     このロジッククラスの戻り値は、
 *     以下の仕様に基づき変換され このロジッククラスの戻り値として返します。<br>
 *     <br>
 *     <table border="1">
 *      <tr><th>出力アイテムAfterの戻り値</th><th>次の出力アイテム実行有無</th><th>このロジッククラスの戻り値</th></tr>
 *      <tr><td>OK</td><td>○</td><td>OK</td></tr>
 *      <tr><td>ERROR</td><td>×</td><td>ERROR</td></tr>
 *      <tr><td>STOP</td><td>×</td><td>STOP</td></tr>
 *      <tr><td>CANCEL</td><td>×</td><td>CANCEL</td></tr>
 *      <tr><td>SKIP</td><td>○</td><td>OK</td></tr>
 *      <tr><td>SKIP_ALL</td><td>○</td><td>OK</td></tr>
 *      <tr><td>FRAME_CLOSE</td><td>×</td><td>SKIP_ALL</td></tr>
 *      <tr><td>FRAME_QUIT</td><td>×</td><td>SKIP_ALL</td></tr>
 *      <tr><td>SYSTEM_EXIT</td><td>×</td><td>SKIP_ALL</td></tr>
 *      <tr><td>SYSTEM_QUIT</td><td>×</td><td>SKIP_ALL</td></tr>
 *     <table>
 *   </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の内容を記述   -->
 *      <ol><li>ケースロジックアイテム(複数)</li></ol>
 *      <!--  ここまで   -->
 *      </td>
 *      <td>
 *      <!-- OutputRecordの内容を記述    -->
 *       <ol><li>処理ロジックアイテム(複数) <br> 但し、In引数の数 + 1 設定する必要がある</li></ol>
 *      <!--  ここまで   -->
 *      </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>
 *
 * @author mki
 * @version 1.0
 */
public class StructureIfElse extends AbstractClient {

	/**
	 * 入力アイテムに設定があれば、エラー処理があると認識する
	 * IOパラメータ取得。{@link #execute() execute} の前に実行される。
	 *
	 * @return int int OK=処理続行、ERROR=異常終了、CANCEL=処理を中断(正常終了)
	 */
	public int getIOParameter() throws Throwable {
		if (getInRecordCount() == (getOutRecordCount() + 1)) {
			errorMessage = "出力引数の数は 入力引数+1 でなければいけません。";
			return IO_ERROR;
		}
		return OK;
	}

	/**
	 * 出力アイテムのAfter処理を順次実行する
	 * 各Afterの戻り値が OK 出ない場合には処理中断し実行リストに処理を戻す。
	 * 但し、SKIP or SKIP_ALL の場合には OK とみなし処理続行する。
	 *
	 * @return int BusinessRuleの戻り値を参照
	*/
	public int execute() throws Throwable {
	    log(Level.FINER, "- If Else start - " + getLogicalName(), null);
		int result = OK;
		int size = getInRecordCount();
		for (int i = 0; i < size; i++) {
			result = changeReturn(executeItemAfterExecution(getInItem(i), i));
			//条件に当てはまったとき
			if (result == OK) {
                log(
					Level.FINER,
					" -- case MATCH → case:"
						+ getInItem(i).getLogicalName()
						+ ", execute:"
						+ getOutItem(i).getLogicalName(), null);
				return changeReturn(executeItemAfterExecution(getOutItem(i), i));
			}
		}
		//どの条件に当てはまらなかったとき
        log(Level.FINER, " -- Case NO Match → execute : " + getOutItem(size).getLogicalName(), null);
		return changeReturn(executeItemAfterExecution(getOutItem((size)), (size)));

	}

	/**
	 * 出力アイテムのAfterを実行
	 */
	protected int executeItemAfterExecution(Item item, int index) {
		Vector executions = item.getAfterExecutions();
		return ExecutionExecuter.runExecutions(executions, getManager());
	}

	/**
	 * 入力アイテムのAfterの戻り値を、このロジッククラスの戻り値に変換
	 *
	 * @param result
	 * @return
	 */
	protected int changeReturn(int result) {
		// SKIP , SKIP_ALL の場合には OKを戻り値に返す
		if (result == SKIP || result == SKIP_ALL) {
			return OK;
		}
		// 処理内にて画面終了 もしくは システム終了された場合には以降の処理は中断
		// 終了処理自体は既に終了しているため、SKIP_ALL 返す
		else if (result == FRAME_CLOSE || result == FRAME_QUIT || result == SYSTEM_EXIT || result == SYSTEM_QUIT) {
			return SKIP_ALL;
		} else {
			return result;
		}
	}

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