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

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 javax.xml.transform.dom.DOMResult;

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

import blanco.bcel.BlancoBcelJavaClass2Xml;
import blanco.commons.util.BlancoJavaSourceUtil;
import blanco.commons.util.BlancoNameUtil;
import blanco.commons.util.BlancoStringUtil;
import blanco.commons.util.BlancoXmlUtil;
import blanco.opendocument.AbstractZipEditor;
import blanco.opendocument.BlancoOpenDocumentUtil;
import blanco.uno.BlancoUnoConverter;

/**
 * Javaのクラスファイルを入力としてドキュメントを出力します。
 * 
 * @author IGA Tosiki
 */
public class BlancoJUnitJavaClass2Doc {

    public void process(final String inFullJavaClassName,
            final File metaTemplate, final File outputDocument)
            throws IOException {
        new File("./tmp/junit").mkdirs();

        // classファイルをxmlに変換
        String classLocation = "./bin/"
                + BlancoStringUtil.replaceAll(inFullJavaClassName, '.', '/')
                + ".class";
        final File fileJavaClassXml = new File("./tmp/junit/"
                + BlancoNameUtil.trimJavaPackage(inFullJavaClassName) + ".xml");
        new BlancoBcelJavaClass2Xml().process(classLocation, fileJavaClassXml);

        File fileWrk = new File("./tmp/junit/aaa.ods");
        File fileWrk2 = new File("./tmp/junit/aaa.after.ods");

        // テンプレートファイルをodsに変換
        new BlancoUnoConverter().convertAsCalc(metaTemplate, fileWrk);

        new AbstractZipEditor() {
            protected boolean processEntry(String entryName,
                    InputStream inStream, OutputStream outStream)
                    throws IOException {
                if (entryName.equals("content.xml") == false) {
                    // content.xml以外は処理しません。
                    return false;
                }

                final DOMResult result = BlancoXmlUtil
                        .transformFile2Dom(fileJavaClassXml);

                final String ENCODE = "utf-8";

                final String strLine = stream2String(inStream, ENCODE);

                final Element elementFields = BlancoXmlUtil.getElement(result
                        .getNode(), "blancoBcel/Fields");
                final String targetName = getTargetName(elementFields);
                boolean isTemplateProcessed = false;

                // 行イメージを取得します。
                final String templateLineString = BlancoOpenDocumentUtil
                        .getTableRowFromContent(strLine, "testView");
                if (templateLineString != null) {
                    if (strLine.indexOf(templateLineString) >= 0) {
                        isTemplateProcessed = true;
                        final int startPos = strLine
                                .indexOf(templateLineString);
                        // 発見
                        String strHead = strLine.substring(0, startPos);
                        final String strTail = strLine.substring(startPos
                                + templateLineString.length());

                        {
                            // ここでXML処理が必要です。
                        }

                        strHead = strHead.replaceAll(">#testTargetName<", ">"
                                + targetName + "<");
                        outStream.write(strHead.getBytes(ENCODE));

                        int lineNo = 0;

                        final Element elementMethods = BlancoXmlUtil
                                .getElement(result.getNode(),
                                        "blancoBcel/Methods");
                        final NodeList methodsList = elementMethods
                                .getChildNodes();
                        for (int indexMethod = 0; indexMethod < methodsList
                                .getLength(); indexMethod++) {
                            final Node nodeMethod = methodsList
                                    .item(indexMethod);
                            if (nodeMethod instanceof Element == false) {
                                continue;
                            }
                            final Element eleMethod = (Element) nodeMethod;
                            final Element eleLines = BlancoXmlUtil.getElement(
                                    eleMethod, "Lines");
                            final NodeList lineList = eleLines.getChildNodes();
                            for (int indexLine = 0; indexLine < lineList
                                    .getLength(); indexLine++) {
                                final Node nodeLine = lineList.item(indexLine);
                                if (nodeLine instanceof Element == false) {
                                    continue;
                                }
                                final Element eleLine = (Element) nodeLine;
                                final String operand = BlancoXmlUtil
                                        .getTextContent(eleLine, "Operand");
                                if (operand == null) {
                                    continue;
                                }
                                if (operand.startsWith("\"[試験]") == false) {
                                    continue;
                                }

                                String line = templateLineString.replaceAll(
                                        ">#autono<", ">" + (++lineNo) + "<");

                                line = line.replaceAll(">#testView<", ">観点<");
                                line = line
                                        .replaceAll(
                                                ">#testDescription<",
                                                ">"
                                                        + BlancoJavaSourceUtil
                                                                .escapeStringAsJavaDoc(operand)
                                                        + "<");

                                outStream.write(line.getBytes(ENCODE));
                            }
                        }

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

                if (isTemplateProcessed == false) {
                    throw new IllegalArgumentException("ひとつも置換しませんでした。");
                }
                // 目当てのcontent.xmlを処理できました。
                return true;
            }
        }.process(fileWrk, fileWrk2);

        new BlancoUnoConverter().convertAsCalc(fileWrk2, outputDocument);
    }

    /**
     * ストリームを文字列に変換します。
     * 
     * @param inStream
     * @param encode
     * @return
     * @throws IOException
     */
    static final String stream2String(final InputStream inStream,
            final String encode) throws IOException {
        final StringBuffer strbuf = new StringBuffer();
        // ここで開くReaderはクローズしてはなりません。
        final BufferedReader reader = new BufferedReader(new InputStreamReader(
                inStream, encode));
        for (;;) {
            final String line = reader.readLine();
            if (line == null) {
                // もとのデータの終端に到達しました。
                break;
            }
            strbuf.append(line);
        }
        return strbuf.toString();
    }

    static final String getTargetName(final Element elementFields) {
        final NodeList constantFieldList = elementFields
                .getElementsByTagName("ConstantField");
        for (int indexField = 0; indexField < constantFieldList.getLength(); indexField++) {
            final Node nodeLook = constantFieldList.item(indexField);
            if (nodeLook instanceof Element == false) {
                continue;
            }
            final String name = BlancoXmlUtil.getTextContent(
                    (Element) nodeLook, "Name");
            if (name.equals("TARGET_NAME")) {
                return BlancoXmlUtil
                        .getTextContent((Element) nodeLook, "Value");
            }
        }
        return null;
    }
}
