package com.huigou.explorer.converters.bpmn;

import com.alibaba.fastjson.JSONArray;
import com.huigou.exception.ApplicationException;
import com.mxgraph.model.mxCell;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.model.mxGraphModel;
import com.mxgraph.util.mxPoint;
import org.activiti.bpmn.model.*;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * @author yonghuan
 */
public class SequenceFlowConverter implements ElementConverter {

    private ActivitiListenerParser activitiListenerParser;

    public void setActivitiListenerParser(ActivitiListenerParser activitiListenerParser) {
        this.activitiListenerParser = activitiListenerParser;
    }

    @Override
    public boolean supports(Object mxElement) {
        return (mxElement instanceof mxCell) && ((mxCell) mxElement).isEdge();
    }

    @Override
    public void convert(BpmnModel bpmnModel, mxGraphModel graphModel, Object mxElement) {
        mxCell cell = (mxCell) mxElement;

        String name = cell.getAttribute("label");
        String code = cell.getAttribute("code");
        if (cell.getSource() == null) {
            throw new ApplicationException(String.format("没有找到连线 [%s] 的源", StringUtils.isNotBlank(name) ? name : code));
        }
        SequenceFlow sf = new SequenceFlow();
        String sourceRef = ((mxCell) cell.getSource()).getAttribute("code");
        sf.setSourceRef(sourceRef);
        if (cell.getTarget() == null) {
            throw new ApplicationException(String.format("没有找到连线 [%s] 的目标", StringUtils.isNotBlank(name) ? name : code));
        }
        sf.setId(code);
        sf.setName(name);
        sf.setConditionExpression(cell.getAttribute("conditionExpression"));
        sf.setSkipExpression(cell.getAttribute("skipExpression"));
        String targetRef = ((mxCell) cell.getTarget()).getAttribute("code");
        sf.setTargetRef(targetRef);
        Optional.ofNullable(cell.getAttribute("executionListeners"))
                .filter(StringUtils::isNotBlank)
                .map(JSONArray::parseArray)
                .map(activitiListenerParser::parse)
                .ifPresent(executionListeners -> ((HasExecutionListeners) sf).setExecutionListeners(executionListeners));
        bpmnModel.getProcesses().get(0).addFlowElement(sf);

        // 连线GraphicInfo
        List<GraphicInfo> graphicInfos = new ArrayList<>(4);
        GraphicInfo source = new GraphicInfo();
        source.setElement(sf);

        mxGeometry sourceGeometry = cell.getSource().getGeometry();
        source.setX(sourceGeometry.getX());
        source.setY(sourceGeometry.getY());
        graphicInfos.add(source);

        Optional.ofNullable(cell.getGeometry().getPoints())
                .filter(Objects::nonNull)
                .map(List::stream)
                .map(points -> points.map(point -> mxPointToGraphicInfo(point, sf)))
                .map(points -> points.collect(Collectors.toList()))
                .ifPresent(points -> graphicInfos.addAll(points));

        GraphicInfo target = new GraphicInfo();
        target.setElement(sf);
        mxGeometry targetGeometry = cell.getTarget().getGeometry();
        target.setX(targetGeometry.getX());
        target.setY(targetGeometry.getY());
        graphicInfos.add(target);
        bpmnModel.addFlowGraphicInfoList(sf.getId(), graphicInfos);

    }

    private GraphicInfo mxPointToGraphicInfo(mxPoint mxPoint, BaseElement baseElement) {
        GraphicInfo graphicInfo = new GraphicInfo();
        graphicInfo.setX(mxPoint.getX());
        graphicInfo.setY(mxPoint.getY());
        graphicInfo.setElement(baseElement);
        return graphicInfo;
    }
}
