/*
 * 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 org.opengion.fukurou.system.OgRuntimeException ;		// 6.4.2.0 (2016/01/29)
import java.io.File;

import org.opengion.hayabusa.db.DBTableModel;
import static org.opengion.fukurou.system.HybsConst.BUFFER_MIDDLE;	// 6.1.0.0 (2014/12/26) refactoring

/**
 * 帳票処理要求を管理するキューオブジェクトです。
 * このオブジェクトでは、帳票の定義及びデータと、処理中に発生したエラーメッセージを管理します。
 * また、このキューを生成したオブジェクトもこのオブジェクトにセットされます。
 *
 * @og.group 帳票システム
 *
 * @version  4.0
 * @author   Hiroki.Nakamura
 * @since    JDK1.6
 */
public class ExecQueue {

	/** 実行方法 {@value} */
	protected static final String OUT_ODS_ONLY		= "1";
	/** 実行方法 {@value} */
	protected static final String OUT_PRINT_ONLY	= "2";
	/** 実行方法 {@value} */
	protected static final String OUT_ODS_PRINT		= "3";
	/** 実行方法 {@value} */
	protected static final String OUT_ODS_PDF		= "P";
	/** 実行方法 {@value} */
	protected static final String OUT_ODS_PRINT_PDF	= "Q";
	/** 実行方法 {@value} */
	protected static final String OUT_ODS_EXCEL		= "E";
	/** 実行方法 {@value} */
	protected static final String OUT_ODS_ODS		= "S"; // 4.3.3.4 (2008/11/01) 追加
	/** 実行方法 {@value} */
	protected static final String IN_INPUT_ONLY		= "5";
	/** 実行方法 {@value} */
	protected static final String IN_EXEC_ONLY		= "6";
	/** 実行方法 {@value} */
	protected static final String IN_INPUT_EXEC		= "7";
	/** 実行方法 {@value} */
	protected static final String RFID_PRINT		= "A";
	/** 実行方法 {@value} */
	protected static final String RFID_ALLPRINT		= "B";
	/** 実行方法 {@value} */
	protected static final String RFID_ALLERASE		= "C";
	/** 実行方法 {@value} */
	protected static final String RFID_SEQERASE		= "D";

	// 5.9.0.0 (2015/09/04) CSV出力対応
	/** 実行方法 {@value} */
	protected static final String CSV_PRINT			= "G";
	/** 実行方法 {@value} */
	protected static final String CSV_PRINT_EXCEL	= "H";
	/** 実行方法 {@value} */
	protected static final String CSV_PRINT_PDF		= "I";
	/** 実行方法 {@value} */
	protected static final String CSV_PRINT_EXCEL2	= "J"; // 5.9.4.2 (2016/01/15) EXCEL2追加

	/** 最大シート数 {@value} */
	protected static final int MAX_SHEETS_PER_FILE	= 256; // 5.1.2.0 (2010/01/01)

	private String		ykno		;
	private String		systemId	;
	private DBTableModel body		;
	private DBTableModel header		;
	private DBTableModel footer		;
	private String		listId		;
	private String		pdfPasswd	;
	private String		lang		;
	private String		threadId	;
	private String		templateName;
	private String		outputType	;
	private String		printerName	;
	private String		outputName	;
	private boolean		fglocal		;
	private boolean		fgcut		;
	private QueueManager manager	;
	private String		prgdir		;		// 4.3.3.0 (2008/10/01) 板金RFID対応。
	private String		prgfile		;		// 4.3.3.0 (2008/10/01)
	private String		prtid		;		// 4.3.3.0 (2008/10/01)

	private String		grpid		;		// 5.9.2.2 (2015/11/20)
	private String		dmngrp		;		// 5.9.2.2 (2015/11/20)
	private int			pageCnt		;		// 5.1.2.0 (2010/01/01) 処理したページ数
	private int			rowCnt		;		// 5.1.2.0 (2010/01/01) 処理した行数
	private boolean		isDataEnd	;		// 5.1.2.0 (2010/01/01) 全データが処理されたか (メソッド名と同じ変数名変更)

