/*
 * blanco Framework
 * Copyright (C) 2004-2009 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.sample.jsf.proxy;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.el.ELContext;
import javax.el.ELResolver;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.servlet.http.HttpServletResponse;

import blanco.sample.jsf.BlancoJsfSample1AddLogic;
import blanco.sample.jsf.BlancoJsfSample1CompleteLogic;
import blanco.sample.jsf.BlancoJsfSample1DownloadLogic;
import blanco.sample.jsf.BlancoJsfSample1InitializeLogic;
import blanco.sample.jsf.BlancoJsfSample1ModifyLogic;
import blanco.sample.jsf.BlancoJsfSample1ViewLogic;
import blanco.sample.jsf.db.query.SimpleBookInsertInvoker;
import blanco.sample.jsf.db.query.SimpleBookSelectIterator;
import blanco.sample.jsf.util.BlancoJsfDownloadInfo;
import blanco.sample.jsf.util.BlancoJsfLogicException;
import blanco.sample.jsf.util.BlancoJsfProxyUtil;

/**
 * JSF の Managed Bean と実際の処理とをつなぐプロキシ・クラス。
 *
 * <p>faces-config.xml には以下のように登録します。</p>
 * <pre>
 * &lt;managed-bean&gt;
 * 	&lt;managed-bean-name&gt;BlancoJsfSample1Logic&lt;/managed-bean-name&gt;
 * 	&lt;managed-bean-class&gt;blanco.sample.jsf.proxy.BlancoJsfSample1LogicProxy&lt;/managed-bean-class&gt;
 * &lt;managed-bean-scope&gt;request&lt;/managed-bean-scope&gt;
 * &lt;/managed-bean&gt;
 * </pre>
 */
@SuppressWarnings("serial")
public class BlancoJsfSample1LogicProxy extends String {
    /**
     * 初期化されたかどうか。
     */
    private boolean fIsInitialized = false;

    /**
     * ページの処理結果。
     */
    private String fOutcome = "error";

    /**
     * 画面ロード時。
     *
     * @return 処理内容にかかわらず、何も戻しません。
     */
    public String getLoad() {
        if (fIsInitialized == false) {
            initialize(null);
            fIsInitialized = true;
        }
        view(null);

        return "";
    }

