/*
 * 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.report2;

import java.io.File;
// import java.util.Arrays;										// 8.0.0.0 (2021/07/31) Delete

import org.opengion.fukurou.system.ThrowUtil ;					// 7.1.0.0 (2020/01/27)
import org.opengion.fukurou.system.DateSet;						// 6.4.2.0 (2016/01/29)
import org.opengion.fukurou.system.LogWriter;
import org.opengion.fukurou.system.OgRuntimeException ;			// 6.4.2.0 (2016/01/29)
import org.opengion.fukurou.util.StringUtil;
import org.opengion.fukurou.util.UnicodeCorrecter;				// 5.9.3.3 (2015/12/26) package を､mail → util に移動のため
import org.opengion.fukurou.db.DBFunctionName;
import org.opengion.fukurou.db.DBUtil;
import org.opengion.fukurou.db.ApplicationInfo;
//import org.opengion.fukurou.mail.MailTX;						// 7.4.4.0 (2021/06/30) Delete
import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.db.DBTableModel;
import org.opengion.hayabusa.db.DBTableModelUtil;
import org.opengion.hayabusa.resource.ResourceFactory;
import org.opengion.hayabusa.resource.ResourceManager;
import static org.opengion.fukurou.system.HybsConst.CR ;		// 6.1.0.0 (2014/12/26)

/**
 * DBからｷｭｰを作成するためのｸﾗｽです｡
 * ｷｭｰはGE5xﾃｰﾌﾞﾙから作成されます｡
 *
 * ｷｭｰ生成時点(処理ｽﾚｯﾄﾞにｽﾀｯｸした時点)では､帳票ﾃﾞｰﾀのﾃｰﾌﾞﾙﾓﾃﾞﾙは作成されません｡
 * 帳票ﾃﾞｰﾀは､各ｽﾚｯﾄﾞからset()ﾒｿｯﾄﾞを呼び出したﾀｲﾐﾝｸﾞで生成されます｡
 *
 * 処理開始及び､完了のｽﾃｰﾀｽは､GE50の完成ﾌﾗｸﾞに更新されます｡
 * また､ｴﾗｰ発生時のﾒｯｾｰｼﾞは､GE56に更新されます｡
 *
 * @og.group 帳票ｼｽﾃﾑ
 *
 * @version  4.0
 * @author   Hiroki.Nakamura
 * @since    JDK1.6
 */
public final class QueueManager_DB implements QueueManager {

	/** ｺﾈｸｼｮﾝにｱﾌﾟﾘｹｰｼｮﾝ情報を追記するかどうか指定 */
	private static final boolean USE_DB_APPLICATION_INFO  = HybsSystem.sysBool( "USE_DB_APPLICATION_INFO" ) ;

	private static final String DBID = HybsSystem.sys( "RESOURCE_DBID" );		// 5.5.5.1 (2012/08/07) ﾘｿｰｽ系DBID 付け忘れ対応

	// 4.3.7.0 (2009/06/01) HSQLDB対応
	// 5.1.4.0 (2010/03/01) ﾃﾞｰﾀﾍﾞｰｽ名 でなく､DBID名で検索するように変更します｡
	private static final String CON = DBFunctionName.getFunctionName( "CON", null );

//	// 5.2.0.0 (2010/09/01) Ver4互換ﾓｰﾄﾞ対応
//	// 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
//	private static final String OUT_FILE = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "OUTFILE" : "OUT_FILE";
//	private static final String OUT_DIR = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "OUTDIR" : "OUT_DIR";

