package com.casic.dcms.utils;

import android.content.Context;
import android.util.Log;

import com.amap.api.location.AMapLocation;
import com.amap.api.location.AMapLocationClient;
import com.amap.api.location.AMapLocationClientOption;
import com.amap.api.location.AMapLocationListener;
import com.amap.api.services.core.AMapException;
import com.amap.api.services.core.LatLonPoint;
import com.amap.api.services.geocoder.GeocodeResult;
import com.amap.api.services.geocoder.GeocodeSearch;
import com.amap.api.services.geocoder.RegeocodeAddress;
import com.amap.api.services.geocoder.RegeocodeQuery;
import com.amap.api.services.geocoder.RegeocodeResult;
import com.casic.dcms.utils.callback.IAddressListener;
import com.casic.dcms.utils.callback.ICommunityListener;
import com.casic.dcms.utils.callback.ILocationListener;
import com.esri.arcgisruntime.concurrent.ListenableFuture;
import com.esri.arcgisruntime.data.Feature;
import com.esri.arcgisruntime.data.FeatureQueryResult;
import com.esri.arcgisruntime.data.QueryParameters;
import com.esri.arcgisruntime.layers.FeatureLayer;

import java.util.Iterator;

public class LocationHelper {
    private static final String TAG = "LocationHelper";
    private static final double pi = 3.14159265358979324;
    private static final double a = 6378245.0; //  a: 卫星椭球坐标投影到平面地图坐标系的投影因子。
    private static final double ee = 0.00669342162296594323; //  ee: 椭球的偏心率平方。
    private final AMapLocationClientOption mLocationOption = new AMapLocationClientOption();
    private AMapLocationClient mLocationClient;

    private LocationHelper() {
    }

    private static final class LocationHelperHolder {
        static final LocationHelper INSTANCE = new LocationHelper();
    }

    /**
     * 双重锁单例
     */
    public static LocationHelper get() {
        return LocationHelper.LocationHelperHolder.INSTANCE;
    }

    /**
     * 高德sdk定位
     */
    public void getCurrentLocation(Context context, ILocationListener listener, boolean isOnce) {
        mLocationClient = new AMapLocationClient(context);
        mLocationOption.setLocationMode(AMapLocationClientOption.AMapLocationMode.Hight_Accuracy);
        mLocationOption.setOnceLocation(isOnce);//设置是否只定位一次,默认为false
        mLocationOption.setInterval(30 * 1000L);//设置定位间隔,单位毫秒,默认为2000ms
        //给定位客户端对象设置定位参数
        mLocationClient.setLocationOption(mLocationOption);
        //设置定位回调监听
        mLocationClient.setLocationListener(new AMapLocationListener() {
            @Override
            public void onLocationChanged(AMapLocation aMapLocation) {
                if (aMapLocation != null) {
                    if (aMapLocation.getErrorCode() == 0) {
                        listener.onAMapLocationGet(aMapLocation);
                    } else {
                        listener.onAMapLocationGet(null);
                        Log.e(TAG, "location Error, ErrCode:" + aMapLocation.getErrorCode()
                                + ", errInfo:" + aMapLocation.getErrorInfo());
                    }
                }
            }
        });
        //启动定位
        mLocationClient.startLocation();
    }

    public void stopLocation() {
        if (mLocationClient != null) {
            mLocationClient.stopLocation();
            Log.d(TAG, "stopLocation: 停止定位");
        }
    }

