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

import java.io.File;
import java.util.List;

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

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.transformer.BlancoCgTransformerFactory;
import blanco.cg.valueobject.BlancoCgClass;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.commons.util.BlancoJavaSourceUtil;
import blanco.commons.util.BlancoNameAdjuster;
import blanco.commons.util.BlancoXmlUtil;

public class BlancoEclipsePluginGenExpandEditor {
    /**
     * 内部的に利用するblancoCg用ファクトリ。
     */
    private BlancoCgObjectFactory fCgFactory = null;

    /**
     * 内部的に利用するblancoCg用ソースファイル情報。
     */
    private BlancoCgSourceFile fCgSourceFile = null;

    /**
     * 内部的に利用するblancoCg用クラス情報。
     */
    private BlancoCgClass fCgClass = null;

    public final void expand(final Element elementCommon,
            final NodeList listList, final File directoryTarget) {
        final String pluginName = BlancoXmlUtil.getTextContent(elementCommon,
                "name");
        final String packageName = BlancoXmlUtil.getTextContent(elementCommon,
                "packageName");
        final String description = BlancoXmlUtil.getTextContent(elementCommon,
                "description");

        // 従来と互換性を持たせるため、/mainサブフォルダに出力します。
        final File fileBlancoMain = new File(directoryTarget.getAbsolutePath()
                + "/main");

        fCgFactory = BlancoCgObjectFactory.getInstance();
        fCgSourceFile = fCgFactory.createSourceFile(packageName + ".editors",
                "このソースコードは blanco Frameworkによって自動生成されています。");
        fCgSourceFile.getLangDoc().getDescriptionList().add(
                "Eclipseプラグイン [" + pluginName + "]の抽象エディタクラス");

        fCgClass = fCgFactory.createClass("Abstract"
                + BlancoNameAdjuster.toClassName(pluginName) + "Editor",
                "Eclipseプラグイン [" + pluginName + "]の抽象エディタクラス。");
        fCgSourceFile.getClassList().add(fCgClass);

        fCgClass.setAbstract(true);

        fCgSourceFile.getImportList().add("java.io.ByteArrayInputStream");

        fCgSourceFile.getImportList().add("java.io.ByteArrayOutputStream");
        fCgSourceFile.getImportList().add("java.io.IOException");
        fCgSourceFile.getImportList().add(
                "java.io.UnsupportedEncodingException");
        fCgSourceFile.getImportList().add("javax.xml.transform.dom.DOMResult");
        fCgSourceFile.getImportList().add("org.w3c.dom.Document");
        fCgSourceFile.getImportList().add("org.eclipse.swt.events.FocusEvent");
        fCgSourceFile.getImportList().add(
                "org.eclipse.swt.events.FocusListener");
        fCgSourceFile.getImportList().add("blanco.commons.util.BlancoXmlUtil");

        fCgClass
                .getExtendClassList()
                .add(
                        fCgFactory
                                .createType("org.eclipse.ui.editors.text.TextEditor"));

        if (description != null) {
            fCgClass.getLangDoc().getDescriptionList().add(
                    BlancoJavaSourceUtil.escapeStringAsJavaDoc(description)
                            + "<br>");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("Abstract"
                    + BlancoNameAdjuster.toClassName(pluginName) + "Editor",
                    "エディタクラスのコンストラクタです。");
            fCgClass.getMethodList().add(method);
            method.setConstructor(true);

            final List listLine = method.getLineList();

            listLine.add("// 所定のエンコーディングをもって入出力を実現するためにプロバイダをセットしています。");
            listLine.add("setDocumentProvider(new " + pluginName
                    + "DocumentProvider());");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("setFocus",
                    "フォーカスがセットされた場合に呼び出されます。");
            fCgClass.getMethodList().add(method);
            method.setFinal(true);
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "isSaveAsAllowed", "名前を付けて保存が許可されているかどうか。");
            fCgClass.getMethodList().add(method);
            method.setFinal(true);
            method.setReturn(fCgFactory
                    .createReturn("boolean", "常にfalseを戻します。"));

            final List listLine = method.getLineList();
            listLine.add("return false;");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "isSaveOnCloseNeeded", "エディタが閉じられる際に保存が必要かどうかを戻します。");
            fCgClass.getMethodList().add(method);
            method.setFinal(true);
            method
                    .setReturn(fCgFactory.createReturn("boolean",
                            "常にtrueを戻します。"));

