package com.bohuikeji.frame.module.admin.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bohuikeji.frame.module.admin.component.RedisUtil;
import com.bohuikeji.frame.module.admin.component.StaticComponent;
import com.bohuikeji.frame.module.admin.entity.vo.AddressVo;
import com.bohuikeji.frame.module.admin.exception.WebVerifiedException;
import jodd.http.HttpRequest;
import jodd.http.HttpResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.junit.Test;

import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 高德和百度地图接口
 * @author 10552
 */
@Slf4j
public final class MapUtils {

    /**
     * 注入REDIS
     */
    private static final RedisUtil redisUtil= SpringUtil.getBean(RedisUtil.class);


    /**
     * 地图类型
     */
     enum Type{
        //百度
        BAIDU,
        //高德
        GAODE,
    }

    /**
     * 地理编码
     * @return
     */
    public static AddressVo getAddressGeo(String addressStr) {
        AddressVo addressVo=redisUtil.get("sys:cache:address:str:"+addressStr,AddressVo.class);
        if (addressVo!=null){
            return addressVo;
        }
        JSONObject result=AmapApi.geo(addressStr);
        if (result!=null){
            addressVo=getAddressByGeo(addressStr,result,Type.GAODE);
            redisUtil.set("sys:cache:address:str:"+addressStr,addressVo,60*30);
            return addressVo;
        }
        result=BmapApi.geo(addressStr);
        if (result!=null){
            //如高德无法解析，先利用百度解析经纬度，再使用经纬度给高德解析
            JSONObject location=result.getJSONObject("location");
            String lng=location.getString("lng");
            String lat=location.getString("lat");
            //先转换百度坐标系为高德坐标系
            addressVo=getAddressReGeo(AmapApi.convert(lng+","+lat));
            redisUtil.set("sys:cache:address:str:"+addressStr,addressVo,60*30);
            return addressVo;
        }
        throw new WebVerifiedException("不是合法的地址格式，请修改后再次提交！");
    }

    /**
     * 逆地理编码
     * @return
     */
    public static JSONObject getReGeo(String location){
        //log.info("待解析经纬度：[{}]",location);
        JSONObject result=AmapApi.regeo(location);
        if (result!=null){
            return result.getJSONObject("addressComponent");
        }
        throw new RuntimeException("无法解析经纬度，请检查输入");
    }

    /**
     * 逆地理编码
     * @return
     */
    public static AddressVo getAddressReGeo(String location){
        String[] lt=location.split(",");
        /*BigDecimal lat=new BigDecimal(lt[0]).setScale(6, RoundingMode.DOWN);
        BigDecimal lng=new BigDecimal(lt[1]).setScale(6, RoundingMode.DOWN);*/
        location= lt[0] +","+ lt[1];
        AddressVo addressVo=redisUtil.get("sys:cache:location:"+location,AddressVo.class);
        if (addressVo!=null){
            return addressVo;
        }

        //log.info("待解析经纬度：[{}]",location);
        JSONObject result=AmapApi.regeo(location);
        if (result!=null){
            //log.info("高德逆地理编码完成：[{}]",result);
            addressVo=getAddressByReGeo(result,Type.GAODE);
            String[] split=location.split(",");
            //log.info("经纬度数组下标：[{}]",split[1]);
            addressVo.setLng(split[0]);
            addressVo.setLat(split[1]);
            //缓存半小时
            redisUtil.set("sys:cache:location:"+location,addressVo,60*30);
            return addressVo;
        }
        result=BmapApi.regeo(location);
        if (result!=null){
            log.info("百度地理逆编码完成：[{}]",result);
            addressVo=getAddressByReGeo(result,Type.BAIDU);
            redisUtil.set("sys:cache:location:"+location,addressVo,60*30);
            return addressVo;
        }
        throw new RuntimeException("无法解析经纬度，请检查输入");
    }

