package com.base.plan.service;

import com.base.api.model.PointRpcDTO;
import com.base.core.model.enity.ArcCoreDTO;
import com.base.core.model.enity.GridInfoCoreDTO;
import com.base.core.model.enity.ReportPoint;
import com.base.plan.assembler.RegionAssembler;
import com.base.plan.mapper.GridInfoMapper;
import com.base.plan.model.dto.ReportPointDTO;
import com.base.plan.model.entity.GridInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

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

@Service
@Slf4j
public class ArcService {

    @Resource
    GridInfoMapper gridDao;

    /**
     * 根据经纬度集合生成弧段信息（ARC是区域内横向维度的网格集合）
     * @param pointDTOList 点集合（需要明确serial为0的点）
     * @return 弧段信息
     */
    public List<ArcCoreDTO> getPointListArcList(List<PointRpcDTO> pointDTOList){
        List<ArcCoreDTO> arcList = null;
        try{
            ReportPoint reportPointDTO = getReportPointDTO(pointDTOList);
            if (reportPointDTO!=null){
                arcList = getGridCode(reportPointDTO);
            }
        }catch (Exception e){
            log.error(e.getMessage(),e);
        }
        return arcList;
    }


    public ReportPoint getReportPointDTO(List<PointRpcDTO> pointDTOList) {

        float lonW = 1000;
        float lonE = -1000;
        float latN = -1000;
        float latS = 1000;
        //定义：第0个是最左边的点
        float lon0 = 0;
        for (PointRpcDTO pointDTO : pointDTOList) {
            int sequenceId = Integer.parseInt(pointDTO.getSerial());
            if (sequenceId == 0) {
                lon0 = Float.parseFloat(pointDTO.getLongitude());
            }
        }

        for (PointRpcDTO pointDTO : pointDTOList) {
            float lon = Float.parseFloat(pointDTO.getLongitude());
            float lat = Float.parseFloat(pointDTO.getLatitude());
            //为了处理逆子午线的特殊情况，选把负的经度值转为正值计算，之后再转回--zhanghy20170420
            if ((lon < lon0) && (lon < 0)) {//20180703 增加<0判断
                lon = 360 + lon;
            }

            if (lon < lonW) {
                lonW = lon;
            }
            if (lon > lonE) {
                lonE = lon;
            }
            if (lat > latN) {
                latN = lat;
            }
            if (lat < latS) {
                latS = lat;
            }

        }
        //把转换过的经度值转回来
        if (lonW > 180) {
            lonW = lonW - 360;
        }
        if (lonE > 180) {
            lonE = lonE - 360;
        }

        if (Math.abs(latN) > 90 || Math.abs(latS) > 90 || Math.abs(lonW) > 180 || Math.abs(lonE) > 180) {
            return null;
        }

        return new ReportPoint(lonW, lonE, latN, latS);
    }


