package org.itscool.stylist.io;

import java.util.ArrayList;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.itscool.commons.bean.BeanFactory;
import org.itscool.commons.bean.BeanFactoryRuntimeException;
import org.itscool.commons.util.ServletTagUtil;
import org.itscool.stylist.tag.HtmlTag;
import org.itscool.stylist.tag.HtmlText;

/**
 * 解析済みのXHTMLに実行結果を反映し、応答用のXHTMLデータを作成する
 * スーパークラスです
 * @author kano
 * @version 1.00A 2006/08/09 新規作成
 */
public class HtmlConverter {
    /**
     * EL式の開始キーワード
     */
    public static final String TAG_START = "${";
    /**
     * EL式の終了キーワード
     */
    public static final String TAG_END = "}";
    /**
     * 改行コード
     */
    public static final String LINE = System.getProperty("line.separator");
    /**
     * タブ
     */
    public static final String TAB = "    ";
    /**
     * ServletContextインスタンス
     */
    protected ServletContext context;
    
    /**
     * HttpServletRequestインスタンス
     */
    protected HttpServletRequest req;
    
    
    public void setContext(ServletContext context) {
        this.context = context;
    }
    
    public void setReq(HttpServletRequest req) {
        this.req = req;
    }
    
    /**
     * インスタンスの初期化を行います
     * @param context ServletContextインスタンス
     * @param req HttpServletRequestインスタンス
     */
//    public HtmlConverter(ServletContext context, HttpServletRequest req){
//        this.context = context;
//        this.req = req;
//    }
    public void init(ServletContext context, HttpServletRequest req){
        this.context = context;
        this.req = req;
    }
    
    /**
     * 応答用のXHTMLデータの作成を開始します
     * @param node HtmlTagインスタンス
     * @return 応答データ
     */
    public String convert(HtmlTag node){
        return convert(node, "");
    }
    