            final List listLine = method.getLineList();
            listLine.add("return true;");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "setFocusLostHandler", "");
            fCgClass.getMethodList().add(method);
            method.setFinal(true);
            method.setAccess("protected");
            method.getParameterList().add(
                    fCgFactory.createParameter("target",
                            "org.eclipse.swt.widgets.Control", ""));

            final List listLine = method.getLineList();
            listLine.add("target.addFocusListener(new FocusListener() {");
            listLine.add("public void focusGained(FocusEvent e) {");
            listLine.add("}");
            listLine.add("");
            listLine.add("public void focusLost(FocusEvent e) {");
            listLine.add("saveToTextEditor();");
            listLine.add("}");
            listLine.add("}");
            listLine.add(");");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "loadFromTextEditor", "テキストエディタがデータをロードする際に呼び出されます。");
            fCgClass.getMethodList().add(method);
            method.getLangDoc().getDescriptionList().add(
                    "このメソッドは blancoで独自に規定するものです。");
            method.setFinal(true);
            method.setAccess("protected");

            final List listLine = method.getLineList();

            listLine
                    .add("final String editorText = getDocumentProvider().getDocument(getEditorInput()).get();");
            listLine.add("");
            listLine.add("final DOMResult result;");
            listLine.add("try {");
            listLine
                    .add("result = BlancoXmlUtil.transformStream2Dom(new ByteArrayInputStream(editorText.getBytes(\"UTF-8\")));");
            listLine.add("} catch (UnsupportedEncodingException e) {");
            listLine.add("e.printStackTrace();");
            listLine.add("return;");
            listLine.add("}");
            listLine.add("");
            listLine.add("loadFromTextEditorInternal(result);");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "loadFromTextEditorInternal", "実際にデータをロードする処理内容を記述します。");
            fCgClass.getMethodList().add(method);
            method.setAccess("protected");
            method.setAbstract(true);
            method.getParameterList().add(
                    fCgFactory.createParameter("argResult",
                            "javax.xml.transform.dom.DOMResult", ""));
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "saveToTextEditor", "テキストエディタがデータをセーブする際に呼び出されます。");
            fCgClass.getMethodList().add(method);
            method.setFinal(true);
            method.setAccess("protected");
            method.getLangDoc().getDescriptionList().add(
                    "このメソッドは blancoで独自に規定するものです。");

            final List listLine = method.getLineList();

            listLine.add("Document document = saveToTextEditorInternal();");
            listLine.add("if (document == null) {");
            listLine.add("return;");
            listLine.add("}");
            listLine.add("");
            listLine
                    .add("final ByteArrayOutputStream outStream = new ByteArrayOutputStream();");
            listLine
                    .add("BlancoXmlUtil.transformDom2Stream(document, outStream);");
            listLine.add("try {");
            listLine.add("outStream.flush();");
            listLine
                    .add("final String result = new String(outStream.toByteArray(), \"UTF-8\");");
            listLine
                    .add("final String pastEditorText = getDocumentProvider().getDocument(getEditorInput()).get();");
            listLine.add("if (pastEditorText.equals(result) == false) {");
            listLine.add("// 内容が異なる場合にのみ書き込みを行います。");
            listLine
                    .add("getDocumentProvider().getDocument(getEditorInput()).set(result);");
            listLine.add("}");
            listLine.add("} catch (UnsupportedEncodingException e) {");
            listLine.add("e.printStackTrace();");
            listLine.add("return;");
            listLine.add("} catch (IOException e) {");
            listLine.add("e.printStackTrace();");
            listLine.add("return;");
            listLine.add("}");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "saveToTextEditorInternal", "実際にデータをセーブする処理内容を記述します。");
            fCgClass.getMethodList().add(method);
            method.setAccess("protected");
            method.setAbstract(true);
            method.setReturn(fCgFactory
                    .createReturn("org.w3c.dom.Document", ""));
        }

        // ソースコードを実際に生成します。
        BlancoCgTransformerFactory.getJavaSourceTransformer().transform(
                fCgSourceFile, fileBlancoMain);
    }
}