    /**
     * 步行距离
     * @param origins 起点坐标
     * @param destination 目的地坐标
     * @return 返回驾车距离(单位:米)
     */
    public static Long getWalkDistance(String origins,String destination){
        return AmapApi.walkDistance(origins,destination).getJSONArray("paths").getJSONObject(0).getLong("distance");
    }
    /**
     * 测量距离
     * @param origins 起点坐标
     * @param destination 目的地坐标
     * @return 返回驾车距离(单位:米)
     */
    public static Long getDistance(String origins,String destination){
        return AmapApi.distance(origins,destination).getLong("distance");
    }
    /**
     * 测量距离（米）
     * @param origins 起点坐标
     * @param destination 目的地坐标
     * @return 返回驾车距离(单位:米)
     */
    public static Long getDistance(AddressVo origins,AddressVo destination){
        long disc=1;
        try{
            //驾车规划
            disc=AmapApi.driver(origins.getLng()+","+origins.getLat(),destination.getLng()+","+destination.getLat())
                    .getJSONArray("paths").getJSONObject(0).getLong("distance");
            //disc= Objects.requireNonNull(AmapApi.electricBicycle(origins.getLng() + "," + origins.getLat(), destination.getLng() + "," + destination.getLat()))
            //        .getJSONArray("paths").getJSONObject(0).getLong("distance");
            //log.error("######################骑行：{}",disc0);
            //log.error("######################驾车：{}",disc);
        }catch (Exception e){
            throw new WebVerifiedException("不是合法的地址格式，请修改后再次提交！");
        }
        return disc;
    }

    /**
     * 测量距离（米）
     * @param origins 起点坐标
     * @param destination 目的地坐标
     * @return 返回驾车距离(单位:米)
     */
   /* public static JSONObject getDistanceTest(AddressVo origins,AddressVo destination){
        long disc=1;
        JSONObject jsonObject = new JSONObject();
        try{
            //骑行规划
            long  disc0= Objects.requireNonNull(AmapApi.electricBicycle(origins.getLng() + "," + origins.getLat(), destination.getLng() + "," + destination.getLat()))
                    .getJSONArray("paths").getJSONObject(0).getLong("distance");
            //骑行规划
            long  disc1= Objects.requireNonNull(AmapApi.bicycle(origins.getLng() + "," + origins.getLat(), destination.getLng() + "," + destination.getLat()))
                    .getJSONArray("paths").getJSONObject(0).getLong("distance");
            //驾车规划
            long disc2= Objects.requireNonNull(AmapApi.driver(origins.getLng() + "," + origins.getLat(), destination.getLng() + "," + destination.getLat()))
                    .getJSONArray("paths").getJSONObject(0).getLong("distance");
            //原始计算距离
            long disc3= Objects.requireNonNull(AmapApi.distance(origins.getLng() + "," + origins.getLat(), destination.getLng() + "," + destination.getLat())).getLong("distance");
            BigDecimal diandong = new BigDecimal(disc0).setScale(1, BigDecimal.ROUND_DOWN);//直接删除多余的小数，2.3513直接被截断位2.3
            BigDecimal qixing = new BigDecimal(disc1).setScale(1, BigDecimal.ROUND_DOWN);
            BigDecimal jiache = new BigDecimal(disc2).setScale(1, BigDecimal.ROUND_DOWN);
            BigDecimal yuanshi = new BigDecimal(disc3).setScale(1, BigDecimal.ROUND_DOWN);

            jsonObject.put("电动车划",diandong.divide(new BigDecimal("1000.00"),1, BigDecimal.ROUND_DOWN));
            jsonObject.put("骑行规划",qixing.divide(new BigDecimal("1000.00"),1, BigDecimal.ROUND_DOWN));
            jsonObject.put("驾车规划",jiache.divide(new BigDecimal("1000.00"),1, BigDecimal.ROUND_DOWN));
            jsonObject.put("原始距离",yuanshi.divide(new BigDecimal("1000.00"),1, BigDecimal.ROUND_DOWN));
        }catch (Exception e){
            throw new WebVerifiedException("不是合法的地址格式，请修改后再次提交！");
        }

        return jsonObject;
    }*/


