/*
 * 作成日: 2006/10/26
 *
 * ＲＴＥデータチェッククラス
 * 
 */

package jp.co.ntt.lms.imode.extension;

import java.util.Hashtable;

/**
 * RunTimeEnvironmentデータモデルをチェックするクラスです。
 *
 * @author ntc-sakai
 * 
 */
public class RunTimeFormat {
	// 一般的なRTEデータモデル
	private static final String [][]dataModel  = {
			{"cmi.learner_id"                 , "r" },
			{"cmi.learner_name"               , "r" },
			{"cmi.location"                   , "rw"},
			{"cmi.credit"                     , "r" },
			{"cmi.success_status"             , "rw"},
			{"cmi.completion_status"          , "rw"},
			{"cmi.entry"                      , "r" },
			{"cmi.score.scaled"               , "rw"},
			{"cmi.score.raw"                  , "rw"},
			{"cmi.score.max"                  , "rw"},
			{"cmi.score.min"                  , "rw"},
			{"cmi.total_time"                 , "r" },
			{"cmi.mode"                       , "r" },
			{"cmi.suspend_data"               , "rw"},
			{"cmi.launch_data"                , "r" },
			{"cmi.evalution.comments"         , "r" },
			{"cmi.evalution.interactions"     , "r" },
			{"cmi.evalution.objectives_status", "r" },
			{"cmi.scaled_passing_score"       , "r" },
			{"cmi.max_time_allowed"           , "r" },
			{"cmi.time_limit_action"          , "r" },
			{"cmi.learner_preference.audio"   , "rw"},
			{"cmi.learner_preference.language", "rw"},
			{"cmi.learner_preference.speed"   , "rw"},
			{"cmi.learner_preference.text"    , "rw"},
			{"cmi.exit"                       , "w" },
			{"cmi.session_time"               , "w" }
	};

	// objectivesモデル(cmi.objectives.n.xxx.yyy.zzzのxxx.yyy.zzz部分)
	private static final String [][]objectivesModel = {
			{"id"               , "rw"},
			{"score.scaled"     , "rw"},
			{"score.raw"        , "rw"},
			{"score.max"        , "rw"},
			{"score.min"        , "rw"},
			{"success_status"   , "rw"},
			{"completion_status", "rw"}
	};

	// lms Commentsモデル
	private static final String [][]lmsCommentsModel = {
			{"date_time", "r"},
			{"location" , "r"},
			{"comment"  , "r"}
	};

	// Commentsモデル
	private static final String [][]commentsModel = {
			{"date_time", "rw"},
			{"location" , "rw"},
			{"comment"  , "rw"}
	};

	// Interactionsモデル
	private static final String [][]interactionsModel = {
			{"id"              , "rw"},
			{"type"            , "rw"},
			{"timestamp"       , "rw"},
			{"learner_response", "rw"},
			{"result"          , "rw"},
			{"weighting"       , "rw"},
			{"latency"         , "rw"},
			{"description"     , "rw"}
	};

	private static Hashtable dataModelList;
	private static Hashtable objectivesModelList;
	private static Hashtable lmsCommentsModelList;
	private static Hashtable commentsModelList;
	private static Hashtable interactionsModelList;

	static {
		dataModelList = new Hashtable();
		for(int i = 0; i < dataModel.length; i++) {
			dataModelList.put(dataModel[i][0], dataModel[i][1]);
		}

		objectivesModelList = new Hashtable();
		for(int i = 0; i < objectivesModel.length; i++) {
			objectivesModelList.put(objectivesModel[i][0], objectivesModel[i][1]);
		}

		lmsCommentsModelList = new Hashtable();
		for(int i = 0; i < lmsCommentsModel.length; i++) {
			lmsCommentsModelList.put(lmsCommentsModel[i][0], lmsCommentsModel[i][1]);
		}

		commentsModelList = new Hashtable();
		for(int i = 0; i < commentsModel.length; i++) {
			commentsModelList.put(commentsModel[i][0], commentsModel[i][1]);
		}

		interactionsModelList = new Hashtable();
		for(int i = 0; i < interactionsModel.length; i++) {
			interactionsModelList.put(interactionsModel[i][0], interactionsModel[i][1]);
		}
	}

