/*
このファイルの中身は、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) ______________________________________.
*/

//
//	LoServerクラス
//			変更履歴
//				2004.01.08	新規作成	五木田 泰史
//

package jp.co.ntt.lms.lo;

import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;

import org.apache.commons.lang.StringEscapeUtils;

import jp.co.ntt.lms.Common.status.PropagateControl;
import jp.co.ntt.lms.Common.status.StatusPropagation;
import jp.co.ntt.lms.Common.status.prerequisite.Prerequisite;
import jp.co.ntt.lms.Common.status.prerequisite.PrerequisiteException;
import jp.co.ntt.lms.Common.status.prerequisite.PrerequisiteParseException;
import jp.co.ntt.lms.lo.util.LoLogSQLMaker;
import jp.co.ntt.lms.xmo.DataAccess;
import jp.co.ntt.lms.xmo.Environment;
import jp.co.ntt.lms.xmo.MessageData;
import jp.co.ntt.lms.xmo.XMOPropertyDef;
import jp.co.ntt.lms.xmo.Assignments.AssignUsableList;
import jp.co.ntt.lms.xmo.Assignments.AssignmentsClient;
import jp.co.ntt.lms.xmo.Assignments.AssignmentsTable;
import jp.co.ntt.lms.xmo.Base.XMSBaseClient;
import jp.co.ntt.lms.xmo.GroupAndPeople.GroupAndPeopleClient;
import jp.co.ntt.lms.xmo.GroupAndPeople.GroupAndPeopleTable;
import jp.co.ntt.lms.xmo.Lo.LoClient;
import jp.co.ntt.lms.xmo.LoRelation.LoRelationClient;
import jp.co.ntt.lms.xmo.RoleAssignments.RoleAssignmentsClient;
import jp.co.ntt.lms.xmo.util.ChangeEncode;
import jp.co.ntt.lms.xmo.util.DebugLog;

/**
 * LoServerクラス
 *
 * <PRE>
 *   Loの基本機能を共通化したクラス。
 *   Loの基本機能インタフェースクラスを所有する。
 *   上位はLoTopクラス、下位は各Loクラス。
 *   永続的な起動状態を確保するためjava.rmi.server.UnicastRemoteObjectクラス
 *   を継承します。
 * </PRE>
 *
 */