	// 4.3.3.6 (2008/11/15) ﾏﾙﾁｻｰﾊﾞ対応追加(GE12から処理対象ﾃﾞｰﾓﾝｸﾞﾙｰﾌﾟ取得)
	// 4.3.7.0 (2009/06/01) HSQLDB対応
	// 5.2.0.0 (2010/09/01) Ver4互換ﾓｰﾄﾞ対応
	// 5.4.2.0 (2011/12/26) PRTID,PRGDIR,PRGFILE取得
	// 5.9.2.2 (2015/11/20) GROUPID追加
	// 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
	// 5.10.0.0 (2018/06/08) FGNOML(ﾒｰﾙ不要ﾌﾗｸﾞ)を追加
	// 7.4.4.0 (2021/06/30) openGionV8事前準備(GE54.FGNOML廃止)
	// 8.0.1.0 (2021/10/29) 未使用のGE54_TRIGを廃止(HSQL,FSQL,BSQL廃止)
	private static final String SQL_SELECT_GE50 =
//		"SELECT A.SYSTEM_ID, A.YKNO, A.LISTID, A."+OUT_DIR+", A."+OUT_FILE+", A.PDF_PASSWD"
		"SELECT A.SYSTEM_ID, A.YKNO, A.LISTID, A.OUT_DIR, A.OUT_FILE, A.PDF_PASSWD"
		+ ", B.LANG, B.FGRUN, B.DMN_GRP "
//		+ ", C.MODELDIR, C.MODELFILE, D.PRTNM, C.FGLOCAL, C.FGCUT, C.BSQL, C.HSQL, C.FSQL "	// 8.0.1.0 (2021/10/29) Modify
		+ ", C.MODELDIR, C.MODELFILE, D.PRTNM, C.FGLOCAL, C.FGCUT "
		+ " ,B.PRTID, B.PRGDIR, B.PRGFILE "
		+ " ,A.GROUPID "							// 5.9.2.2 (2015/11/20)
//		+ " ,C.FGNOML "								// 5.10.0.0 (2018/06/08)
	//	+ " , '0' as FGNOML "						// 5.10.0.0 (2018/06/08) , 6.9.8.1 (2018/06/11) 互換性の関係で､とりあえず､'0' を設定 7.4.4.0 (2021/06/30) Delete
		+ "FROM GE50 A "
		+ "INNER JOIN GE53 B "
		+ "ON A.SYSTEM_ID = B.SYSTEM_ID AND A.JOKEN = B.JOKEN "
		+ "INNER JOIN GE54 C "
		+ "ON A.SYSTEM_ID = C.SYSTEM_ID AND A.LISTID = C.LISTID "
		+ "LEFT OUTER JOIN GE55 D "
		+ "ON B.SYSTEM_ID = D.SYSTEM_ID AND B.PRTID = D.PRTID "
		+ "WHERE A.FGKAN='1' "
		+ "AND EXISTS ( SELECT 'X' FROM GE12 E "
		+				"WHERE	E.FGJ				='1' "
		+				"AND		E.SYSTEM_ID 	= '"
		+				HybsSystem.sys( "SYSTEM_ID" )
		+				"' "
		+				"AND		E.CONTXT_PATH	= '"
		+				HybsSystem.sys( "HOST_URL" )
		+				"' "
		+				"AND		E.PARAM_ID		LIKE 'REPORT2_HANDLE_DAEMON_%' "
		+				"AND		E.PARAM			= 'RUN_'" + CON + "A.SYSTEM_ID" + CON + "'_'" + CON + "B.DMN_GRP"
		+			") "
		+ "ORDER BY "
		+ HybsSystem.sys( "REPORT_DAEMON_ORDER_BY" );

	// 5.1.2.0 (2010/01/01) ﾍﾟｰｼﾞ数､ﾃﾞｰﾀ数をGE50に更新する｡
	private static final String SQL_UPDATE_GE50 =
		"UPDATE GE50 SET FGKAN = ?, DMN_NAME = ?, DMN_HOST = ?, SUDATA = ?, SUPAGE = ?, DYUPD = ? WHERE SYSTEM_ID = ? AND YKNO = ?";

	// 7.1.0.0 (2020/01/27) GE50のUPDATEでｴﾗｰ時に､最小限の情報のみ更新する｡
	private static final String SQL_UPDATE_GE50_ERR =
		"UPDATE GE50 SET FGKAN = ?, DYUPD = ? WHERE SYSTEM_ID = ? AND YKNO = ?";

	private static final String SQL_INSERT_GE56 =
		"INSERT INTO GE56 ( FGJ, SYSTEM_ID, YKNO, ERRMSG, DYSET, DYUPD, USRSET, USRUPD, PGUPD ) "
		+ " VALUES ( '1', ?, ? ,? ,? ,? ,? ,? ,? )" ;

