package com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.iml;

import com.alibaba.fastjson.JSON;
import com.jiayue.ipfcst.common.core.util.DateMomentUtil;
import com.jiayue.ipfcst.common.data.abst.equipmentstatus.AbstractEquipmentStatusData;
import com.jiayue.ipfcst.common.data.constant.enums.DataSourceEnum;
import com.jiayue.ipfcst.common.data.constant.enums.ElectricFieldTypeEnum;
import com.jiayue.ipfcst.common.data.constant.enums.EquipmentTypeEnum;
import com.jiayue.ipfcst.common.data.entity.*;
import com.jiayue.ipfcst.common.data.repository.PowerLimitPlanSignRepository;
import com.jiayue.ipfcst.console.service.*;
import com.jiayue.ipfcst.dataexchange.container.ProtocolDataContainer;
import com.jiayue.ipfcst.dataexchange.dataprocesser.WeatherStationStatusDataFilter;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.BaseDataGainer;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.NumOrBool;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.iml.GetDataFromContainer;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datagainerhandler.iml.PointDataCalculator;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.AbstractDataPacker;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.powerofreference.BasePowerOfReferenceCalculator;
import com.jiayue.ipfcst.dataexchange.exception.DataExchangeException;
import com.jiayue.ipfcst.dataexchange.service.EquipmentAttributeService;
import com.jiayue.ipfcst.dataexchange.service.ProtocolGatherDataPointService;
import com.jiayue.ipfcst.dataexchange.service.SaveEquipmentStatusData;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 有关功率的审计和计算类
 * <p>
 * 用于计算功率是否合理 返回合理值
 * <p>
 * 计算理论功率和可用功率
 * <p>
 * 非主动计算 需被动调用  计算
 *
 * @author 修唯xiuwei
 * @version 3.0
 */
@Slf4j
@Service
public class PowerStationDataPacker extends AbstractDataPacker<PowerStationStatusData> {

  /**
   * 参照功率的计算方式标识
   * 理论功率计算方式
   */
  private static final String LGJSFS = "lgjsfs";


  /**
   * 判断是否限电的容量倍率 标识
   * 处在 容量*该倍率之下的实际功率 不统计是否限电
   */
  private static final String SFPDXD = "sfpdxd";


  /**
   * 限电系数 标识
   * 如果  参照功率 - 实际功率 > 实际功率*该系数  则判断为限电
   */
  private static final String XDXS = "xdxs";


  /**
   * 短期和超短期平均数计算可用功率所乘 系数最小值
   */
  private static final String KYGLJSMIN = "kygljsMIN";


  /**
   * 短期和超短期平均数计算可用功率所乘 系数最大值
   */
  private static final String KYGLJSMAX = "kygljsMAX";


  /**
   * 限电时间范围
   */
  private static final String POWER_LIMIT_TIME_RANGE = "powerLimitTimeRange";


  /**
   * 场站状态数据快速刷新参数
   */
  private static final String QUICK_REFRESH_STATION_STATUS_DATA ="QuickRefreshStationStatusData";

  /**
   * 场站状态数据快速刷新参数的默认值
   */
  private static final String QUICK_REFRESH_STATION_STATUS_DATA_DEFAULT ="0";

  /**
   * 限电时间范围
   */
  private static final String POWER_LIMIT_TIME_RANGE_DEFAULT = "";
  /**
   * 限电时间所使用的日期格式
   */
  private static final DateTimeFormatter POWER_LIMIT_TIME_FORMATTER = DateTimeFormat.forPattern("HH:mm");


  /**
   * 限电时间范围
   */
  private int[] powerLimitTimeRange = null;

