package org.itscool.weber.action;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import javax.servlet.ServletConfig;

import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.itscool.commons.bean.BeanFactory;

import org.itscool.commons.collection.InitParamMap;
import org.itscool.commons.document.BeanToXmlDocument;
import org.itscool.commons.request.GeneralForm;
import org.itscool.commons.request.UploadFile;
import org.itscool.weber.controller.FrontServlet;
import org.w3c.dom.Document;


/**
 * Action.execute()引数ラップクラス
 * file name : ActionBucket.java <BR>
 * @author KANO
 * @since jdk1.4.1
 * @version 1.00A 2004/11/1
 */
public class ActionBucketImpl implements ActionBucket {
    /** サーブレットインスタンス */
    private FrontServlet lnkServlet;
    
    /** HttpServletRequestインスタンス */
    private HttpServletRequest request;
    
    /** HttpServletResponseインスタンス */
    private HttpServletResponse response;
    
    /** リクエストパラメータ保有オブジェクト */
    private Object form;
    
    /** アクションを許可する権限リスト */
    private HashMap roles;
    
    /**
     * サーブレットコンテキストからRealPathを取得します
     * @param path 相対パス
     * @return サーブレットコンテキストからのRealPathを返します
     */
    public String getRealPath(String path){
        ServletConfig config = lnkServlet.getServletConfig();
        ServletContext context = null;
        if( config != null ){
            context = config.getServletContext();
        }else{
            context = lnkServlet.getServletContext();
        }
        path = context.getRealPath(path);
        return path;
    }
    
    /**
     * クエリー文字列を取得します
     * @return クエリー文字列
     */
    public String getQueryString(){
        return request.getQueryString();
    }
    
    /**
     * FrontServletインスタンスを取得します
     * @return FrontServletインスタンス
     */
    public FrontServlet getServlet() {
        return lnkServlet;
    }
    
    /**
     * FrontServletインスタンスをセットします
     * @param servlet FrontServletインスタンス
     */
    public void setServlet(FrontServlet servlet) {
        this.lnkServlet = servlet;
    }
    
//    /**
//     * HttpServletRequestインスタンスの取得
//     * @return HttpServletRequestインスタンス
//     */
//    public HttpServletRequest getRequest() {
//        return request;
//    }
    
//    /**
//     * HttpServletResponseインスタンスの取得
//     * @return HttpServletResponseインスタンス
//     */
//    public HttpServletResponse getResponse() {
//        return response;
//    }
    
    /**
     * パラメータで指定されたテキストを出力します
     * @param buff テキスト情報
     */
    public void print(String buff) throws IOException{
        BeanFactory factory = BeanFactory.getInstance();
        InitParamMap params = (InitParamMap)factory.getInstance("InitParams");
        String encode = (String) params.getParam("encoding");
        if( encode != null ){
            response.setContentType("text/html; charset=" + encode);
        }
        PrintWriter writer = response.getWriter();
        writer.write(buff);
        writer.flush();
        writer.close();
    }
    