	private static final int STATUS_COMPLETE	= 2;			// 済
	private static final int STATUS_EXECUTE		= 3;			// 実行中
	private static final int STATUS_ERROR		= 8;			// ｱﾌﾟﾘｴﾗｰ

	private static QueueManager manager = new QueueManager_DB();

	/** ｱﾌﾟﾘｹｰｼｮﾝ情報 */
	private static final ApplicationInfo APP_INFO;		// 6.4.1.1 (2016/01/16) appInfo → APP_INFO refactoring
	static {
		if( USE_DB_APPLICATION_INFO ) {
			APP_INFO = new ApplicationInfo();
			// ﾕｰｻﾞｰID,IPｱﾄﾞﾚｽ,ﾎｽﾄ名
			APP_INFO.setClientInfo( "ReportDaemon", HybsSystem.HOST_ADRS, HybsSystem.HOST_NAME );
			// 画面ID,操作,ﾌﾟﾛｸﾞﾗﾑID
			APP_INFO.setModuleInfo( "ReportDaemon", "QueueManager", "QueueManager" );
		}
		else {
			APP_INFO = null;
		}
	}

	/**
	 * ｲﾝｽﾀﾝｽの生成を禁止します｡
	 */
	private QueueManager_DB() {}

	/**
	 * ｲﾝｽﾀﾝｽを返します｡
	 *
	 * @return	帳票処理ｷｭｰの管理ﾏﾈｰｼﾞｬ
	 */
	public static QueueManager getInstance() {
		return manager;
	}

	/**
	 * 帳票処理ｷｭｰを作成します｡
	 *
	 * @og.rev 4.3.0.0 (2008/07/15) ｽﾚｯﾄﾞIDにｼｽﾃﾑIDを付加します｡
	 * @og.rev 5.1.2.0 (2010/01/01) HSQL,FSQL,BSQLのｾｯﾄを廃止します｡(このｸﾗｽ内でﾃﾞｰﾀを直接分割)
	 * @og.rev 5.4.3.0 (2011/12/26) PRTIDの取得
	 * @og.rev 5.5.5.1 (2012/08/07) ﾘｿｰｽ系DBID 付け忘れ対策
	 * @og.rev 6.3.9.0 (2015/11/06) Use block level rather than method level synchronization.(PMD)
	 * @og.rev 5.9.2.2 (2015/11/20) GrpId,DmnGrp 追加
	 * @og.rev 5.10.0.0 (2018/06/08) FGNOML対応
	 * @og.rev 5.10.9.2 (2019/03/15) 5.10.9.0の対応修正
	 * @og.rev 7.4.4.0 (2021/06/30) openGionV8事前準備(GE54.FGNOML廃止)
	 * @og.rev 8.0.1.0 (2021/10/29) 未使用のGE54_TRIGを廃止(HSQL,FSQL,BSQL廃止)
	 */
	public void create() {
		// ｷｭｰをｽﾀｯｸするまでの例外は､ScheduleTagでcatchされﾃﾞｰﾓﾝがｽﾘｰﾌﾟする｡
		final String[][] ge50vals = DBUtil.dbExecute( SQL_SELECT_GE50, new String[0], APP_INFO, DBID );	// 5.5.5.1 (2012/08/07)

		// 6.3.9.0 (2015/11/06) 元々のsynchronizedの必要性が分からないが､帳票なのでとりあえず入れておきます｡
		synchronized( ge50vals ) {
			for( int i=0; i<ge50vals.length; i++ ) {
				final ExecQueue queue = new ExecQueue();
				queue.setSystemId(	ge50vals[i][0] );
				queue.setYkno(		ge50vals[i][1] );
				queue.setListId(	ge50vals[i][2] );
//				queue.setOutputName( new File( ge50vals[i][3] ).getAbsolutePath() , ge50vals[i][4] , ge50vals[i][7] , ge50vals[i][1] ); // 4.3.0.0 (2008/07/18) 要求番号を出力ﾌｧｲﾙ名に利用
				queue.setOutputName( HybsSystem.url2absPath( ge50vals[i][3] ) , ge50vals[i][4] , ge50vals[i][7] , ge50vals[i][1] );		// 5.10.9.2 (2019/03/15)
				queue.setPdfPasswd( ge50vals[i][5] );
				queue.setLang(		ge50vals[i][6] );
				queue.setOutputType( ge50vals[i][7] );
				queue.setThreadId(	ge50vals[i][0] + "_" + StringUtil.nval( ge50vals[i][8] , "_DEFALUT_" ) );	// 4.3.0.0 (2008/07/15)
//				queue.setTemplateName( new File( ge50vals[i][9] ).getAbsolutePath() + File.separator + ge50vals[i][10] );
				queue.setTemplateName( HybsSystem.url2absPath( ge50vals[i][9] ) + File.separator + ge50vals[i][10]);	// 5.10.9.2 (2019/03/15)
				queue.setPrinterName( ge50vals[i][11] );
				queue.setFglocal(	"1".equals( ge50vals[i][12] ) );
				queue.setFgcut(		"1".equals( ge50vals[i][13] ) );

//				queue.setPrtId(		ge50vals[i][17] ); 		// 5.4.3.0 8.0.1.0 (2021/10/29) Modify
				queue.setPrtId(		ge50vals[i][14] );
//				queue.setPrgDir(	ge50vals[i][18] ); 		// 5.4.3.0 8.0.1.0 (2021/10/29) Modify
				queue.setPrgDir(	ge50vals[i][15] );
//				queue.setPrgFile(	ge50vals[i][19] ); 		// 5.4.3.0 8.0.1.0 (2021/10/29) Modify
				queue.setPrgFile(	ge50vals[i][16] );

//				queue.setGrpId(		ge50vals[i][20] );		// 5.9.2.2 (2015/11/20) 8.0.1.0 (2021/10/29) Modify
				queue.setGrpId(		ge50vals[i][17] );
				queue.setDmnGrp(	ge50vals[i][8]  );		// 5.9.2.2 (2015/11/20)
	//			queue.setFgnoml(	ge50vals[i][21] );		// 5.10.0.0 (2018/06/08) 7.4.4.0 (2021/06/30) Delete

				queue.setManager( this );

				ExecThreadManager.insertQueue( queue );
			}
		}
	}

