/*
このファイルの中身は、NTT オープンソースライセンス　バージョン 1.0（「本
契約」という）の適用を受けます。
本契約を遵守しない限り、このファイルを使用してはなりません。
本契約のコピーは、次のＵＲＬから入手できます。
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

本契約に基づき頒布されるソフトウェアは、現状のまま、明示又は黙示のあらゆ
る種類の保証なしで、頒布されます。本契約に基づく権利及び制限を律する特定
の文言については、本契約を参照してください。

「オリジナルコード」は、 NTT Cyber Space Laboratories Code です。 
「オリジナルコード」の「初期開発者」は、日本電信電話株式会社です。  
日本電信電話株式会社により創作された部分は、Copyright (C) 2004 
日本電信電話株式会社 です。
全ての権利が留保されます。 
「コントリビュータ」：_____________________________________ 


The contents of this file are subject to the NTT Opensource License
Version 1.0 (the License); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
【配布サイトのURL】 http://www.oss.ecl.ntt.co.jp/lms/

Software distributed under the License is distributed on an AS IS
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.

The Original Code is NTT Cyber Space Laboratories Code .

The Initial Developer of the Original Code is NIPPON TELEGRAPH AND 
TELEPHONE CORPORATION.
Portions created by the NIPPON TELEGRAPH AND TELEPHONE CORPORATION 
are Copyright (C) 2004 NIPPON TELEGRAPH AND TELEPHONE CORPORATION. 
All Rights Reserved.

Contributor(s) ______________________________________.
*/

//
//	Evaluate 管理XMO サーバクラス
//			変更履歴
//				2004.01.08	新規作成	五木田　泰史
//
package jp.co.ntt.lms.xmo.Evaluate;

import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.RMISecurityManager;
import java.rmi.server.UnicastRemoteObject;
import java.util.*;
import java.sql.*;

import org.apache.commons.lang.StringEscapeUtils;

import jp.co.ntt.lms.xmo.*;
import jp.co.ntt.lms.xmo.Message.Message;
import jp.co.ntt.lms.xmo.util.DebugLog;
import jp.co.ntt.lms.xmo.Assignments.AssignmentsClient;
import jp.co.ntt.lms.xmo.GroupAndPeople.GroupAndPeopleClient;
import jp.co.ntt.lms.xmo.GroupAndPeople.GroupAndPeopleTable;
import jp.co.ntt.lms.xmo.LoRelation.LoRelationClient;
import jp.co.ntt.lms.lo.*;

/**
 * Evaluate 管理XMO サーバクラスです。<BR>
 * XMO基本メソッドを実装し、クライアントからの登録、更新、削除、検索処理
 * 要求をうけそれぞれの処理を行います。<BR>
 * RMIサーバとして動作するためRemoteインタフェースであるXMOインタフェースを実装し、
 * 永続的な起動状態を確保するためjava.rmi.server.UnicastRemoteObjectクラスを継承します。
 * @author T.Nijou
 * @version 0.0.0.1 2004/01/08
 */
