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

import java.io.File;
import java.io.IOException;

import javax.xml.transform.sax.SAXResult;

import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;

import blanco.commons.util.BlancoJavaSourceUtil;
import blanco.commons.util.BlancoNameAdjuster;
import blanco.ig.expander.ClassExpander;
import blanco.ig.expander.Type;
import blanco.ig.expander.method.MethodExpander;
import blanco.ig.generator.GeneratorSetting;
import blanco.ig.generator.ImplementGenerator;
import blanco.sax.util.BlancoSaxUtil;

/**
 * 解析用XMLを入力して具象化SAXライターのテストクラスを生成します。<br>
 * このクラスでは、ConcreteSaxSerializerを生成します。<br>
 * <br>
 * 入力する解析用XMLファイルは、恣意的なものを準備します。現時点では かなり限定的なものになります。<br>
 * 仮定1: 解析用XMLのアトリビュートはすべて指定されて来るものと仮定します。<br>
 * 仮定2: 異なる階層において同じ名前のエンティティが存在しないものと仮定します。<br>
 * 参考:http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/org/xml/sax/ContentHandler.html<br>
 * 
 * @author IGA Tosiki
 */
public class BlancoSaxXml2SerializerTest {
    /**
     * テスト用のエントリポイント
     * 
     * @param args
     */
    public static void main(String[] args) {
        try {
            new BlancoSaxXml2SerializerTest().process(new File(
                    BlancoSaxXml2Handler.MAIN_INPUT_FILENAME), "blanco",
                    "blanco.plugin.soap.concretesax",
                    "BlancoSoapBlancoFwSerializer");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * ソースコード生成処理を実行します。
     * 
     * @param sourceFile
     * @param targetDirectory
     * @param packageName
     * @param className
     * @throws IOException
     */
    public void process(final File sourceFile, final String targetDirectory,
            final String packageName, final String className)
            throws IOException {
        // Javaソースコードを生成のための設定
        GeneratorSetting setting = new GeneratorSetting();
        // 出力先ディレクトリを設定します。
        setting.setWorkDirectory(targetDirectory);
        ImplementGenerator implementGenerator = new ImplementGenerator(setting);
        // 作成したクラスを登録します。
        implementGenerator.addTest(getClassExpander(sourceFile, packageName,
                className));
        // 実際にソースコード生成を実行します。
        implementGenerator.generate();
        // System.out.println("ソースコード生成が完了しました。");
    }

    /**
     * 生成後のクラス展開を実行します。
     * 
     * @param sourceFile
     * @param packageName
     * @param className
     * @return
     */
    private ClassExpander getClassExpander(final File sourceFile,
            final String packageName, final String className) {
        return new ClassExpander(new Type(packageName, className + "Test")) {
            protected void expandClassStruct() {
                addFileComment(className + "具象化SAXクラステストクラス<br>");
                getJavaDoc().addLine(className + "具象化SAXクラステストクラス<br>");
                getJavaDoc()
                        .addLine("SAXを利用したXML書き出しをラッピングするクラスのテストクラスです。<br>");
                getJavaDoc().addLine(
                        "このクラスは解析用XMLファイルを入力として具象化SAXクラスとして生成されました。<br>");
                getJavaDoc().addLine("このソースコードはblancoIgにより機械的に自動生成されています。");
                setSuperClass(new Type("junit.framework.TestCase"));

                addMethod(new MethodExpander("testSerializer") {
                    // メソッドのシグニチャ指定
                    public void setupSignature() {
                        addUsingType(new Type("java.io.BufferedOutputStream"));
                        // addUsingType(new
                        // Type("java.io.FileNotFoundException"));
                        addUsingType(new Type("java.io.FileOutputStream"));
                        addUsingType(new Type("java.io.IOException"));
                        addUsingType(new Type("java.io.OutputStream"));
                        // addUsingType(new
                        // Type("javax.xml.transform.TransformerConfigurationException"));
                        addUsingType(new Type("junit.framework.TestCase"));
                        // addUsingType(new Type("org.xml.sax.SAXException"));

                        addException(new Type("java.lang.Exception"));
                    }

                    public void implement() {
                        getData().addLine("OutputStream outStream = null;");
                        getData().addLine("try {");
                        getData()
                                .addLine(
                                        "outStream = new BufferedOutputStream(new FileOutputStream(\"output.xml\"));");
                        getData().addLine(
                                className + " serializer = new " + className
                                        + "(outStream);");
                        getData().addLine("serializer.startDocument();");

                        SAXResult result = new SAXResult(new ContentHandler() {
                            public void endDocument() throws SAXException {
                            }

                            public void startDocument() throws SAXException {
                            }

                            public void characters(char[] ch, int start,
                                    int length) throws SAXException {
                                if (length > 0) {
                                    getData()
                                            .addLine(
                                                    "serializer.characters(\""
                                                            + BlancoJavaSourceUtil
                                                                    .escapeStringAsJavaSource(new String(
                                                                            ch,
                                                                            start,
                                                                            length))
                                                            + "\");");
                                }
                            }

                            public void ignorableWhitespace(char[] arg0,
                                    int arg1, int arg2) throws SAXException {
                            }

                            public void endPrefixMapping(String arg0)
                                    throws SAXException {
                            }

                            public void skippedEntity(String arg0)
                                    throws SAXException {
                            }

                            public void setDocumentLocator(Locator arg0) {
                            }

                            public void processingInstruction(String arg0,
                                    String arg1) throws SAXException {
                            }

                            public void startPrefixMapping(String arg0,
                                    String arg1) throws SAXException {
                            }

                            public void startElement(String arg0, String arg1,
                                    String arg2, Attributes atts)
                                    throws SAXException {
                                String lineStatement = "serializer.startElement"
                                        + BlancoNameAdjuster.toClassName(arg2)
                                        + "(";
                                for (int index = 0; index < atts.getLength(); index++) {
                                    if (index != 0) {
                                        lineStatement += ", ";
                                    }
                                    lineStatement += "\""
                                            + atts.getValue(index) + "\"";
                                }
                                lineStatement += ");";
                                getData().addLine(lineStatement);
                            }

                            public void endElement(String arg0, String arg1,
                                    String arg2) throws SAXException {
                                getData().addLine(
                                        "serializer.endElement"
                                                + BlancoNameAdjuster
                                                        .toClassName(arg2)
                                                + "();");
                            }
                        });

                        BlancoSaxUtil.doTransform(sourceFile, result);

                        getData().addLine("serializer.endDocument();");
                        getData().addLine("outStream.flush();");
                        getData().addLine("} finally {");
                        getData().addLine("try {");
                        getData().addLine("if (outStream != null) {");
                        getData().addLine("outStream.close();");
                        getData().addLine("}");
                        getData().addLine("} catch (IOException e) {");
                        getData().addLine("e.printStackTrace();");
                        getData().addLine("}");
                        getData().addLine("}");
                    }
                });
            }
        };
    }
}
