/**
 * blancoDb-Excel2Xml <br>
 * blancoDb-helperツール: Excelシートを読み込んでblancoDb用の定義XMLファイルを 自動生成するためのユーティリティプログラム
 * <br>
 * 
 * @author Tosiki Iga
 */

package blanco.db.helper;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.xml.transform.TransformerException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;

import org.xml.sax.InputSource;
import org.xml.sax.SAXNotRecognizedException;
import org.xml.sax.SAXNotSupportedException;

import blanco.commons.calc.parser.BlancoCalcParser;
import blanco.commons.calc.parser.block.BlancoCalcParserPropertyBlock;
import blanco.commons.calc.parser.block.BlancoCalcParserPropertyKey;
import blanco.commons.calc.parser.block.BlancoCalcParserTableBlock;
import blanco.commons.calc.parser.block.BlancoCalcParserTableColumn;
import blanco.commons.calc.parser.block.BlancoCalcParserValueMapping;
import blanco.db.BlancoDbConstants;

public abstract class BlancoDbExcel2Xml implements IBlancoDbProgress {
    private static final boolean IS_DEBUG = false;

    /**
     * 入力ディレクトリ
     */
    private File inDirectory = null;

    /**
     * 出力ディレクトリ
     */
    private File outDirectory = null;

    private BlancoDbExcel2Xml() {
    }

    /**
     * デフォルトでは、入力ディレクトリ[sql/excel] 出力ディレクトリ[sql/blanco] で処理を実施します。
     * 
     * @param args
     */
    public static final void main(String[] args) {
        new BlancoDbExcel2Xml(new File("sql/sql2k"), new File("sql/sql2k")) {
            public boolean progress(int progressCurrent, int progressTotal,
                    String progressItem) {
                return true;
            }
        }.processAllFiles();
    }

    /**
     * 入力ディレクトリ、出力ディレクトリ指定を行いながらインスタンスを生成します。
     * 
     * @param inDirectory
     *            入力ディレクトリ
     * @param outDirectory
     *            出力ディレクトリ
     */
    public BlancoDbExcel2Xml(File inDirectory, File outDirectory) {
        this.inDirectory = inDirectory;
        this.outDirectory = outDirectory;
    }

    /**
     * 入力ディレクトリにあるすべてのxlsファイルを処理します
     */
    public void processAllFiles() {
        System.out.println(BlancoDbConstants.PRODUCT_NAME + " ("
                + BlancoDbConstants.VERSION + ") SQL設定ファイルをXML中間ファイルに変換: 開始.");

        if (outDirectory.exists() == false) {
            outDirectory.mkdirs();
        }
        File[] files = inDirectory.listFiles();
        if (files == null) {
            System.out.println("フォルダ[" + inDirectory.getAbsolutePath()
                    + "]には1件もファイルが見つかりませんでした.");
            return;
        }
        for (int index = 0; index < files.length; index++) {
            if (files[index].getName().endsWith(".xls")) {
                if (progress(index + 1, files.length, files[index].getName()) == false) {
                    break;
                }

                process(files[index]);
            }
        }
        System.out.println("SQL設定ファイルをXML中間ファイルに変換: 終了.");
    }

