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

import org.opengion.hayabusa.common.HybsSystem;
import org.opengion.hayabusa.common.HybsSystemException;
import org.opengion.hayabusa.db.DBTableModel;

/**
 * 画面から直接キューを作成するためのクラスです。
 * 各種設定値を直接指定することでDBのマスタ設定を行うことなく帳票出力を行います。
 * 現時点では、出力系の処理しか対応していません。
 *
 * ここで登録されたキューは、別スレッドで処理されるため、#create()メソッドを呼び出した後は、
 * #waitExec()メソッドを呼び出し、処理の終了に同期させる必要があります。
 * エラーが発生した場合は、HybsSystemExceptionを発生します。
 *
 * また、処理のタイムアウトは、システムリソースのREPORT_DAEMON_TIMEOUTで設定します。
 *
 * @og.group 帳票システム
 *
 * @version  4.0
 * @author   Hiroki.Nakamura
 * @since    JDK1.6
 */
public class QueueManager_DIRECT implements QueueManager {

	private final int timeout = HybsSystem.sysInt( "REPORT_DAEMON_TIMEOUT" );

	private static final String SYSTEM_ID = HybsSystem.sys( "SYSTEM_ID" );
	private static final Random RANDOM = new Random();

	private String listId		;
	private String outputName	;
	private String lang			;
	private String outputType	;
	private String templateName	;
	private String printerName	;
	private boolean fglocal		;
	private boolean fgcut		;
	private boolean useSheetName;	// 5.7.6.2 (2014/05/16) PAGEBREAKカラムの値を、シート名として使うかどうか。

	private DBTableModel body	;
	private DBTableModel header	;
	private DBTableModel footer	;

	private boolean isEnd	;
	private String errMsg	;

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

	/**
	 * 帳票処理キューを作成します。
	 *
	 * @og.rev 5.1.6.0 (2010/05/01) 要求単位にスレッドを生成するようにします。
	 * @og.rev 5.7.6.2 (2014/05/16) PAGEBREAKカラムの値を、シート名として使うかどうかをセットします
	 */
	@Override	// QueueManager
	public void create() {
		final ExecQueue queue = new ExecQueue();
		queue.setSystemId( SYSTEM_ID );
		queue.setYkno( "DIRECT_" + Long.toString( RANDOM.nextLong() & 0x7fffffffffffffffL ) );
		queue.setListId( listId );
		queue.setLang( lang );
		queue.setOutputName( outputName );
		queue.setOutputType( outputType );
		// 5.1.6.0 (2010/05/01)
		queue.setThreadId( "DIRECT_" + Long.toString( RANDOM.nextLong() & 0x7fffffffffffffffL ) );
		queue.setTemplateName( templateName );
		queue.setPrinterName( printerName );
		queue.setFglocal( fglocal );
		queue.setFgcut( fgcut );
		queue.setUseSheetName( useSheetName );		// 5.7.6.2 (2014/05/16) PAGEBREAKカラムの値を、シート名として使うかどうかをセットします

		queue.setBody( body );
		queue.setHeader( header );
		queue.setFooter( footer );

		queue.setManager( this );

		// 5.1.6.0 (2010/05/01)
		ExecThreadManager.insertQueueOnNewThread( queue );
	}

	/**
	 * 帳票処理データをキューにセットします。
	 * 画面から発行する場合は、テーブルモデルを直接セットするので、
	 * ここでは何もしません。
	 *
	 * @param	queue	ExecQueueオブジェクト
	 */
	@Override	// QueueManager
	public void set( final ExecQueue queue ) {
		// 何もありません。(PMD エラー回避)
	}

	/**
	 * キューを実行中の状態に更新します。
	 * 画面から発行する場合は、実行中であることを知る必要がないため、
	 * ここでは何もしません。
	 *
	 * @param	queue	ExecQueueオブジェクト
	 */
	@Override	// QueueManager
	public void execute( final ExecQueue queue ) {
		// 何もありません。(PMD エラー回避)
	}

	/**
	 * キューを完了済の状態に更新します。
	 *
	 * @param	queue	ExecQueueオブジェクト
	 */
	@Override	// QueueManager
	public void complete( final ExecQueue queue ) {
		isEnd = true;
	}

	/**
	 * キューをエラーの状態に更新します。
	 *
	 * @param	queue	ExecQueueオブジェクト
	 */
	@Override	// QueueManager
	public void error( final ExecQueue queue ) {
		isEnd = true;
		errMsg = queue.getMsg();
	}

	/**
	 * 処理が完了してするまでスレッドを待ち状態にします。
	 * エラーが発生した場合は、例外が発生します。
	 * また、REPORT_DAEMON_TIMEOUTで指定された期間処理が終了しない場合は、
	 * タイムアウトエラーとなります。
	 *
	 */
	public void waitExec() {
		final long start = System.currentTimeMillis();
		while( true ) {
			if( isEnd ) {
				if( errMsg == null ) {
					break;
				}
				else {
					throw new HybsSystemException( errMsg );
				}
			}

			if( (int)(System.currentTimeMillis() - start) > timeout * 1000 ) {
				throw new HybsSystemException( "帳票処理でタイムアウトになりました" );
			}
			try {
				Thread.sleep( 100 );
			}
			catch( final InterruptedException ex ) { }
		}
	}

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

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

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

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

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

	/**
	 * 出力先のプリンタ名を設定します。
	 *
	 * @param	printerName	出力先のプリンタ名
	 */
	public final void setPrinterName( final String printerName ) {
		this.printerName = printerName;
	}

	/**
	 * ローカルリソースの使用可否を設定します。
	 *
	 * @param fglocal 使用可否[true/false]
	 */
	public void setFglocal( final boolean fglocal ) {
		this.fglocal = fglocal;
	}

	/**
	 * ページエンドカットを行うかを設定します。
	 *
	 * @param fgcut ページエンドカットの使用可否[true:使用/false:通常]
	 */
	public void setFgcut( final boolean fgcut ) {
		this.fgcut = 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;
	}

	/**
	 * ボディーのテーブルモデルを設定します。
	 *
	 * @param body DBTableModelオブジェクト
	 */
	public void setBody( final DBTableModel body ) {
		this.body = body;
	}

	/**
	 * ヘッダーのテーブルモデルを設定します。
	 *
	 * @param header DBTableModelオブジェクト
	 */
	public void setHeader( final DBTableModel header ) {
		this.header = header;
	}

	/**
	 * フッターのテーブルモデルを設定します。
	 *
	 * @param footer DBTableModelオブジェクト
	 */
	public void setFooter( final DBTableModel footer ) {
		this.footer = footer;
	}
}
