/*
 * Copyright (c) 2009 The openGion Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */
package org.opengion.hayabusa.report;

import org.opengion.hayabusa.common.HybsSystem;

import static org.opengion.fukurou.system.HybsConst.CR ;			// 6.1.0.0 (2014/12/26)
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.system.ThrowUtil ;					// 6.4.2.0 (2016/01/29)
import org.opengion.fukurou.mail.MailReceiveListener ;
import org.opengion.fukurou.mail.MailTX ;
import org.opengion.fukurou.mail.MailMessage ;
import org.opengion.fukurou.mail.MailAttachFiles ;

import java.util.Date;

/**
 * MailReceiveListener の実装クラスです。
 * MailRX クラスにセットすることで、メール１件ごとに receive( MailMessage ) メソッドが
 * 呼び出されます。
 * メール１件に、添付ファイルが複数登録されている場合の処理を行っています。
 * 添付ファイルごとに要求番号を採番して、要求番号.xls としてセーブし、帳票要求テーブルに
 * 書き込みます。
 *
 * @og.rev 3.8.0.0 (2005/06/07) 新規追加
 * @og.group 帳票システム
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class ExcelInsertReceiveListener implements MailReceiveListener {

	// EXCEL取込時に使用するテンポラリフォルダ名。ファイル名は、要求番号.xls
	private final String EXCELIN_URL =
		HybsSystem.url2dir( StringUtil.nval(
								HybsSystem.sys( "EXCEL_IN_FILE_URL" ) ,
								HybsSystem.sys( "FILE_URL"   ) + "EXCELIN/" ) ) ;

	private GE50Access ge50	;

	/**
	 * デフォルトコンストラクター
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) PMD refactoring. Each class should declare at least one constructor.
	 */
	public ExcelInsertReceiveListener() { super(); }		// これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。

	/**
	 * メール受信処理で、１メール受信ごとに呼び出されます。
	 * 処理結果を、boolean で返します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) StringUtil#stringStackTrace(Throwable) を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
	 *
	 * @param message MailMessageオブジェクト
	 *
	 * @return	処理結果(正常:true / 異常:false)
	 */
	public boolean receive( final MailMessage message ) {
		System.out.println();
		System.out.println( "Receive " + new Date() );

		String errMsg ;
		boolean okFlag = false;

		// 毎回 オブジェクトを構築します。登録日付が初期化されます。
		ge50 = new GE50Access( "CXXXXX","M_RECEIVE","ExcelInsert" );

		try {
			final String content	= message.getContent();

			final String systemId = getContentParam( content,"SYSTEM_ID" );
			if( systemId == null ) {
				errMsg = "メール本文に SYSTEM_ID=[xx] のキーワードが存在しません。" ;
				errorReport( message,errMsg ) ;
				return okFlag;
			}

			final String from		= message.getHeader( "From" );			// 6.4.1.1 (2016/01/16) PMD refactoring.
			System.out.println( " From:" + from );
			String joken = getContentParam( content,"JOKEN" );
			if( joken == null ) { joken = "EXCELIN"; }

			ge50.setSystemId( systemId );
			ge50.setJoken   ( joken );
			final String subject	= message.getSubject();					// 6.4.1.1 (2016/01/16) PMD refactoring.
			final String msgid		= message.getMessageID();				// 6.4.1.1 (2016/01/16) PMD refactoring.
			ge50.setComments( from + " " + subject + " " + msgid );			// 6.1.0.0 (2014/12/26) refactoring

			final MailAttachFiles attFiles = new MailAttachFiles( message.getMessage() );
			final String[] files = attFiles.getNames();
			if( files == null || files.length == 0 ) {
				errMsg = "メールに EXCEL 添付ファイルが存在しません。" ;
				errorReport( message,errMsg ) ;
				return okFlag;
			}

			// 添付ファイルの数だけ処理します。
			for( int i=0; i<files.length; i++ ) {
				final String attFile = files[i];

				// LISTID を取得します。 EXCELファイル名に(帳票ID)を入れます。
				final int st = attFile.indexOf( '(' );
				final int ed = attFile.indexOf( ')',st );
				if( st < 0 || ed < 0 ) {
					errMsg = "EXCEL 添付ファイルに(帳票ID)が存在しません。[" + attFile + "]" ;
					errorReport( message,errMsg ) ;
					return okFlag;
				}

				final String listId  = attFile.substring( st+1,ed );
				if( listId.isEmpty() ) {
					errMsg = "EXCEL 添付ファイルの(帳票ID)を切り出せません。[" + attFile + "]" ;
					errorReport( message,errMsg ) ;
					return okFlag;
				}

				final String fileDir = EXCELIN_URL + systemId + "/" + listId + "/" ;
				// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid declaring a variable if it is unreferenced before a possible exit point.
				final String ykno    = ge50.makeYkno();		// 新たな要求番号が内部にもセットされる。
				final String file    = ykno + ".xls" ;

				attFiles.saveFileName( fileDir,file,i );

				ge50.setListId( listId );
				ge50.setOutDir( fileDir );
				ge50.setOutFile( files[i] );

				ge50.insertGE50( GE50Access.FG_SET );

				System.out.println( attFile + " -> " + file );
			}
			System.out.println( " End." );
			okFlag = true;
		}
		catch( final Throwable ex ) {
			errMsg = ThrowUtil.ogStackTrace( ex );				// 6.4.2.0 (2016/01/29)
			errorReport( message,errMsg ) ;
			okFlag = false;
		}
		return okFlag;
	}

	/**
	 * メール処理中にエラーが発生した場合の処理を行います。
	 * 処理は、３種類あります。
	 * １．エラーメールを、EXCELIN_URL/ERROR_MAIL フォルダに、メッセージID.txt で保存します。
	 * ２．COMMON_MAIL_SERVER と ERROR_MAIL_TO_USERS が設定されている場合に、
	 *     そのあて先に、返信メールを送信します。
	 * ３．GE50(帳票要求テーブル)と、GE51(帳票エラーテーブル)にエラー状況を書き込みます。
	 *
	 * @param message MailMessageオブジェクト
	 * @param errorMessage エラーメッセージ
	 */
	private void errorReport( final MailMessage message,final String errorMessage ) {
		// エラーメールを 所定のディレクトリに出力します。
		message.saveSimpleMessage( EXCELIN_URL + "/ERROR_MAIL/" );

		final String subject		= "EXCEL取込メール受信中にエラーが発生しました。";
		final String org_from		= message.getHeader( "From" ) ;
		final String ord_subject	= message.getSubject();
		final String content		= message.getContent();
		final String errMsg = subject + CR
					+ " Subject=" + ord_subject + " From=" + org_from + CR
					+ " MessageID=" + message.getMessageID() + CR
					+ " Save ErrorMail=" + EXCELIN_URL + "/ERROR_MAIL/" + CR
					+ errorMessage + CR
					+ "==========================================================="
					+ CR
					+ content ;

		if( ge50 != null ) {
			final String systemId = ge50.getSystemId() ;
			if( systemId == null ) { ge50.setSystemId( "ERR" ); }

			// エラー時の要求番号は、新たに採番しなおします。
			ge50.makeYkno();

			ge50.insertGE50( GE50Access.FG_ERR2 );
			ge50.insertErrorGE56( errMsg );
		}

		// host と user のメール送信先が記述されている場合は、メールでも転送する。
		final String   host = message.getHost();
		final String   from = message.getUser();

		if( host != null && from != null ) {
			final String[] to		= new String[] { org_from };
			final String[] cc = StringUtil.csv2Array( HybsSystem.sys( "ERROR_MAIL_TO_USERS" ) );

			final MailTX tx = new MailTX( host );
			tx.setFrom( from );
			tx.setTo( to );
			if( cc.length > 0 ) { tx.setCc( cc ); }
			tx.setSubject( subject );
			tx.setMessage( errMsg );
			tx.sendmail();
		}
	}

	/**
	 * メッセージ本文より、指定のキーに関連付けられている情報を切り出します。
	 * これは、指定の文字列=[設定値] というキーワードから、設定値を取り出します。
	 * 指定の文字列と=のと間に、スペースを入れないでください。
	 * 設定値の切り出しは、"指定の文字列=[" と "]" の間の文字列を切り出します。
	 * 内部にスペースが入っていても、問題ありません。ただし、] が入っている場合は、
	 * 正常に切り出すことは出来ませんし、エスケープ文字も用意していません。
	 *
	 * @param	content	コンテンツの文字列
	 * @param	key	情報を切り出す時のキー
	 *
	 * @return	設定値 (設定値が見つからない場合:null
	 */
	private String getContentParam( final String content,final String key ) {
		if( content == null || key == null ) { return null; }

		final String newKey = key + "=[" ;

		// キーの存在チェックと場所を求める。
		final int keyAd = content.indexOf( newKey );
		if( keyAd >= 0 ) {
			// [設定値] の終了場所を求める。(見つけた位置＋文字列数)
			final int st = keyAd + newKey.length() ;
			final int ed = content.indexOf( ']' , st );
			if( ed >= 0 ) {
				return content.substring( st,ed );
			}
		}
		return null;
	}
}
