package com.gyee.alarm.rule.expression;


import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

public class Analyzer {

    public static final String FUNCODE = "Function";

    //自定义函数名集合
    public static final HashSet<String> CUSTOM_FUNS = new HashSet<String>() {{
        add("RiseExceed");
        add("LastUpdateTime");
        add("Sustain");
        add("MR");
        add("MAR");
        add("MAX");
        add("MIN");
        add("AVG");
    }};

    public static AlarmExpression getAlarmExpression(String exp) {
        ArrayList<Token> tokens = getTokens(exp);
        return createAlarmExpression(tokens);
    }

    public static ArrayList<Token> getTokens(String exp) {
        ArrayList<Token> tokens = new ArrayList<>();
        int expIndex = 0;
        int tokenIndex = 0;
        while (expIndex < exp.length()) {
            char currentChar = exp.charAt(expIndex);
            //如果当前字符是一个分隔符，则认为这是一个分隔符标记
            //给当前标记和标记类型赋值，并将指针后移
            if (isDelim(currentChar)) {
                Token token = new Token();
                token.setValue(currentChar + "");
                if (currentChar == '(') {
                    token.setTokenType(TokenType.PARENTHESISL);
                    //识别出函数名
                    if (tokens.size() > 0) {
                        Token preToken = tokens.get(tokens.size() - 1);
                        if (preToken.getTokenType() == TokenType.VARIABE &&
                                CUSTOM_FUNS.contains(preToken.getValue())) {
                            preToken.setTokenType(TokenType.CUSTOMFUN);
                        } else {
                            preToken.setTokenType(TokenType.SYSFUN);
                        }
                    }
                } else if (currentChar == ')')
                    token.setTokenType(TokenType.PARENTHESISR);
                else
                    token.setTokenType(TokenType.OTHER);

                if (currentChar != ' ')
                    tokens.add(token);
                tokenIndex = 0;
            } else if (isVariable(currentChar)) {
                if (tokenIndex == 0) {
                    Token token = new Token();
                    token.setValue(currentChar + "");
                    if (currentChar >= '0' && currentChar <= '9')
                        token.setTokenType(TokenType.CONST);
                    else
                        token.setTokenType(TokenType.VARIABE);
                    tokens.add(token);
                } else {
                    Token token = tokens.get(tokens.size() - 1);
                    token.setValue(token.getValue() + currentChar);
                }
                tokenIndex++;
            } else {
                //其他字符，忽略
            }
            expIndex++;
        }

        return tokens;
    }

    //判断一个字符是否为分隔符
    public static boolean isDelim(char c) {
        if (("+-*/><=&|! ,()".indexOf(c) != -1))
            return true;
        return false;
    }

    //判断一个字符是否为字母数字或小数点
    public static boolean isVariable(char c) {
        if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '.' || c == '_')
            return true;

        return false;
    }

    public static AlarmExpression createAlarmExpression(ArrayList<Token> tokens) {
        AlarmExpression alarmExpression = new AlarmExpression();
        alarmExpression.setFunCode("ROOT");

        List<AlarmExpression> subFun = new ArrayList<>();
        int funCnt = 0;
        List<String> varList = new ArrayList<>();
        StringBuilder sbExp = new StringBuilder();

        int tokenIndex = 0;
        while (tokenIndex < tokens.size()) {
            Token token = tokens.get(tokenIndex);
            if (token.getTokenType() == TokenType.VARIABE) {
                if (varList.contains(token.getValue()) == false)
                    varList.add(token.getValue());
                sbExp.append(token.getValue());
            } else if (token.getTokenType() == TokenType.CUSTOMFUN) {
                ArrayList<Token> subTokens = getFunTokens(tokens, tokenIndex);
                AlarmExpression subExp = createCustomFunExpression(subTokens);
                String subFunCode = FUNCODE + funCnt++;
                subExp.setFunCode(subFunCode);
                subExp.setParent(alarmExpression);
                subFun.add(subExp);
                varList.add(subFunCode);
                sbExp.append(subFunCode);

                tokenIndex += subTokens.size();
                continue;
            } else {
                sbExp.append(token.getValue());
            }

            tokenIndex++;
        }

        alarmExpression.setVarList(varList);
        alarmExpression.setExpression(sbExp.toString());
        alarmExpression.setChildren(subFun);

        return alarmExpression;
    }

    private static AlarmExpression createCustomFunExpression(ArrayList<Token> tokens) {
        AlarmExpression alarmExpression = new AlarmExpression();

        List<AlarmExpression> subExps = new ArrayList<>();
        int funCnt = 0;
        List<String> varList = new ArrayList<>();
        List<String> paramList = new ArrayList<>();
        StringBuilder sbExp = new StringBuilder();
        alarmExpression.setFunType(tokens.get(0).getValue());
        sbExp.append(tokens.get(0).getValue());

        int tokenIndex = 1;
        while (tokenIndex < tokens.size()) {
            Token token = tokens.get(tokenIndex);
            if (token.getTokenType() == TokenType.VARIABE) {
                if (varList.contains(token.getValue()) == false)
                    varList.add(token.getValue());
                sbExp.append(token.getValue());
            } else if (token.getTokenType() == TokenType.CUSTOMFUN) {
                ArrayList<Token> subTokens = getFunTokens(tokens, tokenIndex);
                AlarmExpression subExp = createCustomFunExpression(subTokens);
                subExp.setParent(alarmExpression);
                String subFunCode = FUNCODE + funCnt++;
                subExp.setFunCode(subFunCode);
                subExps.add(subExp);
                varList.add(subFunCode);
                sbExp.append(subFunCode);
                tokenIndex += subTokens.size();
                continue;
            } else {
                sbExp.append(token.getValue());
            }

            tokenIndex++;
        }

        alarmExpression.setVarList(varList);
        alarmExpression.setExpression(sbExp.toString());
        alarmExpression.setChildren(subExps);

        return alarmExpression;
    }

    private static ArrayList<Token> getFunTokens(ArrayList<Token> tokens, int startIndex) {
        ArrayList<Token> result = new ArrayList<>();
        int cntL = 0;
        int cntR = 0;
        while (startIndex < tokens.size()) {
            Token token = tokens.get(startIndex);
            result.add(token);
            if (token.getTokenType() == TokenType.PARENTHESISL) {
                cntL++;
            } else if (token.getTokenType() == TokenType.PARENTHESISR) {
                if (++cntR == cntL) {
                    break;
                }
            }
            startIndex++;
        }

        return result;
    }


    public static void main(String[] args) {
        //String exp = "AI041>80 && AI_FJZT!=3";
        //String exp = "LastUpdateTime(AI03229)>=1800 && LastUpdateTime(AI03101)>=1800 && LastUpdateTime(DI07893)>=1800 && LastUpdateTime(DI07436)>=1800 && LastUpdateTime(DI07822)>=1800";

        //String exp = "Sustain(AI022 > 4.5 && AI_FJZT==0,Math.Abs(600-100),60)";

        String exp = "Sustain(FJAI022 > 4.5 && FCAI_FJZT==0 && LastUpdateTime(AI03229)>=1800 && LastUpdateTime(AI03101)>=1800 ,Math.Abs(600-100),60)";

        ArrayList<Token> tokens = getTokens(exp);
        for (Token token : tokens) {
            System.out.println(token.getValue() + "----" + token.getTokenType());
        }

        AlarmExpression alarmExpression = createAlarmExpression(tokens);
        System.out.println(alarmExpression.getFunType());

    }
}