	/**
	 * 帳票処理ﾃﾞｰﾀをｷｭｰにｾｯﾄします｡
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) HSQL,FSQL,BSQLのｾｯﾄを廃止します｡(このｸﾗｽ内でﾃﾞｰﾀを直接分割)
	 *
	 * @param	queue	ExecQueueｵﾌﾞｼﾞｪｸﾄ
	 */
	public void set( final ExecQueue queue ) {
		final String systemId	= queue.getSystemId();
		final String lang		= queue.getLang();
		final String listId		= queue.getListId();
		final String ykno		= queue.getYkno();

		ResourceManager resource = null;
		if( queue.isFglocal() ) {
			resource = ResourceFactory.newInstance( systemId, lang, false );
		}
		else {
			resource = ResourceFactory.newInstance( lang );
		}

		// ﾍｯﾀﾞｰ情報の取得
		final DBTableModel header = new DBTableModelCreator( systemId, listId, ykno, "H", resource ).getTable();

		if( header != null && header.getRowCount() > 0 ) {
			queue.setHeader( header );
		}

		// ﾌｯﾀｰ情報の取得
		final DBTableModel footer = new DBTableModelCreator( systemId, listId, ykno, "F", resource ).getTable();
		if( footer != null && footer.getRowCount() > 0 ) {
			queue.setFooter( footer );
		}

		// ﾎﾞﾃﾞｨｰ情報の取得
		final DBTableModel body = new DBTableModelCreator( systemId, listId, ykno, "B", resource ).getTable();
		// ﾚｲｱｳﾄﾃｰﾌﾞﾙがないと固定長を分割するSQL文が設定されず､DBTableModelがnullになる
		if( body == null ) {
//			queue.addMsg( "[ERROR] DBTableModel doesn't exists! maybe Layout-Table(GE52) is not configured..." + CR );
			queue.addMsg( "[ERROR] DBTableModel doesn't exists! maybe Layout-Table(GE52) or Report-Data(GE51) is not configured..." + CR );	// 5.10.19.0 (2019/12/27)
			queue.setError();
			throw new OgRuntimeException();
		}
		if( body.getRowCount() <= 0 ) {
			queue.addMsg( "[ERROR] Database Body row count is Zero." + ykno + CR );
			queue.setError();
			throw new OgRuntimeException();
		}
		if( body.isOverflow() ) {
			queue.addMsg( "[ERROR]Database is Overflow. [" + body.getRowCount() + "]" + CR );
			queue.addMsg( "[ERROR]Check SystemParameter Data in DB_MAX_ROW_COUNT Overflow" + CR  );
			queue.setError();
			throw new OgRuntimeException();
		}
		queue.setBody( body );
	}