    /**
     * 测量距离（公里）
     * @param origins 起点坐标
     * @param destination 目的地坐标
     * @return 返回驾车距离(单位:千米)
     */
    public static Integer getDistanceKm(AddressVo origins,AddressVo destination){
        long disc=getDistance(origins,destination);
        int discKm=Math.round(disc/1000f);
        return Math.max(discKm, 1);
    }

    /**
     * 测量距离（公里）
     * @param origins 起点坐标
     * @param destination 目的地坐标
     * @return 返回驾车距离(单位:千米)
     */
    public static BigDecimal getDistanceKma(AddressVo origins,AddressVo destination){
        long disc=getDistance(origins,destination);
        BigDecimal diandong = new BigDecimal(disc).setScale(1, BigDecimal.ROUND_DOWN);//直接删除多余的小数，2.3513直接被截断位2.3
        BigDecimal dis = diandong.divide(new BigDecimal("1000.00"),1, BigDecimal.ROUND_DOWN);
        return dis;
    }

    /**
     * 获取该段路程的预估行车时间
     * @param origins 起点地址
     * @param destination 终点地址
     * @return
     */
    public static Long getDurationTime(AddressVo origins,AddressVo destination){
        return AmapApi.distance(origins.getLng()+","+origins.getLat(),destination.getLng()+","+destination.getLat()).getLong("duration");
    }

    /**
     * 创建地理围栏
     * @param points
     * @return
     */
    public static String createGid(String points){
        JSONObject res=AmapApi.createGid(NumberUtils.getShort(),points);
        return res.getString("gid");
    }

    /**
     * 检查Gid，失效返回新的gid
     * @param gid
     * @return
     */
    public static boolean checkGid(String gid){
        JSONObject res=AmapApi.getGid(gid);
        if(res==null){
            return false;
        }
        if(res.getIntValue("page_size")==0){
            return false;
        }
        return true;
    }

    /**
     * 检查坐标是否位于指定的围栏内
     * @return
     */
    public static boolean checkPoint(String gid,String lng,String lat){
        JSONObject res=AmapApi.checkGid(lng+","+lat);
        log.error("高德地图接口调检查坐标是否位于指定的围栏内：[{},{},{}]",gid,lng,lat);
        String retGid=res.getJSONObject("fencing_event_list").getJSONObject("fence_info").getString("fence_gid");
        String in=res.getJSONObject("fencing_event_list").getString("client_status");
        if("in".equals(in)){
            if(gid.equals(retGid)){
                return true;
            }
        }
        return false;
    }


    /**
     * 高德地图获取行政区域
     * @param keywords 行政区名称、citycode、adcode
     * @return
     */
    public static JSONArray getDist(String keywords){
        JSONObject res=AmapApi.district(keywords,1);
        if(res==null){
            return null;
        }
        return res.getJSONArray("districts");
    }

    /**
     * 高德坐标系转为百度
     * @param locations 占位置坐标集合(格式：经度,纬度)
     * @return
     */
    public static List<String[]> gdToBd(List<String> locations){
        StringJoiner joiner=new StringJoiner(";");
        locations.forEach(joiner::add);
        JSONObject res=BmapApi.convert(joiner.toString(),3,5);
        JSONArray dataArry=res.getJSONArray("data");
        List<String[]> rtList=new ArrayList<>(dataArry.size());
        for (int i = 0; i < dataArry.size(); i++) {
            JSONObject locationJs=dataArry.getJSONObject(i);
            String[] location={locationJs.getString("x"),locationJs.getString("y")};
            rtList.add(location);
        }
        return rtList;
    }

