/*
 * $Id: PageResponse.java,v 1.7 2006/05/12 10:47:35 sugimotokenichi Exp $
 * Copyright (C) 2006 SUGIMOTO Ken-ichi
 * 作成日: 2006/03/17
 */
package feat2.impl;

import java.io.IOException;
import java.io.Writer;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import feat2.ApplicationException;
import feat2.CommandContext;
import feat2.FileUploadException;
import feat2.Processor;
import feat2.PropertyAccessException;
import feat2.Response;
import feat2.TemplateLoader;
import feat2.TemplateParsingException;
import feat2.View;
import feat2.config.PageConfig;
import feat2.config.ViewConfig;
import feat2.template.HTMLDocument;
import feat2.template.HTMLElement;
import feat2.template.HTMLTemplate;
import feat2.template.NodeFactory;
import feat2.template.NodeNotFoundException;

public class PageResponse implements Response {

    private PageConfig pageConfig;

    public PageResponse(PageConfig config) {
        this.pageConfig = config;
    }

    public String output(CommandContext ctx) throws IOException, PropertyAccessException, TemplateParsingException, ApplicationException, FileUploadException {

        // テンプレートのロード

        HTMLTemplate template = TemplateLoader.load(pageConfig.getTemplateFile(), ctx.getLocale(), null);
        String encoding = template.getEncoding();
        HTMLDocument doc = template.getDocument();

        // viewの実行

        String ret = processView(doc, ctx);
        if ( ret != null )
            return ret;

        // HTTPヘッダ

        HttpServletResponse response = ctx.getResponse();
        response.setContentType("text/html;charset="+encoding);

        // Cacheコントロール

        if ( pageConfig.getMaxAge() != null ) {

            int maxAge = pageConfig.getMaxAge().intValue();

            if ( maxAge > 0 ) {

                response.setDateHeader("Expires", System.currentTimeMillis() + maxAge * 1000);
                response.setHeader("Cache-Control", "max-age="+maxAge);

            }
            else {

                response.setHeader("Pragma", "no-cache");
                response.setHeader("Cache-Control", "no-cache");

                // HTMLにもmeta要素でno-cacheを指示

                try {
                    HTMLElement html = (HTMLElement)doc.find("html");
                    HTMLElement head;
                    try {
                        head = html.getTag("head");
                    }
                    catch (NodeNotFoundException ex) {
                        head = NodeFactory.createHTMLElement("head", true);
                    }

                    HTMLElement pragma = NodeFactory.createHTMLElement("meta", false);
                    pragma.setAttribute("http-equiv", "Pragma");
                    pragma.setAttribute("content", "no-cache");

                    HTMLElement cacheControl = NodeFactory.createHTMLElement("meta", false);
                    cacheControl.setAttribute("http-equiv", "Cache-Control");
                    cacheControl.setAttribute("content", "no-cache");

                    head.addChild(pragma);
                    head.addChild(cacheControl);
                }
                catch (NodeNotFoundException ex1) {
                }

            }

        }

        // ドキュメントの出力

        Writer writer = response.getWriter();
        writer.write(doc.toHTML());
        writer.flush();
        writer.close();

        return null;

    }

    private String processView(HTMLDocument doc, CommandContext ctx) throws PropertyAccessException, ApplicationException, FileUploadException {

        ViewConfig[] views = pageConfig.getViews();

        for (int i = 0; i < views.length; i++) {

            // 入力値の取得

            Map values = Processor.processInputs(views[i], ctx);

            View view = views[i].getViewInstance();

            // バリデーション

            if ( !Processor.processValidations(view, values, views[i], ctx) )
                return views[i].getErrorResponse().getValue();

            // ビューのプロパティにセット

            Processor.processInjection(view, values);

            // ビューの実行

            try {
                view.format(doc, views[i], ctx);
            }
            catch (Exception ex) {
                throw new ApplicationException(ex);
            }

        }

        return null;

    }

}