  /**
   * 随机数生成器
   */
  private static final Random random = new Random();
  /**
   * 需要反向注入的字段名称
   * 主要包括 系统判断是否限电，可用，理论，样板机参照功率，站内受阻，站外受阻
   * 这些信息是功率预测外的系统没有的，是系统根据已有数据计算所得
   */
  private static final List<String> InjectionProperties = Arrays.asList("isRationingByAutoControl", "ableValue", "theoryValue", "referencePowerBySample", "ablePowerBySample", "ablePowerByMeasuring", "onSiteObstructed", "offSiteObstructed", "openCapacity");
  /**
   * 是否对实际功率进行考核验证   0  不验证   1  验证
   */
  private static final String AUDITREALPOWER = "auditRealPower";
  /**
   * 查询到场站的实际功率的点位
   */
  @Autowired
  ProtocolGatherDataPointService protocolGatherDataPointService;
  /**
   * 查询检修信息
   */
  @Autowired
  OverHaulPlanService overHaulPlanService;
  /**
   * 查询场站的具体信息
   */
  @Autowired
  ElectricFieldService electricFieldService;
  /**
   * 查询nwp 数据获取日升日落的时间
   */
  @Autowired
  NwpService nwpService;
  /**
   * 查询设备属性 确定功率的点位  以及其他功率点的点位
   */
  @Autowired
  EquipmentAttributeService equipmentAttributeService;
  @Autowired
  ForecastPowerShortTermService forecastPowerShortTermService;
  @Autowired
  ForecastPowerUltraShortTermService forecastPowerUltraShortTermService;
  /**
   * 样板机计算参照功率
   */
  @Autowired
  BasePowerOfReferenceCalculator powerOfReferenceCalculatorBySample;
  /**
   * 系统配置变量获取类
   */
  @Autowired
  SysParameterService sysParameterService;
//  /**
//   * 用于从数据库内获取限电状态
//   */
//  @Autowired
//  PowerLimitPlanSignRepository powerLimitPlanSignRepository;
  /**
   * 用于获取日升日落时间
   */
  @Autowired
  WeatherStationStatusDataFilter weatherStationStatusDataFilter;

  /**
   * 存储设备状态数据
   */
  @Autowired
  SaveEquipmentStatusData saveEquipmentStatusData;


  /**
   * 实际 ，理论 ，可用 ，站内受阻 ，站外受阻 ，并网设备数等点位
   * 属性名String --- 点位
   */
  Map<String, ProtocolGatherDataPoint> protocolGatherDataPoints = new HashMap<>();
  /**
   * 场站状态数据实体域
   */
  List<Field> fields = new ArrayList<>();
  @Setter
  @Getter
  private PowerStationStatusData t = new PowerStationStatusData();
  /**
   * 场站信息
   */
  private ElectricField electricField;
  /**
   * 测风/光法 的公式计算器
   */
  private PointDataCalculator<BigDecimal> calculatorOfMeasuring;
  /**
   * 实际功率   场站设备  realValue
   */
  @Setter
  @Getter
  private BaseDataGainer<BigDecimal> realPower;
  /**
   * 实际功率是否需要审核的标志 默认不审核
   */
  private Boolean auditRealPower = false;

  /**
   * 人工控制限电的标识
   * 0  以系统判断结果为准
   * 1 限电
   * 2 不限电
   * 现在由于页面展示的原因  仅开放两种状态   是否限电 1.限电 0.不限电
   * 没有以系统判断结果为准 在不限电的时候默认系统判断结果进行干预
   */
  private Integer rationingByManualControl = 0;

  /**
   * 根据数据库的限电状态记录加载初始的
   * 当数据库里面没有记录时默认 0  不限电
   */
  public Integer getRationingByManualControl() {
//    List<PowerLimitPlanSign> list = powerLimitPlanSignRepository.findAll();
//    if (list.size() > 0) {
//      this.rationingByManualControl = list.get(list.size() - 1).getSign();
//    } else {
      this.rationingByManualControl = 0;
//    }
    return this.rationingByManualControl;
  }

  /**
   * 对DashboardService 开放的手动控制限电的状态修改方法
   * 用于页面上修改后进行通知
   *
   * @param powerLimitPlanSign
   */
  public void setRationingByManualControl(PowerLimitPlanSign powerLimitPlanSign) {
    if (powerLimitPlanSign != null) {
      this.rationingByManualControl = powerLimitPlanSign.getSign();
    }
  }

  public void setRationingByManualControl(Integer sign) {
    this.rationingByManualControl = sign;
  }

  /**
   * 对实际功率合理性进行审核 查看实际功率的合理性
   *
   * @param power 功率
   * @return 更改后的值 double
   */
  public BigDecimal realPowerRationalityAuditor(BigDecimal power) {
    DateTime time = DateTime.now();
    if (this.getElectricField() != null && this.getElectricField().getBackupE() != null && power.compareTo(new BigDecimal(this.getElectricField().getBackupE())) == 1) {
      //当实际功率超过场站的容量时  返回容量
      power = new BigDecimal(this.getElectricField().getBackupE());
      if (power.compareTo(BigDecimal.ZERO) < 0) {
        power = BigDecimal.ZERO;
      }
    }
    //对日升和日落各宽恕30min  如果在日升前30min到 日落后30min 之间
    //如果时间处于日出前30分钟    日落后30分钟   则判定功率为0
    if (this.getElectricField() != null && ElectricFieldTypeEnum.E1.equals(this.getElectricField().getElectricFieldTypeEnum())) {
      if (time.isBefore(weatherStationStatusDataFilter.getSunUpTime().minusMillis(30)) || time.isAfter(weatherStationStatusDataFilter.getSunDownTime().plusMillis(30))) {
        power = BigDecimal.ZERO;
      }
    }
    return power;
  }


