package org.beetl.core.text;

import java.util.Map;
import java.util.Map.Entry;
import java.util.Stack;

import org.beetl.core.exception.BeetlException;
import org.beetl.core.exception.HTMLTagParserException;
import org.beetl.core.statement.GrammarToken;

public class HtmlTagStartFragment extends ScriptFragment {
    HTMLTagContentParser html = null;
    boolean appendCr = false;

    public HtmlTagStartFragment(Source source) {
        super(source);
    }

    @Override
    public StringBuilder getScript() {
        String tagName = null;
        Stack<String> htmlTagStack = source.htmlTagConfig.htmlTagStack;
        try {
            if (html.hasVarBinding && html.hasExportBinding) {
                throw new RuntimeException("不能同时有var 和 export ，只能选一个");
            }
            if (html.hasVarBinding) {
                script.append("htmltagvar");

            } else if (html.hasExportBinding) {
                //AntlrProgramBuilder 遇到此htmltagexport 会认为是htmltagvar，但变量作用域不限制
                script.append("htmltagexport");
            } else if (html.hasRootExportBinding) {
                //AntlrProgramBuilder 遇到此htmltagRootexport 会认为是htmltagvar，变量作用域在整个模板，相当于在模板最开始定义了一个变量
                script.append("htmltagRootExport");
            } else {
                script.append("htmltag");

            }
            tagName = html.getTagName();
            script.append("('").append(tagName).append("',");

            Map<String, String> map = html.getExpMap();
            Map<String, Character> quat = html.getQuatMap();
            if (map.size() != 0) {
                script.append("{");
            }
            for (Entry<String, String> entry : map.entrySet()) {

                String key = entry.getKey();
                String value = entry.getValue();
                if (html.crKey.contains(key)) {
                    script.append(TextParser.cr1);
                }
                // ThinkGem 2017-4-4  增加双引号，支持特殊符号的属性名
                script.append("\"").append(key).append("\"").append(":");
                String attrValue = this.parseAttr(quat.get(key), value);
                script.append(attrValue);

                script.append(",");
            }

            if (map.size() != 0) {
                script.append(html.getHtmlColMapAsString());
                script.append("}");
            } else {
                //去掉逗号
                script.setLength(script.length() - 1);
            }

            if (html.hasVarBinding || html.hasExportBinding || html.hasRootExportBinding) {
                if (map.size() == 0) {
                    // 保持三个参数，第一个为标签函数名，第二个为属性，第三个为申明的变量
                    script.append(",{}");
                }
                if (html.varBidingStr.trim().length() == 0) {
                    String defaultVarName = null;
                    int index = tagName.lastIndexOf(":");
                    if (index == -1) {
                        defaultVarName = tagName;
                    } else {
                        defaultVarName = tagName.substring(index + 1);
                    }
                    script.append(",").append("'").append(defaultVarName).append("'");
                } else {
                    script.append(",").append("'").append(html.varBidingStr).append("'");
                }

            }

            script.append("){");
            if (html.isEmptyTag()) {
                script.append("}");
            } else {
                // 记住开头
                htmlTagStack.push(tagName);
            }

            if (this.appendCr) {
                script.append(TextParser.cr1);
            }
            return script;
        } catch (RuntimeException re) {

            if (tagName == null) {
                tagName = "未知标签";
            }
            GrammarToken token = GrammarToken.createToken(tagName, this.startLine + 1);
            HTMLTagParserException ex = new HTMLTagParserException(re.getMessage());
            ex.pushToken(token);

            ex.line = source.curLine + 1;
            throw ex;

        }
    }

    @Override
    public Fragment consumeAndReturnNext() {
        String htmlTagBindingAttribute = source.htmlTagConfig.htmlTagBindingAttribute;
        html = new HTMLTagContentParser(source.getParser().attributeNameConvert, source.cs, source.p, htmlTagBindingAttribute, true);
        try {
            html.parser();
        } catch (RuntimeException ex) {
            String tagName = html.tagName == null ? "<>" : "<" + html.tagName + ">";
            throw new BeetlException(BeetlException.PARSER_HTML_TAG_ERROR, ex.getMessage(), ex)
                    .pushToken(GrammarToken.createToken(tagName, source.curLine + 1));
        }

        source.move(html.index);
        this.endLine = this.startLine + html.crKey.size();
        return super.findNext();
    }

    public String parseAttr(char q, String attr) {
        String phStart = source.htmlTagConfig.phStart;
        String phEnd = source.htmlTagConfig.phEnd;
        // return attr;
        // attr="aa{bb}cc" => ("aa"+(bb)+"cc") todo:
        // 太难看了，会有很多潜在问题，需要一个专门的解析器，类似字符串模版,或者正则表达式
        StringBuilder sb = new StringBuilder(attr.length() + 10);
        int start = 0;
        int end = 0;
        int index = -1;
        while ((index = attr.indexOf(phStart, start)) != -1) {
            int holdStart = index;
            while ((end = attr.indexOf(phEnd, holdStart)) != -1) {
                if (attr.charAt(end - 1) == '\\') {
                    // 非占位结束符号
                    holdStart = end + 1;
                } else {
                    break;
                }
            }

            if (end == -1) {
                throw new RuntimeException(attr + " 标签属性错误，有站位符号，但找不到到结束符号");
            }

            if (index != 0) {
                // 字符串
                sb.append(q).append(attr.substring(start, index)).append(q).append("+");
            }
            // 占位符号
            String value = attr.substring(index + phStart.length(), end);
            value = value.replace("\\}", "}");
            sb.append("(").append(value).append(")").append("+");
            start = end + phEnd.length();
        }
        // attr = "aaaa";
        if (start == 0) {
            // 全字符串
            return sb.append(q).append(attr).append(q).toString();
        }

        if (start != attr.length()) {
            // 最后一个是字符串
            sb.append(q).append(attr.substring(start, attr.length())).append(q);
        } else {
            // 删除“＋”
            sb.setLength(sb.length() - 1);
        }
        return sb.toString();

    }

    public void appendCr() {
        appendCr = true;
    }

}
