package com.huigou.bpm.management.controller;

import com.huigou.bpm.management.GraphUtils;
import com.huigou.bpm.management.application.ProcessDefinitionApplication;
import com.huigou.bpm.management.domain.model.ProcessDefinition;
import com.huigou.uasp.annotation.ControllerMapping;
import com.huigou.uasp.client.CommonController;
import com.huigou.util.CommonUtil;
import com.huigou.util.SDO;
import com.mxgraph.util.mxUtils;
import com.mxpdf.text.DocumentException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.xml.sax.SAXException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.ParserConfigurationException;
import java.awt.*;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

/**
 * 流程图绘制相关。
 *
 * @author yonghuan
 */
@ControllerMapping("/bpm/graph")
@Controller
public class GraphController extends CommonController {

    @Autowired
    private ProcessDefinitionApplication processDefinitionApplication;

    /**
     * 打开流程图绘制界面
     */
    public String forwardEditor() {
        String procdefId = getSDO().getString("procdefId");
        Assert.hasText(procdefId, "流程定义id不能为空");
        ProcessDefinition definition = processDefinitionApplication.queryById(procdefId);
        return forward(definition.getChartKindId(), definition);
    }

    /**
     * 获取流程图xml
     */
    public String open() throws UnsupportedEncodingException {
        SDO sdo = getSDO();
        String procdefId = sdo.getString("procdefId");
        Assert.hasText(procdefId, "流程定义id不能为空");
        ProcessDefinition definition = processDefinitionApplication.queryById(procdefId);
        Assert.notNull(definition, "流程定义不存在");
        String xml = definition.getXml();
        String filename = definition.getCode() + ".xml";
        Map<String, Object> result = new HashMap<>(2);
        if (xml != null) {
            //  xml = Base64.getEncoder().encodeToString(xml.getBytes());
            result.put("xml", xml);
        }
        result.put("filename", filename);
        return toResult(result);
    }

    /**
     * 保存流程图xml
     */
    public String save() throws Exception {
        SDO sdo = getSDO();
        String procdefId = sdo.getString("procdefId");
        Assert.hasText(procdefId, "流程定义id不能为空");
        String xml = sdo.getString("xml");
        if (xml != null) {
            byte[] bs = Base64.getDecoder().decode(xml);
            xml = new String(bs);
            xml = URLDecoder.decode(xml, StandardCharsets.UTF_8.name());
        }

        ProcessDefinition definition = processDefinitionApplication.queryById(procdefId);
        Assert.notNull(definition, "流程定义不存在");
        definition.setXml(xml);
        String imageXml = sdo.getString("imageXml");
        if (imageXml != null) {
            byte[] bs = Base64.getDecoder().decode(imageXml);
            imageXml = new String(bs);
            imageXml = URLDecoder.decode(imageXml, StandardCharsets.UTF_8.name());
        }
        definition.setImageXml(imageXml);
        definition.setImageHeight(sdo.getInteger("h"));
        definition.setImageWidth(sdo.getInteger("w"));
        processDefinitionApplication.updateProcessDefinitionById(definition);
        return success();
    }

    /**
     * 导出流程图。
     */
    public String export(SDO sdo, HttpServletRequest request, HttpServletResponse response) throws Exception {
        String format = sdo.getString("format");
        String fname = sdo.getString("filename");
        Integer w = sdo.getInteger("w");
        Integer h = sdo.getInteger("h");
        String tmp = sdo.getString("bg");
        String imageXml = sdo.getString("imageXml");
        if (imageXml != null) {
            byte[] bs = Base64.getDecoder().decode(imageXml);
            imageXml = new String(bs);
            imageXml = URLDecoder.decode(imageXml, StandardCharsets.UTF_8.name());
        }

        Color bg = (tmp != null) ? mxUtils.parseColor(tmp) : null;
        // Checks parameters
        // Allows transparent backgrounds only for PNG
        if (bg == null && !format.equals("png")) {
            bg = Color.WHITE;
        }

        if (fname != null && fname.toLowerCase().endsWith(".xml")) {
            fname = fname.substring(0, fname.length() - 4) + format;
        }

        // Writes response
        if ("pdf".equalsIgnoreCase(format)) {
            writePdf(fname, w, h, bg, imageXml, request, response);
        } else {
            writeImage(format, fname, w, h, bg, imageXml, request, response);
        }
        return NONE;
    }

    public String createId() {
        String uuid = CommonUtil.createGUID();
        return toResult(uuid);
    }

    private void writeImage(String format, String fname, int w, int h, Color bg, String xml, HttpServletRequest request, HttpServletResponse response)
            throws IOException, SAXException, ParserConfigurationException {
        if (fname != null) {
            fname = encodeAttachmentName(request, fname);
            response.setContentType("application/x-unknown");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fname + "\"; filename*=UTF-8''" + fname);
        } else if (format != null) {
            response.setContentType("image/" + format.toLowerCase());
        }
        try (OutputStream os = response.getOutputStream()) {
            GraphUtils.writeImage(format, w, h, bg, xml, os);
        }
    }

    /**
     * @throws IOException
     * @throws DocumentException
     * @throws ParserConfigurationException
     * @throws SAXException
     */
    private void writePdf(String fname, int w, int h, Color bg, String xml, HttpServletRequest request, HttpServletResponse response)
            throws DocumentException, IOException, SAXException, ParserConfigurationException {
        response.setContentType("application/pdf");
        if (fname != null) {
            fname = encodeAttachmentName(request, fname);
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fname + "\"; filename*=UTF-8''" + fname);
        }
        try (OutputStream os = response.getOutputStream()) {
            GraphUtils.writePdf(w, h, bg, xml, os);
        }
    }


    @Override
    protected String getPagePath() {
        return "/system/tbpm/editor/";
    }
}