    /**
     * 高德坐标系转为百度
     * @param addressVos
     * @return
     */
    public static List<AddressVo> gdToBd(AddressVo... addressVos){
        StringJoiner joiner=new StringJoiner(";");
        for (int i = 0; i < addressVos.length; i++) {
            joiner.add(addressVos[i].getLocation());
        }
        JSONObject res=BmapApi.convert(joiner.toString(),3,5);
        JSONArray dataArry=res.getJSONArray("data");
        /*List<String[]> rtList=new ArrayList<>(dataArry.size());*/
        List<AddressVo> rts=new ArrayList<>(addressVos.length);
        for (int i = 0; i < dataArry.size(); i++) {
            JSONObject locationJs=dataArry.getJSONObject(i);
            AddressVo tmp= null;
            try {
                tmp = (AddressVo) BeanUtils.cloneBean(addressVos[i]);
            } catch (IllegalAccessException | InstantiationException | InvocationTargetException | NoSuchMethodException e) {
                e.printStackTrace();
            }
            tmp.setLng(locationJs.getString("x"));
            tmp.setLat(locationJs.getString("y"));
            rts.add(tmp);
        }
        return rts;
    }

    public static JSONObject searchPio(String key,String abcode){
        return AmapApi.pioSearch(key,abcode);
    }

    @Test
    public void test(){
        JSONObject res=searchPio("同城急送","150102");
        log.info("{}",res);
    }


    /**
     * 高德地图内部类
     * 封装高德地图接口
     * @author 10552
     */
    private static class AmapApi {
        /**
         * 高德地图——地理编码API
         */
        private static final String AMAP_URL_GEO="https://restapi.amap.com/v3/geocode/geo";
        /**
         * 高德地图——逆地理编码编码API
         */
        private static final String AMAP_URL_REGEO="https://restapi.amap.com/v3/geocode/regeo";

        /**
         * 高德地图-行政区域查询
         */
        private static final String AMAP_URL_DISTIC="https://restapi.amap.com/v3/config/district";
        /**
         * 高德地图——距离测量API
         */
        private static final String AMAP_URL_DIST="https://restapi.amap.com/v3/distance";
        /**
         * 高德地图——坐标系转换接口
         */
        private static final String AMAP_URL_COVER="https://restapi.amap.com/v3/assistant/coordinate/convert";

        /**
         * 高德地图-PIO详情获取
         */
        private static final String AMAP_URL_PIO="https://restapi.amap.com/v3/place/detail";

        /**
         * 高德地图-地理围栏-创建/查询/更新/删除
         * 【备注】Restful接口
         */
        private static final String AMAP_URL_GID="https://restapi.amap.com/v4/geofence/meta";

        /**
         * 高德地图-地理围栏-围栏设备监控
         */
        private static final String AMAP_URL_MOI="https://restapi.amap.com/v4/geofence/status";
        /**
         * 驾车规划
         */
        private static final String AMAP_URL_DRIVER="https://restapi.amap.com/v5/direction/driving";

        /**
         * 骑行规划
         * https://restapi.amap.com/v4/direction/bicycling
         */
        private static final String AMAP_URL_BICYCLE="https://restapi.amap.com/v5/direction/bicycling";
        /**
         * 电动车规划
         * https://restapi.amap.com/v4/direction/bicycling
         */
        private static final String AMAP_URL_ELECTRI_BICYCLE="https://restapi.amap.com/v5/direction/electrobike";

        /**
         * 步行规划
         * https://restapi.amap.com/v4/direction/bicycling
         */
        private static final String AMAP_URL_WALK_BICYCLE="https://restapi.amap.com/v5/direction/walking";

        /**
         * pio地点查询
         */
        private static final String AMP_URL_PIO_SEARCH="https://restapi.amap.com/v5/place/text?parameters";

