package com.yihu.hos.system.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.yihu.hos.common.graph.Edge;
import com.yihu.hos.common.graph.IDGraph;
import com.yihu.hos.core.datatype.CollectionUtil;
import com.yihu.hos.core.datatype.StringUtil;

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

public class ProcessEditor {

    private String code;
    private Map<String, JsonNode> lineMap;
    private Map<String, JsonNode> nodeMap;
    private Iterator<String> nodeIt;
    private IDGraph<String> mDG;
    private StringBuilder bodyBuilder = new StringBuilder();
    private List<String> packageList = new ArrayList<>();
    private StringBuilder otherRouteBuilder = new StringBuilder();
    private StringBuilder preferBuilder = new StringBuilder();

    public String generate(String javaName, String packageName) throws IOException {
        Boolean isFirstNodeFlg = true;
        StringBuilder allBuilder = new StringBuilder();

//        packageBuilder.append("import org.apache.camel.Exchange;\n");
        addPackageList("import org.apache.camel.builder.RouteBuilder;\n");

        preferBuilder.append("public class "+javaName+" extends RouteBuilder {\n");
        preferBuilder.append("public void configure() throws Exception {\n");
        String nodeName = "";
        while(nodeIt.hasNext()) {
            if (isFirstNodeFlg) {
                nodeName = nodeIt.next();
                isFirstNodeFlg = false;
                bodyBuilder.append(montage(nodeName));
            } else {
                List<Edge<String>> edgeList = mDG.getEdgeList(nodeName);
                if (CollectionUtil.isEmpty(edgeList)) {
                    nodeIt.next();
                }
                for (Edge<String> edge : edgeList) {
                    nodeIt.next();
                    nodeName = edge.getDest();
                    bodyBuilder.append(montage(nodeName));
                }
            }
        }
        bodyBuilder.append(";");
        bodyBuilder.append(otherRouteBuilder);
        bodyBuilder.append("\n}\n}");
        StringBuilder packageBuilder = new StringBuilder();
        packageBuilder.append("package " + packageName + ";\n\n");
        packageList.forEach(packageBuilder::append);
        allBuilder.append(packageBuilder).append(preferBuilder).append(bodyBuilder);
        System.out.println(allBuilder.toString());
        return allBuilder.toString();
    }

    public StringBuilder montage(String nodeName) {
        JsonNode node = nodeMap.get(nodeName);
        String nodeType = node.get("nodeType").asText();
        String config = node.get("config").asText();
//        String name = node.get("name").asText();
        StringBuilder bodyBuilderTemp = new StringBuilder();
        if (nodeType.equals("start")) {
            bodyBuilder.append("from(\"");
            bodyBuilder.append(config + "\")");
            if (!StringUtil.isEmpty(code)) {
                bodyBuilder.append(".routeId(\""+code+"\")");
            }
        } else if (nodeType.equals("processor")) {
            String value = node.get("value").asText();
            String className = value.substring(value.lastIndexOf(".") + 1, value.length());

            addPackageList("import " + value + ";\n");
            if (config == null) {
                bodyBuilderTemp.append("\n.process(new "+className+"(\"\"))");
            } else {
                bodyBuilderTemp.append("\n.process(new "+className+"("+config+"))");
            }
        } else if (nodeType.equals("judgement")) {
            judgement(config, nodeName, bodyBuilderTemp);
        } else if (nodeType.equals("circle")) {
            split(config, bodyBuilderTemp);
        } else if (nodeType.equals("aggregate")) {
            aggregate(config, bodyBuilderTemp);
        } else if (nodeType.equals("multicast")) {
            multicast(config, nodeName, bodyBuilderTemp);
        } else if (nodeType.equals("format")) {
            format(config, nodeName, bodyBuilderTemp);
        } else {
//                    bodyBuilder.append("\n.setHeader(Exchange.HTTP_METHOD, constant(\"POST\"))");
            bodyBuilderTemp.append("\n.to(\"");
            bodyBuilderTemp.append(config + "\")");
        }
        while (nodeIt.hasNext()) {
            List<Edge<String>> edgeList = mDG.getEdgeList(nodeName);
            if (CollectionUtil.isEmpty(edgeList)) {
                return bodyBuilderTemp;
            }
            for (Edge<String> edge : edgeList) {
                nodeIt.next();
                nodeName = edge.getDest();
                bodyBuilderTemp.append(montage(nodeName));
            }
        }
        return bodyBuilderTemp;
    }