    /**
     * ファイルのダウンロード
     * クライアントにファイルのダウンロードさせるサンプルです。
     * ブラウザではいきなりファイルが開くのではなく、「保存」するか
     * 「開く」かを選択してもらうダイアログが表示されます。
     * パラメータで指定されたInputStreamデータを出力します
     * @param is InputStreamデータ
     * @throws Exception
     */
    public void print(InputStream is, String resourceName) throws IOException{
        byte[] b = new byte[is.available()];
        for (int i = 0; i < b.length; i++)
            b[i] = (byte)is.read();
        BeanFactory factory = BeanFactory.getInstance();
        InitParamMap params = (InitParamMap)factory.getInstance("InitParams");
        String encode = (String) params.getParam("encoding");
        if( encode != null ){
            response.setContentType("application/octet-stream; charset=" + encode);
        }
       
        response.setHeader("Content-Disposition","attachment;filename="+resourceName);
        response.setContentLength(b.length);
        ServletOutputStream os = response.getOutputStream();
        os.write(b);
        os.close();
    }
    /**
     * パラメータで指定されたXMLドキュメントを出力します
     * @param document XMLドキュメント
     * @throws Exception
     */
    public void printXml(Document document) throws Exception{
        String version = System.getProperty("java.version");
//        System.out.println(version);
        if( version.indexOf("1.4") != 0 ){
//        if( version.indexOf("1.5") == 0 ){
            System.setProperty("javax.xml.transform.TransformerFactory",
                "com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl");
        }
//        System.out.println(document.getInputEncoding());
//        System.out.println(document.getXmlEncoding());
        //application/xml or text/xml
        BeanFactory factory = BeanFactory.getInstance();
        InitParamMap params = (InitParamMap)factory.getInstance("InitParams");
//        InitParamMap info = InitParamMap.getInstance();
        String encode = (String) params.getParam("encoding");
        if( encode != null ){
//modify 2006/11/28 kano start
//          response.setCharacterEncoding(encode);
//          response.setContentType("text/html; charset=" + encode);
            //TODO 暫定的な対応（Transformer.setProperty(OutputKeys.ENCODING, encode);でUTF-8をShift_JISに変換できない)
            if( version.indexOf("1.6") == 0 && document.getXmlEncoding()!=null ){
                response.setContentType("text/xml; charset=" + document.getXmlEncoding());
            }else{
                response.setContentType("text/xml; charset=" + encode);
            }
//modify 2006/11/28 kano end
        }
        ServletOutputStream out = response.getOutputStream();
        // 作成したドキュメントをHttpServletResponseで返す
        TransformerFactory transFactory = TransformerFactory.newInstance();
        Transformer transformer = transFactory.newTransformer();
        if( encode != null && encode.length() > 0 ){
            transformer.setOutputProperty(OutputKeys.ENCODING, encode);
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        }
        DOMSource source = new DOMSource(document);
        StreamResult result = new StreamResult(out);
        transformer.transform(source, result);
        out.flush();
        out.close();
    }
    /**
     * パラメータで指定されたBeanToXMLドキュメントを出力します
     * @param document BeanToXMLドキュメント
     * @throws Exception
     */
    public void printXml(BeanToXmlDocument beanToXml) throws Exception
    {
        Document document = beanToXml.getDocument();
        this.printXml(document);
    }
    
    /**
     * パラメータで指定されたオブジェクトをXMLで出力します<br>
     * オブジェクトbeanの要素名は"bean"がセットされます。<br>
     * 以下はcustomerオブジェクトをXMLに変換する例です。<br>
     * <p>
     * printXml( customer, "customer_list" );
     * </p>
     * <br>
     * <pre>
     * &lt;?xml version="1.0" encoding="Weberのエンコード"?&gt;
     * &lt;customer_list&gt;
     *    &lt;bean&gt;
     *        &lt;customerのメンバ1&gt;
     *        &lt;customerのメンバ2&gt;
     *        &lt;customerのメンバ3&gt;
     *    &lt;/bean&gt;
     * &lt;/customer_list&gt;
     * </pre>
     * @param bean オブジェクト
     * @param rootName オブジェクトのルート要素
     * @throws Exception
     */
    public void printXml(Object bean, String rootName) throws Exception{
        BeanToXmlDocument beanToXml = new BeanToXmlDocument(rootName);
        beanToXml.addElement(bean, "bean");
        printXml(beanToXml);
    }
    
    /**
     * HttpServletRequestインスタンスの設定
     * @param request HttpServletRequestインスタンス
     */
    public void setRequest(HttpServletRequest request) {
        this.request = request;
    }
    
    /**
     * HttpServletResponseインスタンスの設定
     * @param response HttpServletResponseインスタンス
     */
    public void setResponse(HttpServletResponse response) {
        this.response = response;
    }
    
    /**
     * 権限情報リストを取得します
     * @return roles 権限情報リスト
     */
    public HashMap getRoles() {
        return roles;
    }
    /**
     * 権限情報リストをセットします
     * @param roles 権限情報リスト
     */
    public void setRoles(HashMap roles) {
        this.roles = roles;
    }
    
    /**
     * 権限情報をリストに登録します
     * @param roleName 権限名
     */
    public void putRole(String roleName){
        if( roles == null ){
            roles = new HashMap();
        }
        roles.put(roleName, roleName);
    }
    /**
     * フォームオブジェクトを取得します
     * @return フォームオブジェクト
     */
    public Object getForm() {
        return form;
    }
    