        //静态key
        private static final String[] KEYS={
                "efaf78aa997c8b5b1925e18303356e8a"//18547119940
                ,"836ab888e3f913edc11dd54cad0221a0"//付锦涛
                ,"47c8c730cca6186e0c0ae706386a934a"//16604712000
                ,"30cd55d53ff6465d485f3f7b1682e9d3"
                ,"1a00cfe6dce7031a455dcc8b7fc9cbdd"
                ,"58e8bdc9ecdbc1503e549cd777a5dbca"//张占军
                ,"833076b6e92539252d6bc8ed8faa0559"//张文强
                ,"de7bf080805e9ace18596c43e04a3fb0"//陈念冬
                ,"df3883d08cec25f94cfbe930d4c08b5d"//黄付
                ,"b3250aac0caa7c51e1774107be0b2432"//张晓惠
                ,"db4651633e42d18f6d9278993c88ecb0"//付贤环
                ,"da10c5d42acf4955b8cf58e5219c3b96"
                ,"60c7ddf79751576bae5c5a7e9cdc2a6a"
                ,"825ef078aa6e0169aadd2c7ad8c09314"//
                ,"02ced337d5244efea04b0bcfed33c051"//
                ,"ce02f450eed4bcdc943df9dd76cd4f13"
                ,"e994fe2c8f2ae8cf6f44928a75ad5d8e"
                ,"6bb4d8181f72da3dd20d9511343d415d"//3617
                ,"c3889d6d49e3d4aecd06ee7b1aaaadb1"//3617
                ,"74ffabef9aadea3aed014de7ea91b742"//3617
        };

        private static final String[] gaoDeKEYS={
               "6bb4d8181f72da3dd20d9511343d415d"//3617
                ,"c3889d6d49e3d4aecd06ee7b1aaaadb1"//3617
                ,"74ffabef9aadea3aed014de7ea91b742"//3617
        };


        /**
         * 地理编码
         * @return
         */
        static JSONObject geo(String address){
            JSONObject json=judge(getReq(AMAP_URL_GEO)
                    .query("address", address)
                    .send());
            if (json!=null){
                if(json.getInteger("count")>0){
                    return json.getJSONArray("geocodes").getJSONObject(0);
                }
                log.error("高德地图——地理编码API解析式失败，返回值：[{}]",json);
            }
            return null;
        }
        /**
         * 逆地理编码
         * @return
         */
        static JSONObject regeo(String location){
            JSONObject json=judge(getReq(AMAP_URL_REGEO)
                    .query("location", location)
                    .send());
            if (json!=null){
                return json.getJSONObject("regeocode");
            }
            return null;
        }

        /**
         * 步行距离
         * @param origin
         * @param destination
         * @return
         */
        private static JSONObject walkDistance(String origin,String destination){
            JSONObject json=judge(getReq(AMAP_URL_WALK_BICYCLE)
                    .query("origin", origin)
                    .query("destination", destination)
                    .send());
            if (json!=null){
                log.info("高德骑行路径规划接口返回：[{}]",json);
                return json.getJSONObject("route");
            }
            return null;
        }
        /**
         * 测量距离
         * @param origins
         * @param destination
         * @return
         */
        static JSONObject distance(String origins,String destination){
            JSONObject json=judge(getReq(AMAP_URL_DIST)
                    .query("origins", origins)
                    .query("destination", destination)
                    .send());
            if (json!=null){
                log.info("高德距离测量接口返回：[{}]",json);
                return json.getJSONArray("results").getJSONObject(0);
            }
            return null;
        }

        /**
         * 高德行政区域查询
         * @param keywords
         * @return
         */
        static JSONObject district(String keywords,int subdistrict){
            if(subdistrict>3||subdistrict<0){
                subdistrict=1;
            }
            JSONObject json=judge(getReq(AMAP_URL_DISTIC)
                    .query("keywords", keywords)
                    .query("subdistrict", subdistrict)
                    .send());
            if (json!=null){
                //log.info("高德行政区域查询接口返回：[{}]",json);
                if(json.getJSONArray("districts").size()<1){
                    log.error("高德地图未找到地址信息，检索关键子：[{}]，高德返回:[{}]",keywords,json.toJSONString());
                    return null;
                }
                return json.getJSONArray("districts").getJSONObject(0);
            }
            return null;
        }

        /**
         * 将百度坐标系转换未高德坐标系
         * @return
         */
        private static String convert(String location){
            JSONObject json=judge(getReq(AMAP_URL_COVER)
                    .query("locations", location)
                    .query("coordsys", "baidu")
                    .send());
            if (json!=null){
                log.info("百度坐标系转换高德接口返回：[{}]",json);
                return json.getString("locations");
            }
            return null;
        }