public class Evaluate extends UnicastRemoteObject
	implements XMO, EvaluateMessage, EvaluateTable
{

	//////////////////////////////////////////////////////////////////
	// メソッド名定義
	//////////////////////////////////////////////////////////////////
	/** 登録メソッド名です */
	private static final String METHOD1 = "insert";	// 登録
	/** 更新メソッド名です */
	private static final String METHOD2 = "update";	// 更新
	/** 削除メソッド名です */
	private static final String METHOD3 = "delete";	// 削除
	/** 検索メソッド名です */
	private static final String METHOD4 = "select";	// 検索

	/**
	 * グループテーブルアクセスクラスを保持します
	 */
	private EvaluateDataAccess pobjDataAccess = new EvaluateDataAccess();

	/**
	 * コンストラクタです。
	 */
	public Evaluate() throws RemoteException {
		// リモートオブジェクトをエクスポートする
		// java.rmi.server.UnicastRemoteObject の
		// 引数なしのコンストラクタを呼び出す
		super();
	}

	/**
	 * メニュー一覧を返します
	 * @return Vector メニュー一覧
	 */
	public Vector getMenuList(Hashtable htbParam) {
		Vector vecMenuList = new Vector();
		try {
			EvaluateEnv objEnv = EvaluateEnv.getInstance();
			checkAssign(htbParam);
			String check1 = (String)htbParam.get(LoPropertyDef.MANAGE_ASSIGN);
			String check2 = (String)htbParam.get(LoPropertyDef.LEARNER_ASSIGN);
			// 管理アサインされているか学習アサインされている場合メニューを取得する
			if((check1 != null && check1.equals("1")) || 
				(check2 != null && check2.equals("1")))
			{
				vecMenuList = objEnv.getMenuList();
			}
		}
		catch( Exception e ) {
			e.printStackTrace();
			return new Vector();
		}
		return vecMenuList;
	}

	/**
	 * メソッド一覧を返します
	 * @return Vector
	 */
	public Vector getMethodList() {
		Vector vecMethod = new Vector();
		vecMethod.add( METHOD1 );
		vecMethod.add( METHOD2 );
		vecMethod.add( METHOD3 );
		vecMethod.add( METHOD4 );
		return vecMethod;
	}

	/**
	 * デフォルトメニューを返します
	 * @return String
	 */
	public MenuData getDefaultMenu() {
		return null;
	}

	/**
	 * このXMOで定義された、メソッドのクライアント側からの入り口になるメソッドです。
	 * @param strMethodName 実行するメソッド名を指定します
	 * @param htData メソッドで実行するパラメータを指定します<BR>
	 *               なお必要なキーと値は各DAOの処理メソッドの説明を参照して下さい。
	 * @retunr Object 戻り値（さまざまな戻り値に対応するためObject型としてあります)<BR>
	 *                受け取り側では適切な値にキャストする必要があります。
	 */
	public Object execute( String strMethodName, Hashtable htData ) {
		Object objReturn = null;

		if( strMethodName.equals( METHOD1 ) ) {
			objReturn = insert( htData );
		}
		else if( strMethodName.equals( METHOD2 ) ) {
			objReturn = update( htData );
		}
		else if( strMethodName.equals( METHOD3 ) ) {
			objReturn = delete( htData );
		}
		else if( strMethodName.equals( METHOD4 ) ) {
			objReturn = select( htData );
		}

		return objReturn;
	}

	/**
	 * 起動確認（必ずtrueを返す）
	 * @return boolean 必ずtrueが返ります
	 */
	public boolean isLaunch() {
		return true;
	}

	/**
	 * Evaluateテーブルへ登録処理を行います。<BR>
	 * 以下のパラメータチェックを行い、すべてOKの場合は
	 * DAOの登録処理メソッドを実行します。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             LOID                    LoID
	 *             USER                    ユーザーID
	 *             SCORE                   得点
	 *             CUSTOM_MSG_DIR          コメント
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 登録情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納して返します)
	 */
	private Vector insert( Hashtable htData ) {
		Vector vecReturn = new Vector();
		MessageData objMessage = null;

		// 登録処理のパラメータチェックを行います
		String strMessage = insertCheck( htData );

		// パラメータチェックOKのときは登録処理を行う
		if( strMessage.equals( "" ) ) {
			try {
				pobjDataAccess.insert( htData );
			}
			catch( XMOException xe ) {
				// 登録で例外が発生した場合はXMOExceptionからMessageDataを取得する
				objMessage = xe.getMessageData();
				DebugLog.write( this.getClass(), objMessage.getMessage(), DebugLog.HIGHT );
			}
		}
		else {
			DebugLog.write( this.getClass(), strMessage, DebugLog.HIGHT );
			objMessage = getMessageData( strMessage );
		}

		vecReturn.add( objMessage );

		return vecReturn;
	}

	/**
	 * Evaluateテーブルへ更新処理を行います。<BR>
	 * 以下のパラメータチェックを行い、すべてOKの場合は
	 * DAOの更新処理メソッドを実行します。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             LOID                    LoID
	 *             USER                    ユーザーID
	 *             SCORE                   得点
	 *             CUSTOM_MSG_DIR          コメント
	 *          ---------------------------------------------
	 *             CONDITION_KEY           更新条件文
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 登録情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納して返します)
	 */
	private Vector update( Hashtable htData ) {
		Vector vecReturn = new Vector();
		MessageData objMessage = null;

		// 更新処理のパラメータチェックを行います
		String strMessage = updateCheck( htData );
		// パラメータチェックOKの時は更新処理を行う
		if( strMessage.equals( "" ) ) {
			try {
				pobjDataAccess.update( htData );
			}
			catch( XMOException xe ) {
				objMessage = xe.getMessageData();
				DebugLog.write( this.getClass(), objMessage.getMessage(), DebugLog.HIGHT );
			}
		}
		else {
			DebugLog.write( this.getClass(), strMessage, DebugLog.HIGHT );
			objMessage = getMessageData( strMessage );
		}
		// メッセージデータオブジェクトの作成
		vecReturn.add( objMessage );
		return vecReturn;
	}

	/**
	 * Evaluateテーブルへ削除処理を行います。<BR>
	 * 以下のパラメータチェックを行い、すべてOKの場合は
	 * DAOの削除処理メソッドを実行します。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             CONDITION_KEY           更新条件文
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 削除情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納して返します)
	 */
	private Vector delete( Hashtable htData ) {
		MessageData objMessage = null;
		Vector vecReturn = new Vector();
		try {
			pobjDataAccess.delete( htData );
		}
		catch( XMOException xe ) {
			objMessage = xe.getMessageData();
			DebugLog.write( this.getClass(), objMessage.getMessage(), DebugLog.HIGHT );
		}
		vecReturn.add( objMessage );
		return vecReturn;
	}

	/**
	 * Evaluateテーブルへ検索処理を行います。<BR>
	 * 以下のパラメータチェックを行い、すべてOKの場合は
	 * DAOの検索処理メソッドを実行します。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             CONDITION_KEY           更新条件文
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 検索情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納し、２番目移行に
	 *                      AssignmentsDataクラスを格納して返します。)
	 */
	private Vector select( Hashtable htData ) {
		MessageData objMessage = null;
		Vector vecResult = new Vector();
		try {
			vecResult = pobjDataAccess.select( htData );
		}
		catch( XMOException xe ) {
			objMessage = xe.getMessageData();
			DebugLog.write( this.getClass(), objMessage.getMessage(), DebugLog.HIGHT );
		}

		// 配列の1番目にメッセージデータを格納
		vecResult.add( 0, objMessage );
		return vecResult;
	}

	/**
	 * メッセージオブジェクトを作成します
	 * @param strMessageID メッセージID
	 * @return MessageData メッセージオブジェクト 例外発生時はnullを返します
	 */
	private MessageData getMessageData( String strMessageID) {
		MessageData objMessage = null;
		try {
			objMessage = Message.getInstance().getMessageData( strMessageID, MSG_FIEL_PATH, MSG_FILE_NAME );
		}
		catch( Exception e ) {

		}
		return objMessage;
	}

	/**
	 * 登録処理のパラメータチェックを行います<BR>
	 * 以下のパラメータのチェックを行います。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             LOID                    LoID
	 *             USER                    ユーザーID
	 *             SCORE                   得点
	 *             CUSTOM_MSG_DIR          コメント
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htbParam パラメータ
	 * @return String エラー時はエラー番号 OKのときは空文字を返します
	 */
	private String insertCheck( Hashtable htbParam ) {

		String strMessage = "";
		String strCheck = "";

		// LoIDのチェック(必須チェックあり)
		strCheck = (String)htbParam.get( LOID );
		strMessage = EvaluateCheck.checkLoID( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// ユーザーIDのチェック(必須チェックあり)
		strCheck = (String)htbParam.get( USER );
		strMessage = EvaluateCheck.checkUserID( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 得点のチェック
		strCheck = (String)htbParam.get( SCORE );
		strMessage = EvaluateCheck.checkScore( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// コメントのチェック
		strCheck = (String)htbParam.get( CUSTOM_MSG_DIR );
		strMessage = EvaluateCheck.checkCustomMsgDir( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 正常時は空文字を返す
		return "";
	}

	/**
	 * 更新処理のパラメータチェックを行います<BR>
	 * 以下のパラメータのチェックを行います。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             LOID                    LoID
	 *             USER                    ユーザーID
	 *             SCORE                   得点
	 *             CUSTOM_MSG_DIR          コメント
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htbParam パラメータ
	 * @return String エラー時はエラー番号 OKのときは空文字を返します
	 */
	private String updateCheck( Hashtable htbParam ) {

		String strMessage = "";
		String strCheck = "";

		// LoIDのチェック
		strCheck = (String)htbParam.get( LOID );
		strMessage = EvaluateCheck.checkLoID( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// ユーザーIDのチェック
		strCheck = (String)htbParam.get( USER );
		strMessage = EvaluateCheck.checkUserID( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 得点のチェック
		strCheck = (String)htbParam.get( SCORE );
		strMessage = EvaluateCheck.checkScore( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// コメントのチェック
		strCheck = (String)htbParam.get( CUSTOM_MSG_DIR );
		strMessage = EvaluateCheck.checkCustomMsgDir( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 正常時は空文字を返す
		return "";
	}
	

	/**
	 * LOの管理アサイン、学習アサイン状況を調べます。<BR>
	 * 管理アサイン、学習アサインされている場合はパラメータで渡したHastable内に以下のように情報を格納します。
	 * <PRE>
	 *              KEY      | 管理アサイン | 学習アサイン |
	 *       MANAGE_ASSIGN   |      ○      |              |
	 *       LEARNER_ASSIGN  |              |      ○      |
	 * </PRE>
	 * @param htbParam 情報格納用のHashtable
	 */
	private void checkAssign( Hashtable htbParam )
		throws XMOException
	{
		try {
			// ユーザIDの取得
			String strUserID = (String)htbParam.get( LoPropertyDef.USER );
			// LOIDの取得
			String strLoID = (String)htbParam.get( LoPropertyDef.LOID );

			if( strUserID == null || strLoID == null ) {
				// ユーザIDとLOIDのどちらかが設定されていない場合は処理は行わない
				return;
			}

			if( strUserID.equals( XMOPropertyDef.ROOT_USER ) ) {
				// ルートユーザの場合は管理アサイン、学習アサイン両方を設定する
				htbParam.put( LoPropertyDef.MANAGE_ASSIGN, "1" );
				htbParam.put( LoPropertyDef.LEARNER_ASSIGN, "1" );
				return;
			}

			// 指定したLoIDのアサイン状況を再帰的に調べます。
			checkAssignRef( htbParam, strLoID );

		}
		catch( XMOException le ) {
			throw le;
		}
		catch( Exception e ) {
			throw new XMOException( SYSTEM_ERR );
		}
	}
	
	/**
	 * 再帰呼び出し用のメソッド<BR>
	 * ユーザIDとLOIDを受け取りアサイン情報を取得します。
	 * @param htbParam 情報格納用のHashtable
	 * @param strLoID 検索対象のLOID
	 */
	private void checkAssignRef( Hashtable htbParam, String strLoID )
		throws XMOException, Exception
	{
		// 管理アサイン、学習アサイン情報を取り出す。
		String strManageAssign = (String)htbParam.get( LoPropertyDef.MANAGE_ASSIGN );
		String strLearnerAssign = (String)htbParam.get( LoPropertyDef.LEARNER_ASSIGN );
		// すでに管理アサイン、学習アサイン情報が設定されていた場合は処理を行わない
		if( strManageAssign != null &&
			strLearnerAssign != null ) {
			return;
		}

		// ユーザIDの取得
		String strUserID = (String)htbParam.get( LoPropertyDef.USER );

		// ユーザIDからMemberShipIDを取得する
		StringBuffer sbSubQuery = new StringBuffer();
		sbSubQuery.append( "(SELECT " );
		sbSubQuery.append( GroupAndPeopleTable.MEMBER_SHIP_ID );
		sbSubQuery.append( " FROM " );
		sbSubQuery.append( GroupAndPeopleTable.TABLE_NAME );
		sbSubQuery.append( " WHERE " );
		sbSubQuery.append( GroupAndPeopleTable.CHILD_ID );
		sbSubQuery.append( "='" + StringEscapeUtils.escapeSql(strUserID) +"') " );

		// LOIDを子IDに設定して、親IDを取得する
		LoRelationClient objLoRelation = new LoRelationClient();
		objLoRelation.setChildID( strLoID );
		// 検索処理実行
		if( !objLoRelation.select() ) {
			// 検索処理に失敗した場合
			throw new XMOException( objLoRelation.getMessage() );
		}

		// 検索結果の取得
		while( objLoRelation.next() ) {
			String strParentID = objLoRelation.getParentID();

			String strMaterialID = strParentID + strLoID;

			// Assignmentsの検索処理
			AssignmentsClient objAss = new AssignmentsClient();
			// 検索条件文を作成する
			String strCondition = objAss.MATERIAL_ID + "='" + StringEscapeUtils.escapeSql(strMaterialID) + "' AND " + objAss.MEMBER_SHIP_ID + " in " + sbSubQuery.toString();
			// 検索条件を設定する
			objAss.setCondition( strCondition );
			// 検索処理実行
			if( !objAss.select() ) {
				// 検索処理に失敗した場合
				throw new XMOException( objAss.getMessage() );
			}

			// 検索結果の取得
			while( objAss.next() ) {
				// 管理アサインの取得
				strManageAssign = objAss.getManagementAuthority();
				if( strManageAssign.equals( "1" ) ) {
					// ハッシュテーブルに設定する
					htbParam.put( LoPropertyDef.MANAGE_ASSIGN, strManageAssign );
				}
				// 学習アサインの取得
				strLearnerAssign = objAss.getLearnAuthority();
				if( strLearnerAssign.equals( "1" ) ) {
					// ハッシュテーブルに設定する
					htbParam.put( LoPropertyDef.LEARNER_ASSIGN, strLearnerAssign );
				}
			}

			// 親LOIDで上記の処理を再帰的に繰り返す。
			checkAssignRef( htbParam, strParentID );
		}
	}

}

