/*
 * blanco Framework
 * Copyright(C) 2006-2008 NTT DATA BUSINESS BRAINS CORPORATION.
 * 
 * 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.soap.terasoluna.rich.task;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;

import javax.xml.transform.TransformerException;

import blanco.commons.util.BlancoFileUtil;
import blanco.commons.util.BlancoNameUtil;
import blanco.soap.terasoluna.rich.ParseTelegramProcessDefInfo;
import blanco.soap.terasoluna.rich.TerasolunaBLogicWsdl2BLogicInterface;
import blanco.soap.terasoluna.rich.TerasolunaBLogicWsdl2Controller;
import blanco.soap.terasoluna.rich.TerasolunaBLogicWsdl2NamespacesProperties;
import blanco.valueobject.BlancoValueObjectXml2JavaClass;
import blanco.xsd.BlancoXsdXsd2Castor;
import blanco.xsd.BlancoXsdXsd2ValueObject;
import blanco.xsd.parser.BlancoXsdParser;
import blanco.xsd.parser.ComplexTypeStructure;

/**
 * blancoSOAPのTERASOLUNA Rich用拡張のAntタスク。
 * 
 * このクラスは blanco Framework内の既存クラスを参考として作成されました。
 * 
 * @author IGA Tosiki
 */
public class BlancoSoap4TerasolunaRichTask extends
        AbstractBlancoSoap4TerasolunaRichTask {
    /**
     * Antタスクから呼び出されるユーザコードのエントリポイント。
     */
    protected void process() throws IllegalArgumentException {
        try {
            final File fileMetadir = new File(getMetadir());
            if (fileMetadir.exists() == false) {
                throw new IllegalArgumentException("メタディレクトリ[" + getMetadir()
                        + "]が存在しません。");
            }

            new File(getTargetdir()).mkdirs();

            // テンポラリディレクトリの作成。
            final File fileTmpValueObject = new File(getTmpdir()
                    + "/valueobject");
            fileTmpValueObject.mkdirs();

            // XSDをValueObjectに変換します。
            xsd2ValueOjbect(fileMetadir, fileTmpValueObject);

            // Castor設定ファイルを生成します。
            xsd2Castor(fileMetadir);

			// WSDLファイルからコントローラ、ビジネスロジックのインターフェース
			// およびコマンドプロパティファイルを生成します。
            wsdl2Java(fileMetadir);

        } catch (IOException e) {
            e.printStackTrace();
            throw new IllegalArgumentException(e.toString());
        } catch (TransformerException e) {
            e.printStackTrace();
            throw new IllegalArgumentException(e.toString());
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
            throw e;
        } catch (Exception e) {
            e.printStackTrace();
            throw new IllegalArgumentException(e.toString());
        }
    }

    /**
     * XSDをValueObjectに変換する。
     * 
     * @param fileMetaDir
     * @throws Exception
     */
    private void xsd2ValueOjbect(final File fileMetaDir,
            final File fileTmpValueObject) throws Exception {
        final File[] fileMeta1 = fileMetaDir.listFiles();
        if (fileMeta1 == null) {
            throw new IllegalArgumentException("メタディレクトリ["
                    + fileMetaDir.getAbsolutePath() + "]のファイル一覧の取得に失敗しました。");
        }

        for (int index = 0; index < fileMeta1.length; index++) {
            if (fileMeta1[index].getName().endsWith(".xsd") == false) {
                continue;
            }

            new BlancoXsdXsd2ValueObject().process(fileMeta1[index],
                    fileTmpValueObject);
        }

        final File[] fileMeta2 = fileTmpValueObject.listFiles();
        if (fileMeta2 == null) {
            throw new IllegalArgumentException("テンポラリディレクトリ["
                    + fileTmpValueObject.getAbsolutePath()
                    + "]のファイル一覧の取得に失敗しました。");
        }

        for (int index = 0; index < fileMeta2.length; index++) {
            if (fileMeta2[index].getName().endsWith(".blancovalueobject") == false) {
                continue;
            }

            new BlancoValueObjectXml2JavaClass().process(fileMeta2[index],
                    new File(getTargetdir()));
        }
    }

    /**
     * XSDファイルからCastorファイルを展開する。
     * 
     * @param fileMetaDir
     *            メタファイルが格納されているディレクトリ。
     * @throws Exception
     *             例外が発生した場合。
     */
    private void xsd2Castor(final File fileMetaDir) throws Exception {
        final File[] fileMeta1 = fileMetaDir.listFiles();
        if (fileMeta1 == null) {
            throw new IllegalArgumentException("メタディレクトリ["
                    + fileMetaDir.getAbsolutePath() + "]のファイル一覧の取得に失敗しました。");
        }

        for (int index = 0; index < fileMeta1.length; index++) {
            if (fileMeta1[index].getName().endsWith(".xsd") == false) {
                continue;
            }

            final String fileName = BlancoNameUtil
                    .trimFileExtension(fileMeta1[index].getName());

            final BlancoXsdParser parser = new BlancoXsdParser();
            final ComplexTypeStructure type = parser.process(fileMeta1[index],
                    fileName);

            InputStream inStream = null;
            OutputStream outStream = null;
            try {
                inStream = new BufferedInputStream(new FileInputStream(
                        fileMeta1[index]));
                outStream = new BufferedOutputStream(new FileOutputStream(
                        getTargetdir() + "/main/"
                                + type.getTypeOfJava().replace('.', '/')
                                + ".xml"));
                new BlancoXsdXsd2Castor()
                        .process(inStream, fileName, outStream);
                outStream.flush();
            } finally {
                if (inStream != null) {
                    inStream.close();
                }
                if (outStream != null) {
                    outStream.close();
                }
            }

            // 2006.04.25 追記:現在処理しているXSDそのものをCastorマッピングファイルと同じディレクトリ向けにコピー。
            BlancoFileUtil.copy(fileMeta1[index], new File(getTargetdir()
                    + "/main/" + type.getTypeOfJava().replace('.', '/')
                    + ".xsd"));
        }
    }

    /**
	 * WSDLファイルからコントローラ、ビジネスロジックのインターフェースおよびコマンドプロパティファイルを生成する。
     * 
     * @param fileMetaDir
     *            メタファイルが格納されているディレクトリ。
     * @throws Exception
     *             例外が発生した場合。
     */
    private void wsdl2Java(final File fileMetaDir) throws Exception {
        final File[] fileMeta1 = fileMetaDir.listFiles();
        if (fileMeta1 == null) {
            throw new IllegalArgumentException("メタディレクトリ["
                    + fileMetaDir.getAbsolutePath() + "]のファイル一覧の取得に失敗しました。");
        }

        final HashMap mapTelegramProcessDef = new ParseTelegramProcessDefInfo()
                .process(new File(getTmpdir()));

        final TerasolunaBLogicWsdl2NamespacesProperties propertyGenerator = new TerasolunaBLogicWsdl2NamespacesProperties();

        final File blancoTargetDirectory = new File(getTargetdir());

        for (int index = 0; index < fileMeta1.length; index++) {
            if (fileMeta1[index].getName().endsWith(".wsdl") == false) {
                continue;
            }

            propertyGenerator.parse(fileMeta1[index]);

            new TerasolunaBLogicWsdl2Controller().process(fileMeta1[index],
                    mapTelegramProcessDef, blancoTargetDirectory);
            new TerasolunaBLogicWsdl2BLogicInterface().process(
                    fileMeta1[index], mapTelegramProcessDef,
                    blancoTargetDirectory);
        }

        final OutputStream outStream = new BufferedOutputStream(
                new FileOutputStream(getTargetdir() + "/main/"
                        + TerasolunaBLogicWsdl2NamespacesProperties.FILE_NAME));
        try {
            propertyGenerator.generate(outStream);
            outStream.flush();
        } finally {
            outStream.close();
        }
    }
}
