package com.base.track.service;

import Jama.Matrix;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.base.api.client.*;
import com.base.api.model.*;
import com.base.api.model.request.FzTaskInfoRpcReqDTO;
import com.base.api.model.request.PayloadRpcReqDTO;
import com.base.api.model.request.QueryLinkCountDTO;
import com.base.api.model.request.QueryStationAddRpcDTO;
import com.base.orbit.utils.BizUtils;
import com.base.orbit.utils.DateUtils;
import com.base.orbit.utils.IdGenerator;
import com.base.orbit.utils.StringUtil;
import com.base.track.mapper.TrbutDataMapper;
import com.base.track.model.dto.request.CxStationDTO;
import com.base.track.model.dto.request.QueryEphListDTO;
import com.base.track.model.dto.request.TrbutRequestDTO;
import com.base.track.model.dto.response.*;
import com.base.track.model.entity.*;
import com.google.common.collect.Lists;
import com.plan.api.client.StripRpcService;
import com.plan.api.client.WindowResourceRpcService;
import com.plan.api.model.StripRpcDTO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author cxl
 * @since 2022-06-23
 */
@Service
@Slf4j
public class TrbutDataService extends ServiceImpl<TrbutDataMapper, TrbutData> {

    private final double geo_h;
    private final double GM = 398600.5;
    private final double Re = 6378.137;

    public TrbutDataService() {
        double we = 7.292115e-5;
        double geo_a = Math.pow(GM / Math.pow(we, 2), (1 / 3.0));
        geo_h = geo_a - Re;
    }

    @Resource
    TrbutDataMapper trbutDataMapper;
    @Resource
    EphDataService ephService;
    @Resource
    StationRpcService stationRpcService;
    @Resource
    InstanceRpcService instanceRpcService;
    @Resource
    SatelliteRpcService satelliteRpcService;
    @Resource
    AntennaRpcService antennaRpcService;
    @Resource
    TrbutAntennaDataService trbutAntennaDataService;
    @Resource
    LinkCountRpcService linkCountRpcService;
    @Resource
    FzTaskRpcService fzTaskRpcService;
    @Resource
    PayloadRpcService payloadRpcService;
    @Resource
    StripRpcService stripRpcService;
    @Resource
    WindowResourceRpcService windowResourceRpcService;


    public void deleteByDate(String startTime, String endTime) {
        trbutDataMapper.deleteByDate(startTime, endTime);
    }

    public List<TrbutDataDTO> selTrButDataByVo(CxStationVo cxStationVo) {
        List<TrbutDataDTO> res = new ArrayList<>();
        List<TrbutData> trbutDatas = trbutDataMapper.selTrButData(cxStationVo); //  进出站信息
        trbutDatas.stream().forEach(trbutData -> {
            TrbutDataDTO trbutDataDTO = new TrbutDataDTO();
            BeanUtils.copyProperties(trbutData, trbutDataDTO);
            res.add(trbutDataDTO);
        });
        return res;
    }

    public TrbutDataListReDTO selTrButDataByFz(CxStationDTO cxStationDTO) {

        List<TrbutAntennaData> trbutAntennaDatas = trbutAntennaDataService.list();
        List<AntennaRpcDTO> antennaRpcDTOList = antennaRpcService.selAllAntenaInfos();

        List<TrbutDataListReDTOZJ> trbutDataListReDTOZJS = new ArrayList<>();
        List<TrbutDataListReDTODMZ> trbutDatas = new ArrayList<>();
        TrbutDataListReDTO trbutDataListReDTO = new TrbutDataListReDTO();
        CxStationVo cxStationVo = new CxStationVo();
        cxStationVo.setCodes(cxStationDTO.getCodes());
        cxStationVo.setCxStartTime(cxStationDTO.getCxStartTime());
        cxStationVo.setCxEndTime(cxStationDTO.getCxEndTime());
        List<TrbutData> trbutData = trbutDataMapper.selTrButData(cxStationVo);
        Map<Integer, List<TrbutData>> trbutMap = trbutData.stream().collect(Collectors.groupingBy(TrbutData::getStationType));
        trbutMap.forEach((k, v) -> {
            if (k == 0) {
                List<TrbutDataListReDTODMZ> trbutDataListReDTODMZS = BizUtils.copyEntityToDto(TrbutDataListReDTODMZ.class, v);
                trbutDataListReDTODMZS.stream().forEach(trbutDataListRe -> {
                    List<TrbutAntennaData> trbutAntennaData = trbutAntennaDatas.stream().filter(e -> trbutDataListRe.getId().equals(e.getTrbutId())).collect(Collectors.toList());
                    trbutAntennaData.stream().forEach(trbutAntennaDataVo -> {
                        List<AntennaRpcDTO> antennaRpcDTOS = antennaRpcDTOList.stream().filter(e -> trbutAntennaDataVo.getAntennaId().equals(e.getId())).collect(Collectors.toList());
                        antennaRpcDTOS.stream().forEach(antennaRpcDTO -> {
                            trbutDataListRe.setAntennaCaliber(antennaRpcDTO.getTxkj());
                            trbutDataListRe.setIdent(trbutAntennaDataVo.getIdent());
                            trbutDataListRe.setJssl(antennaRpcDTO.getJssl());
                        });
                    });
                });
                trbutDatas.addAll(trbutDataListReDTODMZS);
            } else {
                List<TrbutDataListReDTOZJ> trbutDataListReDTOZJs = BizUtils.copyEntityToDto(TrbutDataListReDTOZJ.class, v);
                trbutDataListReDTOZJS.addAll(trbutDataListReDTOZJs);
            }
        });
        trbutDataListReDTO.setTrbutDataListReDTOZJS(trbutDataListReDTOZJS);
//        List<TrbutDataListReDTODMZ> washTrbutDatas = washTrbutData(trbutDatas, cxStationDTO.getReqIds());
        trbutDataListReDTO.setTrbutDataListReDTODMZS(trbutDatas);
        return trbutDataListReDTO;
    }

