/*
 * 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 org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.Shell;
import org.opengion.fukurou.util.ApplicationInfo;
import org.opengion.fukurou.db.DBUtil;

/**
 * 【レポート出力】DBTableModel オブジェクトをレポート形式に返還するタグリブクラスです。
 * このオブジェクトに、 データ（DBTableModel)と、コントローラ（DBTableReport クラス)を与えて、
 * 外部からコントロールすることで、各種形式で データ（DBTableModel)を表示させることが
 * 可能です。
 *
 * 各属性は、{&#064;xxxx} 変数が使用できます。
 * これは、ServletRequest から、xxxx をキーに値を取り出し,この変数に
 * 割り当てます。つまり、このxxxxをキーにリクエストすれば、
 * この変数に値をセットすることができます。
 *
 * http://localhost/query.jsp?KEY1=VLA1&KEY2=VAL2
 *
 * のようなリクエストで、{&#064;KEY1} とすれば、 VAL1 がセットされます。
 *
 * @og.group 帳票システム
 *
 * @version  4.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK5.0,
 */
public class ReportPrint {
	// 3.6.1.0 (2005/01/05) Shell の タイムアウトを設定
	private final int TIMEOUT = HybsSystem.sysInt( "REPORT_DAEMON_TIMEOUT" );

	private static final String CR     = HybsSystem.CR ;
	private final StringBuilder errMsg = new StringBuilder();

	private final String	SYSTEM_ID	;
	private final String	YKNO		;
	private final String	PRTID		;
	private       String	PRTNM		;
	private final String	programFile	;
	private final String	htmlDir		;
	private final String	modelFile	;
	private final String	pdfFile		;
	private final String	DMN_GRP		;		// 3.8.0.5 (2005/08/26)
	private final boolean	DEBUG		;	// 3.8.5.0 (2006/03/06) デバッグ用のフラグを追加

	private String		shellCmd	= null;

	// GE55 のプリンタ名を取得するSQL文です。
	// 4.0.0 (2005/01/31) 共有 system_id を、考慮
	private static final String GE55_SELECT =
		"select prtnm,system_id" +
		" from GE55" +
		" where fgj = '1'" +
		" and  system_id in (?,'**')" +
		" and  prtid = ?" ;

	private static final int GE55_PRTNM		= 0;
	private static final int GE55_SYSTEM_ID	= 1;

	/** コネクションにアプリケーション情報を追記するかどうか指定 */
	public static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;

	// 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfo オブジェクトを設定
	private final ApplicationInfo appInfo;

	/**
	 * コンストラクター
	 *
	 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfo オブジェクトを設定
	 *
	 * @param system_id システムID
	 * @param ykno 要求番号
	 * @param prtId プリンターID
	 * @param prgFile 実行プログラムID
	 * @param inDir レポート入力ディレクトリ
	 * @param outFile 出力ファイル名
	 * @param dmnGrp  デーモングループ
	 * @param debug デバッグフラグ
	 */
	public ReportPrint( final String system_id, final String ykno, final String prtId,
						final String prgFile,final String inDir,String mdlFile,
						final String outFile,final String dmnGrp,final boolean debug ) {
		SYSTEM_ID 	= system_id;
		YKNO      	= ykno;
		PRTID     	= prtId;
		programFile	= prgFile ;
		htmlDir		= inDir ;
		modelFile	= mdlFile ; // 4.0.1.0 (2007/12/18)
		pdfFile		= outFile ;
		DMN_GRP		= dmnGrp;				// 3.8.0.5 (2005/08/26)
		DEBUG	 	= debug;

		// 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfo オブジェクトを設定
		if( USE_DB_APPLICATION_INFO ) {
			appInfo = new ApplicationInfo();
			// ユーザーID,IPアドレス,ホスト名
			appInfo.setClientInfo( SYSTEM_ID,HybsSystem.HOST_ADRS,HybsSystem.HOST_NAME );
			// 画面ID,操作,プログラムID
			appInfo.setModuleInfo( "ReportPrint",YKNO,PRTID );
		}
		else {
			appInfo = null;
		}
	}