        /**
         * 使用id精确查询
        * @param pioId
         * @return
         */
        /*private static JSONObject detail(String pioId){
            JSONObject json=judge(getReq(AMAP_URL_PIO)
                    .query("id", pioId)
                    .send());
            if (json!=null){
                log.info("高德PIO地点精确查询接口返回：[{}]",json);
                return json.getJSONArray("pios").getJSONObject(0);
            }
            return null;
        }*/

        /**
         * 创建地理围栏
         * @param name
         * @param points
         * @return
         */
        private static JSONObject createGid(String name,String points){
            JSONObject body=new JSONObject();
            body.put("name",name);body.put("points",points);
            JSONObject json=judgeV4(postReq(AMAP_URL_GID)
                    .body(body.toJSONString())
                    .send());
            if (json!=null){
                log.info("高德创建地理围栏接口返回：[{}]",json);
                return json.getJSONObject("data");
            }
            return null;
        }

        /**
         * 查询地理围栏
         * @param gid
         * @return
         */
        private static JSONObject getGid(String gid){
            JSONObject json=judgeV4(getReq(AMAP_URL_GID)
                    .query("gid",gid)
                    .send());
            if (json!=null){
                log.info("高德查询地理围栏接口返回：[{}]",json);
                return json.getJSONObject("data");
            }
            return null;
        }

        /**
         * 删除地理围栏
         * @param gid
         * @return
         */
        private static JSONObject delGid(String gid){
            JSONObject json=judgeV4(deleteReq(AMAP_URL_GID)
                    .query("gid",gid)
                    .send());
            if (json!=null){
                log.info("高德删除地理围栏接口返回：[{}]",json);
                return json.getJSONObject("data");
            }
            return null;
        }
        private static JSONObject checkGid(String location){
            JSONObject json=judgeV4(getReq(AMAP_URL_MOI)
                    .query("diu",NumberUtils.getShort())
                    .query("locations",location)
                    .send());
            if (json!=null){
                log.info("高德围栏设备监控接口返回：[{}]",json);
                return json.getJSONObject("data");
            }
            return null;
        }

        /**
         * 驾车路劲规划——最短距离方式
         * @param origin
         * @param destination
         * @return
         */
        private static JSONObject driver(String origin,String destination){
            JSONObject json=judge(getReq(AMAP_URL_DRIVER)
                    .query("origin", origin)
                    .query("destination", destination)
                    .query("strategy",2)
                    .send());
            if (json!=null){
                //log.info("高德驾车路径规划接口返回：[{}]",json);
                return json.getJSONObject("route");
            }
            return null;
        }
        /**
         * 骑行——最短距离方式
         * @param origin
         * @param destination
         * @return
         */
        /*private static JSONObject bicycle(String origin,String destination){
            JSONObject json=judge(getReq(AMAP_URL_BICYCLE)
                    .query("origin", origin)
                    .query("destination", destination)
                    .send());
            if (json!=null){
                log.info("高德骑行路径规划接口返回：[{}]",json);
                return json.getJSONObject("route");
            }
            return null;
        }*/

        /**
         * 电动车——最短距离方式
         * @param origin
         * @param destination
         * @return
         */
        private static JSONObject electricBicycle(String origin,String destination){
            JSONObject json=judge(getReq(AMAP_URL_ELECTRI_BICYCLE)
                    .query("origin", origin)
                    .query("destination", destination)
                    .send());
            if (json!=null){
                log.info("高德骑行路径规划接口返回：[{}]",json);
                return json.getJSONObject("route");
            }
            return null;
        }

        /**
         * 搜索PIO
         * @param key
         * @return
         */
        private static JSONObject pioSearch(String key,String adcode){
            JSONObject json=judge(getReq(AMP_URL_PIO_SEARCH)
                    .query("keywords", key)
                    .query("region",adcode)
                    .query("city_limit",true)
                    .send());
            if (json!=null){
                //log.info("@@@@@@@@@@@@@@@@@@@@@@@@@@搜索PIO：{}",json);
                return json;
            }
            return null;
        }