	/**
	 * ｷｭｰを実行中の状態に更新します｡
	 *
	 * @param	queue	ExecQueueｵﾌﾞｼﾞｪｸﾄ
	 */
	public void execute( final ExecQueue queue ) {
		status( queue, STATUS_EXECUTE );
	}

	/**
	 * ｷｭｰを完了済の状態に更新します｡
	 *
	 * @param	queue	ExecQueueｵﾌﾞｼﾞｪｸﾄ
	 */
	public void complete( final ExecQueue queue ) {
		status( queue, STATUS_COMPLETE );
	}

	/**
	 * ｷｭｰをｴﾗｰの状態に更新します｡
	 *
	 * @param	queue	ExecQueueｵﾌﾞｼﾞｪｸﾄ
	 */
	public void error( final ExecQueue queue ) {
		status( queue, STATUS_ERROR );
		insertErrorMsg( queue );
	}

	/**
	 * GE50の状況Cを更新します｡
	 *
	 * @og.rev 4.2.4.1 (2008/07/09) 更新日時をｾｯﾄ
	 * @og.rev 5.1.2.0 (2010/01/01) 行数､ﾍﾟｰｼﾞ数も更新する
	 * @og.rev 5.5.5.1 (2012/08/07) ﾘｿｰｽ系DBID 付け忘れ対策
	 * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します｡
	 * @og.rev 7.1.0.0 (2020/01/27) ここでDB登録ｴﾗｰが発生すると実行中のまま止まるので､ｴﾗｰ処理を入れます｡
	 *
	 * @param	queue	ExecQueueｵﾌﾞｼﾞｪｸﾄ
	 * @param	status	状況C
	 */
	private void status( final ExecQueue queue, final int status ) {

		final String dyupd = DateSet.getDate( "yyyyMMddHHmmss" ) ;			// 6.4.2.0 (2016/01/29)

		final String[] args = new String[] {
			  String.valueOf( status )						// FGKAN
			, queue.getThreadId()							// DMN_NAME
			, HybsSystem.sys( "HOST_NAME" )					// DMN_HOST
			, String.valueOf( queue.getExecRowCnt() )		// SUDATA
			, String.valueOf( queue.getExecPagesCnt() )		// SUPAGE
			, dyupd											// DYUPD
			, queue.getSystemId()							// SYSTEM_ID
			, queue.getYkno()								// YKNO
		};

		// 7.1.0.0 (2020/01/27) ここでDB登録ｴﾗｰが発生すると実行中のまま止まるので､ｴﾗｰ処理を入れます｡
		try {
			DBUtil.dbExecute( SQL_UPDATE_GE50, args, APP_INFO, DBID );	// 5.5.5.1 (2012/08/07)
		}
		catch( final Throwable th ) {
			final String errMsg = "状況Cを更新時にｴﾗｰが発生しました｡" + CR ;
			queue.addMsg( errMsg );
			queue.addMsg( ThrowUtil.ogStackTrace( th ) );
			LogWriter.log( errMsg );
			LogWriter.log( th );

			final String[] args2 = new String[] {
				  String.valueOf( STATUS_ERROR )			// FGKAN
				, dyupd										// DYUPD
				, queue.getSystemId()						// SYSTEM_ID
				, queue.getYkno()							// YKNO
			};

			DBUtil.dbExecute( SQL_UPDATE_GE50_ERR, args2, APP_INFO, DBID );

			if( status != STATUS_ERROR ) {
				insertErrorMsg( queue );					// ｴﾗｰ時以外は､ｴﾗｰﾃｰﾌﾞﾙに書き込む｡
			}
		}
	}