	/**
	 * レポート出力処理を実行します。
	 *
	 * @return 結果 (正常：true / 異常：false)
	 */
	public boolean execute() {
		System.out.print( "ReportPrint Started ... " );
		boolean flag ;

		try {
			flag = initialDataSet();
			if( flag ) { System.out.print( "INIT," ); }

			if( flag ) {
				flag = makeShellCommand();
				if( flag ) { System.out.print( "SHELL," ); }
			}

			if( flag ) {
				flag = programRun();
				if( flag ) { System.out.print( "RUN," ); }
				// 3.8.5.3 (2006/06/30) 帳票処理実行時エラーの再実行
	//			else {
	//				System.out.println();
	//				System.out.println( "帳票印刷時にエラーが発生しました。リトライします。" );
	//				System.out.println( "YKNO=[" + YKNO + "],PRTID=[" + PRTID + "],DMN_GRP=[" + DMN_GRP + "]" );
	//				System.out.println();
	//				flag = programRun();
	//				if( flag ) { System.out.print( "RUN 2," ); }
	//				else {
	//					System.out.println( "帳票印刷リトライに失敗しました。YKNO=[" + YKNO + "]" );
	//				}
	//			}
			}
		}
		catch ( RuntimeException ex ) {
			errMsg.append( "ReportPrint Execute Error! " ).append( CR ) ;
			errMsg.append( "==============================" ).append( CR );
			errMsg.append( StringUtil.stringStackTrace( ex ) ) ;
			errMsg.append( CR ) ;
			flag = false;
		}

		System.out.println( "End." );
		return flag ;
	}

	/**
	 * 初期データセットを行います。
	 * ここでは、GE55 テーブルより必要な情報を取得します。
	 *
	 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfo オブジェクトを設定
	 *
	 * @return 結果 (正常：true / 異常：false)
	 */
	private boolean initialDataSet() {
		if( PRTID == null ) {
			errMsg.append( "PRTID columns does not exist in GE55 table." ).append( CR );
			errMsg.append( "==============================" ).append( CR );
			errMsg.append( "SYSTEM_ID=[" ).append( SYSTEM_ID ).append( "] , " );
			errMsg.append( "PRTID=["     ).append( PRTID     ).append( "]" );
			errMsg.append( CR );
			return false;
		}

		String[] args = new String[] { SYSTEM_ID,PRTID };
		// prtnm,system_id
		String[][] vals = DBUtil.dbExecute( GE55_SELECT,args,appInfo );	// 3.8.7.0 (2006/12/15)
		if( vals == null || vals.length == 0 ) {
			errMsg.append( "Data does not exist in GE55 table." ).append( CR );
			errMsg.append( "==============================" ).append( CR );
			errMsg.append( "SYSTEM_ID=[" ).append( SYSTEM_ID ).append( "] , " );
			errMsg.append( "PRTID=["     ).append( PRTID     ).append( "]" );
			errMsg.append( CR );
			return false;
		}

		int row = 0;
		// 検索結果が複数帰ったとき、SYSTEM_ID が 指定されている方のデータ(行)を採用する。
		for( int i=0; i<vals.length; i++ ) {
			if( SYSTEM_ID.equalsIgnoreCase( vals[i][GE55_SYSTEM_ID] ) ) { row = i; break; }
		}

		PRTNM = StringUtil.nval( vals[row][GE55_PRTNM],PRTNM );

		if( DEBUG ) {
			System.out.println( "SYSTEM_ID   =" + SYSTEM_ID   );
			System.out.println( "YKNO        =" + YKNO        );
			System.out.println( "PRTID       =" + PRTID       );
			System.out.println( "PRTNM       =" + PRTNM       );
			System.out.println( "programFile =" + programFile );
			System.out.println( "htmlDir     =" + htmlDir     );
			System.out.println( "pdfFile     =" + pdfFile     );
			System.out.println( "DMN_GRP     =" + DMN_GRP     );
			System.out.println( "GE55_SELECT =" + GE55_SELECT );
		}

		return true;
	}