	private boolean		useSheetName;		// 5.7.6.2 (2014/05/16) PAGEBREAKカラムの値を、シート名として使うかどうか。

	private final StringBuilder errMsg = new StringBuilder( BUFFER_MIDDLE );

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

	/**
	 * 要求NOをセットします。
	 *
	 * @param ykno 要求NO
	 */
	public void setYkno( final String ykno ) {
		this.ykno = ykno;
	}

	/**
	 * 要求NOを取得します。
	 *
	 * @return	要求NO
	 */
	public String getYkno() {
		return ykno;
	}

	/**
	 * システムIDをセットします。
	 *
	 * @param systemId システムID
	 */
	public void setSystemId( final String systemId ) {
		this.systemId = systemId;
	}

	/**
	 * システムIDを取得します。
	 *
	 * @return  StringシステムID
	 */
	public String getSystemId() {
		return systemId;
	}

	/**
	 * ボディー部分のDBTableModelをセットします。
	 *
	 * @param body DBTableModelオブジェクト
	 */
	public void setBody( final DBTableModel body ) {
		this.body = body;
	}

	/**
	 * ボディー部分のDBTableModelを取得します。
	 *
	 * @return	ボディー部分のDBTableModelオブジェクト
	 */
	public DBTableModel getBody() {
		return body;
	}

	/**
	 * ヘッダー部分のDBTableModelをセットします。
	 *
	 * @param header DBTableModelオブジェクト
	 */
	public void setHeader( final DBTableModel header ) {
		this.header = header;
	}

	/**
	 * ヘッダー部分のDBTableModelを取得します。
	 *
	 * @return	ヘッダー部分のDBTableModelオブジェクト
	 */
	public DBTableModel getHeader() {
		return header;
	}

	/**
	 * フッター部分のDBTableModelをセットします。
	 *
	 * @param footer DBTableModelオブジェクト
	 */
	public void setFooter( final DBTableModel footer ) {
		this.footer = footer;
	}

	/**
	 * フッター部分のDBTableModelを取得します。
	 *
	 * @return	フッター部分のDBTableModelオブジェクト
	 */
	public DBTableModel getFooter() {
		return footer;
	}

	/**
	 * 帳票IDをセットします。
	 *
	 * @param listId 帳票ID
	 */
	public void setListId( final String listId ) {
		this.listId = listId;
	}

	/**
	 * 帳票IDを取得します。
	 *
	 * @return 帳票ID
	 */
	public String getListId() {
		return listId;
	}

	/**
	 * PDFパスワードをセットします。
	 *
	 * @param pdfPasswd PDFパスワード
	 */
	public void setPdfPasswd( final String pdfPasswd ) {
		this.pdfPasswd = pdfPasswd;
	}

	/**
	 * PDFパスワードを取得します。
	 *
	 * @return PDFパスワード
	 */
	public String getPdfPasswd() {
		return pdfPasswd;
	}

	/**
	 * 言語をセットします。
	 *
	 * @param lang 言語
	 */
	public void setLang( final String lang ) {
		this.lang = lang;
	}

	/**
	 * 言語を取得します。
	 *
	 * @return 言語
	 */
	public String getLang() {
		return lang;
	}

	/**
	 * 雛形ファイル名をセットします。
	 *
	 * @param templateName 雛形ファイル名
	 */
	public void setTemplateName( final String templateName ) {
		this.templateName = templateName;
	}

	/**
	 * 雛形ファイル名を取得します。
	 *
	 * @return 帳票雛形ファイル名
	 */
	public String getTemplateName() {
		return templateName;
	}

	/**
	 * 実行方法をセットします。
	 *
	 * @param outputType 実行方法
	 */
	public void setOutputType( final String outputType ) {
		this.outputType = outputType;
	}

	/**
	 * 出力タイプを取得します。
	 *
	 * @return 出力タイプ
	 */
	public String getOutputType() {
		return outputType;
	}

	/**
	 * プリンター名をセットします。
	 *
	 * @param  printerName プリンター名
	 */
	public void setPrinterName( final String printerName ) {
		this.printerName = printerName;
	}