    public void judgement(String config, String nodeName, StringBuilder builder) {
        builder.append("\n.choice()");
        builder.append("\n.when("+config+")");
        String trueNodeName = "";
        String falseNodeName = "";
        for (Edge<String> edge : mDG.getEdgeList(nodeName)) {
            nodeIt.next();
            String nextNodeName = edge.getDest();
            String nextLineName = edge.getName();
            JsonNode nextLine = lineMap.get(nextLineName);
            if (nextLine.get("config") != null && nextLine.get("config").asText().equals("true")) {
                trueNodeName = nextNodeName;
            } else {
                falseNodeName = nextNodeName;
            }
        }

        builder.append("\n.to(\"direct:ja\")");
        builder.append("\n.otherwise()");
        builder.append("\n.to(\"direct:jb\")");
        builder.append("\n.end()");

        StringBuilder trueBuilder = montage(trueNodeName);
        StringBuilder falseBuilder = montage(falseNodeName);
        otherRouteBuilder.append("\nfrom(\"direct:ja\")").append(trueBuilder).append(";");
        otherRouteBuilder.append("\nfrom(\"direct:jb\")").append(falseBuilder).append(";");

    }

    public void split(String config, StringBuilder builder) {
        addPackageList("import com.yihu.hos.broker.util.Split;\n");
        builder.append("\n.split().method(Split.class, \""+config+"\")");
    }

    public void aggregate(String config, StringBuilder builder) {
        addPackageList("import com.yihu.hos.broker.util.Aggregate;\n");
        builder.append("\n.aggregate(header(\""+config+"\"), new Aggregate()).completionSize(3)");
    }

    public void multicast(String config, String nodeName, StringBuilder builder) {

        String directs = "";
        int i = 'a';
        List<String> directList = new ArrayList<>();
        List<Edge<String>> edgeList = mDG.getEdgeList(nodeName);
        for (Edge<String> edge : edgeList) {
            nodeIt.next();
            String direct = "direct:m" + (char)i++;
            directList.add(direct);
            directs += "\"" + direct + "\",";
            StringBuilder directBuilder = new StringBuilder();
            directBuilder.append("\nfrom(\"");
            directBuilder.append(direct + "\")");
            nodeName = edge.getDest();
            otherRouteBuilder.append(directBuilder).append(montage(nodeName)).append(";");
        }

        directs = StringUtil.substring(directs, 0, directs.length() - 1);

        builder.append("\n.multicast().stopOnException().to("+directs+").end()");
    }

    public void format(String config, String nodeName, StringBuilder builder) {

        addPackageList("import org.apache.camel.model.dataformat.XmlJsonDataFormat;\n");
        preferBuilder.append("XmlJsonDataFormat xmlJsonFormat = new XmlJsonDataFormat();\n");
        builder.append("\n."+config + "(xmlJsonFormat)");
    }

    public void addPackageList(String pack) {
        if (!packageList.contains(pack)) {
            packageList.add(pack);
        }
    }

    public void setCode(String code) {
        this.code = code;
    }


    public void setLineMap(Map<String, JsonNode> lineMap) {
        this.lineMap = lineMap;
    }

    public void setNodeIt(Iterator<String> nodeIt) {
        this.nodeIt = nodeIt;
    }

    public void setNodeMap(Map<String, JsonNode> nodeMap) {
        this.nodeMap = nodeMap;
    }

    public void setmDG(IDGraph<String> mDG) {
        this.mDG = mDG;
    }
}