    /**
     * 指定のExcel設定ファイルを処理します。
     * 
     * @param blancoDbSettingFile
     */
    public void process(File blancoDbSettingFile) {
        System.out
                .println("blancoDbの設定ファイル ["
                        + blancoDbSettingFile.getAbsolutePath()
                        + "] (Excelブック)を処理します.");

        // try {
        // workbook = Workbook.getWorkbook(blancoDbSettingFile);
        // } catch (BiffException ex) {
        // System.err.println("予期せぬ例外.指定のExcelブック読込に失敗しました.データ形式が不正です.:"
        // + ex.toString());
        // return;
        // } catch (IOException ex) {
        // System.err.println("予期せぬ例外.指定のExcelブック読込に失敗しました.:" + ex.toString());
        // return;
        // }

        BlancoCalcParserPropertyBlock blockItem = new BlancoCalcParserPropertyBlock(
                "attribute");
        blockItem.setStartString(new String[] { "業務", "領域" });
        blockItem
                .setValueMapping(new BlancoCalcParserValueMapping[] {
                        new BlancoCalcParserValueMapping(new String[] { "○",
                                "あり" }, "true"),
                        new BlancoCalcParserValueMapping(new String[] { "なし" },
                                "false"),
                        new BlancoCalcParserValueMapping(
                                new String[] { "検索型" }, "iterator"),
                        new BlancoCalcParserValueMapping(
                                new String[] { "実行型" }, "invoker"),
                        new BlancoCalcParserValueMapping(
                                new String[] { "必ず１件処理" }, "true"),
                        new BlancoCalcParserValueMapping(
                                new String[] { "複数件(0を含む)" }, "false"),
                        new BlancoCalcParserValueMapping(new String[] {
                                "FORWARD_ONLY", "なし" }, "forward_only"),
                        new BlancoCalcParserValueMapping(new String[] {
                                "INSENSITIVE", "あり" }, "insensitive"),
                        new BlancoCalcParserValueMapping(
                                new String[] { "SENSITIVE" }, "sensitive") });

        BlancoCalcParserPropertyKey item = new BlancoCalcParserPropertyKey(
                "gamen-id", new String[] { "画面ID" });
        item.setSearchRangeX(4);
        blockItem.add(item);

        item = new BlancoCalcParserPropertyKey("name", new String[] { "クエリ名" });
        item.setSearchRangeX(4);
        blockItem.add(item);

        item = new BlancoCalcParserPropertyKey("query-type",
                new String[] { "SQLタイプ" });
        item.setSearchRangeX(8);
        blockItem.add(item);

        item = new BlancoCalcParserPropertyKey("single",
                new String[] { "期待する処理件数" });
        item.setSearchRangeX(8);
        blockItem.add(item);

        item = new BlancoCalcParserPropertyKey("scroll", new String[] {
                "スクロール属性", "カーソル属性" });
        item.setSearchRangeX(8);
        blockItem.add(item);

        item = new BlancoCalcParserPropertyKey("updatable",
                new String[] { "更新可能属性" });
        item.setSearchRangeX(8);
        blockItem.add(item);

        BlancoCalcParser parser = new BlancoCalcParser();
        parser.add(blockItem);

        // 別のブロック
        BlancoCalcParserTableBlock iteblockItem = new BlancoCalcParserTableBlock(
                "parameters");
        iteblockItem.setStartString(new String[] { "SQL入力パラメータ", "パラメータ定義" });
        iteblockItem.setSearchRangeForTitleY(2);
        iteblockItem.setRowName("parameter");

        BlancoCalcParserTableColumn iteitem = new BlancoCalcParserTableColumn(
                "name", new String[] { "パラメータID" });
        iteblockItem.add(iteitem);

        iteitem = new BlancoCalcParserTableColumn("type",
                new String[] { "タイプ" });
        iteblockItem.add(iteitem);

        iteitem = new BlancoCalcParserTableColumn("パラメータ名",
                new String[] { "パラメータ名" });
        iteblockItem.add(iteitem);

        parser.add(iteblockItem);

        // 別のブロック
        iteblockItem = new BlancoCalcParserTableBlock("query");
        iteblockItem.setStartString(new String[] { "SQL文" });
        iteblockItem.setEndString(new String[] { "SQLエリア終了" });
        iteblockItem.setSearchRangeForTitleY(1);
        iteblockItem.setSearchRangeY(100);
        iteitem = new BlancoCalcParserTableColumn("query-line",
                new String[] { "SQL文" });
        iteblockItem.add(iteitem);
        parser.add(iteblockItem);

        SAXSource source = new SAXSource(parser, new InputSource(
                blancoDbSettingFile.getAbsolutePath()));

        // parser.chainContentHandlerStream(new BlancoDbExcelContentHandler(
        // new SystemOutContentHandler()));
        parser.chainContentHandlerStream(new BlancoDbExcelContentHandler());

        OutputStream outStream = null;
        try {
            // ルートノード名を指定。
            parser.setProperty(BlancoCalcParser.URI_PROPERTY_NAME_WORKBOOK,
                    "blanco-db");
            outStream = new BufferedOutputStream(new FileOutputStream(
                    outDirectory.getAbsolutePath()
                            + "/"
                            + blancoDbSettingFile.getName().replaceAll(".xls",
                                    ".xml")));
            BlancoCalcParser.getTransformer().transform(source,
                    new StreamResult(outStream));
            outStream.flush();
            outStream.close();
            outStream = null;
        } catch (TransformerException ex) {
            System.out.println("XMLドキュメント保存時に変換例外が発生しました.:" + ex.toString());
            ex.printStackTrace();
            return;
        } catch (IOException ex3) {
            System.out.println("XMLドキュメント保存時に入出力例外が発生しました.:" + ex3.toString());
            ex3.printStackTrace();
            return;
        } catch (SAXNotRecognizedException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        } catch (SAXNotSupportedException e) {
            // TODO 自動生成された catch ブロック
            e.printStackTrace();
        } finally {
            if (outStream != null) {
                try {
                    outStream.close();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }
    }
}