/*
 * 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 BlancoEclipsePluginGenExpandWizard {
    /**
     * 内部的に利用する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 displayName = BlancoXmlUtil.getTextContent(elementCommon,
                "displayName");

        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 + ".wizards",
                "このソースコードは blanco Frameworkによって自動生成されています。");
        fCgSourceFile.getLangDoc().getDescriptionList().add(
                "Eclipseプラグイン [" + pluginName + "]のウィザードクラス");

        fCgClass = fCgFactory.createClass("Abstract"
                + BlancoNameAdjuster.toClassName(pluginName) + "Wizard",
                "Eclipseプラグイン [" + pluginName + "]のウィザードクラス。");
        fCgSourceFile.getClassList().add(fCgClass);

        fCgClass.setAbstract(true);

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

        fCgSourceFile.getImportList().add("org.eclipse.ui.IWorkbenchPage");
        fCgSourceFile.getImportList().add(
                "org.eclipse.core.runtime.CoreException");
        fCgSourceFile.getImportList().add("org.eclipse.ui.PlatformUI");
        fCgSourceFile.getImportList().add("org.eclipse.ui.ide.IDE");
        fCgSourceFile.getImportList().add("org.eclipse.ui.PartInitException");
        fCgSourceFile.getImportList().add(
                "org.eclipse.core.resources.IProjectNature");
        fCgSourceFile.getImportList().add(
                "org.eclipse.core.resources.IResource");

        fCgSourceFile.getImportList().add(
                packageName + "." + BlancoNameAdjuster.toClassName(pluginName)
                        + "PluginConstants");

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

        fCgClass.getExtendClassList().add(
                fCgFactory.createType("org.eclipse.jface.wizard.Wizard"));
        fCgClass.getImplementInterfaceList().add(
                fCgFactory.createType("org.eclipse.ui.INewWizard"));

        final BlancoCgField fieldSelection = fCgFactory.createField(
                "selection", "org.eclipse.jface.viewers.ISelection", "");
        fCgClass.getFieldList().add(fieldSelection);

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

            final List listLine = method.getLineList();

            listLine.add("super();");
            listLine.add("setNeedsProgressMonitor(true);");
            listLine.add("setWindowTitle(\"" + displayName + " Wizard\");");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("init", "");
            fCgClass.getMethodList().add(method);

            method.getParameterList().add(
                    fCgFactory.createParameter("workbench",
                            "org.eclipse.ui.IWorkbench", ""));
            method.getParameterList().add(
                    fCgFactory.createParameter("selection",
                            "org.eclipse.jface.viewers.IStructuredSelection",
                            ""));

            final List listLine = method.getLineList();
            listLine.add("this.selection = selection;");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "performFinish", "");
            fCgClass.getMethodList().add(method);

            method.setReturn(fCgFactory.createReturn("boolean", ""));

            final List listLine = method.getLineList();

            listLine.add("// 基本的にチェックはウィザード側で終了していると仮定します。");
            listLine.add("IProject proj = getProject(selection);");
            listLine.add("if (proj == null) {");
            listLine.add("return false;");
            listLine.add("}");
            listLine.add("");
            listLine.add("// ここで ファイルを新規作成します。");
            listLine.add("IFile file = proj.getFile("
                    + BlancoNameAdjuster.toClassName(pluginName)
                    + "PluginConstants" + ".TARGET_FILENAME);");
            listLine.add("doFinish(file);");
            listLine.add("");
            listLine
                    .add("IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();");
            listLine.add("try {");
            listLine.add("// エディタを開きます。");
            listLine.add("IDE.openEditor(page, file, \"" + packageName
                    + ".editors\");");
            listLine.add("} catch (PartInitException e) {");
            listLine.add("// 例外は無視します。");
            listLine.add("}");
            listLine.add("");
            listLine.add("return true;");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("addPages",
                    "");
            fCgClass.getMethodList().add(method);

            final String classNameBase = BlancoNameAdjuster
                    .toClassName(pluginName);

            final List listLine = method.getLineList();

            listLine.add("final Abstract" + classNameBase
                    + "WizardPage page = new " + classNameBase
                    + "WizardPage(selection);");
            listLine.add("addPage(page);");

            listLine.add("final " + classNameBase + "WizardPage2 page2 = new "
                    + classNameBase + "WizardPage2(selection);");
            listLine.add("addPage(page2);");

            listLine.add("final " + classNameBase + "WizardPage3 page3 = new "
                    + classNameBase + "WizardPage3(selection);");
            listLine.add("addPage(page3);");

            listLine.add("final " + classNameBase + "WizardPage4 page4 = new "
                    + classNameBase + "WizardPage4(selection);");
            listLine.add("addPage(page4);");

            listLine.add("final Abstract" + classNameBase
                    + "WizardPage99 page99 = new " + classNameBase
                    + "WizardPage99(selection);");
            listLine.add("addPage(page99);");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("getProject",
                    "ISelectionから IProject(プロジェクト)を取得します。");
            fCgClass.getMethodList().add(method);

            method.setStatic(true);

            method.getParameterList().add(
                    fCgFactory.createParameter("selection",
                            "org.eclipse.jface.viewers.ISelection", ""));
            method.setReturn(fCgFactory.createReturn(
                    "org.eclipse.core.resources.IProject", ""));

            final List listLine = method.getLineList();

            listLine.add("IProject proj = null;");
            listLine
                    .add("IStructuredSelection ssel = (IStructuredSelection) selection;");
            listLine.add("if (ssel.isEmpty()) {");
            listLine.add("return null;");
            listLine.add("}");
            listLine.add("Object obj = ssel.getFirstElement();");
            listLine.add("if (obj instanceof IProjectNature) {");
            listLine.add("// プロジェクトの場合には、これが入ってきます。");
            listLine.add("IProjectNature nature = (IProjectNature) obj;");
            listLine.add("proj = nature.getProject();");
            listLine.add("} else if (obj instanceof IResource) {");
            listLine.add("IResource res = (IResource) obj;");
            listLine.add("proj = res.getProject();");
            listLine.add("} else {");
            listLine.add("System.out.println(obj.getClass());");
            listLine.add("return null;");
            listLine.add("}");
            listLine.add("return proj;");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod("doFinish",
                    "");
            fCgClass.getMethodList().add(method);

            method.setAccess("private");

            method.getParameterList().add(
                    fCgFactory.createParameter("file",
                            "org.eclipse.core.resources.IFile", ""));

            final List listLine = method.getLineList();

            listLine.add("try {");
            listLine.add("InputStream stream = openContentStream();");
            listLine.add("if (file.exists()) {");
            listLine.add("// なにもしません。");
            listLine.add("} else {");
            listLine.add("file.create(stream, false, null);");
            listLine.add("}");
            listLine.add("stream.close();");
            listLine.add("} catch (IOException e) {");
            listLine.add("} catch (CoreException e) {");
            listLine.add("e.printStackTrace();");
            listLine.add("}");
        }

        {
            final BlancoCgMethod method = fCgFactory.createMethod(
                    "openContentStream", "");
            fCgClass.getMethodList().add(method);

            method.setAccess("private");

            method
                    .setReturn(fCgFactory.createReturn("java.io.InputStream",
                            ""));

            final List listLine = method.getLineList();

            listLine
                    .add("String contents = \""
                            + BlancoJavaSourceUtil
                                    .escapeStringAsJavaSource("<?xml version=\"1.0\" encoding=\"UTF-8\"?><blanco/>")
                            + "\";");
            listLine
                    .add("return new ByteArrayInputStream(contents.getBytes());");
        }

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