package com.yihu.hos.system.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.hos.config.MongoConfig;
import com.yihu.hos.core.datatype.StringUtil;
import com.yihu.hos.core.encrypt.DES;
import com.yihu.hos.system.dao.AppDao;
import com.yihu.hos.system.dao.AppServiceDao;
import com.yihu.hos.system.dao.FlowProcessDao;
import com.yihu.hos.system.model.SystemServiceEndpoint;
import com.yihu.hos.system.model.SystemServiceFlowProcess;
import com.yihu.hos.web.framework.model.Result;
import com.yihu.hos.web.framework.util.GridFSUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.File;
import java.io.FileWriter;
import java.util.*;

@Service("ProcessManager")
public class ProcessManager {

    public static final String BEAN_ID = "ProcessManager";

    @Resource(name = AppDao.BEAN_ID)
    private AppDao appDao;
    @Resource(name = AppServiceDao.BEAN_ID)
    private AppServiceDao appServiceDao;
    @Resource(name = FlowProcessDao.BEAN_ID)
    private FlowProcessDao processDao;

    private ObjectMapper objectMapper = new ObjectMapper();

    public Result getAllApp() throws Exception {
        String hql = "select * from SystemServiceEndpoint";
        List<SystemServiceEndpoint> serviceEndpointList = appServiceDao.getEntityList(SystemServiceEndpoint.class, hql);
        String result = objectMapper.writeValueAsString(serviceEndpointList);
        return Result.success(result);
    }

    public Result getAllAppService() throws Exception {
        String hql = "select * from SystemServiceEndpoint";
        List<SystemServiceEndpoint> serviceEndpointList = appServiceDao.getEntityList(SystemServiceEndpoint.class, hql);
        String result = objectMapper.writeValueAsString(serviceEndpointList);
        return Result.success(result);
    }

    public Result getAppServiceByAppId(String appId) throws Exception {
        String hql = "select * from SystemServiceEndpoint where appId = "+appId+"";
        List<SystemServiceEndpoint> serviceEndpointList = appServiceDao.getEntityList(SystemServiceEndpoint.class, hql);
        String result = objectMapper.writeValueAsString(serviceEndpointList);
        return Result.success(result);
    }

    public void saveProcess(String code, String name, String fileName, String positionJsonStr) throws Exception {
        SystemServiceFlowProcess process = new SystemServiceFlowProcess();
        process.setCode(code);
        process.setName(name);
        process.setResult(positionJsonStr);
        process.setFileName(fileName);
        processDao.saveEntity(process);
    }

