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


import com.jiayue.ipfcst.common.data.abst.equipmentstatus.AbstractEquipmentStatusData;
import com.jiayue.ipfcst.common.data.constant.enums.DataSourceEnum;
import com.jiayue.ipfcst.common.data.entity.ProtocolGatherDataPoint;
import com.jiayue.ipfcst.common.data.entity.WeatherStationInfo;
import com.jiayue.ipfcst.common.data.entity.WeatherStationStatusData;
import com.jiayue.ipfcst.dataexchange.container.ProtocolDataContainer;
import com.jiayue.ipfcst.dataexchange.dataprocesser.CheckDataRecode;
import com.jiayue.ipfcst.dataexchange.dataprocesser.DataAuditor;
import com.jiayue.ipfcst.dataexchange.dataprocesser.datapacker.AbstractDataPacker;
import com.jiayue.ipfcst.dataexchange.exception.DataExchangeException;
import lombok.Getter;
import lombok.Setter;
import org.joda.time.DateTime;

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

/**
 * 装备数据的包装类 点表转类属性
 *
 * @author 修唯xiuwei
 * @version 3.0
 */
@Getter
public class
EquipmentDataPacker<T extends AbstractEquipmentStatusData> extends AbstractDataPacker<T> {

  /**
   * 设备号
   */
  @Setter
  Integer equipmentNo;


  /**
   * 实时采集数据池
   */
  ProtocolDataContainer protocolDataContainer = ProtocolDataContainer.getInstance();

  /**
   * 为需要进行审计的数据进行统一管理
   */
  private Map<Integer, CheckDataRecode> checkDataRecodeMap = new HashMap<>();

  /**
   * 所有需要采集的数据点
   */
  private List<ProtocolGatherDataPoint> pointList;

  /**
   * 将点位与类的属性对应上的map
   */
  private Map<ProtocolGatherDataPoint, Field> point2FiledMap = new HashMap<>();

  /**
   * 构造方法，在方法中获取传入类型的属性，存入map中，以便后期使用
   *
   * @param newInstance T的实例 直接new 对象（）；
   * @param pointList   点表集合
   */
  public EquipmentDataPacker(T newInstance, List<ProtocolGatherDataPoint> pointList) {
    t = newInstance;
    if (pointList == null || pointList.size() == 0) {
      return;
    }
    parseGatherDataPoint(pointList);
  }

  /**
   * 解析采集数据点
   *
   * @param pointList 点列表
   */
  public void parseGatherDataPoint(List<ProtocolGatherDataPoint> pointList) {
    this.pointList = pointList;
    this.equipmentNo = pointList.get(0).getEquipmentId();
    point2FiledMap = new HashMap<>();
    checkDataRecodeMap = new HashMap<>();
    List<Field> fields = new ArrayList<>();
    fields.addAll(Arrays.asList(t.getClass().getDeclaredFields()));
    fields.addAll(Arrays.asList(AbstractEquipmentStatusData.class.getDeclaredFields()));
    for (Field f : fields) {
      for (ProtocolGatherDataPoint p : pointList) {
        if (f.getName().equals(p.getEquipmentAttribute().getFieldName())) {
          f.setAccessible(true);
          point2FiledMap.put(p, f);
          if (p.getNeedAudit() != null && p.getNeedAudit()) {
            checkDataRecodeMap.put(p.getId(), new CheckDataRecode());
          }
          if (DataSourceEnum.GENERATE.equals(p.getDataSource())) {
            protocolDataContainer.addCalculator(p);
          }
        }
      }
    }
  }

  /**
   * 通过反射机制将容器中的数据封装入设备描述的实体类 同时对数据合理性进行校验 仅对数据类型为BigDecimal的数据进行合理性校验
   *
   * @return AbstractEquipmentData 设备状态数据
   * @throws DataExchangeException 异常
   */
  @Override
  public synchronized T packageData() throws DataExchangeException {
    T data;
    try {
      data = (T) t.getClass().newInstance();
    } catch (InstantiationException e) {
      throw new DataExchangeException(40101, "传入实体类实例化失败");
    } catch (IllegalAccessException e) {
      throw new DataExchangeException(40102, "传入实体类构建实例时权限异常");
    }
    Type type;
    if (this.point2FiledMap == null) {
      return data;
    }
    for (Map.Entry<ProtocolGatherDataPoint, Field> entry : point2FiledMap.entrySet()) {
      try {
        if (protocolDataContainer.isYxContains(entry.getKey().getId())
          || protocolDataContainer.isYcContains(entry.getKey().getId())) {
          type = entry.getValue().getGenericType();
          if (Boolean.class.equals(type) || boolean.class.equals(type)) {
            entry.getValue().set(data, protocolDataContainer.getBoolean(entry.getKey().getId()));
          } else if (BigDecimal.class.equals(type)) {
            if (entry.getKey().getNeedAudit() != null && entry.getKey().getNeedAudit()) {
              entry.getValue().set(data,
                DataAuditor.auditData(entry.getKey(), checkDataRecodeMap.get(entry.getKey().getId()),
                  protocolDataContainer.getNumber(entry.getKey().getId())));
            } else {
              entry.getValue().set(data,
                protocolDataContainer.getNumber(entry.getKey().getId()).setScale(2, BigDecimal.ROUND_HALF_UP));
            }
          } else if (Integer.class.equals(type) || int.class.equals(type)) {
            entry.getValue().set(data, protocolDataContainer.getNumber(entry.getKey().getId()).intValue());
          }
        } else {
          // 协议通道未能将数据采入池子，表达的意思就是长时间做假数据
        }
      } catch (IllegalAccessException e) {
        e.printStackTrace();
        throw new DataExchangeException(40103, "传入实体域注入值时权限异常");
      } catch (IllegalArgumentException e) {
        e.printStackTrace();
        throw new DataExchangeException(40104, "传入实体域注入值时类型异常");
      }
    }
    data.setEquipmentNo(equipmentNo);
    data.setTime(DateTime.now().withMillisOfSecond(0).withSecondOfMinute(0).toDate());
    return data;
  }

}
