package org.itscool.commons.request;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;

import org.itscool.commons.bean.BeanFactory;
import org.itscool.commons.logging.AbstractLog;
import org.itscool.commons.logging.SimpleLog;
import org.itscool.commons.util.StringUtil;
import org.itscool.commons.util.URLDecodeUtil;


/**
 * 抽象リクエストパラメータ保持クラス
 * @version 1.00A yyyy/mm/dd 新規作成
 * @version 1.00B 2006/03/08 POSTメソッド以外で重複パラメータが存在する場合、
 * 最初に選択された項目しか保持されない現象への対応を追加。
 */
public abstract class HttpGeneralForm extends GeneralForm{
    /** 重複キーリスト */
    private HashMap duplicateKeys = new HashMap();
    protected static AbstractLog log;
    
    static{
        BeanFactory factory = BeanFactory.getInstance();
        try{
            log = (AbstractLog)factory.getInstance("Log");
            if(!log.isInit()){
                log = (AbstractLog)factory.createInstance("Log");
            }
        }catch(Exception ioe){
            log = SimpleLog.getInstance();
            log.info(ioe.getMessage());
        }
    }

//move 2006/12/08 kano start -> GeneralFormFactory
//    /**
//     * HttpServletRequestインスタンスの受信処理
//     * @param req HttpServletRequestインスタンス
//     * @throws IOException
//     */
//    public void parseData(HttpServletRequest req, String encode) throws IOException {
//        //System.out.println("MMMEEEETTTTHHHHOOOODDD:"+req.getMethod());
//        
//        ByteArrayOutputStream bao = new ByteArrayOutputStream();
//        DataInputStream dis = new DataInputStream(req.getInputStream());
//        
//        boolean flag=true;
//        while(flag) {
//            try {
//                byte b=dis.readByte();
//                bao.write(b);
//            } catch(EOFException e){
//                flag=false;
//            }
//        }
//        //formアクションにてmethod属性が指定されていない場合はInputStreamが取得
//        //できない現象の対応
//        if( bao.size() == 0 ){
//            doDefaultParseData(req, encode);
//        }else{
//            doParseData(bao.toByteArray(), encode);
//        }
//    }
//move 2006/12/08 kano end -> GeneralFormFactory    
    
//    public void parseData(HttpServletRequest req) throws IOException {
//        ByteArrayOutputStream bao = new ByteArrayOutputStream();
//        InputStreamReader isr = new InputStreamReader(req.getInputStream(), "JISAutoDetect");
//        BufferedReader br = new BufferedReader(isr);
//
//        boolean flag=true;
//        StringBuffer sb = new StringBuffer();
//        while(flag) {
//            try {
//                String str = br.readLine();
//                if(str == null){
//                    flag = false;
//                    break;
//                }
//                sb.append( str );
//
//            } catch(EOFException e){
//                flag=false;
//            }
//        }
//
//        //formアクションにてmethod属性が指定されていない場合はInputStreamが取得
//        //できない現象の対応
//        if( sb.length() == 0 || sb.toString().length() == 0 ){
//            doDefaultParseData(req);
//        }else{
//            doParseData(sb.toString().getBytes("ISO-8859-1"));
//            System.out.println(new String( sb.toString().getBytes(),  "JIS" ));
//        }
//    }
//
    /**
     * リクエストパラメータを解析します
     * @param buffer HttpServletRequestインスタンスのInputStreamから
     * 取得したバイトデータ
     * @param encode エンコーディング
     */
    protected abstract void doParseData(byte[] buffer, String encode );
    