	/**
	 * GE56にｴﾗｰﾒｯｾｰｼﾞを出力します｡
	 *
	 * @og.rev 4.4.0.1 (2009/08/08) ｴﾗｰﾒｯｾｰｼﾞ機能追加
	 * @og.rev 5.5.5.1 (2012/08/07) ﾘｿｰｽ系DBID 付け忘れ対策
	 * @og.rev 6.4.2.0 (2016/01/29) DateSet.getDate( String ) を利用するように修正します｡
	 * @og.rev 5.10.0.0 (2018/06/08) ﾒｰﾙ送信条件を追加
	 * @og.rev 6.9.8.1 (2018/06/11) 帳票ｴﾗｰﾒｰﾙの改修(ﾒｰﾙ不要ﾌﾗｸﾞ=trueで不要､falseが必要)
	 * @og.rev 7.4.4.0 (2021/06/30) openGionV8事前準備(GE54.FGNOML廃止)
	 *
	 * @param	queue	ExecQueueｵﾌﾞｼﾞｪｸﾄ
	 */
	private void insertErrorMsg( final ExecQueue queue ) {
		String errmsg = queue.getMsg();
		if( errmsg.length() > 1300 ) {
			errmsg = errmsg.substring( errmsg.length() - 1300, errmsg.length() );
		}

		final String dyset = DateSet.getDate( "yyyyMMddHHmmss" ) ;			// 6.4.2.0 (2016/01/29)

		final String[] args
		= new String[]{ queue.getSystemId(), queue.getYkno(), errmsg
				, dyset, dyset, "UNKNOWN", "UNKNOWN", "UNKNOWN" };

		DBUtil.dbExecute( SQL_INSERT_GE56, args, APP_INFO, DBID );	// 5.5.5.1 (2012/08/07)

//		sendMail( queue, errmsg ); // 4.4.0.1 (2009/08/08)
		// 5.10.0.0 (2018/06/08) ﾒｰﾙ送信条件を追加
//		if(!"1".equals(queue.getFgnoml())){
		// 7.4.4.0 (2021/06/30) Delete
	//	if( ! queue.isFgnoml() ) {		// 6.9.8.1 (2018/06/11)
	//		sendMail( queue, errmsg );	// 4.4.0.1 (2009/08/08)
	//	}
	}

	// /**
	// * ｴﾗｰ情報のﾒｰﾙ送信を行います｡
	// * ｴﾗｰﾒｰﾙは､ｼｽﾃﾑﾊﾟﾗﾒｰﾀ の COMMON_MAIL_SERVER(ﾒｰﾙｻｰﾊﾞｰ)と
	// * ERROR_MAIL_FROM_USER(ｴﾗｰﾒｰﾙ発信元)と､ERROR_MAIL_TO_USERS(ｴﾗｰﾒｰﾙ受信者)
	// * がすべて設定されている場合に､送信されます｡
	// *
	// * @og.rev 4.4.0.1 (2009/08/08) 追加
	// * @og.rev 5.7.0.4 (2013/11/29) listIdの絞込み
	// * @og.rev 7.4.4.0 (2021/06/30) openGionV8事前準備(GE54.FGNOML廃止)
	// *
	// * @param	queue		ExecQueueｵﾌﾞｼﾞｪｸﾄ
	// * @param	inErrMsg	ｴﾗｰﾒｯｾｰｼﾞ
	// */
	// private void sendMail( final ExecQueue queue, final String inErrMsg ) {