	/**
	 * プリンター名を取得します。
	 *
	 * @return プリンタ名
	 */
	public String getPrinterName() {
		return printerName;
	}

	/**
	 * 処理要求を処理するスレッドIDをセットします。
	 *
	 * @param threadId スレッドID
	 */
	public void setThreadId( final String threadId ) {
		this.threadId = threadId;
	}

	/**
	 * 処理要求を処理するスレッドIDを取得します。
	 *
	 * @return スレッドID
	 */
	public String getThreadId() {
		return threadId;
	}

	/**
	 * 出力ファイル名をセットします。
	 *
	 * @param outputName 出力ファイル名
	 */
	public void setOutputName( final String outputName ) {
		this.outputName = outputName;
	}

	/**
	 * 出力ファイル名を設定します。
	 * GE50に設定されていない場合は第四引数(要求番号)を利用する。
	 * その場合、タイプに応じた拡張子が自動設定される。
	 *
	 * ".xls" : OUT_ODS_EXCEL
	 * ".pdf" : OUT_ODS_PDF , OUT_ODS_PRINT_PDF
	 * ".ods" : OUT_ODS_ODS
	 * ".xml" : RFID_PRINT , RFID_ALLPRINT , RFID_ALLERASE , RFID_SEQERASE
	 * ".csv" : CSV_PINT , CSV_PRINT_EXCEL , CSV_PRINT_PDF
	 *
	 * @og.rev 4.3.3.4 (2008/11/01) ODS出力対応
	 * @og.rev 5.4.3.0 (2011/12/26) RFIDデフォルト対応
	 * @og.rev 5.4.4.1 (2012/02/03) RFID拡張子変更
	 * @og.rev 5.9.0.0 (2015/09/04) CSV対応
	 *
	 * @param	outputDir	出力ディレクトリ名
	 * @param	outputFile	出力ファイル名
	 * @param	type		タイプ
	 * @param	yokyu		要求番号(ファイル名が指定されていない場合のファイル名)
	 *
	 */
	public void setOutputName( final String outputDir, final String outputFile, final String type, final String yokyu ){
		final StringBuilder filePath = new StringBuilder( BUFFER_MIDDLE );
		filePath.append( outputDir ).append( File.separator );		// 6.0.2.5 (2014/10/31) char を append する。

		if( outputFile == null || outputFile.isEmpty() ){ // ファイル名が指定されていない場合は要求番号を利用する。
			if( OUT_ODS_EXCEL.equals( type ) ){
				filePath.append( yokyu );
				filePath.append( ".xls" );
			}
			else if( OUT_ODS_PDF.equals( type ) || OUT_ODS_PRINT_PDF.equals( type ) ){
				filePath.append( yokyu );
				filePath.append( ".pdf" );
			}
			// 4.3.3.4 (2008/11/01) 追加
			else if( OUT_ODS_ODS.equals ( type ) ){
				filePath.append( yokyu );
				filePath.append( ".ods" );
			}
			// 5.4.3.0 (2011/12/26) 追加
			// 5.4.4.2 (2012/02/03) .txtではなく.xml
			else if( ExecQueue.RFID_PRINT.equals( type ) || ExecQueue.RFID_ALLPRINT.equals( type )
					|| ExecQueue.RFID_ALLERASE.equals( type ) || ExecQueue.RFID_SEQERASE.equals( type ) ) {
				filePath.append( yokyu );
				filePath.append( ".xml" ); //txt-xml
			}
			// 5.9.0.0 (2015/09/04) 追加
			// 5.9.4.2 (2016/01/13) EXCEL2追加
			else if( ExecQueue.CSV_PRINT.equals( type ) || ExecQueue.CSV_PRINT_EXCEL.equals( type )
					|| ExecQueue.CSV_PRINT_PDF.equals( type ) || ExecQueue.CSV_PRINT_EXCEL2.equals( type ) ) {
				filePath.append( yokyu );
				filePath.append( ".csv" );
			}
		}
		else {
			filePath.append( outputFile );
		}

		this.outputName = filePath.toString();
	}