    public String formatJson(String flowJsonStr) throws Exception {
//        flowJsonStr = "{\n" +
//                "    \"code\": \"cralwer\",\n" +
//                "    \"nodes\": {\n" +
//                "        \"node_1\": {\n" +
//                "            \"name\": \"quartz\",\n" +
//                "            \"value\": \"quartz://myGroup/myTimerName?cron=0/3 * * * * ?\",\n" +
//                "            \"type\": \"service\"\n" +
//                "        },\n" +
//                "        \"node_2\": {\n" +
//                "            \"name\": \"CollectProcessor0\",\n" +
//                "            \"value\": \"collect.processor.CollectProcessor0\",\n" +
//                "            \"type\": \"processor\"\n" +
//                "        },\n" +
//                "        \"node_3\": {\n" +
//                "            \"name\": \"crawler\",\n" +
//                "            \"value\": \"http4://localhost:8088/crawler/patientList\",\n" +
//                "            \"type\": \"service\"\n" +
//                "        }\n" +
//                "    },\n" +
//                "    \"lines\": {\n" +
//                "        \"line_1\": {\n" +
//                "            \"from\": \"node_1\",\n" +
//                "            \"to\": \"node_2\"\n" +
//                "        },\n" +
//                "        \"line_2\": {\n" +
//                "            \"from\": \"node_2\",\n" +
//                "            \"to\": \"node_3\"\n" +
//                "        }\n" +
//                "    }\n" +
//                "}";
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode flowJson = objectMapper.readValue(flowJsonStr, JsonNode.class);
        String code = flowJson.get("code").asText();
        String javaName = toUpperCaseFirstOne(code)+"Route";
        //sort flow by lines
        JsonNode lines = flowJson.get("lines");
        Iterator<JsonNode> lineIterator = lines.iterator();
        String[] nodeNameArray = new String[lines.size() + 1];
        Boolean isFirstLineFlg = true;
        while (lineIterator.hasNext()) {
            JsonNode line = lineIterator.next();
            String nodeNameFrom = line.get("from").asText();
            String nodeNameTo = line.get("to").asText();
            if (isFirstLineFlg) {
                nodeNameArray[0] = nodeNameFrom;
                nodeNameArray[1] = nodeNameTo;
                isFirstLineFlg = false;
                continue;
            }
            for (int i=0; i<nodeNameArray.length; i++) {
                if (nodeNameArray[i].equals(nodeNameFrom)) {
                    if (StringUtil.isEmpty(nodeNameArray[i + 1])) {
                        nodeNameArray[i + 1] = nodeNameTo;
                    } else {
                        insertArray(nodeNameTo, nodeNameArray, i + 1);
                    }
                    break;
                } else if (nodeNameArray[i].equals(nodeNameTo)) {
                    insertArray(nodeNameFrom, nodeNameArray, i);
                }
            }
        }

        //get nodeMap by nodes
        JsonNode nodes = flowJson.get("nodes");
        Map<String, JsonNode> nodeMap = new HashMap<>();
        Iterator<Map.Entry<String, JsonNode>> nodeIterator = nodes.fields();
        //for the java code import processor class
        List<String> processorImport = new ArrayList<>();
        while (nodeIterator.hasNext()) {
            Map.Entry<String, JsonNode> map = nodeIterator.next();
            JsonNode node = map.getValue();
            String type = node.get("type").asText();
            if (type.equals("processor")) {
                processorImport.add(node.get("value").asText());
            }
            nodeMap.put(map.getKey(), map.getValue());

        }

        //mosaic the java code
        Boolean isFirstNodeFlg = true;
        StringBuilder javaBuilder = new StringBuilder();

        javaBuilder.append("package "+code+".route;\n\n");
        javaBuilder.append("import org.apache.camel.Exchange;\n");
        javaBuilder.append("import org.apache.camel.builder.RouteBuilder;\n");
        for (String packageName : processorImport) {
            javaBuilder.append("import " + packageName + ";\n");
        }

        javaBuilder.append("public class "+javaName+" extends RouteBuilder {\n");
        javaBuilder.append("public void configure() throws Exception {\n");
        for (String nodeName : nodeNameArray) {
            JsonNode node = nodeMap.get(nodeName);
            String type = node.get("type").asText();
            String value = node.get("value").asText();
            String name = node.get("name").asText();
            if (isFirstNodeFlg) {
                javaBuilder.append("from(\"");
                javaBuilder.append(value + "\")");
                javaBuilder.append(".routeId(\""+code+"\")");
                isFirstNodeFlg = false;
            } else {
                if (type.equals("processor")) {
                    javaBuilder.append("\n.process(\"new "+name+"())");
                } else {
                    javaBuilder.append("\n.setHeader(Exchange.HTTP_METHOD, constant(\"POST\"))");
                    javaBuilder.append("\n.to(\"");
                    javaBuilder.append(value + "\")");
                }
            }
        }
        javaBuilder.append("\n}\n}");

        System.out.println(javaBuilder.toString());
        String packageFilePath = System.getProperty("user.dir");

        String filePath = packageFilePath + "/" + javaName + ".java";
        File file = new File(filePath);

        FileWriter fw = new FileWriter(file);
        fw.write(javaBuilder.toString());
        fw.flush();
        fw.close();//这里只是产生一个JAVA文件,简单的IO操作

        //upload to mongo
        String dbName = "upload";
        String newFileName;
        try {
            newFileName = GridFSUtil.uploadFile(dbName, filePath, file.getName());
            if (!StringUtil.isEmpty(newFileName)) {
                return newFileName;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    public void insertArray(String nodeName, String[] array, int index) {
        for (int i=index; i<array.length; i++) {
            String nodeNameTemp = array[i];
            array[i] = nodeName;
            nodeName = nodeNameTemp;
        }
    }

    //首字母转大写
    public String toUpperCaseFirstOne(String s)
    {
        if(Character.isUpperCase(s.charAt(0)))
            return s;
        else
            return (new StringBuilder()).append(Character.toUpperCase(s.charAt(0))).append(s.substring(1)).toString();
    }

}
