/*******************************************************************************
 * Copyright (c) 2009 IGA Tosiki, NTT DATA BUSINESS BRAINS Corp.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    IGA Tosiki (NTT DATA BUSINESS BRAINS Corp.) - initial API and implementation
 *******************************************************************************/
/*
 * blanco Framework
 * Copyright (C) 2009 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.pdf.report;

import java.io.File;
import java.io.IOException;

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.transformer.java.BlancoCgJavaSourceTransformer;
import blanco.cg.valueobject.BlancoCgClass;
import blanco.cg.valueobject.BlancoCgField;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.commons.util.BlancoNameAdjuster;
import blanco.pdf.page.BlancoPdfPageUtil;
import blanco.pdf.page.valueobject.BlancoPdfItemDef;
import blanco.pdf.page.valueobject.BlancoPdfPageDef;
import blanco.pdf.report.valueobject.BlancoPdfReportProcessInput;
import blanco.pdf.valueobject.BlancoPdfSetting;
import blanco.valueobject.BlancoValueObjectXml2JavaClass;
import blanco.valueobject.valueobject.BlancoValueObjectClassStructure;
import blanco.valueobject.valueobject.BlancoValueObjectFieldStructure;

/**
 * XML ファイルからソースコードを自動生成。
 * 
 * @author Tosiki IGA
 */
public class BlancoPdfReportProcessImpl implements BlancoPdfReportProcess {
    protected BlancoPdfReportProcessInput fInput = null;

    /**
     * {@inheritDoc}
     */
    public int execute(final BlancoPdfReportProcessInput input)
            throws IOException, IllegalArgumentException {
        fInput = input;

        final File pageDir = new File(input.getConfdir() + "/page");
        for (File look : pageDir.listFiles()) {
            if (look == null) {
                continue;
            }
            if (look.isDirectory()) {
                continue;
            }

            if (look.getName().endsWith(".xml") == false) {
                continue;
            }

            final String pageName = look.getName().substring(0,
                    look.getName().length() - ".xml".length());
            if (input.getVerbose()) {
                progress("pageName: " + pageName);
            }

            BlancoPdfPageDef pageDef = null;
            {
                // TODO マルチフォーム対応。
                final BlancoPdfSetting setting = new BlancoPdfSetting();
                setting.setConfPath(input.getConfdir());
                pageDef = BlancoPdfPageUtil.read(setting, pageName);
            }

            new File("./tmp");

            generateItemBean(pageDef);
            generatePdfReport(pageDef);
        }

        return 0;
    }

    /**
     * ItemBean ソースコードを生成。
     * 
     * @param pageDef
     * @throws IOException
     */
    void generateItemBean(final BlancoPdfPageDef pageDef) throws IOException {
        final BlancoValueObjectClassStructure classStructure = new BlancoValueObjectClassStructure();
        classStructure.setPackage(pageDef.getPackage() + ".items");
        classStructure.setName(BlancoNameAdjuster
                .toClassName(pageDef.getName())
                + "PdfReportItems");
        classStructure.setDescription("PDF 項目群。");
        for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
            final BlancoValueObjectFieldStructure field = new BlancoValueObjectFieldStructure();
            field.setName(BlancoNameAdjuster.toClassName(itemDef.getName()));
            field.setType("java.lang.String");
            classStructure.getFieldList().add(field);
        }