        /**
         * ####################公共方法######################
         */
        private static final Random rand = new Random();

        /**
         * 随机获取一条key
         * @return
         */
        private static String getKey(){
            try{
                if(LocalDateTime.now().isBefore(LocalDateTime.of(LocalDateTime.now().getYear(),LocalDateTime.now().getMonth(),LocalDateTime.now().getDayOfMonth(),18,00,00))){
                    return KEYS[ rand.nextInt(KEYS.length)];
                }else {
                    return gaoDeKEYS[ rand.nextInt(gaoDeKEYS.length)];
                }
            }catch (Exception e){
                return KEYS[0];
            }
        }

        /**
         * 获取高德地图请求端(GET方式)
         * @param URL
         * @return
         */
        private static HttpRequest getReq(String URL){
            return HttpRequest.get(URL).query("key", getKey());
        }
        /**
         * 获取高德地图请求端（POST方式）
         * @param URL
         * @return
         */
        private static HttpRequest postReq(String URL){
            return HttpRequest.post(URL).query("key",getKey());
        }
        /**
         * 获取高德地图请求端（PATCH方式）
         * @param URL
         * @return
         */
        private static HttpRequest patchtReq(String URL){
            return HttpRequest.patch(URL).query("key",getKey());
        }
        /**
         * 获取高德地图请求端（DELETE方式）
         * @param URL
         * @return
         */
        private static HttpRequest deleteReq(String URL){
            return HttpRequest.delete(URL).query("key",getKey());
        }
        /**
         * 检查接口返回值（仅适用v3接口版本）
         * @param response
         * @return
         */
        private static JSONObject judge(HttpResponse response){
            JSONObject json=JSON.parseObject(response.bodyText());
            if(1==json.getInteger("status")){
                return json;
            }
            if("20000".equals(json.getString("infocode"))){
                //log.info("高德地图接口调用失败,参数错误！!返回信息：[{}]",response.bodyText());
                return null;
            }
            log.error("高德地图接口调用失败!返回信息：[{}]",response.bodyText());
            return null;
        }
        /**
         * 检查接口返回值（仅适用v4接口版本）
         * @param response
         * @return
         */
        private static JSONObject judgeV4(HttpResponse response){
            JSONObject json=JSON.parseObject(response.bodyText());
            if(0==json.getInteger("errcode")){
                return json;
            }
            log.error("高德地图接口调用失败!请求信息：[{}]",response.getHttpRequest().queryString());
            log.error("高德地图接口调用失败!返回信息：[{}]",response.bodyText());
            return null;
        }

    }


    /**
     * 百度地图内部类
     * 封装百度地图接口
     * @author 10552
     */
    private static class BmapApi{
        /**
         * 百度地图——地理编码API
         */
        private static final String BMAP_URL_GEO="http://api.map.baidu.com/geocoding/v3/";
        /**
         * 百度地图——逆地理编码API
         */
        private static final String BMAP_URL_REGEO="http://api.map.baidu.com/reverse_geocoding/v3/";

        private static final String BMAP_URL_COVER="https://api.map.baidu.com/geoconv/v1/";

        private static final Random rand = new Random();
        private static final String[] ak={
                "IzVewdGN59AEiuD8D7WQQhGNgfIbmAxK"//18547119940
                ,"bUHv7Sh4AyQvH9HPyRGyKD90vQpfOiIG"//付锦涛
        };

        /**
         * 百度——地理编码
         * @param address
         * @return
         */
        static JSONObject geo(String address) {
            JSONObject json=judge(getReq(BMAP_URL_GEO)
                    .query("address", address)
                    .query("output","json")
                    .send());
            log.info("百度地图地理编码接口返回");
            return json;
        }

        /**
         * 百度——逆地理编码
         * @param location
         * @return
         */
        static JSONObject regeo(String location) {
            JSONObject json=judge(getReq(BMAP_URL_REGEO)
                    .query("location", location)
                    .send());
                return json;
        }