	// 	final String   host = HybsSystem.sys( "COMMON_MAIL_SERVER" );
	// 	final String   from = HybsSystem.sys( "ERROR_MAIL_FROM_USER" );
	// 	final String[] to = StringUtil.csv2Array( HybsSystem.sys( "ERROR_MAIL_TO_USERS" ) );
	// 	final String   match_txt = HybsSystem.sys( "REPORT_ERRMAIL_REGEX" ); // 5.7.0.4 (2013/11/29)
	// 	if( host != null && from != null && to.length > 0 ) {
	// 		if( match_txt == null || match_txt.isEmpty()
	// 				|| queue.getListId() == null || queue.getListId().isEmpty()
	// 				|| queue.getListId().matches( match_txt )){	// 5.7.0.4 (2013/11/29)
	// 			// 5.7.0.4 (2013/11/29) listid追加
	// 			final String subject = "SYSTEM_ID=[" + queue.getSystemId() + "] , YKNO=[" + queue.getYkno() + "] , "
	// 						   + "THREAD_ID=[" + queue.getThreadId() + "] , DMN_HOST=[" + HybsSystem.HOST_NAME + "]"
	// 						   + "LISTID=["+ queue.getListId() + "]";
	// 			try {
	// 				final MailTX tx = new MailTX( host );
	// 				tx.setFrom( from );
	// 				tx.setTo( to );
	// 				tx.setSubject( "帳票ｴﾗｰ：" + subject );
	// 				tx.setMessage( inErrMsg );
	// 				tx.sendmail();
	// 			}
	// 			catch( final Throwable ex ) {
	// 				final String errMsg = "ｴﾗｰ時ﾒｰﾙ送信に失敗しました｡" + CR
	// 							+ " SUBJECT:" + subject					+ CR
	// 							+ " HOST:" + host						+ CR
	// 							+ " FROM:" + from						+ CR
	// 							+ " TO:"   + Arrays.toString( to )		+ CR
	// 							+ ex.getMessage();		// 5.1.8.0 (2010/07/01) errMsg 修正
	// 				LogWriter.log( errMsg );
	// 				LogWriter.log( ex );
	// 			}
	// 		}
	// 	}
	// }

	/**
	 * 帳票明細ﾃﾞｰﾀを帳票ﾚｲｱｳﾄﾃｰﾌﾞﾙに従って分割し､その結果をDBTableModelとして
	 * 生成します｡
	 * ﾃﾞｰﾀの分割は､ﾊﾞｲﾄ数ﾍﾞｰｽで行われるため､ｴﾝｺｰﾄﾞを正しく指定する必要があります｡
	 * ｴﾝｺｰﾄﾞ指定は､ｼｽﾃﾑﾘｿｰｽのDB_ENCODEで指定します｡
	 *
	 * ﾚｲｱｳﾄﾃｰﾌﾞﾙが存在しない場合､又は､帳票ﾃﾞｰﾀが存在しない場合､DBTableModelは
	 * nullで返されます｡
	 *
	 * @og.rev 6.9.0.2 (2018/02/13) GE51の検索順(order by)を追加します｡
	 */
	public static final class DBTableModelCreator {
//		// 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
//		// 5.2.0.0 (2010/09/01) Ver4互換ﾓｰﾄﾞ対応
//		private static final String CLM = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "COLUMN_NAME" : "CLM";
//		private static final String TEXT_DATA = HybsSystem.sysBool( "VER4_COMPATIBLE_MODE" ) ? "TEXT" : "TEXT_DATA";

		// 5.2.0.0 (2010/09/01) Ver4互換ﾓｰﾄﾞ対応
		// 5.4.4.3 (2012/02/09) FGUSE条件追加対応
		// 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
		private static final String SQL_SELECT_GE52 =
//			" select " + CLM + ", START_POS, USE_LENGTH"
			" select CLM, START_POS, USE_LENGTH"
			+ " from GE52"
			+ " where SYSTEM_ID = ?"
			+ " and LISTID = ?"
			+ " and KBTEXT = ?"
			+ " and FGJ = '1'"
			+ " and FGUSE = '1'" // 5.4.4.3
			+ " order by SEQ";

