/*******************************************************************************
 * 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.task;

import blanco.cg.BlancoCgObjectFactory;
import blanco.cg.valueobject.BlancoCgClass;
import blanco.cg.valueobject.BlancoCgMethod;
import blanco.cg.valueobject.BlancoCgSourceFile;
import blanco.commons.util.BlancoNameAdjuster;
import blanco.pdf.page.valueobject.BlancoPdfBlockDef;
import blanco.pdf.page.valueobject.BlancoPdfItemDef;
import blanco.pdf.page.valueobject.BlancoPdfPageDef;

/**
 * ページ操作に関するクラス。
 * 
 * @author Tosiki IGA
 */
class BlancoPdfReportGeneratePageOperation {
    void consolidatePage(final BlancoPdfPageDef pageDef,
            final BlancoCgObjectFactory cgFactory,
            final BlancoCgSourceFile cgSourceFile, final BlancoCgClass cgClass) {
        final BlancoCgMethod method = cgFactory.createMethod("consolidatePage",
                "ページの集約処理をおこないます。すべての項目の値をもとに処理されるものです。");
        cgClass.getMethodList().add(method);
        method.getParameterList().add(
                cgFactory.createParameter("itemsList", "java.util.List<"
                        + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems>", "ページ集約したい項目群。"));
        method.getLineList().add(
                BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems prev = null;");
        method.getLineList().add(
                "for (int index = 0; index < itemsList.size(); index++) {");
        method.getLineList().add(
                "final " + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems next = itemsList.get(index);");
        method.getLineList().add("if (prev == null) {");
        method.getLineList().add("prev = next;");
        method.getLineList().add("continue;");
        method.getLineList().add("}");
        method.getLineList().add("");
        method.getLineList().add("// 項目の値を比較。");
        method.getLineList().add("if (canConsolidatePage(prev, next)) {");
        method.getLineList().add("// ページを集約します。");

        if (pageDef.getBlockList().size() > 0) {
            method.getLineList().add(
                    "prev.get"
                            + BlancoNameAdjuster.toClassName(pageDef
                                    .getBlockList().get(0).getName())
                            + "List().addAll(next.getBlock01List());");
            method.getLineList().add("itemsList.remove(index);");
            method.getLineList().add("index--;");
        }
        method.getLineList().add("} else {");
        method.getLineList().add("prev = next;");
        method.getLineList().add("}");
        method.getLineList().add("}");
    }

    void canConsolidatePage(final BlancoPdfPageDef pageDef,
            final BlancoCgObjectFactory cgFactory,
            final BlancoCgSourceFile cgSourceFile, final BlancoCgClass cgClass) {
        final BlancoCgMethod method = cgFactory.createMethod(
                "canConsolidatePage", "ページ集約できるかどうかをチェック。");
        cgClass.getMethodList().add(method);
        method.setReturn(cgFactory.createReturn("boolean", "集約できるかどうか。"));
        method.getParameterList().add(
                cgFactory.createParameter("prev", pageDef.getPackage()
                        + ".items."
                        + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems", "比較元。"));
        method.getParameterList().add(
                cgFactory.createParameter("next", pageDef.getPackage()
                        + ".items."
                        + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems", "比較先。"));
        for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
            if (itemDef.getHidden()) {
                // 隠しフィールドは比較対象としません。
                continue;
            }

            method.getLineList().add(
                    "if (prev.get"
                            + BlancoNameAdjuster.toClassName(itemDef.getName())
                            + "() == null || next.get"
                            + BlancoNameAdjuster.toClassName(itemDef.getName())
                            + "() == null) {");
            method.getLineList().add(
                    "if (prev.get"
                            + BlancoNameAdjuster.toClassName(itemDef.getName())
                            + "() != next.get"
                            + BlancoNameAdjuster.toClassName(itemDef.getName())
                            + "()) {");
            method.getLineList().add("return false;");
            method.getLineList().add("}");
            method.getLineList().add(
                    "} else if (prev.get"
                            + BlancoNameAdjuster.toClassName(itemDef.getName())
                            + "().compareTo(next.get"
                            + BlancoNameAdjuster.toClassName(itemDef.getName())
                            + "()) != 0) {");
            method.getLineList().add("return false;");
            method.getLineList().add("}");
            method.getLineList().add("");
        }
        method.getLineList().add("return true;");
    }

    void breakPageByRowCount(final BlancoPdfPageDef pageDef,
            final BlancoCgObjectFactory cgFactory,
            final BlancoCgSourceFile cgSourceFile, final BlancoCgClass cgClass) {
        final BlancoCgMethod method = cgFactory.createMethod(
                "breakPageByRowCount", "所定の行数をもとにページをブレークします。こちらではページを分割します。");
        cgClass.getMethodList().add(method);
        method.getParameterList().add(
                cgFactory.createParameter("itemsList", "java.util.List<"
                        + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems>", "ブレーク処理したい項目群。"));

        if (pageDef.getBlockList().size() == 0) {
            return;
        }

        final BlancoPdfBlockDef blockDef = pageDef.getBlockList().get(0);

        method.getLineList().add(
                "for (int index = 0; index < itemsList.size(); index++) {");
        method.getLineList().add(
                "final " + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems look = itemsList.get(index);");
        // TODO 1 件目のみ処理しています。
        method.getLineList().add(
                "if (look.get"
                        + BlancoNameAdjuster.toClassName(blockDef.getName())
                        + "List().size() > " + blockDef.getMaxOccurs() + ") {");
        method.getLineList().add("// ページを分割します。");
        method.getLineList().add(
                "final " + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems add = new "
                        + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems();");

        for (BlancoPdfItemDef items : pageDef.getItemList()) {
            method.getLineList().add(
                    "add.set" + BlancoNameAdjuster.toClassName(items.getName())
                            + "(look.get"
                            + BlancoNameAdjuster.toClassName(items.getName())
                            + "());");
        }
        method.getLineList().add("");
        method.getLineList().add(
                "for (int indexBlock = 0; indexBlock < "
                        + blockDef.getMaxOccurs() + "; indexBlock++) {");
        method.getLineList().add(
                "add.getBlock01List().add(look.get"
                        + BlancoNameAdjuster.toClassName(blockDef.getName())
                        + "List().get(0));");
        method.getLineList().add(
                "look.get" + BlancoNameAdjuster.toClassName(blockDef.getName())
                        + "List().remove(0);");
        method.getLineList().add("}");
        method.getLineList().add("itemsList.add(index, add);");
        method.getLineList().add("}");
        method.getLineList().add("}");
    }

    void processPageContinuity(final BlancoPdfPageDef pageDef,
            final BlancoCgObjectFactory cgFactory,
            final BlancoCgSourceFile cgSourceFile, final BlancoCgClass cgClass) {
        final BlancoCgMethod method = cgFactory.createMethod(
                "processPageContinuity", "ページの継続性に関する処理を実施します。");
        cgClass.getMethodList().add(method);
        method.getParameterList().add(
                cgFactory.createParameter("itemsList", "java.util.List<"
                        + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems>", "処理対象。"));

        if (pageDef.getBlockList().size() == 0) {
            return;
        }

        method.getLineList().add(
                BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems prev = null;");
        method.getLineList().add(
                "for (int index = 0; index < itemsList.size(); index++) {");
        method.getLineList().add(
                "final " + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems next = itemsList.get(index);");
        method.getLineList().add("if (prev == null) {");
        method.getLineList().add("prev = next;");
        method.getLineList().add("continue;");
        method.getLineList().add("}");
        method.getLineList().add("");
        method.getLineList().add("// 項目の値を比較。");
        method.getLineList().add("if (canConsolidatePage(prev, next)) {");
        for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
            if (itemDef.getHiddenOnMiddlePage()) {
                method.getLineList().add(
                        "prev.set"
                                + BlancoNameAdjuster.toClassName(itemDef
                                        .getName()) + "(null);");
            }
        }
        method.getLineList().add("} else {");
        for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
            if (itemDef.getHiddenOnEndPage()) {
                method.getLineList().add(
                        "prev.set"
                                + BlancoNameAdjuster.toClassName(itemDef
                                        .getName()) + "(null);");
            }
        }
        method.getLineList().add("}");
        method.getLineList().add("prev = next;");
        method.getLineList().add("}");
        for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
            if (itemDef.getHiddenOnEndPage()) {
                method.getLineList().add(
                        "prev.set"
                                + BlancoNameAdjuster.toClassName(itemDef
                                        .getName()) + "(null);");
            }
        }
    }

    void applyPageNo(final BlancoPdfPageDef pageDef,
            final BlancoCgObjectFactory cgFactory,
            final BlancoCgSourceFile cgSourceFile, final BlancoCgClass cgClass) {
        final BlancoCgMethod method = cgFactory.createMethod("applyPageNo",
                "ページ番号を付与。");
        cgClass.getMethodList().add(method);
        method.getParameterList().add(
                cgFactory.createParameter("itemsList", "java.util.List<"
                        + BlancoNameAdjuster.toClassName(pageDef.getName())
                        + "PdfReportItems>", "ページ処理したい項目群。"));

        boolean isPageNoExist = false;
        for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
            if (itemDef.getPageNo()) {
                isPageNoExist = true;
                break;
            }
        }

        if (isPageNoExist) {
            method.getLineList().add("int pageNo = 1;");
            method.getLineList().add(
                    "for (" + BlancoNameAdjuster.toClassName(pageDef.getName())
                            + "PdfReportItems items : itemsList) {");
            for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
                if (itemDef.getPageNo()) {
                    method.getLineList().add(
                            "items.set"
                                    + BlancoNameAdjuster.toClassName(itemDef
                                            .getName())
                                    + "(BigDecimal.valueOf(pageNo++));");
                }
            }
            method.getLineList().add("}");
            cgSourceFile.getImportList().add("java.math.BigDecimal");
        }

        boolean isTotalPageCountExist = false;
        for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
            if (itemDef.getTotalPageCount()) {
                isTotalPageCountExist = true;
                break;
            }
        }

        if (isTotalPageCountExist) {
            method.getLineList().add(
                    "for (" + BlancoNameAdjuster.toClassName(pageDef.getName())
                            + "PdfReportItems items : itemsList) {");
            for (BlancoPdfItemDef itemDef : pageDef.getItemList()) {
                if (itemDef.getTotalPageCount()) {
                    method
                            .getLineList()
                            .add(
                                    "items.set"
                                            + BlancoNameAdjuster
                                                    .toClassName(itemDef
                                                            .getName())
                                            + "(BigDecimal.valueOf(itemsList.size()));");
                }
            }
            method.getLineList().add("}");
            cgSourceFile.getImportList().add("java.math.BigDecimal");
        }
    }
}