    /**
     * クラスをインスタンス化して処理を実行する際のエントリポイントです。
     *
     * @param nullActionEvent イベント。
     */
    public final void initialize(final ActionEvent nullActionEvent) {
        final FacesContext ctx = FacesContext.getCurrentInstance();

        // 以下のコードでコンパイル・エラーが発生する場合には、クラス [blanco.sample.jsf.BlancoJsfSample1InitializeLogicImpl] を新規に作成してください。
        final BlancoJsfSample1InitializeLogic logic = new blanco.sample.jsf.BlancoJsfSample1InitializeLogicImpl();

        // FacesMessage のワーク。
        final List<FacesMessage> facesMessageList = new ArrayList<FacesMessage>();

        try {
            try {
                logic.execute(this, facesMessageList, ctx);
            } finally {
                // ワーク上の FacesMessage を移送。
                for (FacesMessage facesMessage : facesMessageList) {
                    ctx.addMessage(null, facesMessage);
                }
            }
        } catch (BlancoJsfLogicException ex) {
            // ロジック例外が発生。
        } catch (IllegalArgumentException ex) {
            BlancoJsfProxyUtil.logIllegalArgumentException("無効引数例外: blanco.sample.jsf.BlancoJsfSample1InitializeLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (IOException ex) {
            BlancoJsfProxyUtil.logIOException("入出力例外: blanco.sample.jsf.BlancoJsfSample1InitializeLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Exception ex) {
            BlancoJsfProxyUtil.logException("例外: blanco.sample.jsf.BlancoJsfSample1InitializeLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Error er) {
            BlancoJsfProxyUtil.logError("エラー: blanco.sample.jsf.BlancoJsfSample1InitializeLogicImpl", er);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        }
    }

    /**
     * クラスをインスタンス化して処理を実行する際のエントリポイントです。
     *
     * @param nullActionEvent イベント。
     */
    public final void view(final ActionEvent nullActionEvent) {
        final FacesContext ctx = FacesContext.getCurrentInstance();

        // 以下のコードでコンパイル・エラーが発生する場合には、クラス [blanco.sample.jsf.BlancoJsfSample1ViewLogicImpl] を新規に作成してください。
        final BlancoJsfSample1ViewLogic logic = new blanco.sample.jsf.BlancoJsfSample1ViewLogicImpl();

        // FacesMessage のワーク。
        final List<FacesMessage> facesMessageList = new ArrayList<FacesMessage>();

        try {
            try {
                logic.execute(this, facesMessageList, ctx);
            } finally {
                // ワーク上の FacesMessage を移送。
                for (FacesMessage facesMessage : facesMessageList) {
                    ctx.addMessage(null, facesMessage);
                }
            }
        } catch (BlancoJsfLogicException ex) {
            // ロジック例外が発生。
        } catch (IllegalArgumentException ex) {
            BlancoJsfProxyUtil.logIllegalArgumentException("無効引数例外: blanco.sample.jsf.BlancoJsfSample1ViewLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (IOException ex) {
            BlancoJsfProxyUtil.logIOException("入出力例外: blanco.sample.jsf.BlancoJsfSample1ViewLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Exception ex) {
            BlancoJsfProxyUtil.logException("例外: blanco.sample.jsf.BlancoJsfSample1ViewLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Error er) {
            BlancoJsfProxyUtil.logError("エラー: blanco.sample.jsf.BlancoJsfSample1ViewLogicImpl", er);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        }
    }

    /**
     * クラスをインスタンス化して処理を実行する際のエントリポイントです。
     *
     * @param actionEvent イベント。
     */
    public final void add(final ActionEvent actionEvent) {
        final FacesContext ctx = FacesContext.getCurrentInstance();
        final ELContext elc = ctx.getELContext();
        final ELResolver rslvr = ctx.getApplication().getELResolver();

        // session から Managed Bean [integer] を取得します。
        final Integer argInteger = (Integer) rslvr.getValue(elc, null, "integer");
        // session から Managed Bean [blancoJsfSample2Logic] を取得します。
        final String argString = (String) rslvr.getValue(elc, null, "blancoJsfSample2Logic");

        final Connection conn = BlancoJsfProxyUtil.getConnection();
        boolean isLogicSuccess = false;
        final SimpleBookSelectIterator argSimpleBookSelectIterator = new SimpleBookSelectIterator(conn);
        final SimpleBookInsertInvoker argSimpleBookInsertInvoker = new SimpleBookInsertInvoker(conn);

        // 以下のコードでコンパイル・エラーが発生する場合には、クラス [blanco.sample.jsf.BlancoJsfSample1AddLogicImpl] を新規に作成してください。
        final BlancoJsfSample1AddLogic logic = new blanco.sample.jsf.BlancoJsfSample1AddLogicImpl();

        // FacesMessage のワーク。
        final List<FacesMessage> facesMessageList = new ArrayList<FacesMessage>();

        try {
            fOutcome = "error";
            try {
                final String outcome = logic.execute(this, argInteger, argString, argSimpleBookSelectIterator, argSimpleBookInsertInvoker, conn, facesMessageList, ctx);

                conn.commit();
                isLogicSuccess = true;
                fOutcome = outcome;
            } finally {
                // ワーク上の FacesMessage を移送。
                for (FacesMessage facesMessage : facesMessageList) {
                    ctx.addMessage(actionEvent.getComponent().getClientId(ctx), facesMessage);
                }
                argSimpleBookSelectIterator.close();
                argSimpleBookInsertInvoker.close();
            }
        } catch (BlancoJsfLogicException ex) {
            // ロジック例外が発生。
            fOutcome = "fail";
        } catch (IllegalArgumentException ex) {
            BlancoJsfProxyUtil.logIllegalArgumentException("無効引数例外: blanco.sample.jsf.BlancoJsfSample1AddLogicImpl", ex);
        } catch (IOException ex) {
            BlancoJsfProxyUtil.logIOException("入出力例外: blanco.sample.jsf.BlancoJsfSample1AddLogicImpl", ex);
        } catch (SQLException ex) {
            BlancoJsfProxyUtil.logSQLException("SQL例外: blanco.sample.jsf.BlancoJsfSample1AddLogicImpl", ex);
        } catch (Exception ex) {
            BlancoJsfProxyUtil.logException("例外: blanco.sample.jsf.BlancoJsfSample1AddLogicImpl", ex);
        } catch (Error er) {
            BlancoJsfProxyUtil.logError("エラー: blanco.sample.jsf.BlancoJsfSample1AddLogicImpl", er);
        }

        if (isLogicSuccess == false) {
            try {
                conn.rollback();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        // コネクションの開放。
        BlancoJsfProxyUtil.releaseConnection(conn);
    }

    /**
     * クラスをインスタンス化して処理を実行する際のエントリポイントです。
     *
     * @param actionEvent イベント。
     */
    public final void modify(final ActionEvent actionEvent) {
        final FacesContext ctx = FacesContext.getCurrentInstance();
        final ELContext elc = ctx.getELContext();
        final ELResolver rslvr = ctx.getApplication().getELResolver();

        // session から Managed Bean [bigDecimal] を取得します。
        final BigDecimal argBigDecimal = (BigDecimal) rslvr.getValue(elc, null, "bigDecimal");
        // session から Managed Bean [integer] を取得します。
        final Integer argInteger = (Integer) rslvr.getValue(elc, null, "integer");

        final Connection conn = BlancoJsfProxyUtil.getConnection();
        boolean isLogicSuccess = false;
        final SimpleBookSelectIterator argSimpleBookSelectIterator = new SimpleBookSelectIterator(conn);

        // 以下のコードでコンパイル・エラーが発生する場合には、クラス [blanco.sample.jsf.BlancoJsfSample1ModifyLogicImpl] を新規に作成してください。
        final BlancoJsfSample1ModifyLogic logic = new blanco.sample.jsf.BlancoJsfSample1ModifyLogicImpl();

        try {
            try {
                logic.execute(this, argBigDecimal, argInteger, argSimpleBookSelectIterator, conn, actionEvent);

                conn.commit();
                isLogicSuccess = true;
            } finally {
                argSimpleBookSelectIterator.close();
            }
        } catch (BlancoJsfLogicException ex) {
            // ロジック例外が発生。
        } catch (IllegalArgumentException ex) {
            BlancoJsfProxyUtil.logIllegalArgumentException("無効引数例外: blanco.sample.jsf.BlancoJsfSample1ModifyLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (IOException ex) {
            BlancoJsfProxyUtil.logIOException("入出力例外: blanco.sample.jsf.BlancoJsfSample1ModifyLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (SQLException ex) {
            BlancoJsfProxyUtil.logSQLException("SQL例外: blanco.sample.jsf.BlancoJsfSample1ModifyLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Exception ex) {
            BlancoJsfProxyUtil.logException("例外: blanco.sample.jsf.BlancoJsfSample1ModifyLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Error er) {
            BlancoJsfProxyUtil.logError("エラー: blanco.sample.jsf.BlancoJsfSample1ModifyLogicImpl", er);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        }

        if (isLogicSuccess == false) {
            try {
                conn.rollback();
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
        // コネクションの開放。
        BlancoJsfProxyUtil.releaseConnection(conn);
    }

    /**
     * クラスをインスタンス化して処理を実行する際のエントリポイントです。
     *
     * @param actionEvent イベント。
     */
    public final void download(final ActionEvent actionEvent) {
        final FacesContext ctx = FacesContext.getCurrentInstance();

        final ByteArrayOutputStream outStream = new ByteArrayOutputStream();
        final BlancoJsfDownloadInfo downloadInfo = new BlancoJsfDownloadInfo();
        downloadInfo.setContentType("application/octet-stream");

        // 以下のコードでコンパイル・エラーが発生する場合には、クラス [blanco.sample.jsf.BlancoJsfSample1DownloadLogicImpl] を新規に作成してください。
        final BlancoJsfSample1DownloadLogic logic = new blanco.sample.jsf.BlancoJsfSample1DownloadLogicImpl();

        try {
            try {
                logic.execute(this, downloadInfo, outStream);
                outStream.flush();
                outStream.close();
            } finally {
            }
        } catch (BlancoJsfLogicException ex) {
            // ロジック例外が発生。
        } catch (IllegalArgumentException ex) {
            BlancoJsfProxyUtil.logIllegalArgumentException("無効引数例外: blanco.sample.jsf.BlancoJsfSample1DownloadLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (IOException ex) {
            BlancoJsfProxyUtil.logIOException("入出力例外: blanco.sample.jsf.BlancoJsfSample1DownloadLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Exception ex) {
            BlancoJsfProxyUtil.logException("例外: blanco.sample.jsf.BlancoJsfSample1DownloadLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Error er) {
            BlancoJsfProxyUtil.logError("エラー: blanco.sample.jsf.BlancoJsfSample1DownloadLogicImpl", er);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        }
        try {
            // 実際のダウンロード処理。ダウンロードの成功・失敗は、このメソッドでは保証されない。
            sendBinaryResponse(outStream.toByteArray(), downloadInfo);
        } catch (IOException ex) {
            BlancoJsfProxyUtil.logIOException("入出力例外: ダウンロード: blanco.sample.jsf.BlancoJsfSample1DownloadLogicImpl", ex);
        }
    }

    /**
     * クラスをインスタンス化して処理を実行する際のエントリポイントです。
     *
     * @param argPfAutoCompleteInput リクエスト・ストリング。
     * @return レスポンス・ストリング・リスト。
     */
    public final List<java.lang.String> complete(final String argPfAutoCompleteInput) {
        final List<java.lang.String> pfAutoCompleteResult = new ArrayList<java.lang.String>();
        final FacesContext ctx = FacesContext.getCurrentInstance();

        // 以下のコードでコンパイル・エラーが発生する場合には、クラス [blanco.sample.jsf.BlancoJsfSample1CompleteLogicImpl] を新規に作成してください。
        final BlancoJsfSample1CompleteLogic logic = new blanco.sample.jsf.BlancoJsfSample1CompleteLogicImpl();

        try {
            try {
                logic.execute(this, argPfAutoCompleteInput, pfAutoCompleteResult);
            } finally {
            }
        } catch (BlancoJsfLogicException ex) {
            // ロジック例外が発生。
        } catch (IllegalArgumentException ex) {
            BlancoJsfProxyUtil.logIllegalArgumentException("無効引数例外: blanco.sample.jsf.BlancoJsfSample1CompleteLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (IOException ex) {
            BlancoJsfProxyUtil.logIOException("入出力例外: blanco.sample.jsf.BlancoJsfSample1CompleteLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Exception ex) {
            BlancoJsfProxyUtil.logException("例外: blanco.sample.jsf.BlancoJsfSample1CompleteLogicImpl", ex);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        } catch (Error er) {
            BlancoJsfProxyUtil.logError("エラー: blanco.sample.jsf.BlancoJsfSample1CompleteLogicImpl", er);
            BlancoJsfProxyUtil.redirectPageToErrorHtml(ctx);
        }
        return pfAutoCompleteResult;
    }

    /**
     * 実行結果を取得。
     *
     * @return 次画面情報。
     */
    public final String outcome() {
        return fOutcome;
    }

    /**
     * ダウンロード。
     *
     * @param bufBinary ダウンロード・データ。
     * @param downloadInfo ダウンロード情報。
     * @throws IOException 入出力例外が発生した場合。
     */
    public void sendBinaryResponse(final byte[] bufBinary, final BlancoJsfDownloadInfo downloadInfo) throws IOException {
        final FacesContext context = FacesContext.getCurrentInstance();
        final HttpServletResponse response = (HttpServletResponse) context.getExternalContext().getResponse();
        response.setContentType(downloadInfo.getContentType());
        if (downloadInfo.getAttachment()) {
            response.setHeader("Content-Disposition", "attachment; filename=" + downloadInfo.getFilename());
        }

        // コンテンツをレスポンスにコピー。
        final InputStream inStream = new BufferedInputStream(new ByteArrayInputStream(bufBinary));
        final OutputStream outStream = new BufferedOutputStream(response.getOutputStream());
        final byte[] buf = new byte[8192];
        for (;;) {
            int length = inStream.read(buf);
            if (length <= 0) {
                break;
            }
            outStream.write(buf, 0, length);
        }
        outStream.flush();
        if (response.isCommitted()) {
            try {
                outStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // ここがポイント!!　後続の処理(レンダリング等)を止めます。
        context.responseComplete();
    }
}