	/**
	 * シェルコマンドの文字列を作成します。
	 *
	 * @og.rev 3.8.0.5 (2005/08/26) 引数にデーモングループを追加
	 * @og.rev 3.8.0.8 (2005/10/03) デーモングループのデフォルト値設定
	 * @og.rev 4.0.1.0 (2007/12/18) 帳票のテンポラリーファイルを
	 *
	 * @return 結果 (正常：true / 異常：false)
	 */
	private boolean makeShellCommand() {
		StringBuilder buf = new StringBuilder( HybsSystem.BUFFER_SMALL );

		buf.append( programFile ).append( " " );		// 実行するコマンド
		buf.append( "\"" ).append( htmlDir ).append( HybsSystem.FS );		// 入力HTMLファイル
		buf.append( YKNO ).append( "_*.html\" " );		// 入力HTMLファイル
		buf.append( "\"" ).append( PRTNM ).append( "\" " );	// プリンタ名
		if( pdfFile != null ) {
			buf.append( "\"" ).append( pdfFile ).append( "\" " );		// PDFファイル名
		}
		else {
			// ダミーファイルを指定する必要がある。
			buf.append( "\"" ).append( htmlDir ).append( HybsSystem.FS );
			buf.append( YKNO ).append( ".xls\" " );		// ダミー出力ファイル
		}

		// 3.8.5.0 (2006/03/06) EXCELをオープンするファイル名に要求番号を使う
//		buf.append( YKNO ).append( " " );
		if( modelFile != null ) { // 4.0.1.0 (2007/12/18)
			buf.append( modelFile ).append( " " );		// モデルファイル名(4)
		}
		else {
			buf.append( "DMY_MDL" ).append( " " );		// ダミーモデルファイル名(4)
		}

		// 3.8.5.0 (2006/03/06) DMN_GRPは必須
		buf.append( DMN_GRP ).append( " " );		// デーモングループ

		buf.append( PRTID );		// プリンタID(この名前.pdf でPDFファイルが作成される。)

		shellCmd = buf.toString();
		System.out.println( CR + shellCmd + CR );

		return true;
	}

	/**
	 * 実際のレポート出力処理を行います。
	 *
	 * @og.rev 3.1.9.0 (2003/05/16) Shell への stdout と stderr の取得設定は廃止。ShellTag では、有効。
	 * @og.rev 3.6.1.0 (2005/01/05) Shell の タイムアウトを設定
	 *
	 * @return 結果 (正常：true / 異常：false)
	 */
	private boolean programRun() {
		Shell shell = new Shell();
		shell.setCommand( shellCmd,true );		// BATCHプロセスで実行する
		shell.setWait( true );					// プロセスの終了を待つ
		shell.setTimeout( TIMEOUT );			// 3.6.1.0 (2005/01/05) Shell の タイムアウトを設定

		int rtnCode = shell.exec();				// 0 は正常終了を示す

		if( rtnCode != 0 ) {
			errMsg.append( "Shell Command exequte Error." ).append( CR );
			errMsg.append( "==============================" ).append( CR );
			errMsg.append( shellCmd ).append( CR );
			errMsg.append( shell.getStdoutData() ).append( CR );
			errMsg.append( shell.getStderrData() ).append( CR );
			errMsg.append( CR );
			return false;
		}

		return true;
	}

	/**
	 * エラーが存在した場合に、エラーメッセージを返します。
	 *
	 * @return エラーメッセージ String
	 */
	public String getErrMsg() {
		return errMsg.toString();
	}
}