    /**
     * 查询社区信息
     */
    public void getCurrentCommunity(FeatureLayer communityLayer, QueryParameters queryParameters, ICommunityListener listener) {
        ListenableFuture<FeatureQueryResult> communityFeatureResult = communityLayer.getFeatureTable().queryFeaturesAsync(queryParameters);
        communityFeatureResult.addDoneListener(new Runnable() {
            @Override
            public void run() {
                try {
                    FeatureQueryResult result = communityFeatureResult.get();
                    Iterator<Feature> iterator = result.iterator();
                    Feature feature = iterator.next();
                    //{FID=7, GBID=361024100011001, Note=中大社区、子正社区}
                    listener.onCommunityFeatureGet(feature);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * 经纬度反编码为地址
     */
    public void antiCodingLocation(Context context, LatLonPoint latLonPoint, IAddressListener listener) {
        try {
            GeocodeSearch codeSearch = new GeocodeSearch(context);
            // 第一个参数表示一个LatLonPoint，第二参数表示范围多少米，第三个参数表示是火系坐标系还是GPS原生坐标系
            RegeocodeQuery query = new RegeocodeQuery(latLonPoint, 50, GeocodeSearch.GPS);
            codeSearch.getFromLocationAsyn(query);
            codeSearch.setOnGeocodeSearchListener(new GeocodeSearch.OnGeocodeSearchListener() {
                @Override
                public void onRegeocodeSearched(RegeocodeResult regeocodeResult, int i) {
                    RegeocodeAddress regeocodeAddress = regeocodeResult.getRegeocodeAddress();
                    if (regeocodeAddress != null) {
                        listener.onGetAddress(regeocodeAddress.getFormatAddress());
                    } else {
                        listener.onGetAddress("解析位置失败");
                    }
                }

                @Override
                public void onGeocodeSearched(GeocodeResult geocodeResult, int i) {

                }
            });
        } catch (AMapException e) {
            e.printStackTrace();
        }
    }

    /**
     * check if the point in china
     * 72.004 <= lng <= 137.8347 and 0.8293 <= lat <= 55.8271
     */
    private boolean isOutOfChina(double lng, double lat) {
        if (lng >= 72.004 && lng <= 137.8347) {
            return lat >= 0.8293 && lat <= 55.8271;
        }
        return false;
    }

    public double[] gcjToWgs(double gcjLng, double gcjLat) {
        if (isOutOfChina(gcjLng, gcjLat)) {
            return new double[]{gcjLng, gcjLat};
        }
        double dLng = transformLon(gcjLng - 105.0, gcjLat - 35.0);
        double dLat = transformLat(gcjLng - 105.0, gcjLat - 35.0);
        double radLat = gcjLat / 180.0 * pi;
        double sinLat = Math.sin(radLat);
        sinLat = 1 - ee * sinLat * sinLat;
        double sinLatSqrt = Math.sqrt(sinLat);
        dLng = (dLng * 180.0) / (a / sinLatSqrt * Math.cos(radLat) * pi);
        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (sinLat * sinLatSqrt) * pi);
        return new double[]{gcjLng - dLng, gcjLat - dLat};
    }

    private double transformLon(double lng, double lat) {
        double ret = 300.0 + lat + 2.0 * lng + 0.1 * lat * lat + 0.1 * lat * lng + 0.1 * Math.sqrt(Math.abs(lat));
        ret += (20.0 * Math.sin(6.0 * lat * pi) + 20.0 * Math.sin(2.0 * lat * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lat * pi) + 40.0 * Math.sin(lat / 3.0 * pi)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(lat / 12.0 * pi) + 300.0 * Math.sin(lat / 30.0 * pi)) * 2.0 / 3.0;
        return ret;
    }

    private double transformLat(double lng, double lat) {
        double ret = -100.0 + 2.0 * lat + 3.0 * lng + 0.2 * lng * lng + 0.1 * lat * lng + 0.2 * Math.sqrt(Math.abs(lat));
        ret += (20.0 * Math.sin(6.0 * lat * pi) + 20.0 * Math.sin(2.0 * lat * pi)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(lng * pi) + 40.0 * Math.sin(lng / 3.0 * pi)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(lng / 12.0 * pi) + 320 * Math.sin(lng * pi / 30.0)) * 2.0 / 3.0;
        return ret;
    }
}