    /**
     * フォームオブジェクトをセットします
     * @param object フォームオブジェクト
     */
    public void setForm(Object object) {
        form = object;
    }
    
    /**
     * リクエストスコープにオブジェクトをセットします
     * @param key パラメータのキー
     * @param val パラメータ
     */
    public void setAttribute(String key, Object val){
        request.setAttribute(key, val);
    }
    
    /**
     * リクエストスコープからオブジェクトを取得します
     * @param key パラメータのキー
     * @return リクエストパラメータ
     */
    public Object getAttribute(String key){
        return request.getAttribute(key);
    }
    
    /**
     * セッションスコープにオブジェクトをセットします
     * @param key パラメータのキー
     * @param val パラメータ
     */
    public void setAttributeFromSession(String key, Object val){
        HttpSession session = request.getSession();
        if (session.isNew()) {
            //セッションタイムアウトの値を秒で指定
            BeanFactory factory = BeanFactory.getInstance();
            InitParamMap params = (InitParamMap)factory.getInstance("InitParams");
//        InitParamMap params = InitParamMap.getInstance();
            String sessionTimeoutStr = params.getParam("session-timeout");
            if( sessionTimeoutStr != null ){
                int sessionTimeout = Integer.parseInt(sessionTimeoutStr);
                session.setMaxInactiveInterval(sessionTimeout);
            }
        }
        
        session.setAttribute(key, val);
    }
    
    /**
     * セッションスコープからオブジェクトを取得します
     * @param key パラメータのキー
     * @return リクエストパラメータ
     */
    public Object getAttributeFromSession(String key){
        HttpSession session = request.getSession();
        if (session.isNew()) {
            //セッションタイムアウトの値を秒で指定
            
            BeanFactory factory = BeanFactory.getInstance();
            InitParamMap params = (InitParamMap)factory.getInstance("InitParams");
//        InitParamMap params = InitParamMap.getInstance();
            try{
                int sessionTimeout = Integer.parseInt(params.getParam("session-timeout"));
                session.setMaxInactiveInterval(sessionTimeout);
            }catch(Exception e){}
        }
        
        return session.getAttribute(key);
    }
    
    /**
     * アプリケーションスコープにオブジェクトをセットします
     * @param key パラメータのキー
     * @param val パラメータ
     */
    public void setAttributeFromContext(String key, Object val){
        ServletContext context = lnkServlet.getServletContext();
        context.setAttribute(key, val);
    }
    
    /**
     * アプリケーションスコープからオブジェクトを取得します
     * @param key パラメータのキー
     * @return リクエストパラメータ
     */
    public Object getAttributeFromContext(String key){
        ServletContext context = lnkServlet.getServletContext();
        return context.getAttribute(key);
    }
    
    /**
     * リクエストスコープからオブジェクトを取得します
     * @param key パラメータのキー
     */
    public void removeAttribute(String key){
        request.removeAttribute(key);
    }
    
    /**
     * セッションスコープからオブジェクトを取得します
     * @param key パラメータのキー
     */
    public void removeAttributeFromSession(String key){
        HttpSession session = request.getSession();
        session.removeAttribute(key);
    }
    
    /**
     * アプリケーションスコープからオブジェクトを取得します
     * @param key パラメータのキー
     */
    public void removeAttributeFromContext(String key){
        ServletContext context = lnkServlet.getServletContext();
        context.removeAttribute(key);
    }
    
    /**
     * フォームエラー時の再入力処理
     * リクエストパラメータの値を再セットしなおす
     * @param generalForm フォームインスタンス
     */
    public void setRetryInputParam(GeneralForm generalForm) {
        Set keySet = generalForm.keySet();
        Iterator it = keySet.iterator();
        
        while( it.hasNext() ){
            String paramName = (String)it.next();
            Object paramValue = generalForm.getParameter(paramName);
            if(paramValue instanceof UploadFile){
                UploadFile file = (UploadFile)paramValue;
                String value = file.getPath() + System.getProperty("file.separator")
                + file.getFileName();
                request.setAttribute(paramName, value);
            }else{
                request.setAttribute(paramName, paramValue);
            }
        }
    }
    
    
}
