/*
 * 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.BlancoCgField;
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 BlancoEclipsePluginGenExpandPlugin {
    /**
     * 内部的に利用する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,
                "このソースコードは blanco Frameworkによって自動生成されています。");
        fCgSourceFile.getLangDoc().getDescriptionList().add(
                "Eclipseプラグイン [" + pluginName + "]のプラグインクラス");

        fCgClass = fCgFactory.createClass(BlancoNameAdjuster
                .toClassName(pluginName)
                + "Plugin", "Eclipseプラグイン [" + pluginName + "]のプラグインクラス。");
        fCgSourceFile.getClassList().add(fCgClass);

        // 自分自身をあらわす型。

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

        fCgClass
                .getExtendClassList()
                .add(
                        fCgFactory
                                .createType("org.eclipse.ui.plugin.AbstractUIPlugin"));

        fCgSourceFile.getImportList().add("org.eclipse.core.runtime.IStatus");
        fCgSourceFile.getImportList().add("org.eclipse.core.runtime.Platform");
        fCgSourceFile.getImportList().add("org.eclipse.core.runtime.Status");
        fCgSourceFile.getImportList().add(
                "org.eclipse.jface.resource.ImageDescriptor");
        fCgSourceFile.getImportList().add(
                "org.eclipse.ui.plugin.AbstractUIPlugin");
        fCgSourceFile.getImportList().add("org.osgi.framework.BundleContext");

        final Element elementListRoot = (Element) listList.item(0);
        final NodeList listChildNodes = elementListRoot.getChildNodes();
        for (int index = 0; index < listChildNodes.getLength(); index++) {
            final Element elementList = (Element) listChildNodes.item(index);
            @SuppressWarnings("unused")
            final String no = BlancoXmlUtil.getTextContent(elementList, "no");
            final String action = BlancoXmlUtil.getTextContent(elementList,
                    "action");
            @SuppressWarnings("unused")
            final String attributeDescription = BlancoXmlUtil.getTextContent(
                    elementList, "description");

            if (action == null || action.trim().length() == 0) {
                // actionが指定されていない場合には処理しません。
                continue;
            }

            // TODO ほんとうは、ここでアクション一覧をJavaDocに追記します。
        }

        final BlancoCgField field1 = fCgFactory.createField("plugin",
                fCgSourceFile.getPackage() + "." + fCgClass.getName(),
                "このプラグイン自身の共有インスタンス。");
        field1.setStatic(true);
        fCgClass.getFieldList().add(field1);

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    BlancoNameAdjuster.toClassName(pluginName) + "Plugin", "");
            fCgClass.getMethodList().add(method);

            method.setConstructor(true);

            final List<java.lang.String> listLine = method.getLineList();

            listLine.add("plugin = this;");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("start",
                    "This method is called upon plug-in activation");
            fCgClass.getMethodList().add(method);

            method.getParameterList().add(
                    fCgFactory.createParameter("context",
                            "org.osgi.framework.BundleContext",
                            "プラグインバンドルのコンテキスト"));
            method.getThrowList().add(
                    fCgFactory.createException("java.lang.Exception", ""));

            final List<java.lang.String> listLine = method.getLineList();

            listLine.add("super.start(context);");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("stop",
                    "This method is called when the plug-in is stopped");
            fCgClass.getMethodList().add(method);

            method.getParameterList().add(
                    fCgFactory.createParameter("context",
                            "org.osgi.framework.BundleContext",
                            "プラグインバンドルのコンテキスト"));
            method.getThrowList().add(
                    fCgFactory.createException("java.lang.Exception", ""));

            final List<java.lang.String> listLine = method.getLineList();

            listLine.add("super.stop(context);");
            listLine.add("plugin = null;");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("getDefault",
                    "Returns the shared instance.");
            fCgClass.getMethodList().add(method);

            method.setStatic(true);

            method.setReturn(fCgFactory.createReturn(fCgSourceFile.getPackage()
                    + "." + fCgClass.getName(), "プラグインの共有インスタンス。"));

            final List<java.lang.String> listLine = method.getLineList();

            listLine.add("return plugin;");
        }

        {
            final BlancoCgMethod method = fCgFactory
                    .createMethod(
                            "getImageDescriptor",
                            "Returns an image descriptor for the image file at the given plug-in relative path.");
            fCgClass.getMethodList().add(method);

            method.setStatic(true);

            method.getParameterList().add(
                    fCgFactory.createParameter("path", "java.lang.String",
                            "イメージへのパス"));
            method.setReturn(fCgFactory.createReturn(
                    "org.eclipse.jface.resource.ImageDescriptor",
                    "取得されたイメージデスクリプタ"));

            final List<java.lang.String> listLine = method.getLineList();

            listLine.add("return AbstractUIPlugin.imageDescriptorFromPlugin(\""
                    + packageName + "\", path);");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("log",
                    "Eclipseに対してロギングを行います。");
            fCgClass.getMethodList().add(method);

            method.setStatic(true);

            method.getParameterList().add(
                    fCgFactory.createParameter("ex", "java.lang.Throwable",
                            "ロギングの際に利用する例外オブジェクト"));

            final List<java.lang.String> listLine = method.getLineList();

            listLine
                    .add(BlancoNameAdjuster.toClassName(pluginName)
                            + "Plugin"
                            + ".getDefault().getLog().log(new Status(IStatus.WARNING, \""
                            + packageName + "\", -1, ex.toString(), ex));");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "getPluginRoot", "プラグインのルートディレクトリを取得します。");
            fCgClass.getMethodList().add(method);

            method.getAnnotationList().add("SuppressWarnings(\"deprecation\")");

            method.setStatic(true);

            method.setReturn(fCgFactory.createReturn("java.net.URL",
                    "ルートディレクトリのURL これをgetPath()するとフルパスになります。"));

            method.getThrowList().add(
                    fCgFactory.createException("java.io.IOException", ""));

            final List<java.lang.String> listLine = method.getLineList();

            listLine
                    .add("final URL relativeURL = getDefault().getBundle().getEntry(\"/\");");
            listLine
                    .add("final URL localURL = Platform.asLocalURL(relativeURL);");
            listLine.add("return localURL;");
        }

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