/*
 * blanco Framework
 * Copyright (C) 2004-2005 IGA Tosiki
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 */
package blanco.doclisting;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;

import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import blanco.commons.util.BlancoNameUtil;
import blanco.commons.util.BlancoXmlUtil;
import blanco.doclisting.resourcebundle.BlancoDocListingResourceBundle;
import blanco.opendocument.AbstractZipEditor;
import blanco.opendocument.BlancoOpenDocumentUtil;
import blanco.uno.BlancoUnoConverter;

/**
 * 集約済みの中間XMLファイルからレポートを作成します。
 * 
 * @author IGA Tosiki
 */
public class BlancoDocListingCombinedXml2Report {
    private final BlancoDocListingResourceBundle bundle = new BlancoDocListingResourceBundle();

    private static final boolean IS_DEBUG = false;

    /**
     * 一連の処理を行います。<br>
     * ※前提条件：OpenOffice.orgは既に外側で起動されている必要があります。
     * ※なお、現時点では、CombinedXmlを利用せずに、ディレクトリを走査して一覧を作成しています。
     * 
     * @param fileInputDir
     *            入力ディレクトリ。
     * @param fileOutputDir
     *            出力ディレクトリ。
     * @param xmlMetaSourceFile
     *            XMLメタ情報ソースファイル。
     * @param sourceMetaTemplateDirectory
     *            テンプレートディレクトリ。
     */
    public void process(final File fileInputDir, final File fileOutputDir,
            final File xmlMetaSourceFile, final File sourceMetaTemplateDirectory) {
        final Element documentElementDocListing = BlancoDocListingUtil
                .parseXmlDocument(xmlMetaSourceFile);
        // blancoDocListingのノードを取得します。
        final NodeList nodeListDocListingRoot = documentElementDocListing
                .getElementsByTagName("blancodoclisting-list");
        final NodeList nodeListDocListing = ((Element) nodeListDocListingRoot
                .item(0)).getElementsByTagName("doclisting");
        for (int indexNodeList = 0; indexNodeList < nodeListDocListing
                .getLength(); indexNodeList++) {
            final ArrayList listDocument = new ArrayList();

            final Element eleDocListingList = (Element) nodeListDocListing
                    .item(indexNodeList);
            final String inputFile = BlancoXmlUtil.getTextContent(
                    eleDocListingList, "inputFile");
            if (inputFile == null) {
                continue;
            }

            final String rootElementName = BlancoXmlUtil.getTextContent(
                    eleDocListingList, "rootElementName");
            final String elementNameList = BlancoXmlUtil.getTextContent(
                    eleDocListingList, "elementNameList");
            final String templateFileName = BlancoXmlUtil.getTextContent(
                    eleDocListingList, "templateFileName");

            if (IS_DEBUG) {
                System.out.println("ルートエレメント名[" + rootElementName + "]を処理します");
            }

            final File fileInputFile = new File(fileInputDir.getAbsolutePath()
                    + "/" + inputFile);
            if (fileInputFile.exists() == false) {
                // 中間ファイルがありません。
                if (IS_DEBUG) {
                    System.out.println("一覧中間ファイル["
                            + fileInputFile.getAbsolutePath() + "]が見つかりません。");
                }
                continue;
            }

            if (IS_DEBUG) {
                System.out.println("一覧中間ファイル["
                        + fileInputFile.getAbsolutePath() + "]を処理します。");
            }

            parserXml(fileInputFile, listDocument, rootElementName,
                    elementNameList);

            try {
                outputDocListing(listDocument, elementNameList,
                        sourceMetaTemplateDirectory, templateFileName,
                        fileInputDir, fileOutputDir);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * XMLをパースします。
     * 
     * @param fileRead
     * @param listDocument
     * @param rootElementName
     * @param elementNameList
     */
    private void parserXml(final File fileRead, final ArrayList listDocument,
            final String rootElementName, final String elementNameList) {

        final Element documentElement = BlancoDocListingUtil
                .parseXmlDocument(fileRead);
        if (documentElement == null) {
            if (IS_DEBUG) {
                System.out.println("ルートノードが見つかりません");
            }
            return;
        }
        final NodeList rootNodeList = documentElement.getChildNodes();
        if (rootNodeList == null) {
            return;
        }

        final Element eleRoot = (Element) rootNodeList;
        final NodeList listBlancoTelegramCommon = eleRoot
                .getElementsByTagName(rootElementName);
        final String[] elementList = BlancoNameUtil.splitString(
                elementNameList, ',');
        for (int index = 0; index < listBlancoTelegramCommon.getLength(); index++) {
            final HashMap map = new HashMap();
            final Node node = listBlancoTelegramCommon.item(index);
            for (int indexElement = 0; indexElement < elementList.length; indexElement++) {
                final String key = (String) elementList[indexElement];
                final String value = BlancoXmlUtil.getTextContent(
                        (Element) node, key);
                if (IS_DEBUG) {
                    System.out.println("key[" + key + "] value[" + value + "]");
                }
                map.put(key, value);
            }
            listDocument.add(map);
        }
    }

    /**
     * 収集した情報をもとに一覧を出力します。
     * 
     * @param listDocument
     *            ドキュメント一覧
     * @param elementNameList
     *            エレメントの名前一覧
     * @param templateFileName
     *            テンプレートファイル名
     * @param inputDir
     *            入力元のディレクトリ
     * @param outputDir
     *            出力先のディレクトリ
     * @throws IOException
     */
    private void outputDocListing(final ArrayList listDocument,
            final String elementNameList,
            final File sourceMetaTemplateDirectory,
            final String templateFileName, final File inputDir,
            final File outputDir) throws IOException {
        final String[] elementList = BlancoNameUtil.splitString(
                elementNameList, ',');
        if (elementList.length == 0) {
            throw new IllegalArgumentException("与えられたエレメント名一覧の長さが0です。処理不能です。");
        }

        // ソートは既に中間ファイルの時点で実施済みです。

        new File(outputDir.getAbsolutePath() + "/tmp").mkdirs();

        final BlancoUnoConverter converter = new BlancoUnoConverter();
        converter.convertAsCalc(new File(sourceMetaTemplateDirectory
                .getAbsolutePath()
                + "/" + templateFileName), new File(outputDir.getAbsolutePath()
                + "/tmp/" + templateFileName + ".ods"));

        new AbstractZipEditor() {
            protected boolean processEntry(String entryName,
                    InputStream inStream, OutputStream outStream)
                    throws IOException {
                if (entryName.equals("content.xml") == false) {
                    return false;
                }

                final String ENCODE = "utf-8";
                // ここで開くReaderはクローズしてはなりません。
                final BufferedReader reader = new BufferedReader(
                        new InputStreamReader(inStream, ENCODE));
                boolean isTemplateProcessed = false;
                for (;;) {
                    final String strLine = reader.readLine();
                    if (strLine == null) {
                        // もとのデータの終端に到達しました。
                        break;
                    }

                    // 行イメージを取得します。
                    final String templateLineString = BlancoOpenDocumentUtil
                            .getTableRowFromContent(strLine, elementList[0]);
                    if (templateLineString == null) {
                        continue;
                    }

                    if (strLine.indexOf(templateLineString) >= 0) {
                        isTemplateProcessed = true;
                        final int startPos = strLine
                                .indexOf(templateLineString);
                        // 発見
                        final String strHead = strLine.substring(0, startPos);
                        // System.out.println("[" + strHead + "]");
                        final String strTail = strLine.substring(startPos
                                + templateLineString.length());
                        // System.out.println("[" + strTail + "]");
                        outStream.write(strHead.getBytes(ENCODE));

                        for (int index = 0; index < listDocument.size(); index++) {
                            final HashMap mapLook = (HashMap) listDocument
                                    .get(index);
                            String line = templateLineString.replaceAll(
                                    ">#autono<", ">" + (index + 1) + "<");
                            for (int indexElement = 0; indexElement < elementList.length; indexElement++) {
                                if (line.indexOf(">#"
                                        + elementList[indexElement] + "<") < 0) {
                                    throw new IllegalArgumentException(
                                            bundle
                                                    .getXml2reportMsgErr001(elementList[indexElement]));
                                }
                                String value = (String) mapLook
                                        .get(elementList[indexElement]);
                                if (value == null) {
                                    value = "（記述無し）";
                                }
                                line = line.replaceAll(">#"
                                        + elementList[indexElement] + "<", ">"
                                        + value + "<");
                            }
                            outStream.write(line.getBytes(ENCODE));
                        }

                        outStream.write(strTail.getBytes(ENCODE));
                    } else {
                        outStream.write(strLine.getBytes(ENCODE));
                    }

                }

                if (isTemplateProcessed == false) {
                    throw new IllegalArgumentException(bundle
                            .getXml2reportMsgErr002());
                }
                // 目当てのcontent.xmlを処理できました。
                return true;
            }
        }.process(new File(outputDir.getAbsolutePath() + "/tmp/"
                + templateFileName + ".ods"), new File(outputDir
                .getAbsolutePath()
                + "/tmp/" + templateFileName + ".after.ods"));

        converter.convertAsCalc(new File(outputDir.getAbsolutePath() + "/tmp/"
                + templateFileName + ".after.ods"), new File(outputDir
                .getAbsolutePath()
                + "/" + templateFileName.replaceAll("Template", "")));
    }
}
