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

//
//	CatalogLo　否認サーブレット
//			変更履歴
//				2004.01.08	新規作成	二條　智文
//
package jp.co.ntt.lms.lo.Catalog;

// XMS2 API
import jp.co.ntt.lms.xmo.util.*;
import jp.co.ntt.lms.xmo.Lo.LoClient;
import jp.co.ntt.lms.xmo.People.PeopleClient;
import jp.co.ntt.lms.xmo.Mail.*;

// JAVA API
import java.util.*;
import java.io.*;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import javax.servlet.ServletContext;
import javax.servlet.RequestDispatcher;

/**
 * CatalogLo　否認サーブレット<BR>
 * 以下の処理を行います。
 * <PRE>
 *    アサイン者の認証
 *    被アサイン者の存在チェック
 *    被アサイン者に対するアサイン権限チェック
 *    被アサインLOに対する管理アサインチェック
 *    認証通知メールの送信
 * <PRE>
 * 処理終了後、否認結果画面へ処理結果メッセージを指定してフォワードします。
 */
public class CatalogAssignNgServlet extends HttpServlet {

	// ログ出力定義
	/** パラメータエラー */
	private static final String PARAM_ERR = "パラメータが不正です。";
	/** 処理開始メッセージ */
	private static final String START_LOG = "処理を開始します。";
	/** 処理終了メッセージ */
	private static final String END_LOG = "処理が終了しました。";
	/** DBエラー */
	private static final String DB_ERROR = "データベースエラーが発生しました。";
	/** システムエラー */
	private static final String SYSTEM_ERROR = "システムエラーが発生しました。";

	// 否認通知メールでのログ出力定義
	/** メール送信　ユーザ情報の取得失敗 */
	private static final String MAIL_FAIL_USER_INFO = "ユーザ情報の取得に失敗しました。";
	/** メール送信　メール設定ファイル読み込みエラー */
	private static final String MAIL_FAIL_READ_ENV = "メール設定ファイルの読み込みに失敗しました。";
	/** メール送信　マクロ置換失敗エラー */
	private static final String MAIL_SGCONV_ERR = "マクロ文字列の置換に失敗しました。";
	/** メール送信　テンプレートファイル読み込みエラー */
	private static final String MAIL_TEMPREAD_ERR = "テンプレートファイルの読み込みに失敗しました。";
	/** メール送信　SMTPサーバ接続エラー */
	private static final String MAIL_CONNECT_ERR = "SMTPサーバの接続に失敗しました。";
	/** メール送信　内部矛盾 */
	private static final String MAIL_INTERNAL_ERR = "メール送信で内部矛盾が発生しました。";
	/** メール送信　すべてのメールが未送信 */
	private static final String MAIL_ALL_ERR = "すべてのメールが送信できませんでした。";
	/** メール送信　いくつかのメールが未送信 */
	private static final String MAIL_ANY__ERR = "いくつかのメールが送信できませんでした。";
	/** メール送信　メール送信失敗ユーザ */
	private static final String MAIL_FAIL_USER = "メール送信失敗ユーザ：";
	/** メール送信　メール未送信ユーザ */
	private static final String MAIL_NOT_SEND_USER = "メール未送信ユーザ：";


	/** すべてのログの先頭につける */
	private static final String PREFIX = "CatalogLO：否認処理：";
	private static final String MAIL_PREFIX = "CatalogLO：否認処理：否認通知メール送信処理：";

	// 結果画面への送信メッセージ
	private static final String END_MSG = "否認通知が完了しました。";
	private static final String NO_EXIST_ASSINGLO_MSG = "否認対象のLOが存在しません。";
	private static final String NO_EXIST_CATALOGLO_MSG = "カタログLOが存在しません。";
	private static final String FAIL_CERTIFY_MSG = "認証に失敗しました。";
	private static final String FAIL_SEND_MAIL_MSG = "否認通知メールの送信に失敗しました。";

	// 結果画面の相対URL
	private static final String CATALOGRESULT_URL = "/view/lo/Catalog/CatalogAssignNg.vm";

	// ログイン情報のセッションキー
	private static final String SESSION_USER_ID = "userId";
	private static final String SESSION_PASSWORD = "password";
	private static final String SESSION_LOGIN_ID = "loginId";
	private static final String SESSION_IS_LOGIN = "isLogin";

	/**
	 * コンストラクタ
	 */
	public CatalogAssignNgServlet() {}