    /**
     * リクエストパラメータを取得します
     * @param req HttpServletRequestインスタンス
     */
    public void doDefaultParseData(HttpServletRequest req, String encode)
    throws IOException{
//modify 2006/3/8 kano start
//        Enumeration params = req.getParameterNames();
//        while( params.hasMoreElements() ){
//            String name = (String)params.nextElement();
//            String value = req.getParameter(name);
//            try{
//            	value = URLDecodeUtil.decode(value, encode);
//            }catch(Exception e){
//            	throw new IOException(e.getMessage());
//            }
////            //名前の後に「.x」や「.y」がついてしまう現象への対応
////            int index = name.indexOf(".");
////            if(index != -1){
////                name = name.substring(0, index);
////            }
//            this.addParameter(name, value);
//        }
        
        Map pmap = req.getParameterMap();
        Set hset = pmap.keySet();
        Iterator iter = hset.iterator();
        int hno = hset.size();
        while (iter.hasNext()) {
            String name = (String)iter.next();
            String[] values = (String[])pmap.get(name);
            String value;
            String cValue;
            if( values.length==1){
                try{
                    value = values[0];
                    //文字エンコーディング
                    cValue = URLDecodeUtil.decode(value.toString(), encode);
//add 2006/10/06 kano start
                    //クロススクリプティング対応
                    cValue = URLDecodeUtil.filter(cValue);
                    if(!cValue.equals(value)){
                        log.warn("recieved cross scripting => "+value);
                    }
//add 2006/10/06 kano end
                    
                }catch(Exception e){
                    throw new IOException(e.getMessage());
                }
//                log.debug("request param defaultParse(befor encode) key="+name+" value="+value);
//                log.debug("request param defaultParse(afgter encode) key="+name+" value="+cValue);
                log.trace("request param defaultParse key="+name+" value="+cValue);
                this.addParameter(name, cValue);
            }else{
                for(int i=0; i<values.length; i++){
                    value = values[i];
//add 2006/10/06 kano start
                    //クロススクリプティング対応
                    cValue = URLDecodeUtil.filter(value.toString());
                    if(!cValue.equals(value)){
                        log.warn("recieved cross scripting => "+value);
                    }
                    //文字エンコーディング
                    cValue = URLDecodeUtil.decode(cValue, encode);
//add 2006/10/06 kano end
                    log.trace("request param defaultParse key="+name+" value="+cValue);
                    this.addParameter(name, cValue);
                }
            }
            
        }
        //重複キーによる複数パラメータのマージを行う
        margeParamsByDuplicateKey();
//modify 2006/3/8 kano end
    }
    /**
     * パラメータを追加します
     * @param key パラメータを特定する論理名称
     * @param obj セットするパラメータ
     */
    public void addParameter(String key, Object obj){
//modify 2006/3/8 kano start
//    	名前の後に「.x」や「.y」がついてしまう現象への対応
        int index = key.indexOf(".");
        if(index != -1){
            key = key.substring(0, index);
        }
        Object chkObj = this.getParameter(key);
        
//add 2006/10/06 kano start
        if( obj instanceof java.lang.String){
            //クロススクリプティング対応
            obj = URLDecodeUtil.filter(obj.toString());
        }
//add 2006/10/06 kano end
        
        if( chkObj != null){
            //既に重複パラメータが登録されていないかチェック
            ArrayList duplicateParams = (ArrayList)duplicateKeys.get(key);
            //新規登録時
            if(duplicateParams == null){
                duplicateParams = new ArrayList();
                duplicateKeys.put(key, duplicateParams);
                
                //最初のパラメータをリストに追加
                duplicateParams.add(chkObj);
            }
            //重複パラメータリストをセット
            duplicateParams.add(obj);
        }
//    	//名前の後に「.x」や「.y」がついてしまう現象への対応
//        int index = key.indexOf(".");
//        if(index != -1){
//        	key = key.substring(0, index);
//        }else{
//	    	Object chkObj = this.getParameter(key);
//	    	if( chkObj != null){
//	    		//既に重複パラメータが登録されていないかチェック
//	    		ArrayList duplicateParams = (ArrayList)duplicateKeys.get(key);
//	    		//新規登録時
//	    		if(duplicateParams == null){
//	    			duplicateParams = new ArrayList();
//	    			duplicateKeys.put(key, duplicateParams);
//
//	    			//最初のパラメータをリストに追加
//	    			duplicateParams.add(chkObj);
//	    		}
//	    		//重複パラメータリストをセット
//	    		duplicateParams.add(obj);
//	    	}
//        }
//modify 2006/3/8 kano end
        super.addParameter(key, obj);
    }
    
    /**
     * 複数チェックボックス対応<BR>
     * 重複キーによる複数パラメータをListインターフェースにマージします
     */
    protected void margeParamsByDuplicateKey(){
        Set keySet = duplicateKeys.keySet();
        Iterator it = keySet.iterator();
        
        while(it.hasNext()){
            String paramName = (String)it.next();
            List paramList = (List)duplicateKeys.get(paramName);
            
            //登録済みの単一データを削除
            super.removeParameter(paramName);
            //パラメータリストに置き換え
            super.addParameter(paramName, paramList);
        }
    }
    
    
//    /**
//     * パラメータを追加します
//     * @param key パラメータを特定する論理名称
//     * @param obj セットするパラメータ
//     */
//    public void addParameter(String key, Object obj){
//        this.put(key, obj);
//    }
    
    
}
