/*
 * 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.system.ThrowUtil ;					// 6.4.2.0 (2016/01/29)
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.Shell;
import org.opengion.fukurou.db.ApplicationInfo;
import org.opengion.fukurou.db.DBUtil;
import static org.opengion.fukurou.system.HybsConst.CR ;					// 6.1.0.0 (2014/12/26)
import static org.opengion.fukurou.system.HybsConst.FS;					// 6.1.0.0 (2014/12/26) refactoring
import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;		// 6.1.0.0 (2014/12/26) refactoring

/**
 * 【レポート出力】DBTableModelオブジェクトをレポート形式に返還するタグリブクラスです。
 * このオブジェクトに、 データ(DBTableModel)と、コントローラ(DBTableReport クラス)を与えて、
 * 外部からコントロールすることで、各種形式で データ(DBTableModel)を表示させることが
 * 可能です。
 *
 * 各属性は、{&#064;XXXX} 変数が使用できます。
 * これは、ServletRequest から、xxxx をキーに値を取り出し,この変数に
 * 割り当てます。つまり、このxxxxをキーにリクエストすれば、
 * この変数に値をセットすることができます。
 *
 * http://localhost/query.jsp?KEY1=VLA1&amp;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 final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE );

	private final String	SYSTEM_ID	;
	private final String	YKNO		;
	private final String	PRTID		;
	private       String	prtNM		;		// 6.3.9.0 (2015/11/06) Variables should start with a lowercase character(PMD)
	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	BASE_SYS_ID = "**" ;	// 7.2.6.0 (2020/06/30) ベースシステムID

	private String		shellCmd		;

//	// 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 = ?" ;

	// 7.2.6.1 (2020/07/17) "**"以外にベースとなるSYSTEM_ID(RESOURCE_BASE_SYSTEM_ID)設定の対応
	// GE55 のプリンタ名を取得するSQL文です。
	private static final String GE55_SELECT =
		"SELECT PRTNM,SYSTEM_ID"
		+ " from ("
		+ "  select 0 as SNO,B.* from GE55 B where SYSTEM_ID='**' and PRTID=? and FGJ='1'"	// ｴﾝｼﾞﾝ共通
		+ "  union all"
		+ "  select 1 as SNO,B.* from GE55 B where SYSTEM_ID=? and PRTID=? and FGJ='1'"	// RESOURCE_BASE_SYSTEM_ID
		+ "  union all"
		+ "  select 2 as SNO,B.* from GE55 B where SYSTEM_ID=? and PRTID=? and FGJ='1'"	// 最上位ののSYSTEM_ID
		+ " ) A"
		+ " order by SNO,SYSTEM_ID" ;

	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;
	private final String DBID = HybsSystem.sys( "RESOURCE_DBID" );		// 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対応

	/**
	 * コンストラクター
	 *
	 * @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 mdlFile テンポラリーファイル
	 * @param outFile 出力ファイル名
	 * @param dmnGrp  デーモングループ
	 * @param debug デバッグフラグ
	 */
	public ReportPrint( final String system_id, final String ykno, final String prtId,
						final String prgFile,final String inDir,final 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;
		}
	}

	/**
	 * レポート出力処理を実行します。
	 *
	 * @og.rev 6.4.2.0 (2016/01/29) StringUtil#stringStackTrace(Throwable) を、ThrowUtil#ogStackTrace(Throwable) に置き換え。
	 *
	 * @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( final RuntimeException ex ) {
			errMsg.append( "ReportPrint Execute Error! " ).append( CR )
				.append( "==============================" ).append( CR )
				.append( ThrowUtil.ogStackTrace( ex ) ).append( CR ) ;					// 6.4.2.0 (2016/01/29)
			flag = false;
		}

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

	/**
	 * 初期データセットを行います。
	 * ここでは、GE55 テーブルより必要な情報を取得します。
	 *
	 * @og.rev 3.8.7.0 (2006/12/15) アクセスログ取得の為,ApplicationInfoオブジェクトを設定
	 * @og.rev 5.5.5.1 (2012/08/07) リソース系DBID 付け忘れ対策
	 * @og.rev 7.2.6.1 (2020/07/17) "**"以外にベースとなるSYSTEM_ID(RESOURCE_BASE_SYSTEM_ID)設定の対応
	 *
	 * @return 結果 [true:正常/false:異常]
	 */
	private boolean initialDataSet() {
		final String baseSystemId = HybsSystem.sys( "RESOURCE_BASE_SYSTEM_ID", false );
		BASE_SYS_ID = StringUtil.isEmpty( baseSystemId ) ? "**" : baseSystemId ;

		if( PRTID == null ) {
			errMsg.append( "PRTID columns does not exist in GE55 table." ).append( CR )
				.append( "==============================" ).append( CR )
				.append( "SYSTEM_ID=[" ).append( SYSTEM_ID )
				.append( "] , PRTID=[" ).append( PRTID     ).append( ']' )		// 6.0.2.5 (2014/10/31) char を append する。
				.append( CR );
			return false;
		}

		// 7.2.6.1 (2020/07/17) "**"以外にベースとなるSYSTEM_ID(RESOURCE_BASE_SYSTEM_ID)設定の対応
//		final String[] args = new String[] { SYSTEM_ID,PRTID };
		final String[] args = new String[] { PRTID,BASE_SYS_ID,PRTID,SYSTEM_ID,PRTID };
		// prtnm,system_id
		final String[][] vals = DBUtil.dbExecute( GE55_SELECT,args,appInfo, DBID );	// 5.5.5.1 (2012/08/07)
		if( vals == null || vals.length == 0 ) {
			errMsg.append( "Data does not exist in GE55 table." ).append( CR )
				.append( "==============================" ).append( CR )
				.append( "SYSTEM_ID=[" ).append( SYSTEM_ID )
				.append( "] , PRTID=[" ).append( PRTID     ).append( ']' )		// 6.0.2.5 (2014/10/31) char を append する。
				.append( CR );
			return false;
		}

		// 検索結果が複数帰ったとき、SYSTEM_ID が 指定されている方のデータ(行)を採用する。
		// 7.2.6.1 (2020/07/17) 一番最後のデータを採用する。
		final int row = vals.length;
//		int row = 0;
//		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 );		// 6.3.9.0 (2015/11/06) Variables should start with a lowercase character(PMD)

		if( DEBUG ) {
			System.out.println( "SYSTEM_ID   =" + SYSTEM_ID   );
			System.out.println( "YKNO        =" + YKNO        );
			System.out.println( "PRTID       =" + PRTID       );
			System.out.println( "PRTNM       =" + prtNM       );	// 6.3.9.0 (2015/11/06) Variables should start with a lowercase character(PMD)
			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() {

		// 6.0.2.5 (2014/10/31) char を append する。
		final StringBuilder buf = new StringBuilder( BUFFER_MIDDLE )
			.append( programFile ).append( ' ' )						// 実行するコマンド
			.append( '"' ).append( htmlDir ).append( FS )				// 入力HTMLファイル
			.append( YKNO ).append( "_*.html\" " )						// 入力HTMLファイル
			.append( '"' ).append( prtNM ).append( "\" " );				// プリンタ名 // 6.3.9.0 (2015/11/06) Variables should start with a lowercase character(PMD)

		// 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
		if( pdfFile == null ) {
			// ダミーファイルを指定する必要がある。
			buf.append( '"' ).append( htmlDir ).append( FS )
				.append( YKNO ).append( ".xls\" " );		// ダミー出力ファイル
		}
		else {
			buf.append( '"' ).append( pdfFile ).append( "\" " );		// PDFファイル名
		}

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

		// 3.8.5.0 (2006/03/06) DMN_GRPは必須
		buf.append( DMN_GRP ).append( ' ' )			// デーモングループ		// 6.0.2.5 (2014/10/31) char を append する。
			.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() {
		final Shell shell = new Shell();
		shell.setCommand( shellCmd,true );		// BATCHプロセスで実行する
		shell.setWait( true );					// プロセスの終了を待つ
		shell.setTimeout( TIMEOUT );			// 3.6.1.0 (2005/01/05) Shell の タイムアウトを設定

		final 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
	 * @og.rtnNotNull
	 */
	public String getErrMsg() {
		return errMsg.toString();
	}
}
