/*
 * Copyright (c) 京北方信息技术股份有限公司 Corporation 2021 . All rights reserved.
 *
 */
package net.northking.cctp.flowable.sm;

import io.swagger.annotations.ApiModelProperty;
import net.northking.cctp.common.exception.PlatformRuntimeException;
import net.northking.cctp.flowable.common.exception.FlowAppError;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 状态机定义
 *
 * @author : xiusong.xie
 * @version : 1.0
 */
public class StateProcessDefinition
{
  @ApiModelProperty(value = "主键id", required = true)
  private String id;
  @ApiModelProperty(value = "流程定义名称", required = true)
  private String name;
  @ApiModelProperty(value = "备注")
  private String memo;
  @ApiModelProperty(value = "所有到所有")
  private Boolean allowedAnyToAny = false;
  @ApiModelProperty(value = "是否使用字典", required = true)
  private Boolean usedEnumState = false;
  @ApiModelProperty(value = "字典代码，如果使用字典，则必填")
  private String catalogCode;
  /**
   * 所有的状态
   */
  @ApiModelProperty(value = "节点（状态）")
  private List<State> states = new ArrayList<>();

  /**
   * 所有的事件
   */
  @ApiModelProperty(value = "连接线（事件）")
  private List<Event> events = new ArrayList<>();

  @ApiModelProperty(value = "所有到所有的授权角色")
  private List<String> anyAuthorities;
  @ApiModelProperty(value = "是否启用")
  private Boolean enabled = true;
  @ApiModelProperty("是否启用数据对象")
  private Boolean usedData = false;
  @ApiModelProperty("是否可以编辑")
  private Boolean canModify = true;
  @ApiModelProperty("是否默认")
  private Boolean defaulted = false;
  @ApiModelProperty("是否已删除")
  private Boolean deleted = false;

  public String getId()
  {
    return id;
  }

  public void setId(String id)
  {
    this.id = id;
  }

  public String getName()
  {
    return name;
  }

  public void setName(String name)
  {
    this.name = name;
  }

  public String getMemo()
  {
    return memo;
  }

  public void setMemo(String memo)
  {
    this.memo = memo;
  }

  public String getCatalogCode()
  {
    return catalogCode;
  }

  public void setCatalogCode(String catalogCode)
  {
    this.catalogCode = catalogCode;
  }

  public Boolean getAllowedAnyToAny() {
    return allowedAnyToAny;
  }

  public void setAllowedAnyToAny(Boolean allowedAnyToAny) {
    this.allowedAnyToAny = allowedAnyToAny;
  }

  public Boolean getUsedEnumState() {
    return usedEnumState;
  }

  public void setUsedEnumState(Boolean usedEnumState) {
    this.usedEnumState = usedEnumState;
  }

  public List<EventAuthority> getAuthorities()
  {
    List<EventAuthority> authorities = new ArrayList<>();
    for (Event event : events)
    {
      if (event.getAuthorities() == null || event.getAuthorities().isEmpty()) {
        continue;
      }
      for (String auth : event.getAuthorities())
      {
        EventAuthority authority = new EventAuthority();
        authority.setEventId(event.getId());
        authority.setProcessDefId(this.getId());
        authority.setAuthority(auth);
        authorities.add(authority);
      }
    }
    return authorities;
  }

  public Boolean getEnabled() {
    return enabled;
  }

  public void setEnabled(Boolean enabled) {
    this.enabled = enabled;
  }

  public List<String> getAnyAuthorities() {
    return anyAuthorities;
  }

  public void setAnyAuthorities(List<String> anyAuthorities) {
    this.anyAuthorities = anyAuthorities;
  }

  public Boolean getUsedData() {
    return usedData;
  }

  public void setUsedData(Boolean usedData) {
    this.usedData = usedData;
  }

  public Boolean getCanModify() {
    return canModify;
  }

  public void setCanModify(Boolean canModify) {
    this.canModify = canModify;
  }

  public Boolean getDefaulted() {
    return defaulted;
  }

  public void setDefaulted(Boolean defaulted) {
    this.defaulted = defaulted;
  }

  public Boolean getDeleted() {
    return deleted;
  }