		// 5.2.0.0 (2010/09/01) Ver4互換ﾓｰﾄﾞ対応
		// 6.9.0.2 (2018/02/13) GE51の検索順(order by)を追加します｡
		// 6.9.5.0 (2018/04/23) VER4_COMPATIBLE_MODE 廃止
		private static final String SQL_SELECT_GE51 =
//			" select " + TEXT_DATA
			" select TEXT_DATA"
			+ " from GE51"
			+ " where SYSTEM_ID = ?"
			+ " and YKNO = ?"
			+ " and KBTEXT = ?"
			+ " and FGJ = '1'"
			+ " order by SYSTEM_ID,YKNO,EDNO" ;				// 6.9.0.2 (2018/02/13)

		private static final String ENCODE = HybsSystem.sys( "DB_ENCODE" );

		private final String systemId;
		private final String listId;
		private final String ykno;
		private final String kbtext;
		private final ResourceManager resource;

		private DBTableModel table	;

		/**
		 * ｺﾝｽﾄﾗｸﾀです｡
		 *
		 * @param sid ｼｽﾃﾑID
		 * @param lid 帳票ID
		 * @param yk 要求NO
		 * @param kt ﾃｷｽﾄ区分(H:ﾍｯﾀﾞｰ F:ﾌｯﾀｰ B:ﾎﾞﾃﾞｨｰ)
		 * @param res ﾘｿｰｽﾏﾈｰｼﾞｬｰ
		 */
		public DBTableModelCreator( final String sid, final String lid, final String yk, final String kt, final ResourceManager res ) {
			systemId	= sid;
			listId		= lid;
			ykno		= yk;
			kbtext		= kt;
			resource	= res;
			create();
		}

		/**
		 * 帳票ﾃﾞｰﾀをﾚｲｱｳﾄ定義に従い分割します｡
		 *
		 * @og.rev 5.5.5.1 (2012/08/07) ﾘｿｰｽ系DBID 付け忘れ対策
		 * @og.rev 5.9.3.1 (2015/12/18) SJIS-UTF変換時の波ﾀﾞｯｼｭ問題対応
		 */
		private void create() {
			final String[] ge52Where = new String[] { systemId, listId, kbtext } ;
			final String[][] ge52Vals = DBUtil.dbExecute( SQL_SELECT_GE52, ge52Where, APP_INFO, DBID );	// 5.5.5.1 (2012/08/07)
			if( ge52Vals == null || ge52Vals.length == 0 ) {
				return;
			}

			final String[] ge51Where = new String[] { systemId, ykno, kbtext } ;
			final String[][] ge51Vals = DBUtil.dbExecute( SQL_SELECT_GE51, ge51Where, APP_INFO, DBID );	// 5.5.5.1 (2012/08/07)
			if( ge51Vals == null || ge51Vals.length == 0 ) {
				return;
			}

			String[] clms = new String[ge52Vals.length];
			for( int i=0; i<ge52Vals.length; i++ ) {
				clms[i] = ge52Vals[i][0];
			}

			String[][] vals = new String[ge51Vals.length][ge52Vals.length];
			for( int i=0; i<ge51Vals.length; i++ ) {
				final byte[] bytes = StringUtil.makeByte( UnicodeCorrecter.correctToCP932( ge51Vals[i][0], ENCODE ), ENCODE ); // 5.9.3.1 (2015/12/18)
				for( int j=0; j<ge52Vals.length; j++ ) {
					final int strpos = Integer.parseInt( ge52Vals[j][1] ) - 1;	// 6.0.2.4 (2014/10/17) ﾒｿｯﾄﾞ間違い
					int len = Integer.parseInt( ge52Vals[j][2] );				// 6.0.2.4 (2014/10/17) ﾒｿｯﾄﾞ間違い
					if( strpos >= bytes.length ) {
						vals[i][j] = "";
					}
					else {
						if( strpos + len > bytes.length ) {
							len = bytes.length - strpos;
						}
						vals[i][j] = StringUtil.rTrim( StringUtil.makeString( bytes, strpos, len, ENCODE ) );
					}
				}
			}
			table = DBTableModelUtil.makeDBTable( clms, vals, resource );
		}

		/**
		 * 分割後のDBTableModelを返します｡
		 *
		 * @return 分割後のDBTableModel
		 */
		public DBTableModel getTable() {
			return table;
		}
	}
}
