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

import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import com.jacob.com.ComThread;

import javax.print.PrintServiceLookup;
import javax.print.PrintService;

import java.io.File;

import org.opengion.fukurou.util.FileInfo;
import org.opengion.fukurou.util.StringUtil;
import static org.opengion.fukurou.util.HybsConst.CR;

/**
 * JACOB - Java COM Bridge を使用した、ユーティリティークラスです。
 *
 * JavaからのCOMオートメーションコンポーネント呼び出しを可能とする 
 * JAVA-COMブリッジです。COMライブラリのネイティブな呼び出しにJNIを使います。
 * JACOBは、32bitおよび64bitのJVMをサポートするX86およびx64環境で動作します。 
 * http://sourceforge.jp/projects/sfnet_jacob-project/  (日本語プロジェクト)
 * http://sourceforge.net/projects/jacob-project/       (本家)
 *
 * まずは、EXCEL 関連のみ用意しています。
 *
 * 設定：
 *    jacob-1.18-M2.zip をダウンロードし、
 *      ①jacob-1.18-M2-x64.dll または、jacob-1.18-M2-x86.dll を、
 *        Windowsのシステムディレクトリにコピーします。 （例：C:\Windows\System32）
 *      ②jacob.jar を、クラスパスに登録します。
 *        ここでは、名称を、jacob-1.18-M2.jar に変更し、jre\lib\ext にコピーしています。
 *
 * @og.rev 6.2.4.0 (2015/05/15) 新規作成
 * @og.group その他
 *
 * @version  6.0
 * @author   Kazuhiko Hasegawa
 * @since    JDK8.0,
 */
public final class JacobUtil {
	/** このプログラムのVERSION文字列を設定します。	{@value} */
	private static final String VERSION = "6.2.4.0 (2015/05/15)" ;

	/**
	 * すべてが staticメソッドなので、コンストラクタを呼び出さなくしておきます。
	 */
	private JacobUtil() {}

	/**
	 * Excelファイルを、別の名前（または、同じ名前）にコピーします。
	 *
	 * ファイルのコピーではなく、オープンして、セーブします。
	 * xlsxファイルで、ファイル形式が、おかしいケース(zipで開けない)場合に、
	 * このメソッドで開いてセーブすれば、正しい形式に直せます。
	 *
	 * セーブ先のファイルが既に存在した場合の警告は表示しません。
	 *
	 * @og.rev 6.2.4.0 (2015/05/15) 新規追加
	 *
	 * @param	inFile  入力ファイル
	 * @param	outFile 出力ファイル
	 */
	public static void copyExcel( final File inFile , final File outFile ) {
		final String inPath  = inFile.getAbsolutePath() ;
		final String outPath = outFile.getAbsolutePath() ;

		final ActiveXComponent excl = new ActiveXComponent( "Excel.Application" );
		try {
		//	excl.setProperty( "Visible",	   Variant.VT_TRUE  );		// 表示 ＯＮ
			excl.setProperty( "DisplayAlerts", Variant.VT_FALSE );		// 警告メッセージをON/OFF

			final Dispatch workbooks = excl.getProperty( "Workbooks" ).toDispatch();
			final Dispatch workbook = Dispatch.call( workbooks, "Open", inPath ).toDispatch();

			Dispatch.call( workbook, "SaveAs", outPath );
			Dispatch.call( workbook, "Close" , Variant.VT_FALSE );
		}
		catch ( Throwable th ) {
			final String errMsg = "ActiveXComponent Copy処理中にエラーが発生しました。" + CR
									+ th.getMessage() + CR
									+ " inFile=[" + inFile + "] , outFile=[" + outFile + "]" ;
			System.err.println( errMsg );
			System.err.println( StringUtil.ogStackTrace( th ) );
			throw new RuntimeException( errMsg,th );
		}
		finally {
			excl.invoke( "Quit", new Variant[] {} );
			ComThread.Release();
		}
	}

	/**
	 * Excelファイルを、PDFファイルに変換します。
	 *
	 * ファイルをオープンして、PDFでセーブします。
	 * 例えば、セーブ先のファイルが既に存在した場合、上書き許可のダイアログが
	 *
	 * @og.rev 6.2.4.0 (2015/05/15) 新規追加
	 *
	 * @param	inFile  入力ファイル
	 * @param	outPdf  出力PDFファイル
	 */
	public static void excel2PDF( final File inFile , final File outPdf ) {
		final String inPath  = inFile.getAbsolutePath() ;
		final String outPath = outPdf.getAbsolutePath() ;

		final ActiveXComponent excl = new ActiveXComponent( "Excel.Application" );
		try {
		//	excl.setProperty( "Visible",	   Variant.VT_TRUE  );		// 表示 ＯＮ
			excl.setProperty( "DisplayAlerts", Variant.VT_FALSE );		// 警告メッセージをON/OFF

			final Dispatch workbooks = excl.getProperty( "Workbooks" ).toDispatch();
			final Dispatch workbook = Dispatch.call( workbooks, "Open", inPath ).toDispatch();

			Dispatch.call( workbook, "SaveAs", outPath, new Variant(57) );
			Dispatch.call( workbook, "Close" , Variant.VT_FALSE );
		}
		catch ( Throwable th ) {
			final String errMsg = "ActiveXComponent PDF変換処理中にエラーが発生しました。" + CR
									+ th.getMessage() + CR
									+ " inFile=[" + inFile + "] , outPdf=[" + outPdf + "]" ;
			System.err.println( errMsg );
			System.err.println( StringUtil.ogStackTrace( th ) );
			throw new RuntimeException( errMsg,th );
		}
		finally {
			excl.invoke( "Quit", new Variant[] {} );
			ComThread.Release();
		}
	}

	/**
	 * プリンター名一覧を返します。
	 *
	 * Jacobとは関係ありませんが、印刷する場合のプリンタ名を取得するのに使います。
	 * 
	 * @og.rev 6.2.4.0 (2015/05/15) 新規追加
	 *
	 * @return	プリンター名一覧
	 * @og.rtnNotNull
	 */
	public static String[] getPrinters() {

		final PrintService[] service = PrintServiceLookup.lookupPrintServices( null,null );

		final String[] names = new String[service.length] ;
		for( int i=0; i<service.length; i++ ) {
			names[i] = service[i].getName() ;
		}

		return names ;
	}

	/**
	 * アプリケーションのサンプルです。
	 *
	 * 入力ファイル名 は必須で、第一引数固定です。
	 * 第二引数は、出力ファイル名で、無ければ、第一引数と同じファイル名で、上書き保存されます。
	 * 出力ファイル名の拡張子を、PDF に指定すれば、PDF 変換を行います。
	 *
	 * Usage: java org.opengion.fukurou.model.JacobUtil 入力ファイル名 [出力ファイル名]
	 *
	 * @og.rev 6.2.4.0 (2015/05/15) 新規追加
	 *
	 * @param	args	コマンド引数配列
	 */
	public static void main( final String[] args ) {
		final String usageMsg = "Usage: java org.opengion.fukurou.model.JacobUtil 入力ファイル名 [出力ファイル名]" ;
		if( args.length == 0 ) {
			System.err.println( usageMsg );
			return ;
		}

		final File inFile  = new File( args[0] );
		final File outFile = args.length == 1 ? inFile : new File( args[1] );

		if( FileInfo.isSUFIX( outFile,"pdf" ) ) {
			JacobUtil.excel2PDF( inFile , outFile );
		}
		else {
			JacobUtil.copyExcel( inFile , outFile );
		}
	}
}