	/**
	 * ＧＥＴ要求を処理するメソッド<BR>
	 * @param HttpServletRequest	ＨＴＴＰリクエスト
	 * @param HttpServletResponse	ＨＴＴＰレスポンス
	 * @return void
	 * @exception javax.servlet.ServletException	サーブレット例外
	 * @exception java.io.IOException				入出力例外
	 */
	public void doGet(
		HttpServletRequest request,HttpServletResponse response)
			throws ServletException, IOException
	{
		// リクエスト処理を呼び出します
		this.doRequest(request, response);
	}

	/**
	 * ＰＯＳＴ要求を処理するメソッド<BR>
	 * @param HttpServletRequest	ＨＴＴＰリクエスト
	 * @param HttpServletResponse	ＨＴＴＰレスポンス
	 * @return void
	 * @exception javax.servlet.ServletException	サーブレット例外
	 * @exception java.io.IOException				入出力例外
	 */
	public void doPost(
		HttpServletRequest request,HttpServletResponse response)
			throws ServletException, IOException
	{
		// リクエスト処理を呼び出します
		this.doRequest(request, response);
	}

	/**
	 * 要求を処理するメソッド<BR>
	 * リクエストから以下のパラメータを取得します。<BR>
	 * <PRE>
	 *     LearnerID         被アサイン者ID
	 *     AssignerID       アサイン者ID
	 *     AssignerPass      アサイン者パスワード
	 *     AssignerLoginID   アサイン者ログインID
	 *     AssignLoID        被アサインLOID
	 *     CatalogLoID       カタログLOID
	 * </PRE>
	 * @param HttpServletRequest	ＨＴＴＰリクエスト
	 * @param HttpServletResponse	ＨＴＴＰレスポンス
	 * @return void
	 */
	private void doRequest(
		HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException
	{
		// パラメータの取得
		String strLearnerID			= request.getParameter( "LearnerID" );		// 被アサイン者ID
		String strAssignerID		= request.getParameter( "AssignerID" );		// アサイン者ID
		String strAssignerPass		= request.getParameter( "AssignerPass" );	// アサイン者パスワード
		String strAssignerLoginID	= request.getParameter( "AssignerLoginID" );	// アサイン者ログインID
		String strAssignLoID		= request.getParameter( "AssignLoID" );		// 被アサインLOID
		String strCatalogLoID		= request.getParameter( "CatalogLoID" );	// カタログLOID

		// ログ出力用文言(入力パラメータを":"で区切ったもの)
		String PARAM_LOG_OUT = strLearnerID + ":" + strAssignerID + ":" + strAssignerPass + ":" +
								strAssignerLoginID + ":" + strAssignLoID + ":" + strCatalogLoID;

		LoClient objAssignLo = null;		// アサインLO情報
		LoClient objCatalogLo = null;		// カタログLO情報

		// セッションオブジェクトの取り出し
		HttpSession session = request.getSession();

		// @LOG >info >5
		DebugLog.write( this.getClass(), PREFIX + START_LOG + ":" + PARAM_LOG_OUT,
						DebugLog.MID);

		// パラメータチェック
		if( strLearnerID == null || strLearnerID.equals("") ||
			strAssignerID == null || strAssignerID.equals("") ||
			strAssignerPass == null || strAssignerPass.equals("") ||
			strAssignerLoginID == null || strAssignerLoginID.equals("") ||
			strAssignLoID == null || strAssignLoID.equals("") ||
			strCatalogLoID == null || strCatalogLoID.equals("") )
		{
			// @LOG >err >1
			DebugLog.write( this.getClass(), PREFIX + PARAM_ERR + ":" + PARAM_LOG_OUT,
							DebugLog.HIGHT);

			// パラメータが不正の場合は警告画面に遷移する。
			goWarningpage( request, response, PARAM_ERR );
			return;
		}

		try {
			// 各種チェック結果格納変数
			boolean blResult = false;


			// アサイン者の認証処理を行います。
			// 認証OKの場合はセッションにログイン情報を格納します
			blResult = certifyAssigner( strAssignerID, strAssignerLoginID, strAssignerPass, session );
			if( !blResult ) {
				// @LOG >err >1
				DebugLog.write( this.getClass(), PREFIX + FAIL_CERTIFY_MSG + PARAM_LOG_OUT,
								DebugLog.HIGHT);

				// 認証がNGの場合は否認結果画面へ遷移する。 > "認証に失敗しました。"
				goResultpage( request, response, FAIL_CERTIFY_MSG );
				return;
			}

			// アサインLO情報の取得
			objAssignLo = getLoInfo( strAssignLoID, request, response );
			if( objAssignLo == null ) {
				// @LOG >err >1
				DebugLog.write( this.getClass(), PREFIX + NO_EXIST_ASSINGLO_MSG + PARAM_LOG_OUT,
								DebugLog.HIGHT);

				// 取得できない場合は否認結果画面へ遷移する。 > "否認対象のLOが存在しません。"
				goResultpage( request, response, NO_EXIST_ASSINGLO_MSG );
				return;
			}

			// カタログLO情報の取得
			objCatalogLo = getLoInfo( strCatalogLoID, request, response );
			if( objCatalogLo == null ) {
				// @LOG >err >1
				DebugLog.write( this.getClass(), PREFIX + NO_EXIST_CATALOGLO_MSG + PARAM_LOG_OUT,
								DebugLog.HIGHT);
				// 取得できない場合は否認結果画面へ遷移する。 > "カタログLOが存在しません。"
				goResultpage( request, response, NO_EXIST_CATALOGLO_MSG );
				return;
			}

			// 否認通知メールの送信処理
			CatalogLoEnv objEnv = new CatalogLoEnv();

			// 否認通知メールテンプレートのパスを設定ファイル(Catalog.ini)から取得する
			String strTemplatePath = objEnv.getAssign_ng_mail_temp_path();

			// 否認通知メールの送信
			blResult = sendMail(strLearnerID,
								strAssignerID,
								objAssignLo.getLoTytle(),
								null,
								objCatalogLo.getLoTytle(),
								strTemplatePath );
			if( !blResult ) {
				// メール送信に失敗した場合 > "否認通知メールの送信に失敗しました。"
				goResultpage( request, response, FAIL_SEND_MAIL_MSG );
				return;
			}


			// すべての処理が正常に終了した。 > "否認通知が完了しました。"
			goResultpage( request, response, END_MSG );

		}
		catch( Exception e ) {
			// @LOG >err >1
			DebugLog.write( this.getClass(), PREFIX + SYSTEM_ERROR + ":" + PARAM_LOG_OUT, DebugLog.HIGHT );
			// エラーログへ出力
			DebugLog.write( this.getClass(), e, DebugLog.HIGHT );
			// エラーページへ遷移する
			goErrorPage( request, response, e.getMessage() );
			return;
		}

		// @LOG >info >5
		DebugLog.write( this.getClass(), PREFIX + END_LOG + ":" + PARAM_LOG_OUT,
						DebugLog.MID);
	}

	/**
	 * 警告ページ画面へフォワードするメソッド<BR>
	 * @param HttpServletRequest	ＨＴＴＰリクエスト
	 * @param HttpServletResponse	ＨＴＴＰレスポンス
	 * @param HttpServletResponse	エラーメッセージ
	 * @return void
	 */
	private void goErrorPage(
		HttpServletRequest request, HttpServletResponse response,
		String strMessage)
			throws ServletException, IOException
	{
		request.setAttribute("ErrorMessage", strMessage);
		ServletContext objSc    = getServletContext();
		RequestDispatcher objRd = objSc.getRequestDispatcher("/view/lo/Com/ComErr.vm");
		objRd.forward(request, response);
	}

	/**
	 * エラーページ画面へフォワードするメソッド<BR>
	 * @param HttpServletRequest	ＨＴＴＰリクエスト
	 * @param HttpServletResponse	ＨＴＴＰレスポンス
	 * @param HttpServletResponse	エラーメッセージ
	 * @return void
	 */
	private void goWarningpage(
		HttpServletRequest request, HttpServletResponse response,
		String strMessage)
			throws ServletException, IOException
	{
		response.setContentType( "text/html" );
		request.setAttribute("WarningMessage", strMessage);
		ServletContext objSc    = getServletContext();
		RequestDispatcher objRd = objSc.getRequestDispatcher("/view/lo/Catalog/CatalogWarning.vm");
		objRd.forward(request, response);
	}

	/**
	 * 結果画面へフォワードするメソッド<BR>
	 * @param HttpServletRequest	ＨＴＴＰリクエスト
	 * @param HttpServletResponse	ＨＴＴＰレスポンス
	 * @param HttpServletResponse	エラーメッセージ
	 * @return void
	 */
	private void goResultpage(
		HttpServletRequest request, HttpServletResponse response,
		String strMessage)
			throws ServletException, IOException
	{
		response.setContentType( "text/html" );
		request.setAttribute("message", strMessage);
		ServletContext objSc    = getServletContext();
		RequestDispatcher objRd = objSc.getRequestDispatcher(CATALOGRESULT_URL);
		objRd.forward(request, response);
	}


	/**
	 * 指定されたLOIDのLOを取得します。
	 * @param strLoID LOID
	 * @return LoClient LO情報 (取得できなかった場合はnullを返す)
	 * @exception Exception RMI通信エラー、XMOエラー
	 */
	private LoClient getLoInfo( String strLoID,
								HttpServletRequest request,
								HttpServletResponse response )
		throws Exception
	{
		// 承引依頼LOIDの有効性チェック
		// LO情報をLOXMOより取得します。
		LoClient objLo = new LoClient();
		// 検索条件を設定
		objLo.setWhereLoID(strLoID);
		if( !objLo.select() ) {
			// 検索がうまくいかなかった場合はExceptionを投げる
			throw new Exception( objLo.getMessage() );
		}

		// LOテーブルからLOIDのレコードを取得できたかチェックする
		if( !objLo.next() ) {
			return null;
		}

		return objLo;
	}

	/**
	 * 否認通知メール送信を行います。
	 * @param strLearnerID 被アサイン者のユーザID
	 * @param strAssignerID アサイン者のユーザID
	 * @param strTmaterial 否認してもらいたい教材名
	 * @param strTcatalog カタログ名
	 * @param strTemplatePath テンプレートファイルフルパス
	 * @return boolean 送信結果 true: 成功 false: 失敗
	 * @exception Exception RMI通信エラー
	 */
	private boolean sendMail(
					String strLearnerID,
					String strAssignerID,
					String strTmaterial,
					String strLoginURL,
					String strTcatalog,
					String strTemplatePath
	)
		throws Exception
	{
		// @LOG >info >5
		DebugLog.write( this.getClass(), MAIL_PREFIX + START_LOG + ":" +
						strLearnerID + ":" + strTmaterial,
						DebugLog.MID);

		// メール送信クライアントをインスタンス化
		MailClient mail = new MailClient();

		// メール送信用にString[]にする
		String[] strLearnerIDs = new String[1];
		strLearnerIDs[0] = strLearnerID;

		// 否認通知メールの送信
		int intRes = mail.sendMail(	strLearnerIDs,
									strAssignerID,
									null,
									strTmaterial,
									strLoginURL,
									strTcatalog,
									strTemplatePath );

		if( intRes == MailConst.RESULT_SUCCESS ) {
		}
		else if( intRes == MailConst.RESULT_NOUSER_ERR ) {
			// @LOG >err >1
			DebugLog.write( this.getClass(), MAIL_PREFIX + MAIL_FAIL_USER_INFO + ":" +
							strLearnerID + ":" + strTmaterial,
							DebugLog.HIGHT);
			return false;
		}
		else if( intRes == MailConst.RESULT_SGREAD_ERR ) {
			// @LOG >err >1
			DebugLog.write( this.getClass(), MAIL_PREFIX + MAIL_FAIL_READ_ENV + ":" +
							strLearnerID + ":" + strTmaterial,
							DebugLog.HIGHT);
			return false;
		}
		else if( intRes == MailConst.RESULT_SGCONV_ERR ) {
			// @LOG >err >1
			DebugLog.write( this.getClass(), MAIL_PREFIX + MAIL_SGCONV_ERR + ":" +
							strLearnerID + ":" + strTmaterial,
							DebugLog.HIGHT);
			return false;
		}
		else if( intRes == MailConst.RESULT_TEMPREAD_ERR ) {
			// @LOG >err >1
			DebugLog.write( this.getClass(), MAIL_PREFIX + MAIL_TEMPREAD_ERR + ":" +
							strLearnerID + ":" + strTmaterial,
							DebugLog.HIGHT);
			return false;
		}
		else if( intRes == MailConst.RESULT_CONNECT_ERR ) {
			// @LOG >err >1
			DebugLog.write( this.getClass(), MAIL_PREFIX + MAIL_CONNECT_ERR + ":" +
							strLearnerID + ":" + strTmaterial,
							DebugLog.HIGHT);
			return false;
		}
		else if( intRes == MailConst.RESULT_INTERNAL_ERR ) {
			// 内部矛盾の場合は例外とする
			throw new Exception( MAIL_INTERNAL_ERR );
		}

		// 送信失敗ユーザリスト取得
		ArrayList objNG = mail.checkNgResult();
		// 送信失敗ユーザIDをログに出力
		for( int i = 0; i < objNG.size(); i++ ) {
			// @LOG >info >1
			DebugLog.write( this.getClass(), MAIL_PREFIX + MAIL_FAIL_USER +
							objNG.get(i),
							DebugLog.HIGHT);
		}

		// 未送信ユーザリスト取得
		ArrayList objNotSend = mail.checkNotSendResult();
		// 未送信ユーザIDをログに出力
		for( int i = 0; i < objNotSend.size(); i++ ) {
			// @LOG >info >1
			DebugLog.write( this.getClass(), MAIL_PREFIX + MAIL_NOT_SEND_USER +
							objNotSend.get(i),
							DebugLog.HIGHT);
		}

		// 失敗ユーザ数
		int intNGCount = objNG.size();
		// 未送信ユーザ数
		int intNotSendCount = objNotSend.size();

		// メールを送信しなかった数(メール失敗数 + 未送信数)が
		// 否認通知メール送信先ユーザ同数の場合はメール送信エラーとする
		// （以上はありえないかもしれないがプログラム的には>=で比較)
		if( intNGCount + intNotSendCount >= 1 ) {
			// @LOG >info >1
			DebugLog.write( this.getClass(), MAIL_PREFIX + MAIL_ALL_ERR,
							DebugLog.HIGHT);
			return false;
		}

		// @LOG >info >5
		DebugLog.write( this.getClass(), MAIL_PREFIX + END_LOG + ":" +
						strLearnerID + ":" + strTmaterial,
						DebugLog.MID);

		// すべて正常に送信できた場合はtrueを返す。
		return true;
	}

	/**
	 * アサイン者の認証処理
	 * UserIDでPeople情報を取得し、ログインIDとパスワードが正しいものか
	 * 判定します。<BR>
	 * パスワードは引数で受け取ったパスワードをBase64デコードして確認します。
	 * @param String strUserID アサイン者のユーザID
	 * @param String strLoginID アサイン者のログインID
	 * @param String strEncryptPass アサイン者のパスワード(Base64 エンコードしたもの)
	 * @param session HttpSession オブジェクト 認証OKの場合にログイン情報を格納します。
	 * @return boolean 認証結果を返します。
	 *                 true: 認証OK false: 認証NG
	 * @exception Exception PeopleXMO使用中に発生した例外、XMO例外
	 */
	private boolean certifyAssigner( String strUserID, String strLoginID, String strEncryptPass, HttpSession session )
		throws Exception
	{
		// PeopleXMOをインスタンス化して、アサイン者の情報を取得します。
		PeopleClient objPeople = new PeopleClient();

		// 検索条件にユーザIDを設定する
		objPeople.setWhereUserID( strUserID );

		// 検索の実行を行う。
		if( !objPeople.select() ) {
			// 検索に失敗した場合はエラーをスローする
			throw new Exception( objPeople.getMessage() );
		}

		// 結果の取得
		if( objPeople.next() ) {
			// 検索結果が存在した場合
			// まずパスワードをBase64デコードします。
			String strPass = RmsKPassword.GetDecordPassword( strEncryptPass );

			// ログインIDの比較
			String strDBLoginID = objPeople.getLoginID();
			if( !strLoginID.equals( strDBLoginID ) ) {
				// ログインIDが不正の場合は認証失敗とする
				return false;
			}

			// パスワードの比較
			String strDBPass = objPeople.getEncryptPassword();
			if( !strPass.equals( strDBPass ) ) {
				// パスワードが不正の場合は認証失敗とする
				return false;
			}

			// 認証OKの場合はセッションにログイン情報を格納する
			// 以下の情報を格納
			// 1 userId ･･･ アサイン者のUserID
			// 2 password ･･･ アサイン者のパスワード(デコードされたもの)
			// 3 loginId ･･･ アサイン者のログインID
			// 4 isLogin ･･･ “OK”
			session.setAttribute( SESSION_USER_ID, strUserID );
			session.setAttribute( SESSION_PASSWORD, strPass );
			session.setAttribute( SESSION_LOGIN_ID, strLoginID );
			session.setAttribute( SESSION_IS_LOGIN, "OK" );

		}
		else {
			// 検索結果が一件も無い場合は認証失敗とする
			return false;
		}

		// 認証がすべてOKの場合はtrueを返す。
		return true;

	}
}
