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

//
//	Assignments 管理XMO サーバクラス
//			変更履歴
//				2004.01.08	新規作成	二條智文
//
package jp.co.ntt.lms.xmo.Assignments;

import java.net.URLEncoder;
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Vector;

import org.apache.commons.lang.StringEscapeUtils;

import jp.co.ntt.lms.lo.LoPropertyDef;
import jp.co.ntt.lms.lo.LoTopClient;
import jp.co.ntt.lms.xmo.DataAccess;
import jp.co.ntt.lms.xmo.Environment;
import jp.co.ntt.lms.xmo.MenuData;
import jp.co.ntt.lms.xmo.MessageData;
import jp.co.ntt.lms.xmo.XMO;
import jp.co.ntt.lms.xmo.XMOException;
import jp.co.ntt.lms.xmo.XMOPropertyDef;
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.Mail.MailClient;
import jp.co.ntt.lms.xmo.Mail.MailConst;
import jp.co.ntt.lms.xmo.Message.Message;
import jp.co.ntt.lms.xmo.People.PeopleClient;
import jp.co.ntt.lms.xmo.util.DebugLog;
import jp.co.ntt.lms.xms.logsumup.LoLogCommon_inc;

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

	//////////////////////////////////////////////////////////////////
	// メソッド名定義
	//////////////////////////////////////////////////////////////////
	/** 登録メソッド名です */
	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 static final String METHOD5 = "getUserList";	// アサインユーザリスト取得

	/** アサイン者リスト検索メソッド名です */
	private static final String METHOD6 = "searchAssignerList";

	/** アサイン有効・無効チェックメソッド名 */
	private static final String METHOD7 = "checkAssignUsable";
	/** アサイン有効・無効チェックメソッド名 */
	private static final String METHOD8 = "getAssignInfo";
	/** 学習回数カウントアップメソッド名 */
	private static final String METHOD9 = "countupStudyCount";
	/** メール送信の１回あたりの送信件数を取得するメソッド名称 */
	private static final String METHOD10 = "getSendMailCount";
	/**
	 * ＲＭＩ戻り値Ｍａｐキー：エラーメッセージ。
	 */
	private static final String KEY_ERROR_MESSAGE = "errormessage";

	/**
	 * ＲＭＩ戻り値Ｍａｐキー：送信件数。
	 */
	private static final String KEY_SEND_MAIL_COUNT = "sendMailCount";
	/**
	 * アサインテーブルアクセスクラスを保持します
	 */
	private AssignmentsDataAccess pobjDataAccess = new AssignmentsDataAccess();

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

	/**
	 * メニュー一覧を返します
	 * @return Vector メニュー一覧
	 */
	public Vector getMenuList(Hashtable htbParam) {
		Vector vecMenuList = new Vector();
		try {
			AssignmentsEnv objEnv = AssignmentsEnv.getInstance();

			//選択IDがLOのとき
			if ( ((String)htbParam.get(XMOPropertyDef.PARAM_ID)).startsWith("LO") ) {
				checkAssign(htbParam);
				String check = (String)htbParam.get(LoPropertyDef.MANAGE_ASSIGN);
				//管理アサインされている場合のみメニューを取得する
				if ( check != null && check.equals("1") == true ){
					vecMenuList = objEnv.getMenuList();
				}
			}
			//選択IDがグループのとき
			else{
				vecMenuList = objEnv.getMenuList();
			}
		}
		catch( Exception e ) {
			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 );
		vecMethod.add( METHOD5 );
		vecMethod.add( METHOD6 );
		vecMethod.add( METHOD7 );
		vecMethod.add( METHOD8 );
		vecMethod.add( METHOD9 );
		vecMethod.add( METHOD10 );
		return vecMethod;

	}

	/**
	 * デフォルトメニューを返します
	 * @return MenuData
	 */
	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 );
		}
		else if( strMethodName.equals( METHOD5 ) ) {
			objReturn = getUserList( htData );
		}
		else if( strMethodName.equals( METHOD6 ) ) {
			objReturn = searchAssignerList( htData );
		}
		else if( strMethodName.equals( METHOD7 ) ) {
			objReturn = checkAssignUsable( htData );
		}
	   else if( strMethodName.equals( METHOD8 ) ) {
		   objReturn = getAssignInfo( htData );
	   }
		// 学習回数カウントアップメソッド
		else if( strMethodName.equals( METHOD9 ) ) {
		   objReturn = countupStudyCount( htData );
		}
		// メール送信の１回あたりの送信件数を取得するメソッド
		else if( strMethodName.equals( METHOD10 ) ) {
		   objReturn = getSendMailCount( htData );
		}
		return objReturn;
	}

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

	/**
	 * Assignmentsテーブルへ登録処理を行います。<BR>
	 * 以下のパラメータチェックを行い、すべてOKの場合は
	 * DAOの登録処理メソッドを実行します。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             MEMBER_SHIP_ID          人々ID
	 *             MATERIAL_ID             コンポーネントID
	 *             STUDY_START_DATE        開始日
	 *             END_DATE                終了日
	 *             ASSIGNER                アサイン者
	 *             LEARN_AUTHORITY         学習権限
	 *             MANAGEMENT_AUTHORITY    管理権限
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htData 登録情報
	 * @return Vector 結果（配列の先頭にMessageDataオブジェクトを格納して返します)
	 */
	private Vector insert( Hashtable htData ) {
		Vector vecReturn = new Vector();

		MessageData objMessage = new MessageData();
		// 登録処理のパラメータチェックを行います
		String strMessage = insertCheck( htData );
		if( strMessage.equals( "" ) ) {
			DataAccess objDataAccess = new DataAccess();
			try {
				// コミットの有無チェック用
				boolean blIsCommit = false;
				if( htData.get( DataAccess.CONNECTIONINDEX ) == null ) {
					blIsCommit = true;
				}

				// トランザクションを開始する
				objDataAccess.trans( htData );

				// 現在使用中のコネクションのインデックスを取得
				int intConnectionIndex = objDataAccess.getConnectionIndex();
				// ハッシュテーブルにコネクションインデックスを設定
				htData.put( objDataAccess.CONNECTIONINDEX, new Integer(intConnectionIndex) );

				// 登録処理を行います
				AssignmentsData objData = pobjDataAccess.insert( htData );
				// 登録内容を戻りに追加します
				vecReturn.add( objData );

				// MaterialIDの取得
				String strMaterialID = (String)htData.get( MATERIAL_ID );
				// MemberShipIDの取得
				String strMemberShipID = (String)htData.get( MEMBER_SHIP_ID );
				// アサイン者のユーザIDの取得
				String strAssignerID = (String)htData.get( ASSIGNER );

				objDataAccess.commit();

				// トランザクションが完了しているときのみメールを送信する
				if( blIsCommit ) {
					// メール機能の使用可能チェック
					String strSendMailFlag = (String)htData.get(SEND_MAIL_FLAG);	
					DebugLog.write(this.getClass(), "SendMailFlag :" + strSendMailFlag, DebugLog.ROW);
					if( strSendMailFlag.equals("1")) {		
						// メール送信処理を行います
						DebugLog.write(this.getClass(), "SendMailFlag :" + strSendMailFlag, DebugLog.ROW);
						if(!sendMail( strMaterialID, strMemberShipID, strAssignerID, objData )){
							objMessage = getMessageData( SEND_MAIL_ERR );
						}
					}
				}

			}
			catch( XMOException xe ) {
				DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
				// エラー発生時ロールバック
				// ロールバック
				try { objDataAccess.rollback(); } catch( Exception ex ) {}
				objMessage = xe.getMessageData();
			}
			catch( SQLException se ) {
				DebugLog.write( this.getClass(), se, DebugLog.HIGHT );
				// エラー発生時ロールバック
				// ロールバック
				try { objDataAccess.rollback(); } catch( Exception ex ) {}
				objMessage = getMessageData( DB_ERR );
			}
			catch( Exception e ) {
				DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
				// エラー発生時ロールバック
				// ロールバック
				try { objDataAccess.rollback(); } catch( Exception ex ) {}
				objMessage = getMessageData( SYSTEM_ERR );
			}
		}
		else {
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );	
			objMessage = getMessageData( strMessage );
		}

		// 配列の先頭にメッセージデータを格納する
		vecReturn.add( 0, objMessage );
		return vecReturn;
	}

	/**
	 * メール送信処理を行います
	 */
	private boolean sendMail(
							String strMaterialID,
							String strMemberShipID,
							String strAdminUserID,
							AssignmentsData objData
						)
		throws XMOException, Exception
	{
		boolean boolRet = true;

		// MaterialIDから子IDを取得します
		LoRelationClient objRelation = new LoRelationClient();
		// 検索条件にMaterialIDを追加
		objRelation.setWhereMaterialID( strMaterialID );

		// 検索処理
		if( !objRelation.select() ) {
			// 検索に失敗した場合
			throw new XMOException( objRelation.getMessageData() );
		}

		// 検索結果の取得
		String strLoID = "";
		if( objRelation.next() ) {
			strLoID = objRelation.getChildID();
		}
		else {
			// 検索できない場合
			return false;
		}

		// ユーザIDの検索
		// MembershipIDから子IDを取得します
		GroupAndPeopleClient objGandP = new GroupAndPeopleClient();
		// 検索条件にMembershipIDを設定します
		objGandP.setWhereMemberShipID( strMemberShipID );

		// 検索処理
		if( !objGandP.select() ) {
			// 検索に失敗した場合
			throw new XMOException( objGandP.getMessageData() );
		}

		// 検索結果の取得
		String strUserID = "";
		if( objGandP.next() ) {
			// 検索結果がGroupの場合
			if( objGandP.isGroup() ) {
				// 何もしない
				return true;
			}
			strUserID = objGandP.getChildID();
		}
		else {
			// 検索できない場合
			return false;
		}

		// 送信用のユーザIDリストを作成する
		String[] strUserIDList = new String[1];
		strUserIDList[0] = strUserID;

		// ログインURLの作成
		// ユーザIDからパスワードを取得する
		PeopleClient objPeople = new PeopleClient();
		objPeople.setWhereUserID( strUserID );
		String strLoginID = "";
		String strPassword = "";
		// 検索処理
		if( !objPeople.select() ) {
			// 検索失敗
			throw new XMOException( objPeople.getMessageData() );
		}
		// 検索成功
		if( objPeople.next() ) {
			strLoginID = objPeople.getLoginID();
			strPassword = objPeople.getEncryptPassword();
		}
		// マクロ展開用の文字列を作成
		Hashtable htbMacro = new Hashtable();
		htbMacro.put( AssignmentsEnv.UID, URLEncoder.encode( strLoginID, "UTF-8") );
		htbMacro.put( AssignmentsEnv.PS, strPassword );
		htbMacro.put( AssignmentsEnv.LID, strLoID );
		htbMacro.put( AssignmentsEnv.MTID, strMaterialID );
		AssignmentsEnv objEnv = AssignmentsEnv.getInstance();
		String strLoginURL = objEnv.getLoginURL( htbMacro );
		// テンプレートファイルパスの取得
		String strTemplateFilePath = objEnv.getSendMailPath();

		// 教材名の取得
		LoClient objLo = new LoClient();
		objLo.setWhereLoID( strLoID );
		String strLoTitle = "";
		// 検索処理の実行
		if( !objLo.select() ) {
			throw new XMOException( objLo.getMessageData() );
		}

		// 結果の取得
		if( objLo.next() ) {
			strLoTitle = objLo.getLoTytle();
		}

		// メール送信処理
		MailClient objMail = new MailClient();

		// メール送信実行
		int intResult = objMail.sendMail( strUserIDList, strAdminUserID, null, strLoTitle, strLoginURL, strTemplateFilePath );
		// メール送信結果をデータオブジェクトに格納します
		objData.setMailResult( intResult );
		if( intResult != MailConst.RESULT_SUCCESS ) {
			// メール送信に失敗した場合
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );
			return false;
		}
		else {
			// 配送状況の確認
			// 配送失敗メールの確認
			ArrayList objNgResult = objMail.checkNgResult();
			// 配送失敗メールをデータオブジェクトに格納します
			objData.setNgMailList( objNgResult );
			// 未配送メールの確認
			ArrayList objNotSendResult = objMail.checkNotSendResult();
			// 配送失敗メールをデータオブジェクトに格納します
			objData.setNotSentMailList( objNgResult );


			// 配送状況の確認作業
			for( int i = 0; i < objNgResult.size(); i++ ) {
				String strNgUserID = (String)objNgResult.get(i);
				DebugLog.write(this.getClass(), "メール送信結果:" + strNgUserID + ":" + strLoginID + ":" + "ＤＢ登録成功:送信失敗", DebugLog.HIGHT);
				boolRet = false;
			}

			for( int i = 0; i < objNotSendResult.size(); i++  ) {
				String strNotSendResult = (String)objNotSendResult.get(i);
				DebugLog.write(this.getClass(), "メール送信結果:" + strNotSendResult + ":" + strLoginID + ":" + "ＤＢ登録成功:未送信", DebugLog.HIGHT);
				boolRet = false;
			}
			if ( objNgResult.size() == 0 && objNotSendResult.size() == 0 ){
								DebugLog.write(this.getClass(), "メール送信結果:" + strUserID + ":" + strLoginID + ":" + "ＤＢ登録成功:送信成功", DebugLog.ROW);
			}
		}
		return boolRet;
	}

	/**
	 * 各LOのセットアップメソッドをコールします
	 */
	 // 引数vecAssignUser追加
	private void callSetUp(
							String strMaterialID,
							Vector vecAssignUser,
							String strSetupType,
							int intConnectionIndex,
							String strMemberShipID,
							String strLernAuthority,
							String strManagementAuthority,
							String strStudyStartDate
							 )
		throws XMOException, Exception
	{
		// MaterialIDから子IDを取得します
		LoRelationClient objRelation = new LoRelationClient();
		objRelation.setConnectionIndex( intConnectionIndex );
		// 検索条件にMaterialIDを追加
		objRelation.setWhereMaterialID( strMaterialID );

		// 検索処理
		if( !objRelation.select() ) {
			// 検索に失敗した場合
			throw new XMOException( objRelation.getMessageData() );
		}

		// 検索結果の取得
		String strLoID = "";
		if( objRelation.next() ) {
			strLoID = objRelation.getChildID();
		}
		else {
			// 検索できない場合
			return;
		}

		// ユーザIDの検索
		// MembershipIDから子IDを取得します
		GroupAndPeopleClient objGandP = new GroupAndPeopleClient();
		objGandP.setConnectionIndex( intConnectionIndex );
		// 検索条件にMembershipIDを設定します
		objGandP.setWhereMemberShipID( strMemberShipID );

		// 検索処理
		if( !objGandP.select() ) {
			// 検索に失敗した場合
			throw new XMOException( objGandP.getMessageData() );
		}

		// 検索結果の取得
		String strUserID = "";
		if( objGandP.next() ) {
			// 検索結果が人の場合
			if( !objGandP.isGroup() ) {
				strUserID = objGandP.getChildID();
				// 取得した子IDのセットアップを実行します
				setUp( strLoID, strUserID, strSetupType, intConnectionIndex, strLernAuthority, strManagementAuthority, strStudyStartDate );	
			}
		}
		else {
			// 検索できない場合
			return;
		}

		for(int j=0;j<vecAssignUser.size();j++){							
			strUserID = (String)vecAssignUser.get(j);						
			// 取得した子IDのセットアップを実行します						
			setUp( strLoID, strUserID, strSetupType, intConnectionIndex, strLernAuthority, strManagementAuthority, strStudyStartDate );	
		}																	
	}

	/**
	 * 指定されたLOIDのセットアップメソッドをコールします
	 * @param strMaterialID
	 * @return String[] 子IDリスト
	 */
	private void setUp( String strLoID, String strUserID, String strSetupType, int intConnectionIndex, String strLernAuthority, String strManagementAuthority, String strStudyStartDate )
		throws XMOException, Exception
	{

		// 子IDリストを取得して、子IDのsetUpメソッドを呼ぶ
		String[] strChildList = getChildList( strLoID, intConnectionIndex );

		for( int i = 0; i < strChildList.length; i++ ) {
			// 再帰呼び出し
			setUp( strChildList[i], strUserID, strSetupType, intConnectionIndex, strLernAuthority, strManagementAuthority, strStudyStartDate );	
		}

		// セットアップ処理
		// LOXMOから、指定されたLOIDの情報を取得します
		LoClient objLo = new LoClient();
		objLo.setConnectionIndex( intConnectionIndex );
		// LOIDを検索条件に追加
		objLo.setWhereLoID( strLoID );
		// 検索処理の実行
		if( !objLo.select() ) {
			// 検索処理に失敗した場合は例外をスローする
			throw new XMOException( objLo.getMessageData() );
		}

		// 検索結果の取得
		String strLoType = "";
		if( objLo.next() ) {
			strLoType = objLo.getLoType();
		}

		// RealLOIDを取得します
		objLo.clear();
		String strRealLOID = null;
		if(!objLo.getRealLOIDFromLOID( strLoID )){
			new XMOException("RealLOIDの取得失敗しました。");
		}else{
			strRealLOID = objLo.getRealLOIDResult();
		}

		// 環境クラスをインスタンス化
		Environment objEnv = new Environment();
		// LoServer名の取得
		String strLoServerName = objEnv.getLoServerName();

		// LoTopClientをインスタンス化する
		LoTopClient objLoTop = new LoTopClient( strLoServerName, strLoType );
		// パラメータの設定
		Hashtable htbParam = new Hashtable();
		// UserIDの設定
		htbParam.put( LoTopClient.USER, strUserID );
		// LOIDの設定(F2Fの共通ログをRealLOIDでLOLogを作成します。)
		htbParam.put( LoTopClient.LOID, strRealLOID );
		// 学習アサインの設定
		htbParam.put( LEARN_AUTHORITY, strLernAuthority );
		// 管理アサインの設定
		htbParam.put( MANAGEMENT_AUTHORITY, strManagementAuthority );
		// 学習開始日の設定
		htbParam.put( STUDY_START_DATE, strStudyStartDate );
		// 各LOのsetUpメソッドをコールする
		if( !objLoTop.setUp( strSetupType, htbParam ) ) {
			// ユーザ登録処理に失敗した場合
			throw new XMOException( objLoTop.getMessageData() );
		}
	}

	/**
	 * 子IDリストを取得します
	 */
	private String[] getChildList( String strParentID, int intConnectionIndex )
		throws XMOException, Exception
	{
		// LoRelationから検索
		LoRelationClient objRelation = new LoRelationClient();
		objRelation.setConnectionIndex( intConnectionIndex );
		// 親IDを検索条件に追加
		objRelation.setParentID( strParentID );
		// 検索処理
		if( !objRelation.select() ) {
			// 検索に失敗した場合はXMOExceptionをスローする
			throw new XMOException( objRelation.getMessageData() );
		}

		// 検索結果の取得
		Vector vecResult = new Vector();
		while( objRelation.next() ) {
			vecResult.add( objRelation.getChildID() );
		}

		// String[]に変換
		String[] strResult = new String[vecResult.size()];
		vecResult.copyInto( strResult );

		return strResult;
	}

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

		MessageData objMessage = null;
		// 更新処理のパラメータチェックを行います
		String strMessage = updateCheck( htData );
		if( strMessage.equals( "" ) ) {
			try {
				pobjDataAccess.update( htData );

				// アサイン情報を作成します
				AssignmentsData objData = new AssignmentsData();

				// MaterialIDの取得
				String strMaterialID = (String)htData.get( MATERIAL_ID );
				// MemberShipIDの取得
				String strMemberShipID = (String)htData.get( MEMBER_SHIP_ID );
				// アサイン者のユーザIDの取得
				String strAssignerID = (String)htData.get( ASSIGNER );
				if( strAssignerID != null ) {
					objData.addAssignUser( strAssignerID );
				}

				// メール機能の使用可能チェック
				String strSendMailFlag = (String)htData.get(SEND_MAIL_FLAG);	
				DebugLog.write(this.getClass(), "SendMailFlag :" + strSendMailFlag, DebugLog.ROW);
				if( (strSendMailFlag != null) && (strSendMailFlag.equals("1"))) {
					// メール送信処理を行います
					DebugLog.write(this.getClass(), "SendMailFlag :" + strSendMailFlag, DebugLog.ROW);
					if(!sendMail( strMaterialID, strMemberShipID, strAssignerID, objData )){
						objMessage = getMessageData( SEND_MAIL_ERR );
					}
				}
			}
			catch( XMOException xe ) {
				DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
				objMessage = xe.getMessageData();
			}
			catch( Exception e ) {
				DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
				objMessage = getMessageData( SYSTEM_ERR );
			}
		}
		else {
			DebugLog.write( this.getClass(), new Exception(), DebugLog.HIGHT );	
			objMessage = getMessageData( strMessage );
		}

		vecReturn.add( objMessage );
		return vecReturn;
	}

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

		try {
			pobjDataAccess.delete( htData );
		}
		catch( XMOException xe ) {
			objMessage = xe.getMessageData();
		}

		vecReturn.add( objMessage );
		return vecReturn;
	}

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

		MessageData objMessage = null;
		try {
			vecResult = pobjDataAccess.select( htData );
		}
		catch( XMOException xe ) {
			objMessage = xe.getMessageData();
		}

		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                     説明
	 *          ---------------------------------------------
	 *             MEMBER_SHIP_ID          人々ID
	 *             MATERIAL_ID             コンポーネントID
	 *             STUDY_START_DATE        開始日
	 *             END_DATE                終了日
	 *             ASSIGNER                アサイン者
	 *             LEARN_AUTHORITY         学習権限
	 *             MANAGEMENT_AUTHORITY    管理権限
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htbParam パラメータ
	 * @return String エラー時はエラー番号 OKのときは空文字を返します
	 */
	private String insertCheck( Hashtable htbParam ) {

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

		// 人々IDのチェック(必須チェックあり)
		strCheck = (String)htbParam.get( MEMBER_SHIP_ID );
		strMessage = AssignmentsCheck.checkMemberShipID( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// コンポーネントIDのチェック(必須チェックあり)
		strCheck = (String)htbParam.get( MATERIAL_ID );
		strMessage = AssignmentsCheck.checkMaterialID( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 開始日のチェック(必須チェックあり)
		strCheck = (String)htbParam.get( STUDY_START_DATE );
		strMessage = AssignmentsCheck.checkStudyStartDate( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 終了日のチェック(必須チェックあり)
		strCheck = (String)htbParam.get( END_DATE );
		strMessage = AssignmentsCheck.checkEndDate( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// アサイン者のチェック(必須チェックあり)
		strCheck = (String)htbParam.get( ASSIGNER );
		strMessage = AssignmentsCheck.checkAssigner( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 学習権限のチェック(必須チェックあり)
		strCheck = (String)htbParam.get( LEARN_AUTHORITY );
		strMessage = AssignmentsCheck.checkLearnAuthority( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 管理権限のチェック(必須チェックあり)
		strCheck = (String)htbParam.get( MANAGEMENT_AUTHORITY );
		strMessage = AssignmentsCheck.checkManagementAuthority( strCheck, true );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

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

	/**
	 * 登録処理のパラメータチェックを行います<BR>
	 * 以下のパラメータのチェックを行います。
	 * <PRE>
	 *             key                     説明
	 *          ---------------------------------------------
	 *             ASSIGN_ID               アサインID
	 *             MEMBER_SHIP_ID          人々ID
	 *             MEMBER_SHIP_ID          人々ID
	 *             MATERIAL_ID             コンポーネントID
	 *             STUDY_START_DATE        開始日
	 *             END_DATE                終了日
	 *             ASSIGNER                アサイン者
	 *             LEARN_AUTHORITY         学習権限
	 *             MANAGEMENT_AUTHORITY    管理権限
	 *          ---------------------------------------------
	 * </PRE>
	 * @param htbParam パラメータ
	 * @return String エラー時はエラー番号 OKのときは空文字を返します
	 */
	private String updateCheck( Hashtable htbParam ) {

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

		// 人々IDのチェック
		strCheck = (String)htbParam.get( ASSIGN_ID );
		strMessage = AssignmentsCheck.checkAssignID( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 人々IDのチェック
		strCheck = (String)htbParam.get( MEMBER_SHIP_ID );
		strMessage = AssignmentsCheck.checkMemberShipID( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// コンポーネントIDのチェック
		strCheck = (String)htbParam.get( MATERIAL_ID );
		strMessage = AssignmentsCheck.checkMaterialID( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 開始日のチェック
		strCheck = (String)htbParam.get( STUDY_START_DATE );
		strMessage = AssignmentsCheck.checkStudyStartDate( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 終了日のチェック
		strCheck = (String)htbParam.get( END_DATE );
		strMessage = AssignmentsCheck.checkEndDate( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// アサイン者のチェック
		strCheck = (String)htbParam.get( ASSIGNER );
		strMessage = AssignmentsCheck.checkAssigner( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 学習権限のチェック
		strCheck = (String)htbParam.get( LEARN_AUTHORITY );
		strMessage = AssignmentsCheck.checkLearnAuthority( strCheck, false );
		if( !strMessage.equals( "" ) ) {
			return strMessage;
		}

		// 管理権限のチェック
		strCheck = (String)htbParam.get( MANAGEMENT_AUTHORITY );
		strMessage = AssignmentsCheck.checkManagementAuthority( 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 );
		}
	}

	/**
	 * 教材をアサインされた学習者のリストを返します
	 * @return Vector アサイン学習者リスト
	 */
	public Vector getUserList(Hashtable htbParam) {
		Vector vecUserList = new Vector();
		try {
			// LOIDを取得します。
			String strLOID = (String)htbParam.get(LoPropertyDef.LOID);

			// MaterialIDの検索処理
			LoRelationClient objLoRelation = new LoRelationClient();
			objLoRelation.setWhereChildID(strLOID);
			if( !objLoRelation.select() ) {
				// 検索に失敗した場合
				throw new XMOException( objLoRelation.getMessageData() );
			}

			// 検索結果の取得
			Vector vecMaterialID = new Vector();	// マテリアルIDリスト
			if( objLoRelation.next() ) {
				vecMaterialID.add(objLoRelation.getmaterialID());
			}

			// 親LOのMaterialIDを検索
			objLoRelation.clear();
			// フルパスの取得
			if( !objLoRelation.searchPath(strLOID) )
			{
				// 取得エラーをスローする
				throw new XMOException( objLoRelation.getMessageData() );
			}

			// パスの取得がうまくいった場合、MaterialIDを取得
			String strPath[] = null;	// LOフルパス
			String ParentID = "";
			String G_ParentID = "";
			while( objLoRelation.next() )
			{
				strPath = objLoRelation.getPath();
				if(strPath.length > 2){
					for( int i = 0; i < strPath.length; i++ )
					{
						if(strLOID.equals(strPath[i+1])){
							break;
						}

						// 親のMaterialID取得
						ParentID = strPath[i+1];
						if(!ParentID.equals("")){
							G_ParentID = strPath[i];
						}

						if(!ParentID.equals("") && !G_ParentID.equals("")){
							vecMaterialID.add(G_ParentID + ParentID);
						}
					}
				}
			}

			// マテリアルIDリスト分Loopし、アサインユーザリストを作成
			for( int i = 0; i < vecMaterialID.size(); i++ ) {

				// MemberShipIDの検索処理
				AssignmentsClient objAssignments = new AssignmentsClient();
				objAssignments.setWhereMaterialID((String)vecMaterialID.get(i));
				objAssignments.setWhereLearnAuthority();

				if( !objAssignments.select() ) {
					// 検索に失敗した場合
					throw new XMOException( objAssignments.getMessageData() );
				}

				// 検索結果の取得
				String strMemberShipID = "";
				String strChildID = "";
				while( objAssignments.next() ) {
					strMemberShipID = objAssignments.getMemberShipID();	// MemberShipID

					// ChildIDの検索処理
					GroupAndPeopleClient objGroupAndPeople = new GroupAndPeopleClient();
					objGroupAndPeople.setWhereMemberShipID(strMemberShipID);
					if( !objGroupAndPeople.select() ) {
						// 検索に失敗した場合
						throw new XMOException( objGroupAndPeople.getMessageData() );
					}

					// 検索結果の取得
					while( objGroupAndPeople.next() ) {
						strChildID = objGroupAndPeople.getChildID();
						// 検索結果が人の場合、ユーザリストに加えます。
						if( !objGroupAndPeople.isGroup() ) {
							// LOLogを二重登録を防止
							if(vecUserList.indexOf(strChildID) == -1){
								vecUserList.add(strChildID);
							}
						}
					}

				}
			}
		}
		catch( Exception e ) {
			return new Vector();
		}
		return vecUserList;
	}


	/**
	 * あるユーザにあるLOをアサインしたアサイン者のユーザID
	 * を検索します。<BR>
	 * ユーザは兼務ユーザも含みます。また、LOは上位のアサインまで調べます。<BR>
	 * アサインタイプで検索条件を作成します。
	 * <PRE>
	 *     NON_TYPE    :: アサインタイプ指定なし
	 *     LEARN_TYPE  :: 学習アサインされているもの
	 *     MANAGE_TYPE :: 管理アサインされているもの
	 * </PRE>
	 * @param htbParam
	 *           <PRE>
	 *             USER_ID: ユーザID(String)
	 *             LOID: LOID(String)
	 *             ASSIGN_TYPE: アサインタイプ(Integer)
	 *           </PRE>
	 * @return Vector 0: メッセージデータ(MessageData) 1: アサイン者リスト(String[])
	 */
	private Vector searchAssignerList( Hashtable htbParam ) {

		Vector vecResult = new Vector();
		String[] strAssignerList = null;

		MessageData objMessage = null;

		// パラメータの取り出し
		String strUserID = null;
		String strLoID = null;
		int intAssignType = -1;
		try {
			strUserID = (String)htbParam.get( USER_ID );
			strLoID = (String)htbParam.get( LO_ID );
			intAssignType = ((Integer)htbParam.get( ASSIGN_TYPE )).intValue();
		}
		catch( ClassCastException ce ) {
			// パラメータの型が不正な場合
			objMessage = getMessageData( PARAM_WAR );
			vecResult.add( objMessage );
			return vecResult;
		}

		// パラメータチェック
		if( strUserID == null || strLoID == null ) {
			// パラメータの型が不正な場合
			objMessage = getMessageData( PARAM_WAR );
			vecResult.add( objMessage );
			return vecResult;
		}

		// アサインタイプのチェック
		if( intAssignType != NON_TYPE &&
			intAssignType != LEARN_TYPE &&
			intAssignType != MANAGE_TYPE )
		{
			// パラメータの型が不正な場合
			objMessage = getMessageData( PARAM_WAR );
			vecResult.add( objMessage );
			return vecResult;
		}

		try {
			// LOIDのパスを取得する
			Vector vecLoPath = getLoPath( strLoID );

			// パスリストをMaterialIDリストに変換します。
			String[] strMaterialIDList = convertPathToMaterialID( vecLoPath );

			// アサイン者リストをDBから検索する。
			strAssignerList = pobjDataAccess.selectAssigner( strMaterialIDList, strUserID, intAssignType );
		}
		catch( XMOException xe ) {
			DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
			// 例外クラスからメッセージデータを取得する
			objMessage = xe.getMessageData();
			vecResult.add( objMessage );
			return vecResult;
		}
		catch( SQLException se ) {
			DebugLog.write( this.getClass(), se, DebugLog.HIGHT );
			// DBエラーメッセージを作成する
			objMessage = getMessageData( DB_ERR );
			vecResult.add( objMessage );
			return vecResult;
		}
		catch( Exception e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// システムエラーメッセージを作成する
			objMessage = getMessageData( SYSTEM_ERR );
			vecResult.add( objMessage );
			return vecResult;
		}

		// Vectorの1番目にメッセージデータを格納する
		vecResult.add( objMessage );
		// Vectorの2番目にアサイン者リストを格納する
		vecResult.add( strAssignerList );
		return vecResult;
	}

	/**
	 * LoRelationXMOを使用して、LOIDのパスを取得します。
	 * @param strLoID LOID
	 * @return Vector パスを格納したVector(中身はString[])
	 * @exception XMOException XMO独自例外
	 * @exception Exception システムエラー
	 */
	private Vector getLoPath( String strLoID )
		throws XMOException, Exception
	{

		LoRelationClient objRelation = new LoRelationClient();

		Vector vecRes = new Vector();

		// パスの検索を実行する
		if( !objRelation.searchPath( strLoID ) ) {
			// 検索にシッパした場合は例外をスローする
			throw new XMOException( objRelation.getMessageData() );
		}

		// 検索結果分ループを行い、Vectorに格納する
		while( objRelation.next() ) {
			vecRes.add( objRelation.getPath() );
		}

		return vecRes;


	}

	/**
	 * パスリストをMaterialIDリストに変換します。<BR>
	 * <PRE>
	 *    たとえば、パスが
	 *      [0]: LO0
	 *      [1]: LO1
	 *      [2]: LO2
	 *    とすると、変換で作成されるMaterialIDリストは
	 *      [0]: LO0LO1
	 *      [1]: LO1LO2
	 *    となります。
	 * </PRE>
	 * @param vecPathList パスリスト(中身はString[])
	 * @return String[] MaterialIDリスト
	 */
	private String[] convertPathToMaterialID( Vector vecPathList ) {

		// MaterialIDリストを格納するVector
		Vector vecMaterialList = new Vector();

		for( int i = 0; i < vecPathList.size(); i++ ) {
			String[] strPathList = (String[])vecPathList.get(i);

			for( int j = 0; j < strPathList.length - 1; j++ ) {
				vecMaterialList.add( strPathList[j] + strPathList[j+1] );
			}
		}

		// 返却用String[]
		String[] strRes = new String[vecMaterialList.size()];
		vecMaterialList.copyInto( strRes );

		return strRes;
	}

	/**
	 * ユーザＩＤとＬＯＩＤを指定して、ユーザに対するＬＯのアサインの有効/無効の
	 * 判定を行います。<BR>
	 * 詳細はAssignmentsClientのcheckAssignメソッドを参照してください。
	 * 
	 * @param htbParam
	 * <PRE> Hastableの中身
	 *             user_id: ユーザID
	 *             group_id: グループID 指定された場合は、このグループに限定されたアサインチェックが走ります。<BR>
	 *                    nullを指定すると、ユーザに兼務が存在した場合はすべての兼務がアサインチェックの対象となります。
	 *             lo_id: LOID
	 *             process_type: 処理タイプ以下の2パターンを指定する。
	 *                      SELF: 指定されたLOID自身のアサイン判定
	 *                      UNDER: 指定されたLOIDの直下のアサイン判定
	 * @return Vector
	 * <PRE> Vectorの中身
	 *   [0] MessageData (正常の場合はnull)
	 *   [1] Map 以下の内容が格納される。
	 *       key: LOID
	 *       value: AssignUsableList
	 * </PRE>
	 */
	public Vector checkAssignUsable( Hashtable htbParam ) {

		Vector vecResult = new Vector();
		Map resultMap = new HashMap();
		
		String strUserID = null;
		String strGroupID = null;
		String strLoID = null;
		int intType = 0;
		try {
			// パラメータからユーザIDを取得する
			strUserID = (String)htbParam.get( "user_id" );
			
			// パラメータからグループIDを取得する
			strGroupID = (String)htbParam.get( "group_id" );

			// パラメータからLOIDを取得する
			strLoID = (String)htbParam.get( "lo_id" );

			// パラメータからアサインタイプを取得する
			Integer objType = (Integer)htbParam.get( "process_type" );
			
			intType = objType.intValue();
			
		}
		catch( ClassCastException ex ) {
			vecResult.add(getMessageData( PARAM_WAR ));
			return vecResult;
		}
		if( strUserID == null || strLoID == null ) {
			vecResult.add(getMessageData( PARAM_WAR ));
			return vecResult;
		}
		
		// 処理タイプのチェック
		if( intType != SELF &&
			intType != UNDER )
		{
			vecResult.add(getMessageData( PARAM_WAR ));
			return vecResult;
		}
		
		
		try {
			// チェック日時の取得
			Date checkDate = new Date();
			
			// 上位アサインのアサイン有効・無効判定リストクラスを取得する。
			AssignUsableList upperUsableList = getUppserAssignUsable(
													strUserID, strGroupID, strLoID );

			// チェック日時を設定する
			upperUsableList.setCheckDate( checkDate );
									
			// 処理タイプの判定により処理を振り分ける
			if( intType == SELF ) {
				// 結果マップにLOIDをキーにして格納
				resultMap.put( strLoID, upperUsableList );
			}
			else {
				// 処理タイプが直下の場合
				List underUsableList = pobjDataAccess.getUnderAssignUsable(
											strUserID, strGroupID, strLoID );
										
				// リスト中でアサインが存在しないLOが存在した場合は上位の
				// アサイン判定オブジェクトの内容を書き込む。
				for( int i = 0; i < underUsableList.size(); i++ ) {
					AssignUsableList listTemp = (AssignUsableList)underUsableList.get(i);
					
					if( !listTemp.isExistAssign() ) {
						// 上位アサインの内容をコピーする
						// リストの内容がコピーされる。
						// LOIDとユーザIDはコピーされない。
						upperUsableList.copyList(listTemp);

						// コピーしたリスト内のLOID,ユーザIDを
						// 更新する。
						listTemp.syncID();
					}

					// チェック日時を設定する
					listTemp.setCheckDate(checkDate);
				
					// 結果MapにLOIDをキーにして格納
					resultMap.put( listTemp.getLoID(), listTemp);
				}
			}

			// 正常に終了した場合
			// 1番目にnullを格納
			vecResult.add(null);
			// 2番目にMapを格納
			vecResult.add( resultMap );
			return vecResult;				
		}
		catch( XMOException xe ) {
			DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
			// 例外クラスからメッセージデータを取得する
			vecResult.add( xe.getMessageData() );
			return vecResult;
		}
		catch( SQLException se ) {
			DebugLog.write( this.getClass(), se, DebugLog.HIGHT );
			// DBエラーメッセージを作成する
			vecResult.add( getMessageData( DB_ERR ) );
			return vecResult;
		}
		catch( Exception e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// システムエラーメッセージを作成する
			vecResult.add( getMessageData( SYSTEM_ERR ) );
			return vecResult;
		}

	}


	/**
	 * 階層の上位方向へのアサイン有効・無効オブジェクトの取得
	 * @param strUserID ユーザID
	 * @param strGroupID グループID null の場合は兼務すべてが対象
	 * @param strLoID LOID
	 * @param checkDate チェック対象日時
	 */
	private AssignUsableList getUppserAssignUsable(
								String strUserID,
								String strGroupID,
								String strLoID )
		throws XMOException, SQLException, Exception
	{
			// LOIDのパスを取得する。
			Vector vecLoPath = getLoPath( strLoID );
			// パスリストをMaterialIDリストに変換します。
			// 返却値は階層の上位方向から下位方向への順番に格納される。
			String[] materialIDList = convertPathToMaterialID( vecLoPath );
			
			// 上位アサインのアサイン有効・無効判定リストクラス
			AssignUsableList upperUsableList = null;

			// 上位方向の直近のアサインを判定に用いるため階層の深いほうからチェックを行う。
			for( int i = materialIDList.length - 1; i >= 0 ; i-- ) {
				
				upperUsableList = pobjDataAccess.getAssignUsable(
							strUserID, strGroupID, materialIDList[i]);
				
				if( upperUsableList.isExistAssign() ) {
					
					// 直近のアサインが取得できたら、
					// 処理終了
					break;
				}
			}
			
			if( upperUsableList == null ) {
				upperUsableList = new AssignUsableList();
			}	
			
			// ユーザIDとLOIDを設定する
			upperUsableList.setUserID(strUserID);
			upperUsableList.setLoID(strLoID);
			
			return upperUsableList;	
	}
	

   /**
    * アサイン情報検索条件を生成し、データベースアクセスメソッドを呼び出します。<BR>
	* 検索結果をユーザIDとコンポーネントIDを連結した文字列をキーとしたハッシュに格納します。<BR>
	* 詳細はAssignmentsClientのcheckAssignメソッドを参照してください。
	* 
	* @param htbParam		検索条件
	* @return lstResult	ハッシュを格納したリスト
	*/
	public List getAssignInfo(Hashtable htbParam) {
  	
		List lstResult = new ArrayList();
		Map resultMap = new HashMap();
		LoLogCommon_inc cominc = new LoLogCommon_inc();
		
			
		String strUserID = null;
		String strGroupID = null;
		String strLoID = null;
		int intType = 0;
		String strSubordinateFlg = null;

		try {
			// パラメータからユーザIDを取得する
			strUserID = (String)htbParam.get( "user_id" );
				
			// パラメータからグループIDを取得する
			strGroupID = (String)htbParam.get( "group_id" );
	
			// パラメータからLOIDを取得する
			strLoID = (String)htbParam.get( "lo_id" );
	
			// パラメータからアサインタイプを取得する
			intType = Integer.parseInt((String)htbParam.get( "process_type" ));

			// 配下フラグ｢on 又は off｣を取得する
			strSubordinateFlg = (String)htbParam.get("subordinateFlg");

			if( strLoID == null ) {
				lstResult.add(getMessageData( PARAM_WAR ));
				return lstResult;
			}

			// LO直下のLOIDを取得する
			LoRelationClient loReationClient = new LoRelationClient();
			List loIdList = loReationClient.getLoIds(strLoID);
	
			// LOIDのパスを取得する。
			Vector vecLoPath = getLoPath( strLoID );
	
			// コンポーネントIDリストの生成
	
			// 選択されたLOIDまでのコンポーネントIDを取得
			String[] aryComponentId = convertPathToMaterialID(vecLoPath);
			// コンポーネントIDリストを生成し、String配列からリストへ変換
			List componentIdList = new ArrayList(Arrays.asList(aryComponentId));

			// LO直下のLOが検索の対象の場合
			if (intType == UNDER) {
				// 指定されたLOIDと直下のLOIDを連結したコンポーネントIDを追加する
				for (int i = 0;i < loIdList.size(); i++) {
					componentIdList.add(strLoID + (String)loIdList.get(i));
				}
			}

			// 1000コンポーネントID毎のIN句を生成
			List inComponentList = cominc.getGroupInSql(componentIdList);

			List groupPathList = new ArrayList();
			// グループ+配下選択時
			if (strSubordinateFlg.equals("on") && strUserID == null) {
				GroupAndPeopleClient gapClient = new GroupAndPeopleClient();
				// 指定されたGroupID及び配下の全GroupIDを取得
				groupPathList = gapClient.getGroupIdList(strGroupID, groupPathList);
			} else {
				groupPathList.add(strGroupID);
			}

			// 1000グループ毎のIN句を生成
			List inGroupList = cominc.getGroupInSql(groupPathList);
			// グループのIN句分ループ
			for (int i = 0; i < inGroupList.size(); i++) {

				// コンポーネントのIN句分ループ
				for (int j = 0; j < inComponentList.size(); j++) {
					
					// アサイン情報をＤＢより取得する
					List usableList = 
						pobjDataAccess.getAssignInfo((String)inComponentList.get(j), 
							(String)inGroupList.get(i), strUserID );
			
					// DBより取得したレコード分ループする 
					for( int k = 0; k < usableList.size(); k++ ) {
						// AssignUsableオブジェクトを取得
						AssignUsable assignList = (AssignUsable)usableList.get(k);
						// ハッシュのキー名を生成
						// ユーザIDを取得
						String userId = assignList.getUserID();
						// コンポーネントIDを取得
						String componentId = assignList.getComponentId();
						// ユーザIDとコンポーネントIDを連結した文字列をキーとする
						String assignKey = userId + componentId;
	
						// 結果MapにLOIDをキーにして格納
						resultMap.put( assignKey, assignList);
					}
				}
			}
	
			// 正常に終了した場合
			// 1番目にnullを格納
			lstResult.add(null);
			// 2番目にMapを格納
			lstResult.add( resultMap );
			return lstResult;				


		} catch( ClassCastException ex ) {
			lstResult.add(getMessageData( PARAM_WAR ));
			return lstResult;
		} catch( XMOException xe ) {
			DebugLog.write( this.getClass(), xe, DebugLog.HIGHT );
			// 例外クラスからメッセージデータを取得する
			lstResult.add( xe.getMessageData() );
			return lstResult;
		} catch( SQLException se ) {
			DebugLog.write( this.getClass(), se, DebugLog.HIGHT );
			// DBエラーメッセージを作成する
			lstResult.add( getMessageData( DB_ERR ) );
			return lstResult;
		} catch( Exception e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// システムエラーメッセージを作成する
			lstResult.add( getMessageData( SYSTEM_ERR ) );
			return lstResult;
		}
	}

	/**
	 * 学習回数を１つ増加する。<br>
	 * パラメータ内で指定したユーザID、マテリアルIDの組み合わせの学習回数を１つ増加する。<br>
	 * よって、パラメータには以下の内容が含まれている必要がある。<br>
	 * <table border="1">
	 *	<tr>
	 *		<td>キー</td><td>値</td>
	 *	</tr>
	 *	<tr>
	 *		<td>MEMBERSHIP_ID</td><td>ユーザID</td>
	 *	</tr>
	 *	<tr>
	 *		<td>LO_ID</td><td>教材ID。</td>
	 *	</tr>
	 *	<tr>
	 *		<td>KEY_LO_TYPE</td>
	 *      <td>
	 *        教材種別。<br>
	 *        LoConstantクラスの定数を使用する。<br>
	 *        WBT教材、SmartForce教材、またはPerception教材以外は無指定にする。
	 *      </td>
	 *	</tr>
	 * </table>
	 * 
	 * @param htbParam 上記内容をふくむパラメータテーブル。
	 * @return 正常終了の場合、空Listを戻す。
	 *          失敗した場合、メッセージ（String）を０番目の要素とするListを戻す。
	 * @see AssignmentsTable#MEMBER_SHIP_ID
	 * @see AssignmentsTable#KEY_LO_TYPE
	 * @see AssignmentsTable#LO_ID
	 * @see jp.co.ntt.lms.lo.LoConstant#LO_TYPE_WBT
	 * @see jp.co.ntt.lms.lo.LoConstant#LO_TYPE_SMARTFORCE
	 * @see jp.co.ntt.lms.lo.LoConstant#LO_TYPE_PERCEPTION
	 */
	private List countupStudyCount(Hashtable htbParam) {
		// このメソッドの戻り値
		List lstResult = new ArrayList();
		// ユーザID
		String userID = null;
		// マテリアルID
// 教材の指定にマテリアルIDを使用しなくなったので変数削除。

// マテリアルIDではなくLOIDで渡される場合あり
		// LOID
		String loID = null;

// 教材種別の取得・使用するため変数を宣言
		String loType = null;
		try {
			////////////////////////////////////////////////////////////////////
			// パラメータから必要なIDを取得
			// =================================================================
			// ユーザID
// ユーザIDを取得時にマテリアルIDをキーに取得していた点を修正
			userID = (String)htbParam.get( MEMBER_SHIP_ID );

// 教材の指定にマテリアルIDを使用しなくなった。
// ＬＯＩＤを常に取得、使用する。
			loID = (String)htbParam.get( LO_ID );

			loType = (String)htbParam.get( KEY_LO_TYPE );


			////////////////////////////////////////////////////////////////////
			// カウントアップ
// APIからマテリアルIDを除去、教材種別を追加。
			pobjDataAccess.countupStudyCount(userID, loID, loType);
		} catch( SQLException e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// DBエラーメッセージを作成する
			lstResult.add( getMessageData( DB_ERR ) );
		} catch( Exception e ) {
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// システムエラーメッセージを作成する
			lstResult.add( getMessageData( SYSTEM_ERR ) );
		}
		return lstResult;
	}

	/**
	 * メール送信の１回あたりの送信件数を取得する。
	 * @param htbParam パラメータ・ハッシュテーブル。
	 * @return 送信件数またはエラーメッセージを含むMap。
	 * 以下のキー−値の組み合わせのいずれかを戻す。<br>
	 * <table border="1">
	 *	<tr>
	 *		<td>キー</td><td>型</td><td>内容</td>
	 *	</tr>
	 *	<tr>
	 *		<td>KEY_ERROR_MESSAGE</td><td>String</td><td>エラーメッセージ</td>
	 *	</tr>
	 *	<tr>
	 *		<td>KEY_SEND_MAIL_COUNT</td><td>Integer</td><td>送信件数</td>
	 *	</tr>
	 * </table>
	 * @see #KEY_ERROR_MESSAGE
	 * @see #KEY_SEND_MAIL_COUNT
	 * @see Integer
	 */
	private Map getSendMailCount( Hashtable htbParam ) {
		// このメソッドの戻り値
		Map returnValue = null;

		// アサインメント環境変数クラス 
		AssignmentsEnv objEnv = null;
		// 送信件数
		Integer sendMailCount = null;
		String  strSendMailCount = null;
		
		try {
			returnValue = new HashMap();
			// アサインメント環境変数クラスを取得
			objEnv = AssignmentsEnv.getInstance();
			//一括送信数を取得
			strSendMailCount = objEnv.getSendMailCount();
			// 数値化
			sendMailCount = new Integer(strSendMailCount);
			// 戻り値に格納
			returnValue.put(KEY_SEND_MAIL_COUNT, sendMailCount);
		} catch (Exception e) {
			// 例外発生時は、メッセージを格納
			DebugLog.write(this.getClass(), e,DebugLog.HIGHT);
			returnValue.put(KEY_ERROR_MESSAGE, e.getMessage());
		}
		return returnValue;	
	}

}