    /**
     * 応答用のXHTMLデータを作成します
     * @param node HtmlTagインスタンス
     * @param stab タブ
     * @return 応答データ
     */
    public String convert(HtmlTag node, String stab){
        StringBuffer sb = new StringBuffer();
        String tagName = node.getTagName();
        String tagKind = node.getTagKind();
        String tab=stab;
//		HtmlTag parent = node.getParent();
//		if( parent != null && parent.getTagName().equals(HtmlTag.TEXT)){
//			tab = "";
//		}
        if( tagKind.equals(HtmlTag.KIND_TAG)){
//            HtmlBlockTagConverter converter = new HtmlBlockTagConverter(context, req);
            HtmlBlockTagConverter converter = new HtmlBlockTagConverter();
            converter.init(context, req);
            sb.append(converter.convert( node, tab)).append(LINE);
        } else if( tagKind.equals(HtmlTag.KIND_TEXT)){
//            HtmlTextConverter converter = new HtmlTextConverter(context, req);
            HtmlTextConverter converter = new HtmlTextConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_CDATA)){
//            HtmlCdataConverter converter = new HtmlCdataConverter(context, req);
            HtmlCdataConverter converter = new HtmlCdataConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_COMMENT)){
//            HtmlCommentConverter converter = new HtmlCommentConverter(context, req);
            HtmlCommentConverter converter = new HtmlCommentConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_DISPLAY_ERROR)){
//            HtmlErrorInfoTagConverter converter = new HtmlErrorInfoTagConverter(context, req);
            HtmlErrorInfoTagConverter converter = new HtmlErrorInfoTagConverter();
            converter.init(context, req);
            sb.append(converter.convert()).append(LINE);
        } else if( tagKind.equals(HtmlTag.KIND_SIMPLE_TAG)){
//            HtmlSimpleTagConverter converter = new HtmlSimpleTagConverter(context, req);
            HtmlSimpleTagConverter converter = new HtmlSimpleTagConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_ISNULL)){
            HtmlIsNullConverter converter = new HtmlIsNullConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_ISNOTNULL)){
            HtmlIsNotNullConverter converter = new HtmlIsNotNullConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_WRITE)){
            HtmlWriteTagConverter converter = new HtmlWriteTagConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_EQUAL)
        || tagKind.equals(HtmlTag.KIND_NOTEQUAL)
        || tagKind.equals(HtmlTag.KIND_MOREEQUAL)
        || tagKind.equals(HtmlTag.KIND_LESSEQUAL)
        || tagKind.equals(HtmlTag.KIND_MORETHAN)
        || tagKind.equals(HtmlTag.KIND_LESSTHAN)
        || tagKind.equals(HtmlTag.KIND_MATCH)
        || tagKind.equals(HtmlTag.KIND_NOMATCH)
        ){
//            HtmlCompareTagConverter converter = new HtmlCompareTagConverter(context, req);
            HtmlCompareTagConverter converter = new HtmlCompareTagConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_ITERATE)){
//            HtmlIterateTagConverter converter = new HtmlIterateTagConverter(context, req);
            HtmlIterateTagConverter converter = new HtmlIterateTagConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab));
        } else if( tagKind.equals(HtmlTag.KIND_INCLUDE)){
//            HtmlIncludeTagConverter converter = new HtmlIncludeTagConverter(context, req);
            HtmlIncludeTagConverter converter = new HtmlIncludeTagConverter();
            converter.init(context, req);
            sb.append(converter.convert(node, tab)).append(LINE);
        }
        //カスタムコンバーターの使用
        else{
            BeanFactory factory = BeanFactory.getInstance();
            if( !factory.isInit() ){
                throw new CustConverterInitException("BeanFactory is not initialized.");
            }
            Object obj = null;
            try{
                obj = factory.createInstance( tagKind );
            }catch( BeanFactoryRuntimeException bre ){
                throw new CustConverterInitException("Can not create CustomConverter class  (" + tagKind + ").");
            }
            if( obj instanceof HtmlConverter ){
                HtmlConverter customConverter = (HtmlConverter)obj;
                if( customConverter == null ){
                    throw new CustConverterInitException("Can not create CustomConverter class  (" + tagKind + ").");
                }
                customConverter.setContext(context);
                customConverter.setReq(req);
                sb.append(customConverter.convert(node, tab)).append(LINE);
            }
        }
        return sb.toString();
    }
    
    /**
     * EL式部分を解析します
     * @param tagStr テキスト情報
     * @return ArrayList テキスト情報の解析結果
     */
    public static ArrayList parseEl(String tagStr){
        ArrayList tagList = new ArrayList();
        while( tagStr.length() > 0 ){
            int startKey = tagStr.indexOf(TAG_START);
            int endKey = tagStr.indexOf(TAG_END);
            if (startKey > 0) {
                String value = tagStr.substring(0, startKey);
                HtmlText stag = new HtmlText();
                stag.setKind(HtmlText.KIND_SIMPLE);
                stag.setValue(value);
                tagList.add(stag);
            } else if (startKey == -1 && tagStr.length() > 0) {
                HtmlText stag = new HtmlText();
                stag.setKind(HtmlText.KIND_SIMPLE);
                stag.setValue(tagStr);
                tagList.add(stag);
                return tagList;
            }
            String tagValue = tagStr.substring(startKey, endKey + 1);
            HtmlText tag = new HtmlText();
            tag.setKind(HtmlText.KIND_CONTROL);
            tag.setValue(tagValue);
            tagList.add(tag);
            if (endKey + 1 >= tagStr.length()) {
                return tagList;
            }
            tagStr = tagStr.substring(endKey + 1, tagStr.length());
        }
        return tagList;
    }
    
    
    protected String parseText(ArrayList tagList) {
        StringBuffer sb = new StringBuffer("");
        for(int i=0; i<tagList.size(); i++ ){
            HtmlText tag = (HtmlText)tagList.get(i);
            if( tag.getKind() == HtmlText.KIND_SIMPLE){
//				sb.append(tab);
                sb.append(tag.getValue());
            }else{
                String value = "";
                Object obj = ServletTagUtil.findValue(context, req, tag.getValue(), null);
                if( obj != null ){
                    value = obj.toString();
                }
//				sb.append(tab);
                sb.append(value);
            }
        }
        return sb.toString();
    }
    
}

class CustConverterInitException extends RuntimeException{
    public CustConverterInitException(Exception e){
        super(e);
    }
    
    public CustConverterInitException(String msg){
        super(msg);
    }
}

