/*
 * このソースコードは blanco Frameworkによって自動生成されています。
 * blancoServiceのための変換処理を定義します。
 */
package blanco.service;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.xml.transform.TransformerException;

import blanco.commons.calc.parser.BlancoCalcParser;

/**
 * blancoServiceのための変換処理を定義します。
 */
public class BlancoServiceMeta2Xml {
    /**
     * ExcelファイルのストリームをXMLファイルのストリームに変換します。
     *
     * 定義ファイルは内部的にパスを保持しています。
     *
     * @param inStreamMetaSource メタファイルの入力ストリーム。
     * @param outStreamTarget XMLファイルの出力ストリーム。
     * @throws IOException 入出力例外が発生した場合。
     * @throws TransformerException XML変換例外が発生した場合。
     */
    public void process(final InputStream inStreamMetaSource, final OutputStream outStreamTarget) throws IOException, TransformerException {
        if (inStreamMetaSource == null) {
            throw new IllegalArgumentException("BlancoServiceMeta2Xml: Invalid argument: inStreamMetaSource is null.");
        }
        if (outStreamTarget == null) {
            throw new IllegalArgumentException("BlancoServiceMeta2Xml: Invalid argument: outStreamTarget is null.");
        }

        InputStream inStreamDef = null;
        try {
            // このクラス自身とおなじクラスローダからXML設定ファイルのロードをおこないます。
            final InputStream meta2xmlStream = getClass().getClassLoader().getResourceAsStream("blanco/service/BlancoServiceMeta2Xml.xml");
            if (meta2xmlStream == null) {
                throw new IllegalArgumentException("BlancoServiceMeta2Xml: リソース[blanco/service/BlancoServiceMeta2Xml.xml]の取得に失敗しました.");
            }
            inStreamDef = new BufferedInputStream(meta2xmlStream);
            new BlancoCalcParser().process(inStreamDef, inStreamMetaSource, outStreamTarget);
        } finally {
            if (inStreamDef != null) {
                inStreamDef.close();
            }
        }
    }

    /**
     * ExcelファイルをXMLファイルに変換します。
     *
     * @param fileMeta メタファイルの入力ファイル。
     * @param fileOutput XMLファイルの出力。
     * @throws IOException 入出力例外が発生した場合。
     * @throws TransformerException XML変換例外が発生した場合。
     */
    public void process(final File fileMeta, final File fileOutput) throws IOException, TransformerException {
        if (fileMeta == null) {
            throw new IllegalArgumentException("BlancoServiceMeta2Xml: Invalid argument: fileMeta is null.");
        }
        if (fileOutput == null) {
            throw new IllegalArgumentException("BlancoServiceMeta2Xml: Invalid argument: fileOutput is null.");
        }
        if (fileMeta.exists() == false) {
            throw new IllegalArgumentException("BlancoServiceMeta2Xml: Invalid argument: file file [" + fileMeta.getAbsolutePath() + "] not found.");
        }

        InputStream inStream = null;
        OutputStream outStream = null;
        try {
            inStream = new BufferedInputStream(new FileInputStream(fileMeta));
            outStream = new BufferedOutputStream(new FileOutputStream(fileOutput));

            // ストリームの準備ができたので、実際の処理をおこないます。
            process(inStream, outStream);

            outStream.flush();
        } finally {
            if (inStream != null) {
                inStream.close();
            }
            if (outStream != null) {
                outStream.close();
            }
        }
    }

    /**
     * 指定ディレクトリ内のExcelファイルをXMLファイルに変換します。
     *
     * 指定されたフォルダ内の拡張子[.xls]のファイルを処理します。<br>
     * 処理したデータは もとのファイル名に拡張子[.xml]を付与したファイルへ保存します。
     *
     * @param fileMetadir メタファイルが格納されている入力ディレクトリ。
     * @param targetDirectory 出力ディレクトリ。
     * @throws IOException 入出力例外が発生した場合。
     * @throws TransformerException XML変換例外が発生した場合。
     */
    public void processDirectory(final File fileMetadir, final String targetDirectory) throws IOException, TransformerException {
        if (fileMetadir == null) {
            throw new IllegalArgumentException("BlancoServiceMeta2Xml: Invalid argument: fileMetadir is null.");
        }
        if (targetDirectory == null) {
            throw new IllegalArgumentException("BlancoServiceMeta2Xml: Invalid argument: targetDirectory is null.");
        }
        if (fileMetadir.exists() == false) {
            throw new IllegalArgumentException("BlancoServiceMeta2Xml: Invalid argument: file [" + fileMetadir.getAbsolutePath() + "] not found.");
        }
        final File fileTargetDirectory = new File(targetDirectory);
        if (fileTargetDirectory.exists() == false) {
            // 出力先ディレクトリが存在しないので、事前に作成します。
            fileTargetDirectory.mkdirs();
        }

        // 指定されたディレクトリのファイル一覧を取得します。
        final File[] fileMeta = fileMetadir.listFiles();
        if (fileMeta == null) {
            throw new IllegalArgumentException("BlancoMeta2XmlProcessMeta2Xml: list directory [" + fileMetadir.getAbsolutePath() + "] is failed.");
        }
        for (int index = 0; index < fileMeta.length; index++) {
            if (fileMeta[index].getName().endsWith(".xls") == false) {
                // ファイルの拡張子が処理すべきものとは異なるため処理をスキップします。。
                continue;
            }

            if (progress(index + 1, fileMeta.length, fileMeta[index].getName()) == false) {
                // 進捗表示から処理中断の指示が来たので、処理中断します。
                break;
            }

            try {
                process(fileMeta[index], new File(targetDirectory + "/" + fileMeta[index].getName() + ".xml"));
            } catch (Exception ex) {
                ex.printStackTrace();
                throw new IllegalArgumentException("BlancoServiceMeta2Xml: Exception occurs during processing the file [" + fileMeta[index].getAbsolutePath() + "]. " + ex.toString());
            }
        }
    }

    /**
     * 処理の進捗を示します。
     *
     * 進捗表示をさせたい場合には継承して処理を作りこみます。
     *
     * @param progressCurrent 現在処理している件数の番号。
     * @param progressTotal 総処理件数。
     * @param progressItem 処理しているアイテム名。
     * @return 処理を続行してよいかどうか。falseなら処理中断。
     */
    protected boolean progress(final int progressCurrent, final int progressTotal, final String progressItem) {
        // 常に処理続行を示す true を戻します。
        return true;
    }
}