  /**
   * 得到限电时间范围
   * 返回值为长度为2的int数字
   * 0位是开始的该天的分钟数（从00:00 开始计时到开始时间的分钟数）
   * 1位是结束的该天的分钟数
   * 处于两分钟数之间的时间段可能会被限电
   *
   * @return {@link int[]}
   */
  public int[] getPowerLimitTimeRange() {
    if (powerLimitTimeRange == null) {
      String sysParameter = sysParameterService.getSysParameter(POWER_LIMIT_TIME_RANGE, POWER_LIMIT_TIME_RANGE_DEFAULT);
      if (sysParameter.split("~").length >= 2) {
        String startTimeStr = sysParameter.split("~")[0];
        String endTimeStr = sysParameter.split("~")[1];
        try {
          DateTime startTime = DateTime.parse(startTimeStr, POWER_LIMIT_TIME_FORMATTER);
          DateTime endTime = DateTime.parse(endTimeStr, POWER_LIMIT_TIME_FORMATTER);
          int startMinute = startTime.getMinuteOfDay();
          int endMinute = endTime.getMinuteOfDay();
          powerLimitTimeRange = new int[]{startMinute, endMinute};
        } catch (IllegalArgumentException e) {
          log.error("限电时间段的时间格式不正确");
          powerLimitTimeRange = new int[0];
        } catch (Exception e) {
          log.error("解析限电时间段时异常", e);
          powerLimitTimeRange = new int[0];
        }
      } else {
        log.error("解析限电时间段时异常,或未配置限电时段");
        powerLimitTimeRange = new int[0];
      }
    }
    return this.powerLimitTimeRange;

  }

