package blanco.plugin.pdf.actions;

import java.io.File;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;

import blanco.pdf.BlancoPdfConstants;
import blanco.pdf.page.task.BlancoPdfPageDefCheckerProcessImpl;
import blanco.pdf.page.task.valueobject.BlancoPdfPageDefCheckerProcessInput;
import blanco.pdf.report.task.BlancoPdfReportProcessImpl;
import blanco.pdf.report.task.valueobject.BlancoPdfReportProcessInput;
import blanco.pdf.resourcebundle.BlancoPdfResourceBundle;
import blanco.plugin.pdf.BlancoPdfPlugin;
import blanco.plugin.pdf.BlancoPdfPluginConstants;
import blanco.plugin.pdf.editors.BlancoPdfPluginUtil;

public class BlancoPdfGenerateAction {
    private static final BlancoPdfResourceBundle fBundle = new BlancoPdfResourceBundle();

    /**
     * ソースコード生成処理を実行します。
     * 
     * @param ifile
     *            処理対象のファイル。
     * @param shell
     *            親のシェル。
     * @param workbenchMonitor
     *            ワークベンチモニタ。
     * @param targetLang
     *            出力対象プログラミング言語。
     * @param metaDir
     *            メタディレクトリ。
     * @throws InvocationTargetException
     *             実行時の例外。
     * @throws InterruptedException
     *             割り込み例外。
     * @throws CoreException
     */
    public static final void processBlancoPdfSource(final IFile ifile,
            final Shell shell, IProgressMonitor workbenchMonitor,
            final String runtimePackage, final String confDir)
            throws InvocationTargetException, InterruptedException,
            CoreException {
        final IFolder fConfDir = ifile.getProject().getFolder(confDir);

        if (fConfDir.exists() == false) {
            MessageDialog.openWarning(shell, "ソースコード生成", "構成ディレクトリ (" + confDir
                    + ") が存在しません。処理を中断します。");
            return;
        }

        // MessageDialog.openInformation(shell, "ソースコード生成", "対象["
        // + fConfDir.getLocation().toFile().getAbsolutePath() + "]");

        final BlancoPdfReportProcessInput input = new BlancoPdfReportProcessInput();
        input.setConfdir(fConfDir.getLocation().toFile().getAbsolutePath());
        // input.setRuntimepackage(runtimePackage);

        {
            final IFolder tempRootFolder = ifile.getProject().getFolder("tmp");
            input.setTmpdir(tempRootFolder.getLocation().toFile()
                    .getAbsolutePath());
        }

        {
            final IFolder folderTargetDirectory = ifile.getProject().getFolder(
                    "blanco");
            final File blancoTargetDirectory = folderTargetDirectory
                    .getLocation().toFile();
            input.setTargetdir(blancoTargetDirectory.getAbsolutePath());
        }

        // Eclipse 3.3 対策: begin
        // workbenchMonitorを利用することを停止しました。
        // org.eclipse.swt.SWTException: Invalid thread access が発生してしまいます。
        // Eclipse 3.3 対策: end

        // Eclipse プラグインの所定のルールに従って自動生成ソースコードの文字エンコーディングを決定。
        final String encoding = ifile.getProject().getDefaultCharset(true);
        input.setEncoding(encoding);

        try {
            // PlatformUI.getWorkbench().getProgressService()を有益と判断。
            PlatformUI.getWorkbench().getProgressService().busyCursorWhile(
                    new IRunnableWithProgress() {
                        public void run(final IProgressMonitor monitor)
                                throws InvocationTargetException,
                                InterruptedException {
                            try {
                                monitor.beginTask(
                                        BlancoPdfConstants.PRODUCT_NAME
                                                + "ソースコード生成", 10);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                monitor.subTask("ディレクトリ: テンポラリフォルダの調整。");

                                // テンポラリフォルダを一旦削除します。
                                BlancoPdfPluginUtil
                                        .deleteFolder(
                                                ifile,
                                                monitor,
                                                "tmp"
                                                        + BlancoPdfConstants.TARGET_SUBDIRECTORY);
                                BlancoPdfPluginUtil
                                        .createFolder(
                                                ifile,
                                                monitor,
                                                "tmp"
                                                        + BlancoPdfConstants.TARGET_SUBDIRECTORY);
                                final IFolder tempFolder = BlancoPdfPluginUtil
                                        .findFolder(
                                                ifile,
                                                monitor,
                                                "tmp"
                                                        + BlancoPdfConstants.TARGET_SUBDIRECTORY);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                monitor.subTask(fBundle
                                        .getMetafileDisplayname()
                                        + " (*.xls)を処理します");
                                monitor.worked(1);

                                final IFolder findFolder = BlancoPdfPluginUtil
                                        .findFolder(ifile, monitor, confDir);
                                findFolder.refreshLocal(
                                        IResource.DEPTH_INFINITE, monitor);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                monitor.subTask("フォルダ更新: tmpフォルダ");
                                monitor.worked(1);

                                tempFolder.refreshLocal(
                                        IResource.DEPTH_INFINITE, monitor);

                                monitor.subTask("フォルダ作成: " + "フォルダ");

                                IFolder folderTargetDirectory = ifile
                                        .getProject().getFolder("blanco");
                                if (ifile.getProject().getFolder(confDir)
                                        .exists() == false) {
                                    folderTargetDirectory.create(true, true,
                                            monitor);
                                }

                                monitor.subTask("フォルダ作成: " + "blanco"
                                        + "/mainフォルダ");
                                final IFolder folderTargetDirectoryWithMain = folderTargetDirectory
                                        .getFolder("main");
                                if (ifile.getProject().getFolder(confDir)
                                        .exists() == false) {
                                    folderTargetDirectoryWithMain.create(true,
                                            true, monitor);
                                }

                                monitor.subTask("ソースコード作成");
                                monitor.worked(1);

                                final BlancoPdfReportProcessImpl process = new BlancoPdfReportProcessImpl();
                                process.execute(input);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                monitor.subTask("フォルダ更新: " + "フォルダを更新");
                                monitor.worked(1);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                folderTargetDirectory.refreshLocal(
                                        IResource.DEPTH_INFINITE, monitor);

                                if (BlancoPdfPluginConstants.IS_DEBUG) {
                                    Thread.sleep(1000);
                                }
                            } catch (Exception e) {
                                // 最終防衛ライン
                                e.printStackTrace();
                                throw new InvocationTargetException(e, e
                                        .toString());
                            } catch (Error e) {
                                // 最終防衛ライン
                                e.printStackTrace();
                                throw new InvocationTargetException(e, e
                                        .toString());
                            } finally {
                                // 最後の最後では done扱いとします。
                                monitor.done();
                            }
                        }
                    });
        } catch (InvocationTargetException ex) {
            BlancoPdfPlugin.log(ex);
            // 例外の中から本当の原因を取り出すことがポイントです。
            MessageDialog.openWarning(shell, "ソースコード生成",
                    "例外が発生しました。処理を中断します。\n" + ex.getCause().toString());
            ex.printStackTrace();
        } catch (InterruptedException ex) {
            BlancoPdfPlugin.log(ex);
            MessageDialog.openWarning(shell, "ソースコード生成",
                    "割り込み中断例外が発生しました。処理を中断します。\n" + ex.toString());
            ex.printStackTrace();
        } catch (Exception ex) {
            BlancoPdfPlugin.log(ex);
            MessageDialog.openWarning(shell, "ソースコード生成",
                    "予期せぬ例外が発生しました。処理を中断します。\n" + ex.toString());
            ex.printStackTrace();
        } catch (Error er) {
            BlancoPdfPlugin.log(er);
            MessageDialog.openWarning(shell, "ソースコード生成",
                    "予期せぬエラーが発生しました。処理を中断します。\n" + er.toString());
            er.printStackTrace();
        }
    }