public class LoServer extends UnicastRemoteObject
		implements LoTop, LoPropertyDef, LoMessage
{
	////////////////////////////////////////////////////////////////////////////
	// 内部変数
	////////////////////////////////////////////////////////////////////////////
	protected MenuMaker    mobjMenuMakerIF;
	protected LearnManager mobjLearnManagerIF;
	protected Setup        mobjSetupIF;

	private static final String ERR_URL = "/view/lo/Com/Err.vm";

	////////////////////////////////////////////////////////////////////////////
	// 外部変数
	////////////////////////////////////////////////////////////////////////////

	////////////////////////////////////////////////////////////////////////////
	// 外部関数
	////////////////////////////////////////////////////////////////////////////
	/**
	 * コンストラクタ
	 *
	 */
	public LoServer() throws RemoteException
	{
		super();
	}

	/**
	 * メニュー取得
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータとメニューデータ
	 */
	public Vector getMenuList(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		try
		{
			if(mobjMenuMakerIF != null)
			{
				String strIsStartOnly = "";
				if (htbParam.containsKey("START_ONLY"))
				{
					strIsStartOnly = (String)htbParam.get( "START_ONLY" );
				}
				
				if (strIsStartOnly.equals("on"))
				{
					htbParam.put( LEARNER_ASSIGN, "on" );
					htbParam.put( LEARN_AUTH, "on" );
					htbParam.put( PRERE_FLG, "on" );
				}
				else
				{
					// 管理アサイン、学習アサイン情報を取得します
					checkAssign( htbParam );
					// 学習権限、ログ参照権限情報を取得します
					checkAuth( htbParam );
					// 学習可能判定を行います。
					checkPossibleLearn( htbParam );
				}
				// 正常の場合、メッセージデータはNULLとする
				objRet = mobjMenuMakerIF.makeMenu(htbParam);
				vecRet.add(objRet);
			}
		}
		catch(LOException le)
		{
			DebugLog.write( this.getClass(), le, DebugLog.HIGHT );
			// エラーメッセージオブジェクトを生成
			objMd = createSystemErrMessage(le.getMessage());
		}
		vecRet.add(0, objMd);
		return vecRet;
	}

	/**
	 * セットアップ処理
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータとNULL
	 */
	public Vector setUp(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		try
		{
			if(mobjSetupIF != null)
			{
				// 正常の場合、メッセージデータはNULLとする
				mobjSetupIF.setUp(htbParam);
			}
		}
		catch(LOException le)
		{
			objMd = le.getMessageData();	
			if(objMd == null)				
			{
				// エラーメッセージオブジェクトを生成
				objMd = createSystemErrMessage(le.getMessage());
			}
		}
		vecRet.add(0, objMd);
		return vecRet;
	}

	/**
	 * 学習開始処理
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータと学習開始URL
	 */
	public Vector startLearn(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		DataAccess objDataAccess = new DataAccess();
		try
		{
			// トランザクションの開始
			objDataAccess.trans();
			
			// 正常の場合、メッセージデータはNULLとする
			if( mobjLearnManagerIF != null )
			{
				objRet = mobjLearnManagerIF.startLearn(htbParam, objDataAccess);
				vecRet.add(objRet);
			}
			
			// 例外がスローされない場合はコミット
			objDataAccess.commit();
		}
		catch(LOException le)
		{
			// 例外発生時はロールバック
			try { objDataAccess.rollback(); } catch(Exception e) {}
			// エラーメッセージオブジェクトを生成
			objMd = createSystemErrMessage(le.getMessage());
		}
		catch(SQLException se)
		{
			// 例外発生時はロールバック
			try { objDataAccess.rollback(); } catch(Exception e) {}
			// エラーメッセージオブジェクトを生成
			objMd = createSystemErrMessage(se.getMessage());
		}

		//ステータス伝播処理を追加
		//(上記処理が成功した場合のみ)
		if (objMd == null)
		{
			// ユーザIDの取得
			String strUserID = (String)htbParam.get( USER );
			// LOIDの取得
			String strLoID = (String)htbParam.get( LOID );
			try
			{
				propagateStatus(strUserID, strLoID);
			}
			catch (LOException e)
			{
				// エラーメッセージオブジェクトを生成
				objMd = createSystemErrMessage(e.getMessage());
			}
		}
		
		vecRet.add(0, objMd);
		return vecRet;
	}

	/**
	 * 学習終了処理
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータと学習終了データ
	 */
	public Vector endLearn(Hashtable htbParam)
	{

		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		DataAccess objDataAccess = new DataAccess();
		try
		{
			// トランザクションの開始
			objDataAccess.trans();
			
			if(mobjLearnManagerIF != null)
			{
				// 正常の場合、メッセージデータはNULLとする
				objRet = mobjLearnManagerIF.endLearn(htbParam, objDataAccess);
				vecRet.add(objRet);
			}
			
			// 例外がスローされない場合はコミット
			objDataAccess.commit();
		}
		catch(LOException le)
		{
			// 例外発生時はロールバック
			try { objDataAccess.rollback(); } catch(Exception e) {}
			// エラーメッセージオブジェクトを生成
			objMd = le.getMessageData();
			if(objMd == null){
				objMd = createSystemErrMessage(le.getMessage());
			}
		}
		catch(SQLException se)
		{
			// 例外発生時はロールバック
			try { objDataAccess.rollback(); } catch(Exception e) {}
			// エラーメッセージオブジェクトを生成
			objMd = createSystemErrMessage(se.getMessage());
		}

		//ステータス伝播処理を追加
		//(上記処理が成功した場合のみ)
		if (objMd == null)
		{
			// ユーザIDの取得
			String strUserID = (String)htbParam.get( USER );
			// LOIDの取得
			String strLoID = (String)htbParam.get( LOID );
			try
			{
			    if (strUserID != null && strLoID != null)
			    {
					propagateStatus(strUserID, strLoID);
			    }
			}
			catch (LOException e)
			{
				// エラーメッセージオブジェクトを生成
				objMd = createSystemErrMessage(e.getMessage());
			}
		}

		vecRet.add(0, objMd);
		return vecRet;
	}

	/**
	 * ログ取得処理
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータとログレコードリスト
	 */
	public Vector getLoLog(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		MessageData objMd = null;
		DataAccess objDataAccess = new DataAccess();
		try
		{

			// トランザクションの開始
			objDataAccess.trans();

			// クエリーIDの取得
			String strQueryID = (String)htbParam.get(QUERY_ID);
			if( strQueryID == null ) {
				throw new LOException( "クエリーIDを指定してください。" );
			}
			// クエリー条件の取得
			Vector vecQueryCondition = (Vector)htbParam.get(LOG_CONDITION);
			if( vecQueryCondition == null ) {
				// 条件が指定されていない場合、空のVectorを作成します。
				vecQueryCondition = new Vector();
			}

			LoLogEnvironment objEnv = LoLogEnvironment.getInstance();

			String strQuery = objEnv.getQueryString( strQueryID );

			// クエリーIDが LOG0101 または LOG0201 の場合は条件によって動的にSQLを作成します
			if( strQueryID.equals( LOG0101 ) || strQueryID.equals( LOG0201 ) ) {
				LoLogSQLMaker objSqlMaker = new LoLogSQLMaker( strQueryID, strQuery, vecQueryCondition );
				strQuery = objSqlMaker.makeQuery();
			}
			PreparedStatement objStatement = objDataAccess.prepareStatement(strQuery);
			// 検索条件の設定
			for( int i = 0; i < vecQueryCondition.size(); i++  ) {
				objStatement.setString( i+1, (String)vecQueryCondition.get(i) );
			}
			// クエリーの実行
			ResultSet rs = objStatement.executeQuery();

			ResultSetMetaData meta = rs.getMetaData();
			int intColCount = meta.getColumnCount();

			Vector vecResult = new Vector();
			while( rs.next() ) {
				String[] strResult = new String[intColCount];
				for( int i = 0; i < intColCount; i++ ) {
					strResult[i] = ChangeEncode.setChar( rs.getString( i + 1 ) );
				}
				vecResult.add( strResult );
			}

			String[][] strResult = new String[vecResult.size()][intColCount];
			vecResult.copyInto( strResult );

			// コミット
			objDataAccess.commit();

			// 結果を格納
			vecRet.add( strResult );

		}
		catch(SQLException se)
		{
			DebugLog.write( this.getClass(), se, DebugLog.HIGHT );
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// エラーメッセージオブジェクトを生成
			objMd = createSystemErrMessage("データベースエラーが発生しました。");
		}
		catch(LOException le)
		{
			DebugLog.write( this.getClass(), le, DebugLog.HIGHT );
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// エラーメッセージオブジェクトを生成
			objMd = createSystemErrMessage(le.getMessage());
		}
		catch(Exception e)
		{
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			objMd = createSystemErrMessage(e.getMessage());
		}
		vecRet.add(0, objMd);
		return vecRet;
	}

	/**
	 * ステータス伝播レコードの取得処理
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータとPropagateRelationレコードリスト
	 */
	public Vector getPropagateRelation(Hashtable htbParam)
	{
		Vector vecRet     = new Vector(2);
		MessageData objMd = null;
		DataAccess objDataAccess = new DataAccess();
		try
		{

			// トランザクションの開始
			objDataAccess.trans();

			// RELATEDIDの取得
			String strRelatedID = (String)htbParam.get(RELATEDID);
			if( strRelatedID == null ) {
				throw new LOException( "LoIDを指定してください。" );
			}

			PropagateRelationDataAccess objRelationDataAccess = new PropagateRelationDataAccess();
			// PROPAGATERELATIONテーブルよりRelatedIDを条件としてLOIDを取得
			String[] result = objRelationDataAccess.getRelatedID( strRelatedID, objDataAccess );
			if ( result == null || result.length == 0 ){
				PropagateRelationRecord[] objRecords = new PropagateRelationRecord[0];
				vecRet.add( objRecords );
			}
			else{
				PropagateRelationRecord[] objRecords = new PropagateRelationRecord[result.length];
				for( int i=0; i<result.length; i++){
					objRecords[i] = new PropagateRelationRecord( result[i], strRelatedID );
				}
				vecRet.add( objRecords );
			}
			// コミット
			objDataAccess.commit();
			// 結果を格納
		}
		catch(LOException le)
		{
			DebugLog.write( this.getClass(), le, DebugLog.HIGHT );
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// エラーメッセージオブジェクトを生成
			objMd = createSystemErrMessage(le.getMessage());
		}
		catch(SQLException se)
		{
			DebugLog.write( this.getClass(), se, DebugLog.HIGHT );
			try { objDataAccess.rollback(); } catch( Exception ex ) {}
			// エラーメッセージオブジェクトを生成
			objMd = createSystemErrMessage(se.getMessage());
		}
		vecRet.add(0, objMd);
		return vecRet;
	}

	/**
	 * 教材構造取得<BR>
	 * <PR>
	 *	教材構造を取得するメソッド(ただし派生クラスある場合は
	 *  派生クラスのメソッドをオーバーライドします
	 * </PR>
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータと教材構造データ
	 */
	public Vector getMaterialStruct(Hashtable htbParams)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	private void propagateStatus(String userID, String loID) throws LOException
	{
		// 参照LOIDリストを取得します
		LoClient objLoClient = null;
		try
		{
			objLoClient = new LoClient();
			if(!objLoClient.getListFromRealLOID( loID ))
			{
				throw new LOException("参照LOIDリストの取得失敗しました。");
			}
		}
		catch (Exception e)
		{
			throw new LOException("参照LOIDリストの取得時にエラーが発生しました。");
		}
		String[] strRefList = objLoClient.getRefListResult();
		// 参照リスト分ステータス伝播
		for(int i = 0; i < strRefList.length; i++)
		{
			// ステータス伝搬処理
			StatusPropagation objStatus = new StatusPropagation( userID, strRefList[i] );
			PropagateControl.getInstance().addPropagate(objStatus);
		}
	}
	
	/**
	 * ユーザIDリスト取得処理(共通ログ取得に使用)
	 *
	 * @param String ユーザIDかグループID
	 * @return String[] ユーザIDリスト
	 */
	private String[] expandGroup(String strUserID)
		throws Exception
	{
		String[] strRet  = null;
		// １件目がユーザIDならば即戻す
		if(strUserID.indexOf("GR") == -1)
		{
			strRet    = new String[1];
			strRet[0] = strUserID;
			return strRet;
		}
		// グループならば再帰呼出し処理
		Vector vecList = new Vector();
		getUserIDList(strUserID, vecList);

		// VectorをString[]に変換
		strRet = new String[vecList.size()];
		for(int i = 0; i < vecList.size(); i++)
		{
			strRet[i] = (String)vecList.get(i);
		}
		return strRet;
	}

	/**
	 * LoIDリスト取得処理(共通ログ取得に使用)
	 *
	 * @param String LoID
	 * @return String[] LoIDリスト
	 */
	private String[] expandLo(String strLoID)
		throws Exception
	{
		String[] strRet = null;
		Vector vecList = new Vector();
		getLoIDList(strLoID, vecList);
		strRet = new String[vecList.size()];
		for(int i = 0; i < vecList.size(); i++)
		{
			strRet[i] = (String)vecList.get(i);
		}
		return strRet;
	}

	/**
	 * ユーザIDリスト取得再帰処理(共通ログ取得に使用)
	 *
	 * @param String ユーザID
	 * @param Vector ユーザIDリスト
	 * @return void
	 */
	private void getUserIDList(String strUserID, Vector vecList)
		throws Exception
	{
		GroupAndPeopleClient objGapc = new GroupAndPeopleClient();
		objGapc.setWhereParentID(strUserID);
		if(!objGapc.select())
		{
			DebugLog.write(this.getClass(), "グループ・人取得失敗", DebugLog.ROW);
		}
		while(objGapc.next())
		{
			strUserID = objGapc.getChildID();
			if(objGapc.isGroup())
			{
				getUserIDList(strUserID, vecList);
			}
			else
			{
				vecList.add(strUserID);
			}
		}
	}

	/**
	 * LoIDリスト取得再帰処理(共通ログ取得に使用)
	 *
	 * @param String LoID
	 * @param Vector LoIDリスト
	 * @return void
	 */
	private void getLoIDList(String strLoID, Vector vecList)
		throws Exception
	{
		LoRelationClient objLrc = new LoRelationClient();
		objLrc.setWhereParentID(strLoID);
		if(!objLrc.select())
		{
			DebugLog.write(this.getClass(), "Lo関連取得失敗", DebugLog.ROW);
		}
		while(objLrc.next())
		{
			String strLoChildID = objLrc.getChildID();
			getLoIDList(strLoChildID, vecList);
		}
		vecList.add(strLoID);
	}


	/**
	 * Loタイプ存在チェックメソッド
	 *
	 * @param String LoType
	 * @return boolean LoTypeの有無
	 */
	protected boolean getLoType(String loType) 
		throws LOException {

		boolean isLoType = false;

		if (loType.length() == 0) {
			DebugLog.write(this.getClass(), "パラメータエラー", DebugLog.ROW);
			throw new LOException(SYSTEM_ERR);
		}
		String strCondition = " WHERE " + LO_TYPE + " = " + "'" + StringEscapeUtils.escapeSql(loType) + "' ";
		
		DataAccess objDataAccess = new DataAccess(LO_TYPE);

		try {

			objDataAccess.trans();
			StringBuffer sbSQL = new StringBuffer();
			sbSQL.append("SELECT " + LO_TYPE + " FROM " + LO_TYPE);
			sbSQL.append(strCondition);
			ResultSet rs = objDataAccess.executeQuery(sbSQL.toString());
			if (rs.next()) {
				isLoType = true;
			}

		} catch (SQLException se) {
			DebugLog.write(this.getClass(), "データベースエラー", DebugLog.ROW);
			throw new LOException(DB_ERR);
		}
		return isLoType;
	}

// ここから下は各Loの個別処理が実行される

	/**
	 * 教材リスト取得
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータと教材リスト
	 */
	public Vector getMaterialList(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * メソッドリスト取得
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータとメソッドリスト
	 */
	public Vector getMethodList(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * 初期メニューリスト取得
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータと初期メニューデータ
	 */
	public Vector getDefaultMenu(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * 特殊ログ取得処理
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータとログレコードリスト
	 */
	public Vector getIndividualLog(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * 個別ログ削除
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータとログレコードリスト
	 */
	public Vector deleteIndividualLog(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * 個別ログ更新 各LO(サブクラス)で実装します。
	 * 
	 * @param htbParam パラメータリスト
	 * @return Vector メッセージデータとログレコードリスト
	 */
	public Vector changeTypeUpdateIndividualLog(Hashtable htbParam) {

		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * 実行処理
	 *
	 * @param String
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータと実行結果データ
	 */
	public Vector execute(String strParam, Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * データ取得処理
	 *
	 * @param String
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータと実行結果データ
	 */
	public Vector getData(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * システムエラーメッセージを生成する
	 */
	protected MessageData createSystemErrMessage( String strMessage ) {

		if( strMessage == null ) {
			strMessage = "";
		}

		MessageData objMessage = new MessageData();
		// メッセージの設定
		objMessage.setMessage( strMessage );
		// エラータイプの設定
		objMessage.setMessageType( MessageData.ERR_TYPE );

		try {
			Environment objEnv = new Environment();
			String strSystemURL = objEnv.getSystemURL();
			// エラーURLの作成
			String strURL = strSystemURL + ERR_URL + "?message=" + java.net.URLEncoder.encode( strMessage, "UTF-8");
			// エラーURLの設定
			objMessage.setURL( strURL );
		}
		catch( Exception e ) {
		}

		return objMessage;
	}

	/**
	 * LOの管理アサイン、学習アサイン状況を調べます。<BR>
	 * 管理アサイン、学習アサインされている場合はパラメータで渡したHastable内に以下のように情報を格納します。
	 * <PRE>
	 *              KEY      | 管理アサイン | 学習アサイン |
	 *       MANAGE_ASSIGN   |      ○      |              |
	 *       LEARNER_ASSIGN  |              |      ○      |
	 * </PRE>
	 * @param htbParam 情報格納用のHashtable
	 */
	private void checkAssign( Hashtable htbParam )
		throws LOException
	{
		try {
			// getMenuListの要求がセットアップ項目の場合は処理は行わない
			String strSetUp = (String)htbParam.get( SETUP_STATUS );
			if( strSetUp != null ) {
				return;
			}

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

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

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

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

		}
		catch( LOException le ) {
			throw le;
		}
		catch( Exception e ) {
			throw new LOException( SYSTEM_ERR );
		}
	}

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

		// ユーザIDの取得
		String strUserID = (String)htbParam.get( 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 LOException( objLoRelation.getMessage() );
		}

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

			String strMaterialID = strParentID + strLoID;

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

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

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

	/**
	 * 学習権限とログ参照権限の有無を調べます
	 * <PRE>
	 *              KEY      | 学習権限 | ログ参照権限 |
	 *       LEARN_AUTH      |    ○    |              |
	 *       LOG_AUTH        |          |      ○      |
	 * </PRE>
	 */
	private void checkAuth( Hashtable htbParam )
		throws LOException
	{
		try {
			// ユーザIDの取得
			String strUserID = (String)htbParam.get( USER );
			if( strUserID == null ) {
				return;
			}

// 権限のチェックで、ログ集計の場合は、ターゲットとなる
// グループ・ユーザID(TARGET_ID) をパラメータから取得し，
// 権限の検索処理でしていするグループを決定する。
// ユーザの場合は、その親グループを指定する。		
			String strTargetID = (String)htbParam.get( TARGET_ID );
			String strRoleGroupID = null;
			if( strTargetID != null &&
				strTargetID.length() > 2 )
			{ 
				if( strTargetID.substring(0,2).equals( "PE" ) ) {
					strRoleGroupID = (String)htbParam.get( TARGET_PARENT_ID );						
				}
				else {
					strRoleGroupID = strTargetID;	
				}
			}		
// 権限取得メソッドに絞込みのためのグループIDの引数を追加
// nullの場合はユーザに割当たっているすべてのXMOIDリストを取得する。
// この引数がnullとなる場合は、ログ参照以外のメニュー種痘処理のばあい。
			// ユーザに割当たっているXMOIDリストを取得します
			Vector vecXmoList = getAssignXmoList( strUserID, strRoleGroupID );
			XMSBaseClient objXmoBase = new XMSBaseClient();
			for( int i = 0; i < vecXmoList.size(); i++ ) {
				String strXmoID = (String)vecXmoList.get(i);
				objXmoBase.clear();
				// 検索条件の設定
				objXmoBase.setWhereXmoID( strXmoID );
				// 検索処理
				if( !objXmoBase.select() ) {
					// 検索処理失敗時
					throw new LOException( objXmoBase.getMessage() );
				}

				if( objXmoBase.next() ) {
					String strClassName = objXmoBase.getClassName();
					// 学習権限の場合
					if( strClassName.equals( XMOPropertyDef.LEARN_XMO ) ) {
						// 学習権限をHashtableに入れます
						htbParam.put( LEARN_AUTH, "on" );
					}
					// ログ参照権限の場合
					else if( strClassName.equals( XMOPropertyDef.LOG_XMO ) ) {
						// ログ参照権限をHashtableに入れます
						htbParam.put( LOG_AUTH, "on" );
					}
				}
			}
		}
		catch( LOException le ) {
			throw le;
		}
		catch( Exception e ) {
			throw new LOException( SYSTEM_ERR );
		}
	}

	/**
	 * ユーザに割り当てられているXMOIDのリストを取得します。
	 * @param strUserID ユーザID
	 * @param strRoleGroupID 指定グループに行使できる権限に絞り込む場合に指定する。
	 *                        null の場合は、ユーザのすべての権限を取得する。
	 * @return Vector XmoIDのリスト
	 */
	private Vector getAssignXmoList( String strUserID, String strRoleGroupID )
		throws LOException, Exception
	{
// RoleAssignmentsXMOのXMOリスト取得処理をコールするように変更
// この処理は指定したユーザに割当たっているRoleを権限に展開し，
// そのリストを返す。グループIDを指定するとそのグループを含む上位のグループに対する権限を取得する。
		// 権限割当からユーザに割り当てられている権限を取得する
		RoleAssignmentsClient objRoleAss = new RoleAssignmentsClient();

		if( !objRoleAss.searchXmoList( strUserID, strRoleGroupID ) ) {
			throw new LOException( objRoleAss.getMessage() );
		}

		// 結果格納用ベクター
		Vector vecXmoList = new Vector();

		String[] strTemp = objRoleAss.getXmoList();

		for( int i = 0; i < strTemp.length; i++ ) {
			vecXmoList.add( strTemp[i] );	
		}
		return vecXmoList;
	}


	/**
	 * LOのコピー処理
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータ
	 */
	public Vector doCopy(Hashtable htbParam)
	{
		Vector vecRet     = new Vector(2);
		MessageData objMd = null;

		vecRet.add(0, objMd);
		return vecRet;
	}



	/**
	 * LOクラス名を返却します
	 * @param strLoType LOタイプ
	 * @return LoServer LOインスタンス
	 */
	private LoServer getLoInstance( String strLoType ) throws LOException {

		String	strClassName = "";
		Vector	vecLoList;

		if( strLoType == null ){
			throw new LOException( "LOタイプが存在しません。" );
		}
		try{
			Environment	objEnv = new Environment();
			vecLoList = objEnv.getLoClassName();
		}catch(Exception e){
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			throw new LOException( SYSTEM_ERR );
		}

		boolean bFound = false;
		for(int i=0; i<vecLoList.size(); i++ ){
			String[] LoInfo = (String[])vecLoList.get(i);
			if ( LoInfo[0].equals(strLoType) == true ){
				strClassName = LoInfo[1];
				bFound = true;
				break;
			}
		}
		if ( bFound != true ){
			throw new LOException( "LOタイプに該当するLOクラスが見つかりません。" );
		}

		/* クラス名に該当するクラスを生成 */
		Class classObject;
		try {
			classObject = Class.forName(strClassName);
		} catch(ClassNotFoundException ex) {
			DebugLog.write( this.getClass(), ex, DebugLog.HIGHT );
			throw new LOException( SYSTEM_ERR );
		}

		/* インスタンスを生成する */
		LoServer objLoServer = null;
		try {
			objLoServer = (LoServer)((Class)classObject).newInstance();
		} catch(IllegalAccessException e) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			throw new LOException( SYSTEM_ERR );
		} catch(InstantiationException e) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			throw new LOException( SYSTEM_ERR );
		} catch(ClassCastException e) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			throw new LOException( SYSTEM_ERR );
		}
		return objLoServer;
	}

	/**
	 * 教材構造ファイル取得<BR>
	 * <PR>
	 *	教材構造ファイルの中身を取得するメソッド(ただし派生クラスある場合は
	 *  派生クラスのメソッドをオーバーライドします
	 * </PR>
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータと教材構造ファイル
	 */
	public Vector getMaterialStructFile(Hashtable htbParams)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}

	/**
	 * 個別ログ(CSV)取得処理
	 *
	 * @param Hashtable パラメータリスト
	 * @return Vector メッセージデータとログレコードリスト
	 */
	public Vector getIndividualLogCSV(Hashtable htbParam)
	{
		Vector vecRet     = new Vector();
		Object objRet     = null;
		MessageData objMd = null;
		vecRet.add(objMd);
		vecRet.add(objRet);
		return vecRet;
	}
	/**
	 * 学習が可能かどうかの判定を行います。<BR>
	 * 以下のパターンでHashtableに値を設定します。<BR>
	 * <PRE>
	 *     学習可・不可判定
	 *      1. 前提条件のチェック
	 *              前提条件が設定されていた場合のみチェック。
	 *      2. アサインの有効・無効チェック
	 *      3. 上記1, 2 の結果の和が学習可・不可となる。
	 *
	 *                            key               value
	 *     学習が可能な場合       PRERE_FLG         "on"
	 *     学習が不可能な場合     PRERE_FLG         "off"
	 * </PRE>
	 * 注意: key がPRERE_FLG=前提条件のみを意識した命名になっているのは、
	 * アサインの有効判定が後の開発で発生したものであるため。<BR>
	 * このキーを変更すると全LOに修正が入るため、変更しないこととする。
	 *
	 * @param htbParam 情報格納用のHashtable
	 */
	private void checkPossibleLearn( Hashtable htbParam )
		throws LOException
	{
		try {
			// ユーザIDの取得
			String strUserID = (String)htbParam.get( USER );
			// LOIDの取得
			String strLoID = (String)htbParam.get( LOID );
			// 前提条件の取得
			String strPrere = (String)htbParam.get(PRERE);

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

			// --------------------------------------
			// 前提条件を満たしているか、判定します。
			// --------------------------------------
			boolean posibleLearn = true;
			if(strPrere != null && !strPrere.equals("")){
				// 前提条件クラスをインスタンス化
				Prerequisite objPrerequisite = new Prerequisite(	strPrere,
																	strUserID,
																	strLoID );
				// 前提条件パース
				objPrerequisite.parse();
				posibleLearn = objPrerequisite.isPrerequisited();
			}
			
			// --------------------------------------
			// アサインの有効・無効を判定します。
			// スーパユーザの場合は無条件で有効とする。
			// 前提条件が満たされている場合のみチェック
			// --------------------------------------
			if( posibleLearn ) {
				if( !strUserID.equals( XMOPropertyDef.ROOT_USER ) ) {
					AssignmentsClient client = new AssignmentsClient();
					
					// AssignmentsXMOのアサイン有効・無効チェック関数をコールする
					// 詳細はAssignmentsClientを参照
					Map res = client.checkAssignUsable( 
									strUserID, null, strLoID, 
									AssignmentsClient.SELF);
									
					AssignUsableList usable = (AssignUsableList)res.get(strLoID);
					
					if( usable == null ) {
						// 指定したLOに対応する情報が得られない場合はfalse
						posibleLearn = false;	
					}
					posibleLearn = usable.isUsable();
				}
			}
			
			// 前提条件を満たしている場合は、前提条件フラグをonにする。
			if(posibleLearn){
				htbParam.put( PRERE_FLG, "on" );
			}
			// 前提条件を満たしていない場合は、前提条件フラグをoffにする。
			else{
				htbParam.put( PRERE_FLG, "off" );
			}

		}
		catch( PrerequisiteParseException pp ) {
			throw new LOException( pp.getMessage() );
		}
		catch( PrerequisiteException pe ) {
			throw new LOException( pe.getMessage() );
		}
		catch( Exception e ) {
			throw new LOException( SYSTEM_ERR );
		}
	}
}
