package com.yihu.hos.system.service;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.hos.common.graph.DGraphImpl;
import com.yihu.hos.common.graph.Edge;
import com.yihu.hos.common.graph.IDGraph;
import com.yihu.hos.core.datatype.StringUtil;
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.dao.ProcessorDao;
import com.yihu.hos.system.model.*;
import com.yihu.hos.web.framework.model.Result;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
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 = ProcessorDao.BEAN_ID)
    private ProcessorDao processorDao;
    @Resource(name = FlowProcessDao.BEAN_ID)
    private FlowProcessDao processDao;
    @Resource(name = FlowManager.BEAN_ID)
    private FlowManager flowManager;

    private ObjectMapper objectMapper = new ObjectMapper();

    public Result getAllEndpoints(String endpointName) throws Exception {

        List<SystemServiceEndpoint> serviceEndpointList = appServiceDao.getListByName(endpointName);
        List<String> appIdList = new ArrayList<>();
        Map<String, List<ProcessResultModel>> appServiceMap = new HashMap<>();
        for (SystemServiceEndpoint endpoint : serviceEndpointList) {
            ProcessResultModel resultModel = new ProcessResultModel();
            resultModel.setName(endpoint.getName());
            resultModel.setValue(endpoint.getEndpoint());
            resultModel.setConfig(endpoint.getEndpoint());
            resultModel.setNodeType("service");
            appIdList.add(endpoint.getAppId());

            List<ProcessResultModel> endpointList;
            if (appServiceMap.get(endpoint.getAppId()) != null) {
                endpointList = appServiceMap.get(endpoint.getAppId());
            } else {
                endpointList = new ArrayList<>();
            }
            endpointList.add(resultModel);
            appServiceMap.put(endpoint.getAppId(), endpointList);
        }
        List<SystemApp> appList = appDao.getAllByIdList(appIdList);
        JSONArray jsonArray = new JSONArray();
        for (SystemApp app : appList) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("title", app.getName());
            List<ProcessResultModel> resultModelList = appServiceMap.get(app.getId());
            List<ProcessResultModel> resultModelListListTemp = new ArrayList<>();
            if (app.getName().equals("起始端点")) {

                for (ProcessResultModel resultModel : resultModelList) {
                    resultModel.setNodeType("start");
                    resultModelListListTemp.add(resultModel);
                }
                jsonObject.put("list", resultModelListListTemp);
                jsonArray.add(0, jsonObject);
            } else if (app.getName().equals("结束端点")) {

                for (ProcessResultModel resultModel : resultModelList) {
                    resultModel.setNodeType("end");
                    resultModelListListTemp.add(resultModel);
                }
                jsonObject.put("list", resultModelListListTemp);
                jsonArray.add(1, jsonObject);
            } else {
                resultModelListListTemp = resultModelList;
                jsonObject.put("list", resultModelListListTemp);
                jsonArray.add(jsonObject);
            }
        }
        return Result.success(jsonArray.toString());
    }

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

    public String getFlowchart(Integer flowId) throws Exception {
        SystemServiceFlowProcess serviceFlowProcess = processDao.getFlowProcessByFlowId(flowId);
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("code", serviceFlowProcess.getCode());
        jsonObject.put("name", serviceFlowProcess.getName());
        jsonObject.put("flowId", serviceFlowProcess.getFlowId());
        jsonObject.put("result", serviceFlowProcess.getResult());

        return jsonObject.toString();
    }

    public Result getAllProcessor(String processorName) throws Exception {
        List<SystemServiceFlowProcessor> processorList = processorDao.getListByName(processorName);
        List<ProcessResultModel> resultModelList = new ArrayList<>();
        ProcessResultModel json2xml = new ProcessResultModel();
        json2xml.setName("json转xml格式转换器");
        json2xml.setValue("unmarshal");
        json2xml.setConfig("unmarshal");
        json2xml.setNodeType("format");

        ProcessResultModel xml2json = new ProcessResultModel();
        xml2json.setName("xml转json格式转换器");
        xml2json.setValue("marshal");
        xml2json.setConfig("marshal");
        xml2json.setNodeType("format");
        resultModelList.add(json2xml);
        resultModelList.add(xml2json);

        for (SystemServiceFlowProcessor processor : processorList) {
            ProcessResultModel resultModel = new ProcessResultModel();
            resultModel.setName(processor.getName());
            resultModel.setValue(processor.getPackageName() + "." + processor.getClassName());
            resultModel.setConfig("");
            resultModel.setNodeType("processor");
            resultModelList.add(resultModel);
        }
        String result = objectMapper.writeValueAsString(resultModelList);
        return Result.success(result);
    }

    public void saveProcess(String code, String name, Integer flowId, String positionJsonStr, String flowJsonStr) throws Exception {
        SystemServiceFlowProcess process = new SystemServiceFlowProcess();
        process.setCode(code);
        process.setName(name);
        process.setResult(positionJsonStr);
        process.setFlowId(flowId);
        process.setFlowResult(flowJsonStr);
        processDao.saveEntity(process);
    }

    public void main(String[] args) throws Exception {
        String flowJsonStr = "{\n" +
                "    \"nodes\": {\n" +
                "        \"node_1\": {\n" +
                "            \"name\": \"Quartz\",\n" +
                "            \"value\": \"quartz://myGroup/myTimerName?cron=0/3 * * * * ?\",\n" +
                "            \"nodeType\": \"start\"\n" +
                "        },\n" +
                "        \"node_2\": {\n" +
                "            \"name\": \"DefaultHttpProcessor0\",\n" +
                "            \"value\": \"com.yihu.hos.broker.common.processor.DefaultHttpProcessor\",\n" +
                "\t\t\t\"param\": \"{\\\"jobId\\\":\\\"5ad5c11655d443c30155d477a6b10000\\\"}\",\n" +
                "            \"nodeType\": \"processor\"\n" +
                "        },\n" +
                "        \"node_3\": {\n" +
                "            \"name\": \"Crawler0\",\n" +
                "            \"value\": \"http4://localhost:8088/crawler/patientList?method=post\",\n" +
                "            \"nodeType\": \"service\"\n" +
                "        },\n" +
                "\t\t\"node_4\": {\n" +
                "            \"name\": \"xml2json\",\n" +
                "            \"value\": \"marshal\",\n" +
                "            \"nodeType\": \"format\"\n" +
                "        },\n" +
                "\t\t\"node_5\": {\n" +
                "            \"name\": \"Stream\",\n" +
                "            \"value\": \"stream:out\",\n" +
                "            \"nodeType\": \"end\"\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" +
                "        \"line3\": {\n" +
                "            \"from\": \"node_3\",\n" +
                "            \"to\": \"node_4\"\n" +
                "        },\n" +
                "\t\t\"line4\": {\n" +
                "            \"from\": \"node_4\",\n" +
                "            \"to\": \"node_5\"\n" +
                "        }\n" +
                "    }\n" +
                "}";
//        generateFlow("crawler", "业务流程图", flowJsonStr);
    }

    public Integer generateFlow(String code, String name, String flowJsonStr) throws Exception {
        SystemServiceFlowProcess process = processDao.getFlowProcessByCode(code);
        if (process != null) {
            return null;
        }
        String root = "";
        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode flowJson = objectMapper.readValue(flowJsonStr, JsonNode.class);
        //sort flow by lines

        JsonNode lines = flowJson.get("lines");
        Iterator<Map.Entry<String, JsonNode>> lineIterator = lines.fields();
        //get nodeMap by nodes
        JsonNode nodes = flowJson.get("nodes");
        Iterator<Map.Entry<String, JsonNode>> nodeIterator = nodes.fields();
        //for the java code import processor class
        Map<String, JsonNode> nodeMap = new HashMap<>();
        Map<String, JsonNode> lineMap = new HashMap<>();
        IDGraph<String> mDG = new DGraphImpl<String>();
        while (nodeIterator.hasNext()) {
            Map.Entry<String, JsonNode> map = nodeIterator.next();
            nodeMap.put(map.getKey(), map.getValue());
            String type = map.getValue().get("nodeType").asText();
            if (StringUtil.isEmpty(root) && type.equals("start")) {
                root = map.getKey();
            }
            mDG.add(map.getKey());
        }

        while (lineIterator.hasNext()) {
            Map.Entry<String, JsonNode> map = lineIterator.next();
            lineMap.put(map.getKey(), map.getValue());
            String nodeNameFrom = map.getValue().get("from").asText();
            String nodeNameTo = map.getValue().get("to").asText();
            mDG.add(new Edge<>(nodeNameFrom, nodeNameTo, map.getKey()));
        }
        ProcessEditor editor = new ProcessEditor();
        Iterator<String> nodeIt = mDG.iterator(root);
        editor.setCode(code);
        editor.setNodeIt(nodeIt);
        editor.setmDG(mDG);
        editor.setLineMap(lineMap);
        editor.setNodeMap(nodeMap);
        //generate the java code
        String javaName = toUpperCaseFirstOne(code)+"Route";
        String packageName = code+".route";

        String fileInfo = editor.generate(javaName, packageName);

//        Integer flowId = flowManager.sendAddRoute(code, name, javaName, packageName, fileInfo);
        return null;
    }

    //首字母转大写
    public static 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();
    }
}