	/**
	 * 出力ファイル名を取得します。
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) 256シートを超える場合に対応。2ファイル目以降は、_1、_2･･･をファイル名の後ろにつける
	 * @og.rev 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
	 *
	 * @return 出力先ファイル名
	 * @og.rtnNotNull
	 */
	public String getOutputName() {
		// 6.3.9.0 (2015/11/06) コンストラクタで初期化されていないフィールドを null チェックなしで利用している(findbugs)
		if( outputName == null ) {
			final String errMsg = "#setOutputName(String) または、#setOutputName(String,String,String,String)を先に実行しておいてください。" ;
			throw new OgRuntimeException( errMsg );
		}

		if( pageCnt <= MAX_SHEETS_PER_FILE ) {
			return outputName;
		}
		else {
			final StringBuilder fileName = new StringBuilder( BUFFER_MIDDLE );

			final int idx = outputName.lastIndexOf( '.' );
			final String name = outputName.substring( 0, idx );
			final String suffix = outputName.substring( idx );
			final int addNo = (int)Math.ceil( (double)pageCnt/(double)MAX_SHEETS_PER_FILE ) - 1;

			fileName.append( name ).append( '_' ).append( addNo ).append( suffix );		// 6.0.2.5 (2014/10/31) char を append する。

			return fileName.toString();
		}
	}

	/**
	 * 実行ファイルディレクトリを指定します。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) 板金RFID対応
	 *
	 * @param dir ディレクトリ
	 */
	public void setPrgDir( final String dir ) {
		this.prgdir = dir;
	}

	/**
	 * 実行ファイルディレクトリを取得します。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) 板金RFID対応
	 *
	 * @return プログラムディレクトリ
	 */
	public String getPrgDir() {
		return prgdir;
	}

	/**
	 * 実行ファイル名をセットします。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) 板金RFID対応
	 * @param	file	ファイル名
	 */
	public void setPrgFile( final String file ) {
		this.prgfile = file;
	}

	/**
	 * 実行ファイル名を取得します。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) 板金RFID対応
	 *
	 * @return プログラムファイル名
	 */
	public String getPrgFile() {
		return prgfile;
	}

	/**
	 * プリンタIDをセットします。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) 板金RFID対応
	 * @param	id	プリンタID
	 */
	public void setPrtId( final String id ) {
		this.prtid = id;
	}

	/**
	 * プリンタIDを取得します。
	 *
	 * @og.rev 4.3.3.0 (2008/10/01) 板金RFID対応
	 *
	 * @return プリンタID
	 */
	public String getPrtId() {
		return prtid;
	}

	/**
	 * グループIDをセットします。
	 *
	 * @og.rev 5.9.2.2 (2015/11/20) 
	 *
	 * @param	id	グループID
	 */
	public void setGrpId( final String id ) {
		this.grpid = id;
	}

	/**
	 * グループIDを取得します。
	 *
	 * @og.rev 5.9.2.2 (2015/11/20) 
	 *
	 * @return グループID
	 */
	public String getGrpId() {
		return grpid;
	}

	/**
	 * デーモングループをセットします。
	 *
	 * @og.rev 5.9.2.2 (2015/11/20) 
	 *
	 * @param	name	デーモングループ
	 */
	public void setDmnGrp( final String name ) {
		this.dmngrp = name;
	}

	/**
	 * デーモングループを取得します。
	 *
	 * @og.rev 5.9.2.2 (2015/11/20) 
	 *
	 * @return デーモングループ
	 */
	public String getDmnGrp() {
		return dmngrp;
	}

	/**
	 * ローカルリソース使用フラグをセットします(初期値:false)。
	 *
	 * @param	fglocal	ローカルリソース使用フラグ[true:使用する/false:使用しない]
	 */
	public void setFglocal( final boolean fglocal ) {
		this.fglocal = fglocal;
	}

	/**
	 * ローカルリソース使用フラグを取得します。
	 *
	 * @return ロールリソース使用フラグ[true:使用する/false:使用しない]
	 */
	public boolean isFglocal() {
		return fglocal;
	}