    public List<ArcCoreDTO> getGridCode(ReportPoint rp) throws Exception {


        int lat_s = getLatCode(rp.getS_node_lat());
        int lat_n = getLatCode(rp.getN_node_lat());
        double lon_w = rp.getW_node_lon();
        double lon_e = rp.getE_node_lon();
        int LatSign;
        ArrayList<ArcCoreDTO> temp = new ArrayList<ArcCoreDTO>();
        ArrayList<ArcCoreDTO> temp1 = new ArrayList<ArcCoreDTO>();
        for (; lat_s <= lat_n; lat_s++) {

            String grid_lat = new String();
            if (lat_s < 0) {
                LatSign = 1;
                grid_lat = String.valueOf(LatSign) + String.format("%04d", -lat_s);
            } else {
                LatSign = 0;
                grid_lat = String.valueOf(LatSign) + String.format("%04d", lat_s);
            }

            if ((-180 * 12 <= lon_w && lon_w <= 180 * 12) && (-180 * 12 <= lon_e && lon_e <= 180 * 12)
                    && (-90 * 12 <= lat_s && lat_s <= 90 * 12)) {
                List<GridInfo> gridcode1 = new ArrayList<GridInfo>();
                List<GridInfo> gridcode2 = new ArrayList<GridInfo>();
                // List<Map<Object,Object>> gridcode1 = new
                // ArrayList<Map<Object,Object>>();
                if (lon_w * 60 < -10799) {
                    double neglon = -lon_w;
                    gridcode1 = gridDao.findByCodeLatLon2(grid_lat, neglon, lon_w);
                } else {
                    gridcode1 = gridDao.findByCodeLatLon(grid_lat, lon_w, lon_w);
                }
                if (gridcode1 == null || gridcode1.isEmpty()) {
                    throw new Exception("calculate gridcode error!");
                }
                if (lon_e * 60 < -10799) {
                    double neglon = -lon_e;
                    gridcode2 = gridDao.findByCodeLatLon2(grid_lat, neglon, lon_e);

                } else {
                    gridcode2 = gridDao.findByCodeLatLon(grid_lat, lon_e, lon_e);
                }
                // System.out.println(sql);
                if (gridcode2 == null || gridcode2.isEmpty()) {
                    throw new Exception("calculate gridcode error!");
                }

                if(lon_w>0&&lon_e<0){//处理西经180度与东经180度重合，因此此处包含的网格左边经度为正值，右边经度为负值的情况
                    List<GridInfo> gridcode11 = new ArrayList<GridInfo>();
                    List<GridInfo> gridcode22 = new ArrayList<GridInfo>();
                    gridcode11 = gridDao.findByCodeLatLon(grid_lat, 180, 180);//正经终点
                    gridcode22 = gridDao.findByCodeLatLon(grid_lat, -179.9, -180);//负经终点
                    String code_lon_w1 = gridcode11.get(0).getCodeLon();
                    String code_lon_e1 = gridcode22.get(0).getCodeLon();
                    String code_lon_w = gridcode1.get(0).getCodeLon();
                    String code_lon_e = gridcode2.get(0).getCodeLon();
                    ArcCoreDTO ss = getArc(grid_lat, code_lon_w, code_lon_w1);
                    ArcCoreDTO s2 = getArc(grid_lat, code_lon_e1, code_lon_e);
//					if((ss.getGridlist()!=null) && (s2.getGridlist()!=null)){
//						for(int i=0;i<s2.getGridlist().size();i++){
//							ss.getGridlist().add(s2.getGridlist().get(i));
//						}
//					}
                    temp.add(ss);
                    temp1.add(s2);


                }else{
                    String code_lon_w = gridcode1.get(0).getCodeLon();
                    String code_lon_e = gridcode2.get(0).getCodeLon();
                    ArcCoreDTO ss = getArc(grid_lat, code_lon_w, code_lon_e);

                    temp.add(ss);
                }

                // System.out.println(code_lon_e);


            } else {
                // logger.error("gridservice calculate error:function
                // getGridCode");

                throw new Exception("calculate gridcode2 error!");
            }

        }
        if (temp == null || temp.isEmpty()) {
            throw new Exception("no available arc gridcode");
        } else {
            for (int i = 0; i < temp.size(); i++) {
                List<GridInfo> gridcode3 = new ArrayList<GridInfo>();
                String latcode = temp.get(i).getGridlist().get(0).getId().substring(0, 5);
                double start_num = temp.get(i).getGridlist().get(0).getLatNum();
                int N = temp.get(i).getGridlist().size() - 1;
                double end_num = temp.get(i).getGridlist().get(N).getLatNum();

                gridcode3 = gridDao.findByLatNum(latcode, start_num, end_num);
                List<GridInfoCoreDTO> gridInfoCoreDTOS= RegionAssembler.INSTANTS.gridInfoCoreDTOListAssembler(gridcode3);
                temp.get(i).setGridlist(gridInfoCoreDTOS);
            }
            for (int i = 0; i < temp1.size(); i++) {
                List<GridInfo> gridcode3 = new ArrayList<GridInfo>();
                String latcode = temp1.get(i).getGridlist().get(0).getId().substring(0, 5);
                double start_num = temp1.get(i).getGridlist().get(0).getLatNum();
                int N = temp1.get(i).getGridlist().size() - 1;
                double end_num = temp1.get(i).getGridlist().get(N).getLatNum();

                gridcode3 = gridDao.findByLatNum(latcode, start_num, end_num);
                List<GridInfoCoreDTO> gridInfoCoreDTOS= RegionAssembler.INSTANTS.gridInfoCoreDTOListAssembler(gridcode3);
                temp1.get(i).setGridlist(gridInfoCoreDTOS);
            }
            temp.addAll(temp1);
            return temp;
        }

    }


    /**
     * 根据经纬度计算弧段
     */
    private ArcCoreDTO getArc(String lat,String lon_w,String lon_e){
        ArcCoreDTO arc = new ArcCoreDTO();
        int lon_w_integ = Integer.valueOf(lon_w);
        int lon_e_integ = Integer.valueOf(lon_e);
        if(lon_w_integ > 10000){
            lon_w_integ = 10000 - lon_w_integ;
        }

        if(lon_e_integ > 10000){
            lon_e_integ = 10000 - lon_e_integ;
        }
        String lonsign;
        int s;
        //gaoyue edit 20190813
        if (lon_w_integ<0 && lon_e_integ<0 && lon_w_integ>lon_e_integ)
        {
            int templon;
            templon = lon_w_integ;
            lon_w_integ = lon_e_integ;
            lon_e_integ = templon;
        }//gaoyue edit end

        for(;lon_w_integ <= lon_e_integ;lon_w_integ++){
            if(lon_w_integ < 0){
                lonsign = "1";
                s = - lon_w_integ;
            }
            else{
                lonsign = "0";
                s = lon_w_integ;
            }
            String tempcode = lat + lonsign + String.format("%04d", s);
            //System.out.println(tempcode);
            GridInfoCoreDTO grid = new GridInfoCoreDTO();
            grid.setId(tempcode);
            grid.setLatNum(lon_w_integ);
            //System.out.println(tempcode);
            arc.addGridlist(grid);
        }
        return arc;
    }


    /**
     * 获得网格编码
     **/

    private int getLatCode(double lat) throws Exception {
        int LatCode;
        if (lat == 90) {
            LatCode = ((int) (lat * 12) - 1);
        } else if (lat < 90 && lat >= 0) {
            LatCode = (int) (lat * 12);
        } else if (lat < 0 && lat != -90) {
            LatCode = ((int) (lat * 12) - 1);
        } else if (lat == -90) {
            LatCode = (int) (lat * 12);
        } else {
            throw new Exception("lat is out of range!");
        }
        return LatCode;
    }
}