  /**
   * 获取参照功率
   * lgjsfs  理论功率计算方式
   *
   * @return 参照功率的计算结果
   */
  private BigDecimal getPowerOfReference(PowerStationStatusData powerStationStatusData) {
    String lgjsfs = sysParameterService.getSysParameter(LGJSFS, "0");
    switch (lgjsfs) {
      case "1":
        log.info("使用样板机方式计算参考值");
        if (powerStationStatusData.getReferencePowerBySample() != null) {
          return powerStationStatusData.getReferencePowerBySample().multiply(getOpenRatio());
        } else {
          log.info("样板机方式计算参考值为空返回倍率计算方式");
        }
      case "2":
        log.info("使用测风/光法方式计算参考值");
        if (powerStationStatusData.getReferencePowerByMeasuring() != null) {
          return powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio());
        } else {
          log.info("测风/光法方式计算参考值为空返回倍率计算方式");
        }
      default:
    }
    log.info("不判断限电,直接判断不限电");
    return BigDecimal.valueOf(-99);
  }


  /**
   * 根据实际功率是否需要审核  返回实际功率
   *
   * @return 实际功率数值
   */
  @SneakyThrows
  public BigDecimal getRealPowerVal() {
    if (realPower == null) {
      return BigDecimal.valueOf(-99D);
    }
    if (this.auditRealPower) {
      return realPowerRationalityAuditor(realPower.getData());
    } else {
      BigDecimal power = realPower.getData();
      if (power.compareTo(BigDecimal.ZERO) < 0) {
        power = BigDecimal.ZERO;
      }
      return power;
    }

  }


  /**
   * 初始化
   * 初始化计算器
   * 1.确定场站类别
   * 2.初始化各种map等
   *
   * @return 工具包装器本身
   */
  public PowerStationDataPacker init() {
    //初始化实体域集合
    initEntityFields();
    //初始化场站  场站类型  容量
    getElectricField();
    //初始化实际功率点位
    initPowerStationDataPoint();
    //初始化测风光法计算器
    initCalculatorOfMeasuring();
    return this;
  }

  /**
   * 初始化实际功率过滤器 阻止远超场站容量的实际功率异常数据进入数据池
   */
  private void initPowerFilter(Integer point) {
    ProtocolDataContainer.getInstance().getDataFiltering().addFilter(point, (val) -> {
      if (val.compareTo(new BigDecimal(getElectricField().getBackupE()).multiply(BigDecimal.valueOf(1.5D))) > 0) {
        log.info("实际功率超装机容量的1.5倍，值为：" + val + ",抛出异常");
        throw new RuntimeException("实际功率超装机容量的1.5倍");
      }
      return val;
    });
    if ("1".equals(sysParameterService.getSysParameter(QUICK_REFRESH_STATION_STATUS_DATA, QUICK_REFRESH_STATION_STATUS_DATA_DEFAULT))) {
      log.info("启用快速刷新场站状态数据");
      ProtocolDataContainer.getInstance().getModifyTriggering().addTrigger(point, (val) -> {
        try {
          log.info("快速刷新场站数据,实际功率：{}",val);
          packageData();
        } catch (DataExchangeException e) {
          log.error("快速刷新场站状态数据时，组装场站数据出错");
        }
      });
    }
  }

    /**
     * 初始化实体域集合
     */
    private void initEntityFields () {
      fields.addAll(Arrays.asList(t.getClass().getDeclaredFields()));
      fields.addAll(Arrays.asList(AbstractEquipmentStatusData.class.getDeclaredFields()));
      for (Field f : fields) {
        f.setAccessible(true);
      }

    }

    /**
     * init电站数据点
     * 用以获取实时的实际功率
     * 获取到实际功率的点位
     * 将实际功率的点位存入到
     */
    public void initPowerStationDataPoint () {
      ProtocolGatherDataPoint point = new ProtocolGatherDataPoint();
      //清除默认值
      point.setMagnification(null);
      EquipmentAttribute equipmentAttribute = new EquipmentAttribute();
      equipmentAttribute.setEquipmentType(EquipmentTypeEnum.POWERSTATION);
      point.setEquipmentAttribute(equipmentAttribute);
      List<ProtocolGatherDataPoint> points = protocolGatherDataPointService.get(point);
      for (ProtocolGatherDataPoint p : points) {
        if (p.getDataSource() == DataSourceEnum.GENERATE) {
          if (!"1".equals(p.getGenerationRegulation()) && !"realValue".equals(p.getEquipmentAttribute().getFieldName())) {
            ProtocolDataContainer.getInstance().addCalculator(p);
          }
        }
        this.protocolGatherDataPoints.put(p.getEquipmentAttribute().getFieldName(), p);
      }
      //实际功率
      ProtocolGatherDataPoint dataPoint;
      dataPoint = protocolGatherDataPoints.get("realValue");
      if (dataPoint != null) {
        initPowerFilter(dataPoint.getId());
        if (DataSourceEnum.GENERATE.equals(dataPoint.getDataSource())) {
          ProtocolDataContainer.getInstance().addCalculator(dataPoint);
          this.setRealPower(new GetDataFromContainer(NumOrBool.NUM, dataPoint.getId(), dataPoint.getMagnification()));
        } else {
          this.setRealPower(new GetDataFromContainer(NumOrBool.NUM, dataPoint.getId(), 1.0));
        }
        if ("1".equals(sysParameterService.getSysParameter(AUDITREALPOWER, "0"))) {
          this.auditRealPower = true;
        }
      }
    }


    /**
     * 获取场站的情况
     * 场站的容量
     * 场站的类型 风电or 光伏
     *
     * @return ElectricField 场站信息
     */
    public ElectricField getElectricField () {
      ElectricField electricField = electricFieldService.get();
      if (electricField != null) {
        this.electricField = electricField;
      }
      electricField.setCapacity(new BigDecimal(electricField.getBackupE()));
      electricField.setElectricFieldTypeEnum(ElectricFieldTypeEnum.E1);
      return this.electricField;
    }