        /**
         * 获取百度地图请求端
         * @param URL
         * @return
         */
        private static HttpRequest getReq(String URL){

            return HttpRequest.get(URL).charset("UTF-8")
                    .query("ak",ak[ rand.nextInt(ak.length)]/*StaticComponent.BD_WEB_KEY*/)
                    .query("output","json");
        }
        /**
         * 返回值检查
         * @param response
         * @return
         */
        private static JSONObject judge(HttpResponse response){
            JSONObject json=JSON.parseObject(response.charset("utf-8").bodyText());
            if(0==json.getInteger("status")){
                if(JSON.isValidArray(json.getString("result"))){
                    JSONObject resJson=new JSONObject();
                    resJson.put("data",json.getJSONArray("result"));
                    return resJson;
                }
                return json.getJSONObject("result");
            }
            log.error("百度地图接口调用失败!返回信息：[{}]",response.bodyText());
            return null;
        }

        /**
         * 其他坐标系转换为百度坐标系
         * @param location 经纬度
         * @param from 输入坐标类型(1、GPS坐标（wgs84）；2、搜狗地图坐标系；3、火星坐标系(gcj02)[高德/腾讯等]；百度地图采用的经纬度坐标（bd09ll）；)
         * @param to 输出坐标类型(3、火星坐标系(gcj02)[高德/腾讯等]；5、百度地图采用的经纬度坐标（bd09ll）；)
         * @return
         */
        private static JSONObject convert(String location, Integer from, Integer to){
            JSONObject json=judge(getReq(BMAP_URL_COVER)
                    .query("coords", location).query("from",from).query("to",to)
                    .send());
            return json;
        }
    }

    /**
     * 地理编码接口转AddressVO
     * @param json
     * @return
     */
    private static AddressVo getAddressByGeo(String addressStr,JSONObject json,Type type){
        AddressVo addressVo=new AddressVo();
        addressVo.setAddress(addressStr);
        switch (type){
            case GAODE:
                addressVo.setProvince(json.getString("province"));
                addressVo.setCity(json.getString("city"));
                addressVo.setArea(json.getString("district"));
                String[] location=json.getString("location").split(",");
                addressVo.setLng(location[0]);
                addressVo.setLat(location[1]);
                addressVo.setAdcode(json.getString("adcode"));
                return addressVo;
            case BAIDU:
                addressVo.setLat(json.getJSONObject("location").getString("lat"));
                addressVo.setLat(json.getJSONObject("location").getString("lng"));

                return addressVo;
            default:
                log.error("无法解析地址");
                throw new RuntimeException("无法解析地址");
        }
    }
    /**
     * 逆地理编码接口转AddressVO
     * @param json
     * @return
     */
    private static AddressVo getAddressByReGeo(JSONObject json,Type type){
        //log.info("地址：[{}]",json.toJSONString());
        AddressVo addressVo=new AddressVo();
        switch (type){
            case GAODE:
                addressVo.setAddress(json.getString("formatted_address"));
                JSONObject addressComponent=json.getJSONObject("addressComponent");
                addressVo.setProvince(addressComponent.getString("province"));
                String city=addressComponent.getString("city");
                addressVo.setCity("[]".equals(city)?"":city);
                addressVo.setArea(addressComponent.getString("district"));
                addressVo.setAdcode(addressComponent.getString("adcode"));
                return addressVo;
            case BAIDU:
                addressVo.setAddress(json.getString("formatted_address"));
                addressVo.setLat(json.getJSONObject("location").getString("lat"));
                addressVo.setLat(json.getJSONObject("location").getString("lng"));
                addressVo.setProvince(json.getJSONObject("business").getString("province"));
                addressVo.setCity(json.getJSONObject("business").getString("city"));
                addressVo.setArea(json.getJSONObject("business").getString("district"));
                return addressVo;
            default:
                log.error("无法解析地址");
                throw new RuntimeException("无法解析地址");
        }
    }

}