  public void setDeleted(Boolean deleted) {
    this.deleted = deleted;
  }

  /**
   * 获取初始状态
   *
   * @return 初始状态
   */
  public State findInitialState()
  {
    for (State state : states)
    {
      if (state.getInitialState())
      {
        return state;
      }
    }
    return null;
  }

  /**
   * 获取终态清单
   *
   * @return 终态清单
   */
  public List<State> findFinishedStates()
  {
    List<State> list = new ArrayList<>();
    for (State state : states)
    {
      if (state.getFinishedState())
      {
        list.add(state);
      }
    }
    return list;
  }

  /**
   * 获取状态清单
   *
   * @return 状态清单
   */
  public List<State> getStates()
  {
    return states;
  }

  public void setStates(List<State> states)
  {
    this.states = states;
    for (State state : states)
    {
      state.setProcessDefId(this.getId());
      state.setCatalogCode(this.getCatalogCode());
    }
  }

  /**
   * 获取事件清单
   *
   * @return 事件清单
   */
  public List<Event> getEvents()
  {
    return events;
  }

  public void setEvents(List<Event> events)
  {
    this.events = events;
    for (Event event : events)
    {
      event.setProcessDefId(this.getId());
    }
  }

  /**
   * 状态点重复检查
   *
   */
  public void duplicateStateCheck() {
    List<String> list = new ArrayList<>();
    for (State state : states) {
      if (!list.contains(state.getLabel())) { // 如果没有添加到集合
        list.add(state.getLabel());
      } else {
        throw new PlatformRuntimeException(FlowAppError.DUPLICATED_STATE, state.getLabelText());
      }
    }
  }

  /**
   * 每个节点的流向检测
   * 开始节点：至少有一条是出
   * 正常节点：进出相等
   * 结束节点，至少有一条是进
   */
  public void flowCheck() {
    // 状态重复校验
    duplicateStateCheck();
    Map<String, Integer> sourceMap = new HashMap<>(); // 出
    Map<String, Integer> targetMap = new HashMap<>(); // 进
    for (Event event : events) {    // 处理每条线出现次数
      String source = event.getSource();
      if (!sourceMap.containsKey(source)) {
        sourceMap.put(source, 1);
      } else {
        sourceMap.put(source, sourceMap.get(source) + 1);
      }
      String target = event.getTarget();
      if (!targetMap.containsKey(target)) {
        targetMap.put(target, 1);
      } else {
        targetMap.put(target, targetMap.get(target) + 1);
      }
    }
    // 处理每种节点出现次数的情况
    State initialState = findInitialState();
    // 开始节点
    if (initialState == null) {
      throw new PlatformRuntimeException(FlowAppError.EMPTY_INITIAL_STATE); // 缺少开始节点
    }
    if (!sourceMap.containsKey(initialState.getId()) || sourceMap.get(initialState.getId()) == 0) { // 如果开始节点没有连线或者没有出路，提醒
      throw new PlatformRuntimeException(FlowAppError.INITIAL_STATE_ERROR_EVENT, initialState.getLabelText());
    }
    // 结束节点，校验每个结束节点必须有一条进路
    List<State> finishedStates = findFinishedStates();
    if (finishedStates.isEmpty()) {
      throw new PlatformRuntimeException(FlowAppError.EMPTY_FINISHED_STATE);
    }
    for (State finishedState : finishedStates) {
      boolean finishedFlag = !targetMap.containsKey(finishedState.getId()) || targetMap.get(finishedState.getId()) == 0;
      if (finishedFlag) {
        throw new PlatformRuntimeException(FlowAppError.FINISHED_STATE_ERROR_EVENT, finishedState.getLabelText());  // 有结束节点没有进路
      }
    }

    // 正常节点
    for (State state : states) {
      if (!state.getInitialState() && !state.getFinishedState()) {  // 正常节点
        Integer sourceCount = sourceMap.get(state.getId());
        Integer targetCount = targetMap.get(state.getId());
        if (sourceCount == null || targetCount == null || sourceCount == 0 || targetCount == 0) {
          throw new PlatformRuntimeException(FlowAppError.NORMAL_STATE_ERROR_EVENT, state.getLabelText());
        }
      }
    }

  }

}