    //  todo  查询结果中将数传时长，按照条带观测时长调整
//    public List<TrbutDataListReDTODMZ> washTrbutData(List<TrbutDataListReDTODMZ> trbutDatas, List<String> reqIds) {
//        List<WindowResourceRpcDTO> windowResourceRpcDTOS = windowResourceRpcService.getWindowResourceInfo(reqIds);
//        if (!CollectionUtils.isEmpty(windowResourceRpcDTOS)) {
//            windowResourceRpcDTOS.stream().forEach(windowResourceRpcDTO -> {
//                String resourceId = windowResourceRpcDTO.getResourceId();   //  当前进出站id
//                long dataTransferDuration = Long.valueOf(windowResourceRpcDTO.getDataTransferDuration());  //  条带对当前地面站数传时长(如当前地面站不能接收完整条带则接力数传)
//                TrbutDataListReDTODMZ trbutDataListReDTODMZ = trbutDatas.stream().filter(trbutData -> trbutData.getId().equals(resourceId)).collect(Collectors.toList()).get(0);
//                LocalDateTime receiveStartLocalTime = DateUtils.DateCaseToLocalDateTime(trbutDataListReDTODMZ.getReceiveStartTime());
//                trbutDataListReDTODMZ.setReceiveEndTime(DateUtils.toDate(receiveStartLocalTime.plusSeconds(dataTransferDuration)));
//            });
//        }
//        return trbutDatas;
//    }

