package org.itscool.stylist.controller;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.itscool.commons.bean.BeanFactory;
import org.itscool.commons.collection.InitParamMap;
import org.itscool.commons.util.FileUtil;
import org.itscool.commons.util.TagInfo;
import org.itscool.commons.util.TagUtil;
import org.itscool.stylist.io.HtmlConfigReader;
import org.itscool.stylist.io.HtmlConverter;
import org.itscool.stylist.tag.HtmlRootTag;
import org.itscool.stylist.el.LayoutRegex;

/**
 * XHTMLを解析し、実行結果をXHTML形式で出力するクラスです<br/>
 * Stylist独自の構文を挿入することにより、動的な画面表示も可能です<br/>
 * またベースがXHTML形式であるため、AjaxやRSSとの連携もJSPよりシームレスに
 * 行うことができます。<br/>
 *
 * @author kano
 * @version 1.00A 2006/08/09 新規作成
 */
public class HtmlLayoutServlet4x extends HtmlLayoutServlet{
    /**
     * doGet()、doPost()メソッドの処理を実行します<br>
     * @param req Httpリクエストインスタンス
     * @param res Httpレスポンスインスタンス
     */
    protected void process(HttpServletRequest req, HttpServletResponse res)
    throws ServletException, IOException {
        String path = context.getRealPath(req.getServletPath());
        BeanFactory factory = BeanFactory.getInstance();
        InitParamMap params = (InitParamMap)factory.getInstance("InitParams");
        
        String encode = params.getParam("encoding");
        if(encode == null){
            log.warn("No set inita param[encoding] default set[Shift_JIS]");
            encode = "Shift_JIS";
        }
        HtmlRootTag html = (HtmlRootTag)cacheMap.get(path);
        HtmlConfigReader reader = new HtmlConfigReader();
        reader.setDefaultEncode(encode);
        //キャッシュが存在しないあるいはキャッシュの更新日付が古い場合
        if( html == null || html.getLastModified()!=FileUtil.getLastModified(path)){
            html = new HtmlRootTag(encode);
            reader.create(path, html);
            cacheMap.put(path, html);
            log.trace("HtmlTag instance is created");
        }else{
            log.trace("HtmlTag instance geted from chache");
        }
        log.trace(html.toString(0, ""));
        String convStr;
        
        HtmlConverter converter = new HtmlConverter();
        converter.init(context, req);
        convStr = html.getXml()+System.getProperty("line.separator");
        convStr += html.getDtd()+System.getProperty("line.separator");
        convStr += converter.convert(html);
        //JSP1.2でEL式(簡易版)を使うための処理を追加
        convStr = new String(convStr);
        LayoutRegex regex = new LayoutRegex(context, req);
        //./で始まるパスをWebアプリケーションからの論理パスに変換
        convStr = regex.replacePath(convStr);
//delete 2007/03/19 kano start HtmlTextConverterにて処理
////add 2007/03/17 kano start
//        //Functionを展開する
//        String orgPkg = params.getParam("pkgName");
//        convStr = regex.replaceFunction(orgPkg, convStr);
////add 2007/03/17 kano end
//        //EL式を展開する
//        convStr = regex.replaceEl(convStr);
//delete 2007/03/19 kano end HtmlTextConverterにて処理

        //レイアウト情報を取得
        String servletPath = req.getServletPath();
        String layoutPath = layout(servletPath, req);
        if( layoutPath != null ){
            //HTML情報をHEAD部とBODY部に展開する
            TagInfo body = TagUtil.createTagInfo(convStr, TagInfo.BODY_NAME);
            TagInfo head = TagUtil.createTagInfo(convStr, TagInfo.HEAD_NAME);
            if( body != null ){
                //BODY内部の出力
                req.setAttribute(Globals.REQ_PARAM_INCLUDE_BODY,
                    body.getDataInTag());
                if(head != null ){
                    //HEAD要素記述部の出力（レイアウトで振り分ける）
                    req.setAttribute(Globals.REQ_PARAM_INCLUDE_HEAD,
                        head.getDataInTag());
                }
            }else{
                req.setAttribute(Globals.REQ_PARAM_INCLUDE_BODY, convStr);
            }

            //レイアウト情報を解析します
            String contextPath = req.getServerName();
            int port = req.getServerPort();
//            String layoutPath = context.getRealPath(layoutName);
            HtmlRootTag layoutTag = new HtmlRootTag(encode);
            HtmlConfigReader layoutReader = new HtmlConfigReader();
            layoutReader.setDefaultEncode(encode);
            layoutReader.create(layoutPath, layoutTag);
            convStr = converter.convert(layoutTag);
            if( body != null ){
                //レイアウト要素のbody要素をメインコンテンツのbody要素に置き換える
                String bodyTagStr = body.getStartTag();
                Pattern pattern = Pattern.compile("<body>");
                Matcher matcher = pattern.matcher(convStr);
                convStr = matcher.replaceAll(body.getStartTag());
            }
        }

//        if( !res.isCommitted() ){
//            res.reset();
//            //IE6でローカルHTMLのクッキーが保持されない現象への対応
//            initSessionTimeout(req, res);
//        }
        
        //ContentTypeを設定
        res.setContentType("text/html; charset=" + encode);
        
        //HTMLの解析結果を出力
        PrintWriter writer = res.getWriter();
        writer.write(convStr);
        writer.flush();
        writer.close();
    }
    