        final BlancoValueObjectXml2JavaClass java2Class = new BlancoValueObjectXml2JavaClass();
        java2Class.setEncoding(fInput.getEncoding());
        java2Class.structure2Source(classStructure, new File(fInput
                .getTargetdir()));
    }

    void generatePdfReport(final BlancoPdfPageDef pageDef) {
        final BlancoCgObjectFactory cgFactory = BlancoCgObjectFactory
                .getInstance();
        final BlancoCgSourceFile cgSourceFile = cgFactory.createSourceFile(
                pageDef.getPackage(), null);
        final BlancoCgClass cgClass = cgFactory.createClass(BlancoNameAdjuster
                .toClassName(pageDef.getName())
                + "PdfReport", "PDF レポート。");
        cgSourceFile.getClassList().add(cgClass);

        {
            final BlancoCgField field = cgFactory.createField("fPageDef",
                    "blanco.pdf.page.valueobject.BlancoPdfPageDef",
                    "ページ定義オブジェクト。");
            cgClass.getFieldList().add(field);
        }

        {
            final BlancoCgField field = cgFactory.createField("fPageWriter",
                    "blanco.pdf.page.BlancoPdfPageWriter", "ページ・ライター・オブジェクト。");
            cgClass.getFieldList().add(field);
        }

        {
            final BlancoCgMethod method = cgFactory.createMethod(
                    BlancoNameAdjuster.toClassName(pageDef.getName())
                            + "PdfReport", "1 ページ分のデータをセットします。");
            cgClass.getMethodList().add(method);
            method.setConstructor(true);
            method.getParameterList().add(
                    cgFactory.createParameter("pdfSetting",
                            "blanco.pdf.valueobject.BlancoPdfSetting",
                            "PDF 項目群。"));
            method.getParameterList().add(
                    cgFactory.createParameter("outStream",
                            "java.io.OutputStream", "出力ストリーム。"));
            cgSourceFile.getImportList().add(
                    "blanco.pdf.page.BlancoPdfPageUtil");
            method.getLineList().add(
                    "fPageDef = BlancoPdfPageUtil.read(pdfSetting, \""
                            + pageDef.getName() + "\");");
            method
                    .getLineList()
                    .add(
                            "fPageWriter = new BlancoPdfPageWriter(pdfSetting.getConfPath(), fPageDef, outStream);");
        }

        {
            final BlancoCgMethod method = cgFactory.createMethod("writeItems",
                    "1 ページ分のデータをセットします。");
            cgClass.getMethodList().add(method);
            method.getParameterList().add(
                    cgFactory.createParameter("pdfItems", pageDef.getPackage()
                            + ".items."
                            + BlancoNameAdjuster.toClassName(pageDef.getName())
                            + "PdfReportItems", "PDF 項目群。"));
            cgSourceFile.getImportList().add(
                    "blanco.pdf.valueobject.BlancoPdfMetrix");
            method.getLineList().add(
                    "final BlancoPdfMetrix metrix = new BlancoPdfMetrix();");
            for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
                method.getLineList().add(
                        "metrix.setFont(\"" + itemDef.getFont() + "\");");
                method.getLineList().add(
                        "metrix.setFontSize(" + itemDef.getFontSize() + ");");
                method.getLineList().add(
                        "fPageWriter.drawText("
                                + itemDef.getX()
                                + "f, "
                                + itemDef.getY()
                                + "f, pdfItems.get"
                                + BlancoNameAdjuster.toClassName(itemDef
                                        .getName()) + "(), metrix);");

            }
        }

        {
            final BlancoCgMethod method = cgFactory.createMethod("nextPage",
                    "改ページします。");
            cgClass.getMethodList().add(method);
            method.getLineList().add("fPageWriter.nextPage();");
        }

        {
            final BlancoCgMethod method = cgFactory.createMethod(
                    "drawGridSheet", "グリッド・シートを描画します。");
            cgClass.getMethodList().add(method);
            method.getLineList().add("fPageWriter.drawGridSheet();");
        }

        {
            final BlancoCgMethod method = cgFactory.createMethod("close",
                    "クローズします。");
            cgClass.getMethodList().add(method);
            method.getLineList().add("fPageWriter.close();");
        }

        {
            final BlancoCgMethod method = cgFactory.createMethod(
                    "getPdfWriter", "PDF ライターを取得します。");
            cgClass.getMethodList().add(method);
            method.getAnnotationList().add("Deprecated");
            method.setReturn(cgFactory.createReturn(
                    "com.lowagie.text.pdf.PdfWriter", "内部的に利用しているライターー。"));
            method.getLineList().add("return fPageWriter.getWriter();");
        }

        cgSourceFile.setEncoding(fInput.getEncoding());
        new BlancoCgJavaSourceTransformer().transform(cgSourceFile, new File(
                fInput.getTargetdir() + "/main"));
    }

    /**
     * {@inheritDoc}
     */
    public boolean progress(final String argProgressMessage) {
        System.out.println(argProgressMessage);
        return false;
    }
}