    public static final void processBlancoGenerateTestPdf(final IFile ifile,
            final Shell shell, IProgressMonitor workbenchMonitor,
            final String confDir) throws InvocationTargetException,
            InterruptedException, CoreException {
        final IFolder fConfDir = ifile.getProject().getFolder(confDir);

        if (fConfDir.exists() == false) {
            MessageDialog.openWarning(shell, "PDF テスト生成", "構成ディレクトリ ("
                    + confDir + ") が存在しません。処理を中断します。");
            return;
        }

        final BlancoPdfPageDefCheckerProcessInput input = new BlancoPdfPageDefCheckerProcessInput();
        input.setConfdir(fConfDir.getLocation().toFile().getAbsolutePath());

        {
            final IFolder tempRootFolder = ifile.getProject().getFolder("tmp");
            input.setTmpdir(tempRootFolder.getLocation().toFile()
                    .getAbsolutePath());
        }

        // Eclipse 3.3 対策: begin
        // workbenchMonitorを利用することを停止しました。
        // org.eclipse.swt.SWTException: Invalid thread access が発生してしまいます。
        // Eclipse 3.3 対策: end

        try {
            // PlatformUI.getWorkbench().getProgressService()を有益と判断。
            PlatformUI.getWorkbench().getProgressService().busyCursorWhile(
                    new IRunnableWithProgress() {
                        public void run(final IProgressMonitor monitor)
                                throws InvocationTargetException,
                                InterruptedException {
                            try {
                                monitor.beginTask(
                                        BlancoPdfConstants.PRODUCT_NAME
                                                + "ソースコード生成", 10);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                monitor.subTask("ディレクトリ: テンポラリフォルダの調整。");

                                // テンポラリフォルダを一旦削除します。
                                BlancoPdfPluginUtil
                                        .deleteFolder(
                                                ifile,
                                                monitor,
                                                "tmp"
                                                        + BlancoPdfConstants.TARGET_SUBDIRECTORY);
                                BlancoPdfPluginUtil
                                        .createFolder(
                                                ifile,
                                                monitor,
                                                "tmp"
                                                        + BlancoPdfConstants.TARGET_SUBDIRECTORY);
                                final IFolder tempFolder = BlancoPdfPluginUtil
                                        .findFolder(
                                                ifile,
                                                monitor,
                                                "tmp"
                                                        + BlancoPdfConstants.TARGET_SUBDIRECTORY);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                monitor.subTask(fBundle
                                        .getMetafileDisplayname()
                                        + " (*.xls)を処理します");
                                monitor.worked(1);

                                final IFolder findFolder = BlancoPdfPluginUtil
                                        .findFolder(ifile, monitor, confDir);
                                findFolder.refreshLocal(
                                        IResource.DEPTH_INFINITE, monitor);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                monitor.subTask("フォルダ更新: tmpフォルダ");
                                monitor.worked(1);

                                tempFolder.refreshLocal(
                                        IResource.DEPTH_INFINITE, monitor);

                                monitor.subTask("フォルダ作成: " + "フォルダ");

                                IFolder folderTargetDirectory = ifile
                                        .getProject().getFolder("blanco");
                                if (ifile.getProject().getFolder(confDir)
                                        .exists() == false) {
                                    folderTargetDirectory.create(true, true,
                                            monitor);
                                }

                                monitor.subTask("PDF 作成");
                                monitor.worked(1);

                                final BlancoPdfPageDefCheckerProcessImpl process = new BlancoPdfPageDefCheckerProcessImpl();
                                process.execute(input);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                monitor.subTask("フォルダ更新: " + "フォルダを更新");
                                monitor.worked(1);

                                if (monitor.isCanceled()) {
                                    return;
                                }

                                folderTargetDirectory.refreshLocal(
                                        IResource.DEPTH_INFINITE, monitor);

                                if (BlancoPdfPluginConstants.IS_DEBUG) {
                                    Thread.sleep(1000);
                                }
                            } catch (Exception e) {
                                // 最終防衛ライン
                                e.printStackTrace();
                                throw new InvocationTargetException(e, e
                                        .toString());
                            } catch (Error e) {
                                // 最終防衛ライン
                                e.printStackTrace();
                                throw new InvocationTargetException(e, e
                                        .toString());
                            } finally {
                                // 最後の最後では done扱いとします。
                                monitor.done();
                            }
                        }
                    });
        } catch (InvocationTargetException ex) {
            BlancoPdfPlugin.log(ex);
            // 例外の中から本当の原因を取り出すことがポイントです。
            MessageDialog.openWarning(shell, "ソースコード生成",
                    "例外が発生しました。処理を中断します。\n" + ex.getCause().toString());
            ex.printStackTrace();
        } catch (InterruptedException ex) {
            BlancoPdfPlugin.log(ex);
            MessageDialog.openWarning(shell, "ソースコード生成",
                    "割り込み中断例外が発生しました。処理を中断します。\n" + ex.toString());
            ex.printStackTrace();
        } catch (Exception ex) {
            BlancoPdfPlugin.log(ex);
            MessageDialog.openWarning(shell, "ソースコード生成",
                    "予期せぬ例外が発生しました。処理を中断します。\n" + ex.toString());
            ex.printStackTrace();
        } catch (Error er) {
            BlancoPdfPlugin.log(er);
            MessageDialog.openWarning(shell, "ソースコード生成",
                    "予期せぬエラーが発生しました。処理を中断します。\n" + er.toString());
            er.printStackTrace();
        }
    }
}