    /**
     * レイアウト情報を取得します
     * @param path クライアントから要求されたリクエストURI
     * @param req HttpServletRequestインスタンス
     * @return インクルードを含むフォワード先のJSP名
     */
    protected String layout(String path, HttpServletRequest req)
    throws IOException, ServletException{
        String reqPath = context.getRealPath(req.getServletPath());
        RequestDispatcher dispatch = new RequestDispatcher(reqPath);
        String layoutPath = dispatch.getTemplatePath(RequestDispatcher.LAYOUT);
        if( layoutPath == null ){
            log.trace("[NOT FOUND LAYOUT(" + reqPath + ")]");
            String layoutName =  super.layout(path, req);
            layoutPath = context.getRealPath(layoutName);
            return layoutPath;
        }
        log.trace("[FOUND LAYOUT(" + reqPath + ")]"+layoutPath);
        
        //コンテンツ情報をパースします
        BeanFactory factory = BeanFactory.getInstance();
        InitParamMap params = (InitParamMap)factory.getInstance("InitParams");
        String encode = params.getParam("encoding");
        if(encode == null){
            log.warn("No set inita param[encoding] default set[Shift_JIS]");
            encode = "Shift_JIS";
        }
        
        HtmlRootTag layoutTag = (HtmlRootTag)cacheMap.get(layoutPath);
        HtmlConfigReader reader = new HtmlConfigReader();
        reader.setDefaultEncode(encode);
        if( layoutTag == null || layoutTag.getLastModified()!=FileUtil.getLastModified(layoutPath)){
            layoutTag = new HtmlRootTag(encode);
            File file = new File(layoutPath);
            if( !file.isFile()){
                throw new RequestDispatchException("テンプレートファイル[" + layoutPath + "]が見つかりませんでした");
            }
            reader.create(layoutPath, layoutTag);
            log.trace(layoutTag.toString(0, ""));
            cacheMap.put(layoutPath, layoutTag);
            log.trace("HtmlTag(layout) instance is created");
        }else{
            log.trace("HtmlTag(layout) instance geted from chache");
        }
        
        Object[] templates = dispatch.parseLayoutTag(layoutTag);
        for(int i=0; i<templates.length; i++ ){
            String template = (String)templates[i];
            if( template.equals("body") || template.equals("head")){
                continue;
            }
            setIncludeContents(dispatch, template, req);
        }
        
        return layoutPath;
    }
    
    /**
     * レイアウト情報から部分コンテンツ情報を取得し、リクエストパラメータ
     * にセットします
     * @param dispatch リクエスト情報
     * @param attrName レイアウト情報をあらわすユニークな名前
     * @param req HttpServletRequest情報
     * @throws IOException
     */
    protected void setIncludeContents(RequestDispatcher dispatch,
        String attrName, HttpServletRequest req)
        throws IOException{
        String layoutPath = dispatch.getTemplatePath(attrName);
        if( layoutPath == null ){
//            throw new RequestDispatchException("属性[" + attrName +"]に対応するテンプレートファイルが見つかりませんでした");
            req.setAttribute(Globals.REQ_PARAM_INCLUDE + attrName, "[NOTFOUND LAYOUT PARTS FILE" + attrName + "]"+layoutPath);
            log.trace("[NOTFOUND LAYOUT" + attrName + "]"+layoutPath);
            return;
        }
        log.trace("[FOUND LAYOUT " + attrName + "]"+layoutPath);
        
        //コンテンツ情報が格納されているパスを取得
        String contextPath = req.getServerName();
        int port = req.getServerPort();
//        String layoutPath = context.getRealPath(layoutName);
        
        //コンテンツ情報をパースします
        BeanFactory factory = BeanFactory.getInstance();
        InitParamMap params = (InitParamMap)factory.getInstance("InitParams");
        String encode = params.getParam("encoding");
        if(encode == null){
            log.warn("No set inita param[encoding] default set[Shift_JIS]");
            encode = "Shift_JIS";
        }
        
        HtmlRootTag layoutTag = (HtmlRootTag)cacheMap.get(layoutPath);
        HtmlConfigReader reader = new HtmlConfigReader();
        reader.setDefaultEncode(encode);
        if( layoutTag == null || layoutTag.getLastModified()!=FileUtil.getLastModified(layoutPath)){
            layoutTag = new HtmlRootTag(encode);
            File file = new File(layoutPath);
            if( !file.isFile()){
                throw new RequestDispatchException("テンプレートファイル[" + layoutPath + "]　属性[" + attrName +"]が見つかりませんでした");
            }
            reader.create(layoutPath, layoutTag);
            cacheMap.put(layoutPath, layoutTag);
            log.trace("HtmlTag(layout) instance is created");
        }else{
            log.trace("HtmlTag(layout) instance geted from chache");
        }
        
        HtmlConverter converter = new HtmlConverter();
        converter.init(context, req);
        String convStr = converter.convert(layoutTag);
        LayoutRegex regex = new LayoutRegex(context, req);
        //./で始まるパスをWebアプリケーションからの論理パスに変換
        //できればここの変換もConverterに委譲したい
        convStr = regex.replacePath(convStr);
//delete 2007/03/19 kano start HtmlTextConverterにて処理
////add 2007/03/17 kano start
//        //Functionを展開する
//        String orgPkg = params.getParam("pkgName");
//        convStr = regex.replaceFunction(orgPkg, convStr);
////add 2007/03/17 kano end
//        //EL式を展開する
//        convStr = regex.replaceEl(convStr);
//delete 2007/03/19 kano end HtmlTextConverterにて処理

        //EL式を展開する
        convStr = regex.replaceEl(convStr);
        
        TagInfo body = TagUtil.createTagInfo(convStr, TagInfo.BODY_NAME);
        if( body != null ){
            //BODY内部の出力
            req.setAttribute(Globals.REQ_PARAM_INCLUDE + attrName, body.getDataInTag());
        }else{
            req.setAttribute(Globals.REQ_PARAM_INCLUDE + attrName, convStr);
        }
    }
    
}