	/**
	 * ＣＭＩデータモデルのチェックを行ないます。
	 * 
	 * @param cmiKey CMIデータモデル
	 * @param mode リード時：r ライト時：w
	 * @return 0:正常 401:データモデルエラー 
	 *          404:ライトモードエラー 405:リードモードエラー
	 */
	public String cmiCheck(String cmiKey, String mode) {

		String modetype = (String) dataModelList.get(cmiKey);

		String strRet = "0";

		if (modetype == null) {
			if (cmiKey.startsWith("cmi.objectives.")) {
				// オブジェクティブチェック(cmi.objectives.n.xxx)
				strRet = numModelCheck(objectivesModelList, cmiKey.substring("cmi.objectives.".length()), mode);
			}else if (cmiKey.startsWith("cmi.comments_from_lms.")) {
				// コメントチェック(cmi.comments_from_lms.n
				strRet = numModelCheck(lmsCommentsModelList, cmiKey.substring("cmi.comments_from_lms.".length()), mode);
			} else if (cmiKey.startsWith("cmi.comments_from_learner.")) {
				strRet = numModelCheck(commentsModelList, cmiKey.substring("cmi.comments_from_learner.".length()), mode);
			} else if (cmiKey.startsWith("cmi.interactions.")) {
				strRet = interactionsCheck(cmiKey.substring("cmi.interactions.".length()), mode);
			} else {
				strRet = "401";
			}
		} else 	if (modetype.indexOf(mode) < 0) {
			if (mode != null && mode.equals("w")) {
				strRet = "404";
			} else {
				strRet = "405";
			}
		}

		return strRet;
	}

	/**
	 * 番号付きのＣＭＩデータモデルチェック
	 * 
	 * @param ModelList ＣＭＩデータテーブル
	 * @param cmiKey ＣＭＩデータモデル
	 * @param mode リード時：r ライト時：w
	 * @return 0:正常 401:データモデルエラー 
	 *          404:ライトモードエラー 405:リードモードエラー
	 */
	private String numModelCheck(Hashtable ModelList, String cmiKey, String mode) {
		String[] data = cmiKey.split("\\.");

		if (data.length < 2) {
			// cmi.objectives.xxx
			return "401";
		}

		// 数字チェック
		for (int i = 0; i < data[0].length(); i++) {
			if ((data[0].charAt(i) < '0') || (data[0].charAt(i) > '9')) {
				// 数字以外エラー
				return "401";
			}
		}

		// 
		String strKey = cmiKey.substring(data[0].length()+1);
		String modetype = (String) ModelList.get(strKey);

		if (modetype == null) {
			return "401";
		}

		if (modetype.indexOf(mode) < 0) {
			if (mode != null && mode.equals("w")) {
				return "404";
			} else {
				return "405";
			}
		}

		return "0";

	}

	/**
	 * Interactionsデータモデルチェック
	 * 
	 * @param cmiKey ＣＭＩデータモデル
	 * @param mode リード時：r ライト時：w
	 * @return 0:正常 401:データモデルエラー 
	 *          404:ライトモードエラー 405:リードモードエラー
	 */
	private String interactionsCheck(String cmiKey, String mode) {
		String[] data = cmiKey.split("\\.");

		if (data.length < 2) {
			return "401";
		} else if (data.length == 2) {
			for (int i = 0; i < data[0].length(); i++) {
				if ((data[0].charAt(i) < '0') || (data[0].charAt(i) > '9')) {
					return "401";
				}
			}
			String strKey = cmiKey.substring(data[0].length()+1);
			String modetype = (String) interactionsModelList.get(strKey);
			if (modetype == null) {
				return "401";
			}
			if (modetype.indexOf(mode) < 0) {
				if (mode != null && mode.equals("w")) {
					return "404";
				} else {
					return "405";
				}
			}
		} else if (data.length == 4) {
			if ((data[1].equals("objectives") &&
				 data[3].equals("id")) ||
				(data[1].equals("correct_responses") &&
				 data[3].equals("pattern"))) {
				for (int i = 0; i < data[0].length(); i++) {
					if ((data[0].charAt(i) < '0') || (data[0].charAt(i) > '9')) {
						return "401";
					}
				}
				for (int i = 0; i < data[2].length(); i++) {
					if ((data[2].charAt(i) < '0') || (data[2].charAt(i) > '9')) {
						return "401";
					}
				}
			} else {
				return "401";
			}
		}
		return "0";
	}
}