	/**
	 * ページエンドカットフラグをセットします(初期値:false)。
	 *
	 * @param fgcut ページエンドカットの使用可否[true:使用/false:通常]
	 */
	public void setFgcut( final boolean fgcut ) {
		this.fgcut = fgcut;
	}

	/**
	 * ページエンドカットフラグを取得します。
	 *
	 * @return ページエンドカットフラグ
	 */
	public boolean isFgcut() {
		return fgcut;
	}

	/**
	 * PAGEBREAKカラムの値を、シート名として使うかどうかをセットします(初期値:false)。
	 *
	 * @og.rev 5.7.6.2 (2014/05/16) 新規追加
	 *
	 * @param useSheetName PAGEBREAKカラムのシート名使用可否[true:使用/false:使用しない]
	 */
	public void setUseSheetName( final boolean useSheetName ) {
		this.useSheetName = useSheetName;
	}

	/**
	 * PAGEBREAKカラムの値を、シート名として使うかどうかを取得します。
	 *
	 * @og.rev 5.7.6.2 (2014/05/16) 新規追加
	 *
	 * @return PAGEBREAKカラムのシート名使用可否[true:使用/false:使用しない]
	 */
	public boolean isUseSheetName() {
		return useSheetName;
	}

	/**
	 * キューマネージャーをセットします。
	 *
	 * @param manager キューマネージャー
	 */
	public void setManager( final QueueManager manager ) {
		this.manager = manager;
	}

	/**
	 * 帳票処理データをセットします。
	 * 既にテーブルモデルがセットされている場合は、再セットしません。
	 *
	 */
	public void setData() {
		if( body == null && manager != null ) {
			manager.set( this );
		}
	}

	/**
	 * キューを実行中の状態に更新します。
	 *
	 */
	public void setExecute() {
		if( manager != null ) {
			manager.execute( this );
		}
	}

	/**
	 * キューを完了済の状態に更新します。
	 *
	 */
	public void setComplete() {
		if( manager != null ) {
			manager.complete( this );
		}
	}

	/**
	 * キューをエラーの状態に更新します。
	 */
	public void setError() {
		if( manager != null ) {
			manager.error( this );
		}
	}

	/**
	 * エラーメッセージをセットします。
	 *
	 * @param msg エラーメッセージ
	 */
	public void addMsg( final String msg ) {
		errMsg.append( msg );
	}

	/**
	 * エラーメッセージを取得します。
	 *
	 * @return エラーメッセージ
	 * @og.rtnNotNull
	 */
	public String getMsg() {
		return errMsg.toString();
	}

	/**
	 * 処理したページ数を引数の分だけカウントアップします。
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) 新規追加
	 *
	 * @param pgs カウントアップするページ数
	 */
	public void addExecPageCnt( final int pgs ) {
		pageCnt += pgs;
	}

	/**
	 * 処理したページ数を返します。
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) 新規追加
	 *
	 * @return 処理したページ数
	 */
	public int getExecPagesCnt() {
		return pageCnt;
	}

	/**
	 * 処理した行数をセットします。
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) 新規追加
	 *
	 * @param rws 処理した行数
	 */
	public void setExecRowCnt( final int rws ) {
		rowCnt = rws;
	}

	/**
	 * 処理した行数を返します。
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) 新規追加
	 *
	 * @return 処理した行数
	 */
	public int getExecRowCnt() {
		return rowCnt;
	}

	/**
	 * 全ての行が処理されたかをセットします(初期値:false)。
	 *
	 * これは、処理結果が、256シートを超えていた場合、再度残りのデータについて
	 * 処理を行うかどうかの判定するために、利用します。
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) 新規追加
	 *
	 * @param flag 全ての行が処理されたか
	 */
	public void setEnd( final boolean flag ) {
		isDataEnd = flag;
	}

	/**
	 * 全ての行が処理されているかを返します。
	 *
	 * これは、処理結果が、256シートを超えていた場合、再度残りのデータについて
	 * 処理を行うかどうかの判定するために、利用します。
	 *
	 * @og.rev 5.1.2.0 (2010/01/01) 新規追加
	 *
	 * @return 全ての行が処理されたか
	 */
	public boolean isEnd() {
		return isDataEnd;
	}
}