//    /**
//     * 判断是否限电
//     *
//     * @param powerStationStatusData 场站状态数据
//     * @return 限电？  true： 限电 ； false ：不限电
//     */
//    public boolean judgeIsRationing (PowerStationStatusData powerStationStatusData){
//      if (getPowerLimitTimeRange() != null && getPowerLimitTimeRange().length >= 2) {
//        //当场站配置了限电时间，那么进入限电时间判断
//        int minute = new DateTime(powerStationStatusData.getTime()).getMinuteOfDay();
//        if (minute < getPowerLimitTimeRange()[0] || minute > getPowerLimitTimeRange()[1]) {
//          //如果当前时间在限电时间之外，一律判断为不限电
//          return false;
//        }
//      }
//      //底线功率
//      BigDecimal baseLinePower = this.getElectricField().getCapacity().multiply(new BigDecimal(sysParameterService.getSysParameter(SFPDXD, "1")));
//      BigDecimal coefficient = new BigDecimal(sysParameterService.getSysParameter(XDXS, "0.2")).add(BigDecimal.valueOf(1));
//      BigDecimal referencePower = this.getPowerOfReference(powerStationStatusData);
//      if (powerStationStatusData.getRealValue().compareTo(baseLinePower) == -1) {
//        //实际功率 小于容量的 n%  不统计是否限电  全部视为不限电
//        return false;
//      } else {
//        //参照功率 - 实际功率 > 实际功率 * 限电系数  ？？  大于就限电 小于就不限电
//        return referencePower.compareTo(powerStationStatusData.getRealValue().multiply(coefficient)) == 1;
//      }
//    }


    /**
     * 初始化测风光法计算器
     */
    private void initCalculatorOfMeasuring () {
      this.calculatorOfMeasuring = null;
      ProtocolGatherDataPoint dataPoint = protocolGatherDataPointService.get(null, EquipmentTypeEnum.POWERSTATION, "referencePowerByMeasuring");
      if (dataPoint != null && DataSourceEnum.GENERATE.equals(dataPoint.getDataSource())) {
        this.calculatorOfMeasuring = new PointDataCalculator<>(NumOrBool.NUM, dataPoint.getGenerationRegulation(), dataPoint.getMagnification());
      }
    }

    /**
     * 获取当下时间段的 短期功率和超短期功率的平均数
     *
     * @return 平均数
     */
    @SneakyThrows
    private BigDecimal getForecastPowerAvg () {
      long nowQuarterTime = DateMomentUtil.getMomentTime(System.currentTimeMillis(), 1, 900000L);
      BigDecimal dq = BigDecimal.valueOf(0);
      BigDecimal cdq = BigDecimal.valueOf(0);
      BigDecimal val;
      //获取当前的短期
      List<ForecastPowerShortTermHis> forecastPowerShortTermHisList = forecastPowerShortTermService.getForecastPowerShortTerm(nowQuarterTime, nowQuarterTime);
      if (null != forecastPowerShortTermHisList && forecastPowerShortTermHisList.size() > 0) {
        dq = forecastPowerShortTermHisList.get(0).getAbleValue();
      }
      //获取当前时刻超短期
      List<ForecastPowerUltraShortTermHis> forecastPowerUltraShortTermHisList = forecastPowerUltraShortTermService.getForecastPowerUltraShortTerm(nowQuarterTime, nowQuarterTime);
      if (null != forecastPowerUltraShortTermHisList && forecastPowerUltraShortTermHisList.size() > 0) {
        cdq = forecastPowerUltraShortTermHisList.get(0).getAbleValue();
      }
      val = (dq.add(cdq)).divide(new BigDecimal(2), 2, RoundingMode.HALF_DOWN);
      return val;
    }

    @Override
    public PowerStationStatusData packageData () throws DataExchangeException {
      PowerStationStatusData powerStationStatusData = new PowerStationStatusData();
      try {
        BigDecimal cap = new BigDecimal(getElectricField().getBackupE());
        //设定时间
        powerStationStatusData.setTime(DateTime.now().withMillisOfSecond(0).withSecondOfMinute(0).toDate());
        //设定容量
        powerStationStatusData.setCapacity(cap);
        //设定并网设备数
//        powerStationStatusData.setOnGridNum(this.getElectricField().getGridCE());
        //设定开机容量为装机容量
        powerStationStatusData.setOpenCapacity(cap.subtract(overHaulPlanService.getOverhaulCapacity()));
        //设定场站状态
//        powerStationStatusData.setStatus(this.getElectricField().getElectricFieldTypeEnum().getCode());
        //设定实际功率
        powerStationStatusData.setRealValue(getRealPowerVal());
        //设定 样板机参照功率
        powerStationStatusData.setReferencePowerBySample(powerOfReferenceCalculatorBySample.getEstimatePower());
        if (powerStationStatusData.getReferencePowerBySample() == null || powerStationStatusData.getReferencePowerBySample().compareTo(powerStationStatusData.getRealValue()) == -1) {
          log.warn("样板机法计算值小于实际功率异常，值为：" + powerStationStatusData.getReferencePowerBySample());
          powerStationStatusData.setAbnormalOfSample(powerStationStatusData.getReferencePowerBySample());
          powerStationStatusData.setReferencePowerBySample(((powerStationStatusData.getCapacity().subtract(powerStationStatusData.getRealValue())).multiply(BigDecimal.valueOf(random.nextFloat())).multiply(BigDecimal.valueOf(0.001))).add(powerStationStatusData.getRealValue()).setScale(2, BigDecimal.ROUND_HALF_UP));
        } else if (powerStationStatusData.getReferencePowerBySample().compareTo(powerStationStatusData.getCapacity()) == 1) {
          log.warn("样板机法计算值超装机容量异常，值为：" + powerStationStatusData.getReferencePowerBySample());
          powerStationStatusData.setAbnormalOfSample(powerStationStatusData.getReferencePowerBySample());
          powerStationStatusData.setReferencePowerBySample(powerStationStatusData.getCapacity());
        }
        powerStationStatusData.setAblePowerBySample(powerStationStatusData.getReferencePowerBySample().multiply(getOpenRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
        if (powerStationStatusData.getAblePowerBySample().compareTo(powerStationStatusData.getRealValue()) < 0) {
          powerStationStatusData.setAblePowerBySample(powerStationStatusData.getReferencePowerBySample());
        }
        //设定 测风光法参照功率
        if (this.calculatorOfMeasuring != null) {
          powerStationStatusData.setReferencePowerByMeasuring(this.calculatorOfMeasuring.getData().setScale(2, BigDecimal.ROUND_HALF_UP));
        }
        if (powerStationStatusData.getReferencePowerByMeasuring() == null || powerStationStatusData.getReferencePowerByMeasuring().compareTo(powerStationStatusData.getRealValue()) == -1) {
          log.warn("测风光法计算值小于实际功率异常，值为：" + powerStationStatusData.getReferencePowerByMeasuring());
          powerStationStatusData.setAbnormalOfMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
          powerStationStatusData.setReferencePowerByMeasuring(((getElectricField().getCapacity().subtract(powerStationStatusData.getRealValue())).multiply(BigDecimal.valueOf(random.nextFloat())).multiply(BigDecimal.valueOf(0.001))).add(powerStationStatusData.getRealValue()).setScale(2, BigDecimal.ROUND_HALF_UP));
        } else if (powerStationStatusData.getReferencePowerByMeasuring().compareTo(powerStationStatusData.getCapacity()) == 1) {
          log.warn("测风光法计算值超装机容量异常，值为：" + powerStationStatusData.getReferencePowerByMeasuring());
          powerStationStatusData.setAbnormalOfMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
          powerStationStatusData.setReferencePowerByMeasuring(powerStationStatusData.getCapacity());
        }
        powerStationStatusData.setAblePowerByMeasuring(powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
        if (powerStationStatusData.getAblePowerByMeasuring().compareTo(powerStationStatusData.getRealValue()) < 0) {
          powerStationStatusData.setAblePowerByMeasuring(powerStationStatusData.getReferencePowerByMeasuring());
        }

        //设定 机头风速法参照功率

        powerStationStatusData.setReferencePowerByHubSpeed(saveEquipmentStatusData.getTheoreticalPowerByHubSpeedInHoleStation().divide(BigDecimal.valueOf(1000)).setScale(2, BigDecimal.ROUND_HALF_UP));
        if (powerStationStatusData.getReferencePowerByHubSpeed() == null || powerStationStatusData.getReferencePowerByHubSpeed().compareTo(powerStationStatusData.getRealValue()) == -1) {
          log.warn("机头风速法计算值小于实际功率异常，值为：" + powerStationStatusData.getReferencePowerByHubSpeed());
          powerStationStatusData.setAbnormalOfHubSpeed(powerStationStatusData.getReferencePowerByHubSpeed());
          powerStationStatusData.setReferencePowerByHubSpeed(((getElectricField().getCapacity().subtract(powerStationStatusData.getRealValue())).multiply(BigDecimal.valueOf(random.nextFloat())).multiply(BigDecimal.valueOf(0.001))).add(powerStationStatusData.getRealValue()).setScale(2, BigDecimal.ROUND_HALF_UP));
        } else if (powerStationStatusData.getReferencePowerByHubSpeed().compareTo(powerStationStatusData.getCapacity()) == 1) {
          log.warn("机头风速法计算值超装机容量异常，值为：" + powerStationStatusData.getReferencePowerByHubSpeed());
          powerStationStatusData.setAbnormalOfHubSpeed(powerStationStatusData.getReferencePowerByHubSpeed());
          powerStationStatusData.setReferencePowerByHubSpeed(powerStationStatusData.getCapacity());
        }
        powerStationStatusData.setAblePowerByHubSpeed(powerStationStatusData.getReferencePowerByHubSpeed().multiply(getOpenRatio()).setScale(2, BigDecimal.ROUND_HALF_UP));
        if (powerStationStatusData.getAblePowerByHubSpeed().compareTo(powerStationStatusData.getRealValue()) < 0) {
          powerStationStatusData.setAblePowerByHubSpeed(powerStationStatusData.getReferencePowerByHubSpeed());
        }


//        boolean isRationing = judgeIsRationing(powerStationStatusData);
        boolean isRationing = false;
        //设定是否限电
        powerStationStatusData.setIsRationingByAutoControl(isRationing);
        //设定手动限电的状态
        powerStationStatusData.setIsRationingByManualControl(getRationingByManualControl());
        //设定理论和可用
        if (getRationingByManualControl() == 1 || (isRationing && getRationingByManualControl() == 0)) {
          //限电情况下  平均功率和实际功率取大者 乘倍率
          switch (sysParameterService.getSysParameter("kyglqz", "1")) {
            case "2":
              powerStationStatusData.setAbleValue(powerStationStatusData.getReferencePowerBySample().multiply(getOpenRatio()).setScale(2, RoundingMode.HALF_DOWN));
              break;
            case "3":
              powerStationStatusData.setAbleValue(powerStationStatusData.getReferencePowerByMeasuring().multiply(getOpenRatio()).setScale(2, RoundingMode.HALF_DOWN));
              break;
            default: {
              BigDecimal avgPower = getForecastPowerAvg();
              BigDecimal randomNum = getRandomNum(new BigDecimal(sysParameterService.getSysParameter(KYGLJSMIN, "1")), new BigDecimal(sysParameterService.getSysParameter(KYGLJSMAX, "1.02")));
              if (avgPower.compareTo(powerStationStatusData.getRealValue()) == 1) {
                powerStationStatusData.setAbleValue(avgPower.multiply(randomNum).setScale(2, BigDecimal.ROUND_HALF_UP));
              } else {
                powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(randomNum).setScale(2, BigDecimal.ROUND_HALF_UP));
              }
            }
          }
        } else if ((!isRationing && getRationingByManualControl() == 0)) {
          //不限电 实际功率，理论功率，可用功率  理论=k*可用=k*实际
          powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(BigDecimal.ONE.add(getMagnificationK())).setScale(2, RoundingMode.HALF_DOWN));
        }

        if (powerStationStatusData.getOpenCapacity().compareTo(new BigDecimal(0)) != 0) {
          //设置理论功率
          powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue().multiply(BigDecimal.ONE.add(getMagnificationK())).add(overHaulPlanService.getOverhaulCapacity().multiply(powerStationStatusData.getRealValue().divide(powerStationStatusData.getOpenCapacity(), 2))).setScale(2, RoundingMode.HALF_DOWN));
        } else {
          powerStationStatusData.setTheoryValue(new BigDecimal(0));
        }
        //设置站内受阻
        powerStationStatusData.setOnSiteObstructed(powerStationStatusData.getTheoryValue().subtract(powerStationStatusData.getAbleValue()));
        //设置站外受阻
        powerStationStatusData.setOffSiteObstructed(powerStationStatusData.getAbleValue().subtract(powerStationStatusData.getRealValue()));
      } catch (Exception e) {
        log.error("组装场站状态数据时发生异常", e);
        throw new DataExchangeException(40201, "组装场站状态数据时发生异常");
      }
      try {
        complementDomain(powerStationStatusData);
      } catch (Exception e) {
        log.error("实时区数据补全场站状态数据时发生异常", e);
      }
      try {
        reverseInjection(powerStationStatusData);
      } catch (Exception e) {
        log.error("场站状态数据反向注入实时区时发生异常", e);
      }
      if (powerStationStatusData.getAbleValue().compareTo(BigDecimal.valueOf(-99)) == 0) {
        powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue());
        powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue());
      } else {
        if (powerStationStatusData.getAbleValue().compareTo(powerStationStatusData.getRealValue()) < 0) {
          powerStationStatusData.setAbleValue(powerStationStatusData.getRealValue().multiply(getMagnificationK().add(BigDecimal.ONE)).setScale(2, RoundingMode.HALF_DOWN));
        }
        if (powerStationStatusData.getTheoryValue().compareTo(powerStationStatusData.getAbleValue()) < 0) {
          powerStationStatusData.setTheoryValue(powerStationStatusData.getAbleValue().multiply(getMagnificationK().add(BigDecimal.ONE)).setScale(2, RoundingMode.HALF_DOWN));
        }
      }
      return powerStationStatusData;
    }


    /**
     * 得到随机num
     *
     * @param min 最小值
     * @param max 最大值
     * @return {@link BigDecimal}
     */
    public BigDecimal getRandomNum (BigDecimal min, BigDecimal max){
      return BigDecimal.valueOf(random.nextDouble()).multiply(max.subtract(min)).add(min).setScale(2, RoundingMode.HALF_DOWN);
    }


    /**
     * 主要是为了转发  将 已经计算好的数据 转到实时数据区
     * 主要包括 系统判断是否限电，可用，理论，样板机参照功率，测风/光法参照功率，站内受阻，站外受阻
     *
     * @param powerStationStatusData
     * @throws IllegalAccessException
     */
    private void reverseInjection (PowerStationStatusData powerStationStatusData) throws IllegalAccessException {
      Type type;
      for (Field f : this.fields) {
        try {
          if (protocolGatherDataPoints.containsKey(f.getName()) && InjectionProperties.contains(f.getName())) {
            if (protocolGatherDataPoints.get(f.getName()).getDataSource() == DataSourceEnum.GATHER) {
              continue;
            }
            type = f.getGenericType();
            Integer pid = protocolGatherDataPoints.get(f.getName()).getId();
            if (Boolean.class.equals(type) || boolean.class.equals(type)) {
              ProtocolDataContainer.getInstance().putBoolean(pid, (Boolean) f.get(powerStationStatusData));
            } else {
              ProtocolDataContainer.getInstance().putNumber(pid, (BigDecimal) f.get(powerStationStatusData));
            }
          }
        } catch (Exception e) {
          log.error("反向注入" + f.getName() + "时发生异常", e);
        }
      }
    }


    /**
     * 将实时区数据取出置入场站状态数据
     * <p>
     * 如 开机容量 日上网电量  并网设备数以及备用字段等
     *
     * @param powerStationStatusData
     * @throws IllegalAccessException
     */
    private void complementDomain (PowerStationStatusData powerStationStatusData) throws IllegalAccessException {
      Type type;
      for (Field f : this.fields) {
        /**
         * 由于实际功率和测风光法已经赋值完毕 不用再次赋值
         * 将接入的和公式生成的值完善到对象里
         */
        try {
          if (protocolGatherDataPoints.containsKey(f.getName()) && !"realValue".equals(f.getName()) && !"referencePowerByMeasuring".equals(f.getName())) {
            if (protocolGatherDataPoints.get(f.getName()).getDataSource() == DataSourceEnum.GENERATE && "1".equals(protocolGatherDataPoints.get(f.getName()).getGenerationRegulation())) {
              continue;
            }
            type = f.getGenericType();
            Integer pid = protocolGatherDataPoints.get(f.getName()).getId();
            if (Boolean.class.equals(type) || boolean.class.equals(type)) {
              f.set(powerStationStatusData, ProtocolDataContainer.getInstance().getBoolean(pid));
            } else if (Integer.class.equals(type) || int.class.equals(type)) {
              if (f.get(powerStationStatusData) == null) {
                f.set(powerStationStatusData, ProtocolDataContainer.getInstance().getNumber(pid).setScale(2, BigDecimal.ROUND_HALF_UP).intValue());
              }
            } else {
              //if (((BigDecimal) f.get(powerStationStatusData)).compareTo(BigDecimal.valueOf(-99)) == 0 || f.get(powerStationStatusData) == null) {
              f.set(powerStationStatusData, ProtocolDataContainer.getInstance().getNumber(pid).setScale(2, BigDecimal.ROUND_HALF_UP));
            }
          }
        } catch (Exception e) {
          log.error("组装数据" + f.getName() + "时发生异常", e);
        }
      }

    }

    /**
     * 获取当前时间开机容量比 即开机容量和装机容量的比值
     */
    public BigDecimal getOpenRatio () {
      return BigDecimal.ONE.subtract(overHaulPlanService.getOverhaulCapacity().divide(new BigDecimal(electricField.getBackupE()), 2, RoundingMode.HALF_DOWN));
    }

    /**
     * 获取0.015 - 0.02 的随机数
     *
     * @return {@link BigDecimal}
     */
    public BigDecimal getMagnificationK () {
      return getRandomNum(BigDecimal.valueOf(0.015), BigDecimal.valueOf(0.02));
    }

  }



