package com.activiti6.test;


import com.activiti6.service.impl.ActivitiService;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.converter.BpmnXMLConverter;
import org.activiti.bpmn.model.*;
import org.activiti.bpmn.model.Process;
import org.activiti.editor.constants.ModelDataJsonConstants;
import org.activiti.editor.language.json.converter.BpmnJsonConverter;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.Model;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.engine.test.ActivitiRule;
import org.apache.batik.transcoder.TranscoderException;
import org.apache.batik.transcoder.TranscoderInput;
import org.apache.batik.transcoder.TranscoderOutput;
import org.apache.batik.transcoder.image.PNGTranscoder;
import org.apache.commons.io.FileUtils;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import java.io.*;
import java.util.List;

@SpringBootTest
@RunWith(SpringRunner.class)
public class TestActiviti {

    @Autowired
    ProcessEngine processEngine;
    @Autowired
    private RepositoryService repositoryService;
    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private ActivitiService activitiService;


    @Test
    public void testDynamicDeploy() throws Exception {
        // 1. 创建一个空的BpmnModel和Process对象
        String name = "代码生成流程图";
        String documentation = "代码生成流程图测试!";
        String key = "my-process";
        BpmnModel model = new BpmnModel();
        Process process = new Process();
        model.addProcess(process);
        process.setId(key);
        process.setName(name);
        process.setDocumentation(documentation);
        // 创建Flow元素（所有的事件、任务都被认为是Flow）
        process.addFlowElement(createStartEvent());
        process.addFlowElement(createUserTask("task1", "提交申请", "zdd"));
        process.addFlowElement(createParallelGateway("parallel_in", "并行处理输入"));
        process.addFlowElement(createUserTask("task2", "人事审批", "hr"));
        process.addFlowElement(createUserTask("task3", "领导审批", "boos"));
        process.addFlowElement(createParallelGateway("parallel_out", "并行处理输出"));
        process.addFlowElement(createEndEvent());

        process.addFlowElement(createSequenceFlow("start", "task1"));
        process.addFlowElement(createSequenceFlow("task1", "parallel_in"));
        process.addFlowElement(createSequenceFlow("parallel_in", "task2"));
        process.addFlowElement(createSequenceFlow("parallel_in", "task3"));
        process.addFlowElement(createSequenceFlow("task2", "parallel_out"));
        process.addFlowElement(createSequenceFlow("task3", "parallel_out"));
        process.addFlowElement(createSequenceFlow("parallel_out", "end"));

        // 2. 流程图自动布局（位于activiti-bpmn-layout模块）
        new BpmnAutoLayout(model).execute();
        //saveModel(name, documentation, key, model);
        other(model);
    }

    private void saveModel(BpmnModel bpmnModel) {
        try {
            ObjectNode modelNode = new BpmnJsonConverter().convertToJson(bpmnModel);
            Model modelData = repositoryService.newModel();
            org.activiti.bpmn.model.Process process = bpmnModel.getMainProcess();
            String key = process.getId();
            activitiService.checkName(process);
            String name = process.getName();
            String description = process.getDocumentation();
            modelData.setKey(key);
            modelData.setName(name);

            ObjectNode modelObjectNode = new ObjectMapper().createObjectNode();
            modelObjectNode.put(ModelDataJsonConstants.MODEL_NAME, name);
            modelObjectNode.put(ModelDataJsonConstants.MODEL_REVISION, 1);
            modelObjectNode.put(ModelDataJsonConstants.MODEL_DESCRIPTION, description);
            modelData.setMetaInfo(modelObjectNode.toString());
            repositoryService.saveModel(modelData);
            repositoryService.addModelEditorSource(modelData.getId(), modelNode.toString().getBytes("utf-8"));
        } catch (Exception e) {
            e.printStackTrace();
        }

//        String json_xml = modelNode.toString();
//
//        BpmnXMLConverter bpmnXMLConverter=new BpmnXMLConverter();
//        byte[] convertToXML = bpmnXMLConverter.convertToXML(model);
//
//        String svg_xml =new String(convertToXML);
//
//
//        repositoryService.addModelEditorSource(activitModel.getId(), json_xml.getBytes("utf-8"));
//
//        InputStream svgStream = new ByteArrayInputStream(svg_xml.getBytes("utf-8"));
//        TranscoderInput input = new TranscoderInput(svgStream);
//
//        PNGTranscoder transcoder = new PNGTranscoder();
//        // Setup output
//        ByteArrayOutputStream outStream = new ByteArrayOutputStream();
//        TranscoderOutput output = new TranscoderOutput(outStream);
//
//        // Do the transformation
//        transcoder.transcode(input, output);
//        final byte[] result = outStream.toByteArray();
//        repositoryService.addModelEditorSourceExtra(activitModel.getId(), result);
//        outStream.close();
    }

    private void other(BpmnModel model) throws IOException {
        ActivitiRule activitiRule = new ActivitiRule(processEngine);
        String userHomeDir = "D:/doc/";
        // 3. 把BpmnModel对象部署到引擎
        Deployment deployment = activitiRule.getRepositoryService().createDeployment()
                .addBpmnModel("dynamic-model.bpmn", model).name("Dynamic process deployment")
                .deploy();
        //runtimeSave(activitiRule, userHomeDir);

        //        7. 导出Bpmn文件到本地文件系统
        InputStream processBpmn = activitiRule.getRepositoryService()
                .getResourceAsStream(deployment.getId(), "dynamic-model.bpmn");

        activitiService.convertInputStreamToModel(processBpmn);

        repositoryService.deleteDeployment(deployment.getId(), true);

//        FileUtils.copyInputStreamToFile(processBpmn,
//                new File(userHomeDir + "/process.bpmn20.xml"));
    }



    private void runtimeSave(ActivitiRule activitiRule, String userHomeDir) throws IOException {
        // 4. 启动流程
        ProcessInstance processInstance = activitiRule.getRuntimeService()
                .startProcessInstanceByKey("my-process");

        // 5. 检查流程是否正常启动
        List<Task> tasks = activitiRule.getTaskService().createTaskQuery()
                .processInstanceId(processInstance.getId()).list();

        Assert.assertEquals(1, tasks.size());
        Assert.assertEquals("First task", tasks.get(0).getName());
        Assert.assertEquals("fred", tasks.get(0).getAssignee());

//        6. 导出流程图
//        把文件生成在本章项目的test - classes目录中
        InputStream processDiagram = activitiRule.getRepositoryService()
                .getProcessDiagram(processInstance.getProcessDefinitionId());

        System.out.println(userHomeDir);
        FileUtils.copyInputStreamToFile(processDiagram, new File(userHomeDir + "/diagram.png"));
    }

    protected ParallelGateway createParallelGateway(String id, String name) {
        ParallelGateway parallelGateway = new ParallelGateway();
        parallelGateway.setName(name);
        parallelGateway.setId(id);
        return parallelGateway;
    }

    protected UserTask createUserTask(String id, String name, String assignee) {
        UserTask userTask = new UserTask();
        userTask.setName(name);
        userTask.setId(id);
        userTask.setAssignee(assignee);
        return userTask;
    }

    protected SequenceFlow createSequenceFlow(String from, String to) {
        SequenceFlow flow = new SequenceFlow();
        flow.setSourceRef(from);
        flow.setTargetRef(to);
        return flow;
    }

    protected StartEvent createStartEvent() {
        StartEvent startEvent = new StartEvent();
        startEvent.setId("start");
        return startEvent;
    }

    protected EndEvent createEndEvent() {
        EndEvent endEvent = new EndEvent();
        endEvent.setId("end");
        return endEvent;
    }

}