    public TrbutDataListReDTO selTrButData(CxStationDTO cxStationDTO) {
        TrbutDataListReDTO trbutDataListReDTO = new TrbutDataListReDTO();
        try {
            List<TrbutAntennaData> trbutAntennaDatas = trbutAntennaDataService.list();
            List<AntennaRpcDTO> antennaRpcDTOList = antennaRpcService.selAllAntenaInfos();

            List<TrbutDataListReDTOZJ> trbutDataListReDTOZJS = new ArrayList<>();
            List<TrbutDataListReDTODMZ> trbutDatas = new ArrayList<>();
            Map<String, List<StripRpcDTO>> stringListMap = gruopStripBySatelliteCode(cxStationDTO.getStripIds());
            for (Map.Entry<String, List<StripRpcDTO>> entry : stringListMap.entrySet()) {
                String key = entry.getKey();
                List<StripRpcDTO> value = entry.getValue();

                String[] keystr = key.split("-");
                String SatelliteCode = "";
                String targetName = "";
                if (keystr.length >= 3) {
                    SatelliteCode = keystr[0] + "-" + keystr[1];
                    targetName = keystr[2];
                } else {
                    SatelliteCode = keystr[0];
                    targetName = keystr[1];
                }

                CxStationVo cxStationVo = new CxStationVo();
                cxStationVo.setCodes(Arrays.asList(SatelliteCode));
                Integer maxCircle = Integer.valueOf(value.stream().max(Comparator.comparing(StripRpcDTO::getCircle)).get().getCircle());
                Integer minCircle = Integer.valueOf(value.stream().min(Comparator.comparing(StripRpcDTO::getCircle)).get().getCircle());
                Optional<StripRpcDTO> stripRpcDTO = value.stream().sorted(Comparator.comparing(StripRpcDTO::getObservationEndTime)).findFirst();
                if (stripRpcDTO.isPresent()) {
                    StripRpcDTO stripRpcDTO1 = stripRpcDTO.get();
                    cxStationVo.setCxStartTime(stripRpcDTO1.getObservationEndTime());
                    List<TrbutData> trbutData = trbutDataMapper.selTrButData(cxStationVo);
                    Map<Integer, List<TrbutData>> trbutMap = trbutData.stream().collect(Collectors.groupingBy(TrbutData::getStationType));
                    String finalTargetName = targetName;
                    trbutMap.forEach((k, v) -> {
                        if (k == 0) {
                            //  地面站进出站考虑根据最小最大圈号过滤
                            List<TrbutData> trbutDataList = v.stream().filter(val -> val.getOrbitNum() >= minCircle).collect(Collectors.toList());
                            List<TrbutDataListReDTODMZ> trbutDataListReDTODMZS = BizUtils.copyEntityToDto(TrbutDataListReDTODMZ.class, trbutDataList);
                            trbutDataListReDTODMZS.stream().forEach(trbutDataListRe -> {
                                List<TrbutAntennaData> trbutAntennaData = trbutAntennaDatas.stream().filter(e -> trbutDataListRe.getId().equals(e.getTrbutId())).collect(Collectors.toList());
                                trbutAntennaData.stream().forEach(trbutAntennaDataVo -> {
                                    List<AntennaRpcDTO> antennaRpcDTOS = antennaRpcDTOList.stream().filter(e -> trbutAntennaDataVo.getAntennaId().equals(e.getId())).collect(Collectors.toList());
                                    antennaRpcDTOS.stream().forEach(antennaRpcDTO -> {
                                        trbutDataListRe.setTargetName(finalTargetName);
                                        trbutDataListRe.setAntennaCaliber(antennaRpcDTO.getTxkj());
                                        trbutDataListRe.setIdent(trbutAntennaDataVo.getIdent());
                                        trbutDataListRe.setJssl(antennaRpcDTO.getJssl());
                                    });
                                });
                            });
                            trbutDatas.addAll(trbutDataListReDTODMZS);
                        } else {
                            List<TrbutDataListReDTOZJ> trbutDataListReDTOZJs = BizUtils.copyEntityToDto(TrbutDataListReDTOZJ.class, v);
                            trbutDataListReDTOZJs.stream().forEach(trbutDataListReDTOZJ -> {
                                trbutDataListReDTOZJ.setTargetName(finalTargetName);
                            });
                            trbutDataListReDTOZJS.addAll(trbutDataListReDTOZJs);
                        }
                    });
                }
            }

            List<TrbutDataListReDTOZJ> trbutDataListReDTOZJS1 = trbutDataListReDTOZJS.stream().sorted(Comparator.comparing(TrbutDataListReDTOZJ::getReceiveStartTime)).collect(Collectors.toList());
            trbutDataListReDTO.setTrbutDataListReDTOZJS(trbutDataListReDTOZJS1);

            //  地面站可见 基于数传接收开始时间排序
            List<TrbutDataListReDTODMZ> trbutDataList = trbutDatas.stream().sorted(Comparator.comparing(TrbutDataListReDTODMZ::getReceiveStartTime)).collect(Collectors.toList());
            trbutDataListReDTO.setTrbutDataListReDTODMZS(trbutDataList);
            return trbutDataListReDTO;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据卫星分组条带
     *
     * @param stripIds 条带数组
     */
    public Map<String, List<StripRpcDTO>> gruopStripBySatelliteCode(List<String> stripIds) {
        List<StripRpcDTO> stripRpcDTOS = new ArrayList<>();
        if (Objects.isNull(stripIds)) {
            stripRpcDTOS = stripRpcService.getStripInfo(new ArrayList<>());
        } else {
            stripRpcDTOS = stripRpcService.getStripInfo(stripIds);
        }
        if (!CollectionUtils.isEmpty(stripRpcDTOS)) {
            //  根据卫星目标分组
            Map<String, List<StripRpcDTO>> stripBySatelliteCode = stripRpcDTOS.stream().collect(Collectors.groupingBy(stripReqDTO ->
                    stripReqDTO.getSatelliteCode() + "-" + stripReqDTO.getTargetName()));
            return stripBySatelliteCode;
        }
        return null;
    }


    /**
     * 通过任务id查询关联卫星信息
     */
    public List<PayloadRpcDTO> selSatelliteCodesByReqId(String reqId) {
        List<PayloadRpcDTO> payloadRpcDTOS = new ArrayList<>();
        FzTaskInfoRpcReqDTO fzTaskInfoRpcReqDTO = new FzTaskInfoRpcReqDTO();
        fzTaskInfoRpcReqDTO.setReqIds(Lists.newArrayList(reqId));
        List<FzTaskRpcDTO> fzTaskDTOList = fzTaskRpcService.getFzTaskDTOList(fzTaskInfoRpcReqDTO);
        Optional<FzTaskRpcDTO> fzTaskRpcDTO = fzTaskDTOList.stream().findFirst();
        if (fzTaskRpcDTO.isPresent()) {
            FzTaskRpcDTO fzTaskRpc = fzTaskRpcDTO.get();
            List<String> payloadIdList = fzTaskRpc.getPayloadIdList();
            if (!payloadIdList.isEmpty()) {
                PayloadRpcReqDTO payloadRpcReqDTO = new PayloadRpcReqDTO();
                payloadRpcReqDTO.setPayloadIds(payloadIdList);
                payloadRpcDTOS = payloadRpcService.getPayloadRpcDTOList(payloadRpcReqDTO);
            }
        }
        return payloadRpcDTOS;
    }

    /**
     * 计算每个地面站链路余量值 大于5dB 说明可用 小于5dB 说明不可用
     *
     * @return
     */
    public Integer linkCount(AntennaRpcDTO antennaRpcDTO, SatelliteRpcDTO satelliteRpcDTO) {
        Integer state = 0;
        QueryLinkCountDTO queryLinkCountDTO = new QueryLinkCountDTO();
        queryLinkCountDTO.setAntenna(antennaRpcDTO.getTxkj());
        queryLinkCountDTO.setSatelliteCode(satelliteRpcDTO.getSatelliteCode());

        String stationCode = antennaRpcDTO.getDmzdh();
        List<StationRpcDTO> stationListByStationIdList = stationRpcService.getAllList();
        List<StationRpcDTO> stationAddRpcDTOS = stationListByStationIdList.stream().filter(e -> e.getStationCode().equals(stationCode)).collect(Collectors.toList());
        Optional<StationRpcDTO> stationRpcDTO = stationAddRpcDTOS.stream().findFirst();
        if (stationRpcDTO.isPresent()) {
            queryLinkCountDTO.setStationId(stationRpcDTO.get().getId());
            queryLinkCountDTO.setCarrier(satelliteRpcDTO.getCarrier());
            queryLinkCountDTO.setElevation(Double.valueOf(antennaRpcDTO.getZxjsyj()));
            Double linkCount = linkCountRpcService.linkCount(queryLinkCountDTO);
            state = linkCount > 5.0 ? 0 : 1;
        }
        return state;
    }

    /**
     * 清理信息
     *
     * @param stationIdList
     * @param startTime
     * @param endTime
     */
    public void deleteList(List<String> satelliteCodes, List<String> stationIdList, int stationType, String startTime, String endTime) {
        QueryWrapper<TrbutData> queryWrapper = new QueryWrapper<>();
        if (!CollectionUtils.isEmpty(satelliteCodes))
            queryWrapper.in("satellite_code", satelliteCodes);
        if (!CollectionUtils.isEmpty(stationIdList))
            queryWrapper.in("station_id", stationIdList);
        queryWrapper.eq("station_type", stationType);
        queryWrapper.ge("pit_time", DateUtils.string2LocalDateTime(startTime, DateUtils.YYYY_MM_DD_HH_MM_SS));
        queryWrapper.le("exit_time", DateUtils.string2LocalDateTime(endTime, DateUtils.YYYY_MM_DD_HH_MM_SS));
        this.remove(queryWrapper);
    }


    public void relayTrbutCountAndBatch(TrbutRequestDTO trbutRequestDTO) {

        //查询中继位置
        List<QueryStationAddRpcDTO> yxInfoBasisStationRpcDTOS = stationRpcService.getStationListByStationIdList(trbutRequestDTO.getStationIds());
        if (CollectionUtils.isEmpty(yxInfoBasisStationRpcDTOS)) return;
        List<SatelliteRpcDTO> satelliteRpcDTOS = satelliteRpcService.listByIds(trbutRequestDTO.getSatelliteCodes());
        if (CollectionUtils.isEmpty(satelliteRpcDTOS)) return;
        //查询瞬根
        List<InstanceRpcDTO> instances = instanceRpcService.getListBySatelliteCode(trbutRequestDTO.getSatelliteCodes());
        if (CollectionUtils.isEmpty(instances)) return;

        //查询星历数据
        for (SatelliteRpcDTO satelliteRpcDTO : satelliteRpcDTOS) {

            QueryEphListDTO queryEphListDTO = new QueryEphListDTO();
            queryEphListDTO.setStartTime(trbutRequestDTO.getStartTime());
            queryEphListDTO.setEndTime(trbutRequestDTO.getEndTime());
            queryEphListDTO.setCode(StringUtil.change(satelliteRpcDTO.getSatelliteCode()));

            List<EphDataDTO> calEphRpcDTOS = ephService.getList(queryEphListDTO);
            if (calEphRpcDTOS.isEmpty()) {
                log.warn("sel " + queryEphListDTO.getCode() + " eph data is empty!");
                continue;
            }
            //如一个星存在多个顺根，选取离输入开始时间最近的顺根


            //获取单颗星的星历数组
            double[][] pos = formatPosArr(calEphRpcDTOS);
            Optional<InstanceRpcDTO> yxInfoBasisInstanceRpcDTO = instances.stream().findFirst();
            if (!yxInfoBasisInstanceRpcDTO.isPresent()) {
                continue;
            }
            InstanceRpcDTO yxInfoBasisInstance = yxInfoBasisInstanceRpcDTO.get();
            //获取单颗星的轨道6根数
            double[] countYxInfoBasisInstance = formatEphArr(yxInfoBasisInstance);
            for (QueryStationAddRpcDTO yxInfoBasisStationRpcDTO : yxInfoBasisStationRpcDTOS) {
                Date startTime = calEphRpcDTOS.get(0).getEphTime();
                int dt = (int) (startTime.getTime() / 1000 - yxInfoBasisInstance.getEpochTime().getTime() / 1000);
                if (dt < 0) {
                    continue;
                }
                executeRelayCountAndSave(satelliteRpcDTO, satelliteRpcDTO.getId(), yxInfoBasisStationRpcDTO, countYxInfoBasisInstance, pos, dt, startTime, 65);
            }
        }
    }


    private double[] formatEphArr(InstanceRpcDTO yxInfoBasisInstanceRpcDTO) {
        return new double[]{Double.parseDouble(yxInfoBasisInstanceRpcDTO.getSemiMajorAxis()),
                Double.parseDouble(yxInfoBasisInstanceRpcDTO.getEccentricity()), Double.parseDouble(yxInfoBasisInstanceRpcDTO.getInclination()),
                Double.parseDouble(yxInfoBasisInstanceRpcDTO.getRaan()), Double.parseDouble(yxInfoBasisInstanceRpcDTO.getArgumentOfPerigee()), Double.parseDouble(yxInfoBasisInstanceRpcDTO.getMeanAnoMaly())
        };
    }

    private double[][] formatPosArr(List<EphDataDTO> calEphRpcDTOS) {
        double[][] posArr = new double[calEphRpcDTOS.size()][3];
        for (int i = 0; i < calEphRpcDTOS.size(); i++) {
            posArr[i][0] = calEphRpcDTOS.get(i).getX().doubleValue();
            posArr[i][1] = calEphRpcDTOS.get(i).getY().doubleValue();
            posArr[i][2] = calEphRpcDTOS.get(i).getZ().doubleValue();
        }
        return posArr;
    }

    /**
     * @param satelliteId              WX编号
     * @param yxInfoBasisStationRpcDTO 中继星的位置
     * @param ehp                      轨道6根数
     * @param pos                      星历数组
     * @param dt                       星历eph时间-轨道6根数历元时刻
     * @param utc                      星历eph时间
     * @param min_el
     */
    public void executeRelayCountAndSave(SatelliteRpcDTO satelliteRpcDTO, String satelliteId, QueryStationAddRpcDTO yxInfoBasisStationRpcDTO, final double[] ehp, final double[][] pos, final double dt, final Date utc, final double min_el) {
        SeeTdrss seeTdrss = seeTDRSS(Double.parseDouble(yxInfoBasisStationRpcDTO.getLongitude()), ehp, pos, dt, utc, 65);
        formatTrbutDataList(satelliteRpcDTO, seeTdrss, satelliteId, yxInfoBasisStationRpcDTO, utc);
    }

    /**
     * 根据计算结果获取进出站数据
     *
     * @param seeTdrss 计算结果
     */
    private void formatTrbutDataList(SatelliteRpcDTO satelliteRpcDTO, SeeTdrss seeTdrss, String satelliteId, QueryStationAddRpcDTO yxInfoBasisStationRpcDTO, Date startTime) {
        int[] arr = seeTdrss.get_1flag();
        if (arr == null || arr.length == 0) {
            return;
        }
        List<List<Integer>> lists = new ArrayList<>();
        //业务里面不会出现只有一秒的情况
        int value = arr[0];
        List<Integer> list = new ArrayList<>();
        list.add(value);
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] != value && !CollectionUtils.isEmpty(list)) {
                value = arr[i];
                List<Integer> listAdd = new ArrayList<>(list);
                lists.add(listAdd);
                list.clear();
            } else {
                list.add(arr[i]);
            }
        }
        int markTime = 0;
        for (List<Integer> list1 : lists) {
            Integer first = list1.get(0);
            if (first.equals(1)) {
                Date receiveStartTime = new Date(startTime.getTime() + markTime * 1000L);
                Date receiveEndTime = new Date(receiveStartTime.getTime() + list1.size() * 1000L);
                TrbutData trbutData = new TrbutData();
                trbutData.setId(IdGenerator.getStrId());
                trbutData.setSatelliteId(satelliteId);
                trbutData.setSatelliteCode(satelliteRpcDTO.getSatelliteCode());
                trbutData.setSatelliteName(satelliteRpcDTO.getSatelliteName());
                trbutData.setReceiveStartTime(receiveStartTime);
                trbutData.setReceiveEndTime(receiveEndTime);
                trbutData.setPitTime(receiveStartTime);
                trbutData.setExitTime(receiveEndTime);
                trbutData.setStationType(1);
                trbutData.setStationId(yxInfoBasisStationRpcDTO.getId());
                trbutData.setStationCode(yxInfoBasisStationRpcDTO.getStationCode());
                trbutData.setStationName(yxInfoBasisStationRpcDTO.getStationName());
                trbutData.setCreate_time(new Date());
                long diff = receiveEndTime.getTime() - receiveStartTime.getTime();
                trbutData.setDuration((int) diff);
                trbutData.setTrbutStatus(2);
                delAndSave(trbutData, satelliteId, yxInfoBasisStationRpcDTO.getId(), receiveStartTime, receiveEndTime);
            }
            markTime += list1.size();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void delAndSave(TrbutData trbutData, String satelliteId, String stationId, Date startTime, Date endTime) {
        trbutDataMapper.insert(trbutData);
    }


    /**
     * @param lon    ZJ经度
     * @param ehp    瞬根数据
     * @param pos    xyz数据
     * @param dt     计算总时长
     * @param utc    开始计算时间
     * @param min_el 默认为65，11.5
     * @return SeeTdrss
     */
    public SeeTdrss seeTDRSS(double lon, final double[] ehp, final double[][] pos, final double dt, final Date utc, final double min_el) {
        SeeTdrss ret = new SeeTdrss();
        double sat_a = ehp[0];
        double sat_ecc = ehp[1];
        double sat_inc = ehp[2];
        double sat_omega = ehp[3];
        double sat_w = ehp[4];
        double sat_M0 = ehp[5];
        double pi = Math.PI;
        double sat_T = 2 * pi * Math.sqrt(Math.pow(sat_a, 3) / GM);
        double sat_n = 360 / sat_T;

        double[][] H3 = {{1, 0, 0},
                {0, Math.cos(pi), Math.sin(pi)},
                {0, -Math.sin(pi), Math.cos(pi)}};
        Matrix mH3 = new Matrix(H3);

        int[] flagArr = new int[pos.length];
        double[] EiArr = new double[pos.length];
        double[] AziArr = new double[pos.length];
        double[] DisArr = new double[pos.length];

        Matrix tpos = new Matrix(pos);
        for (int j = 0; j < pos.length; j++) {
            Calendar cal1 = Calendar.getInstance();
            cal1.setTime(new Date(utc.getTime() + (j * 1000L)));
            int year = cal1.get(Calendar.YEAR);
            int month = cal1.get(Calendar.MONTH) + 1;
            int day = cal1.get(Calendar.DATE);
            int hour = cal1.get(Calendar.HOUR);
            int minute = cal1.get(Calendar.MINUTE);
            int second = cal1.get(Calendar.SECOND);

            Inr2Fix inr2Fix = Inr2Fix(year, month, day, hour, minute, second);
            Matrix ih = new Matrix(inr2Fix.getH()).inverse();

            double sat_M = sat_n * (dt + j) + sat_M0;
            double[][] orbit = {{sat_a, sat_ecc, sat_inc, sat_omega, sat_w, sat_M}};
            Matrix morbit = new Matrix(orbit);
            Orbit2Pv orbit2pv = ORBIT2PV(morbit);
            double sat_u = orbit2pv.get_3u();
            Matrix H2 = Ine2Orb(sat_omega, sat_inc, sat_u);

            Matrix matrix = mH3.times(H2.times(ih.times(BLH2XYZ(0, lon, geo_h).transpose().minus(tpos.getMatrix(j, j, 0, 2).transpose()))));
            double[][] aleo2TL_boby = matrix.getArray();
            double Ei = Math.asin(aleo2TL_boby[2][0] / matrix.norm2());
            double Azi = Math.atan2(aleo2TL_boby[0][0], aleo2TL_boby[1][0]);
            double Dis = matrix.norm2();
            Ei = Ei * 180 / pi;
            Azi = Azi * 180 / pi;
            int flag = 0;
            if (Ei >= 90 - min_el) {
                flag = 1;
            }
            flagArr[j] = flag;
            EiArr[j] = Ei;
            AziArr[j] = Azi;
            DisArr[j] = Dis;
        }
        ret.set_1flag(flagArr);
        ret.set_2Ei(EiArr);
        ret.set_3Azi(AziArr);
        ret.set_4Dis(DisArr);
        return ret;
    }

    public Matrix BLH2XYZ(double lat, double lon, double hig) {
        double pi = Math.PI;
        lon = lon * pi / 180;
        lat = lat * pi / 180;

        double E2 = 0.00669437999013;

        double N = Re / Math.sqrt(1 - E2 * Math.sin(lat) * Math.sin(lat));

        double X = (N + hig) * Math.cos(lat) * Math.cos(lon);
        double Y = (N + hig) * Math.cos(lat) * Math.sin(lon);
        double Z = (N * (1 - E2) + hig) * Math.sin(lat);

        double[][] ret = {{X, Y, Z}};
        return new Matrix(ret);
    }

    private double customMatlabFix(double sourceNumber) {
        if (sourceNumber >= 0.0) {
            return Math.floor(sourceNumber);
        } else {
            return Math.ceil(sourceNumber);
        }
    }

    public Inr2Fix Inr2Fix(int year, int month, int day, int hour, int minute, int second) {
        Inr2Fix ret = new Inr2Fix();
        double pi = Math.PI;

        double D = day + hour / 24.0 + minute / ((24 * 60) * 1.0) + second / ((24 * 60 * 60) * 1.0);

        double JD = D - 32075 + customMatlabFix(1461 * (year + 4800 + customMatlabFix((month - 14) / 12.0)) / 4.0) +
                customMatlabFix(367 * (month - 2 - customMatlabFix((month - 14) / 12.0) * 12.0) / 12.0) -
                customMatlabFix(3 * customMatlabFix((year + 4900 + customMatlabFix((month - 14) / 12.0)) / 100.0) / 4.0) - 0.5;

        double t = (JD - 2451545.0) / 36525;

        double GMST = 280.46061837 + 360.98564736629 * (JD - 2451545.0) + 0.000387933 * Math.pow(t, 2) - Math.pow(t, 3) / 38710000.0;

        GMST = GMST - customMatlabFix(GMST / 360) * 360;

        double theta = GMST * pi / 180;

        double[][] H = {{Math.cos(theta), Math.sin(theta), 0},
                {-Math.sin(theta), Math.cos(theta), 0},
                {0, 0, 1}};

        ret.setGMST(GMST);
        ret.setH(H);

        return ret;
    }

    public Orbit2Pv ORBIT2PV(Matrix orbit) {
        Orbit2Pv retItem = new Orbit2Pv();
        double[][] array = orbit.getArray();
        if (array.length != 1 || array[0].length != 6) {
            System.out.println("Wrong number of input arguments");
            return null;
        }

        double pi = Math.PI;
        double a = array[0][0];
        double e = array[0][1];
        double i = array[0][2] * pi / 180;
        double omega = array[0][3] * pi / 180;
        double w = array[0][4] * pi / 180;
        double M = array[0][5] * pi / 180;

        double E = M;
        double es = 1e-6;
        int k = 0;

        double T;
        while (true) {
            T = E;
            E = M + e * Math.sin(E);
            if (Math.abs(E - T) < es) {
                break;
            }
            k = k + 1;
            if (k > 100) {
                System.out.println("kepler equation can not be solved");
                break;
            }
        }

        double f = 2 * Math.atan(Math.sqrt((1 + e) / (1 - e)) * Math.tan(E / 2));
        double u = f + w;

        double mu = 398600.5;
        double p = a * (1 - Math.pow(e, 2));
        double rp = p / (1 + e * Math.cos(f));
        double r_orbitx = rp * Math.cos(f);
        double r_orbity = rp * Math.sin(f);
        double[][] r_orbit = {{r_orbitx, r_orbity, 0}, {0, 0, 0}, {0, 0, 0}};

        double v_orbitx = -Math.sqrt(mu / p) * Math.sin(f);
        double v_orbity = Math.sqrt(mu / p) * (e + Math.cos(f));
        double[][] v_orbit = {{v_orbitx, v_orbity, 0}, {0, 0, 0}, {0, 0, 0}};

        double R11 = Math.cos(omega) * Math.cos(w) - Math.sin(omega) + Math.sin(w) * Math.cos(i);
        double R12 = -Math.cos(omega) * Math.sin(w) - Math.sin(omega) * Math.cos(w) * Math.cos(i);
        double R13 = Math.sin(omega) * Math.sin(i);
        double R21 = Math.sin(omega) * Math.cos(w) + Math.cos(omega) * Math.sin(w) + Math.cos(i);
        double R22 = -Math.sin(omega) * Math.sin(w) + Math.cos(omega) + Math.cos(w) + Math.cos(i);
        double R23 = -Math.cos(omega) * Math.sin(i);
        double R31 = Math.sin(w) * Math.sin(i);
        double R32 = Math.cos(w) * Math.sin(i);
        double R33 = Math.cos(i);

        double[][] R = {{R11, R12, R13},
                {R21, R22, R23},
                {R31, R32, R33}};

        Matrix m_R = new Matrix(R);
        Matrix m_r_orbit = new Matrix(r_orbit);
        Matrix m_v_orbit = new Matrix(v_orbit);

        Matrix m_r = m_R.times(m_r_orbit);
        double[][] r = m_r.getArray();

        Matrix m_v = m_R.plus(m_v_orbit);
        double[][] v = m_v.getArray();

        u = u * 180 / pi;

        retItem.set_1r(r);
        retItem.set_2v(v);
        retItem.set_3u(u);
        retItem.set_4rp(rp);

        return retItem;
    }

    public Matrix Ine2Orb(double sat_omega, double sat_inc, double sat_u) {
        double pi = Math.PI;

        sat_omega = sat_omega * pi / 180;
        sat_inc = sat_inc * pi / 180;
        sat_u = sat_u * pi / 180;

        double[][] H1 = {{Math.cos(sat_omega), Math.sin(sat_omega), 0},
                {-Math.sin(sat_omega), Math.cos(sat_omega), 0},
                {0, 0, 1}};

        double[][] H2 = {{1, 0, 0},
                {0, Math.cos(sat_inc), Math.sin(sat_inc)},
                {0, -Math.sin(sat_inc), Math.cos(sat_inc)}};

        double[][] H3 = {{Math.cos(sat_u), Math.sin(sat_u), 0},
                {-Math.sin(sat_u), Math.cos(sat_u), 0},
                {0, 0, 1}};

        double[][] H4 = {{Math.cos(pi / 2), Math.sin(pi / 2), 0},
                {-Math.sin(pi / 2), Math.cos(pi / 2), 0},
                {0, 0, 1}};
        double[][] H5 = {{1, 0, 0},
                {0, Math.cos(-pi / 2), Math.sin(-pi / 2)},
                {0, -Math.sin(-pi / 2), Math.cos(-pi / 2)}};
        Matrix mH1 = new Matrix(H1);
        Matrix mH2 = new Matrix(H2);
        Matrix mH3 = new Matrix(H3);
        Matrix mH4 = new Matrix(H4);
        Matrix mH5 = new Matrix(H5);

        return mH5.times(mH4).times(mH3).times(mH2).times(mH1);
    }

    public List<TrbutDataDTO> getTrbutDataList(Date observationStartTime, Date observationEndTime) {
        if (observationStartTime != null && observationEndTime != null) {
            QueryWrapper<TrbutData> queryWrapper = new QueryWrapper<>();
            queryWrapper.ge("receive_end_time", observationStartTime);
            queryWrapper.le("receive_end_time", observationEndTime);
            List<TrbutData> list = this.list(queryWrapper);

            List<TrbutDataDTO> res = new ArrayList<>();
            for (TrbutData trbutData1 : list) {
                TrbutDataDTO trbutDataDTO = new TrbutDataDTO();
                BeanUtils.copyProperties(trbutData1, trbutDataDTO);
                res.add(trbutDataDTO);
            }
            return res;
        }
        return new ArrayList<>();
    }

    /**
     * 根据卫星编号查询进出站
     *
     * @param satelliteCode
     * @return
     */
    public List<TrbutDataRpcDTO> selTrButDataByCode(String satelliteCode) {
        QueryWrapper<TrbutData> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("satellite_code", satelliteCode);
        List<TrbutData> trbutDatas = this.list(queryWrapper);
        if (org.springframework.util.CollectionUtils.isEmpty(trbutDatas)) {
            return new ArrayList<>();
        }
        return BizUtils.copyEntityToDto(TrbutDataRpcDTO.class, trbutDatas);
    }

    /**
     * 更改约束冲突策略  saveOrUpdate方法中 默认主键冲突后，触发更新操作
     * 将同一圈的进出站方位角和星地编号设为唯一约束
     */
    public boolean saveOrUpdateByPitTimeAndSatelliteIdAndStationIdAndExitTime(List<TrbutData> trbutDatas) {
        return SqlHelper.saveOrUpdateBatch(entityClass, this.mapperClass, super.log, trbutDatas, DEFAULT_BATCH_SIZE, (sqlSession, trbutData) -> {  // 查询唯一约束对应的记录是否存在
            LambdaQueryWrapper<TrbutData> queryWrapper = Wrappers.<TrbutData>lambdaQuery()
                    .eq(TrbutData::getOrbitNum, trbutData.getOrbitNum())
                    .eq(TrbutData::getSatelliteCode, trbutData.getSatelliteCode())
                    .eq(TrbutData::getStationId, trbutData.getStationId())
                    .eq(TrbutData::getStartAzimuth, trbutData.getStartAzimuth())
                    .eq(TrbutData::getEndAzimuth, trbutData.getEndAzimuth());

            HashMap<Object, Object> map = CollectionUtils.newHashMapWithExpectedSize(1);
            map.put(Constants.WRAPPER, queryWrapper);

            return CollectionUtils.isEmpty(sqlSession.selectList(getSqlStatement(SqlMethod.SELECT_LIST), map));
        }, (sqlSession, trbutData) -> {
            LambdaQueryWrapper<TrbutData> lambdaUpdateWrapper = new LambdaQueryWrapper<>();
            lambdaUpdateWrapper.eq(TrbutData::getOrbitNum, trbutData.getOrbitNum())
                    .eq(TrbutData::getSatelliteCode, trbutData.getSatelliteCode())
                    .eq(TrbutData::getStationId, trbutData.getStationId())
                    .eq(TrbutData::getStartAzimuth, trbutData.getStartAzimuth())
                    .eq(TrbutData::getEndAzimuth, trbutData.getEndAzimuth());
            HashMap<Object, Object> param = CollectionUtils.newHashMapWithExpectedSize(2);
            trbutData.setCreate_time(new Date());
            param.put(Constants.ENTITY, trbutData);
            param.put(Constants.WRAPPER, lambdaUpdateWrapper);
            sqlSession.update(getSqlStatement(SqlMethod.UPDATE), param);
        });
    }
}