package com.abbidot.tracker.util

import android.graphics.PointF
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.sqrt


/**
 *Created  by .yzq on 2022/6/25/025.
 * @link
 * @description:
 */
class LonAndLatUtil {

    companion object {

        //当前用户的GPS经纬度
        var currentUserGPSLat = 0.0
        var currentUserGPSLon = 0.0

        private const val a = 6378245.0
        private const val ee = 0.00669342162296594323

        /**
         *  判断是不是在中国
         *  用引射线法判断 点是否在多边形内部
         *  算法参考：http://www.cnblogs.com/luxiaoxun/p/3722358.html
         */
        private val polygonOfChina: MutableList<PointF> by lazy {
            mutableListOf(
                PointF(49.150669f, 87.415081f),
                PointF(48.366450179f, 85.75270853f),
                PointF(47.0253058185f, 85.3847443554f),
                PointF(45.240655f, 82.5214f),
                PointF(44.8957121295f, 79.9392351487f),
                PointF(43.1166843846f, 80.6751253982f),
                PointF(41.870169f, 79.688216f),
                PointF(39.289619f, 73.617108f),
                PointF(34.230343f, 78.91553f),
                PointF(31.023886f, 79.062708f),
                PointF(27.99898f, 88.702892f),
                PointF(27.179359f, 88.997248f),
                PointF(28.096917f, 89.73314f),
                PointF(26.91578f, 92.161583f),
                PointF(28.194764f, 96.098605f),
                PointF(27.409476f, 98.674227f),
                PointF(23.90855f, 97.570389f),
                PointF(24.077583f, 98.78461f),
                PointF(22.137564f, 99.189351f),
                PointF(21.139895f, 101.764972f),
                PointF(22.274622f, 101.728178f),
                PointF(23.264194f, 105.370843f),
                PointF(22.71912f, 106.695448f),
                PointF(21.9945711661f, 106.7256731791f),
                PointF(21.484705f, 108.020053f),
                PointF(20.447844f, 109.381453f),
                PointF(18.668985f, 108.240821f),
                PointF(17.401734f, 109.933372f),
                PointF(19.508567f, 111.405156f),
                PointF(21.2716775175f, 111.2514995205f),
                PointF(21.9936323233f, 113.4625292629f),
                PointF(22.1818312942f, 113.4258358111f),
                PointF(22.2249729295f, 113.5913115f),
                PointF(22.4501912753f, 113.894684449f),
                PointF(22.5959159322f, 114.3623797842f),
                PointF(22.433461f, 114.519474f),
                PointF(22.9680954377f, 116.8326939975f),
                PointF(25.378822f, 119.966798f),
                PointF(28.3261276204f, 121.7724402562f),
                PointF(31.988361f, 123.880823f),
                PointF(39.87597f, 124.469537f),
                PointF(41.735089f, 126.953172f),
                PointF(41.514216f, 128.314572f),
                PointF(42.984208179f, 131.0676468344f),
                PointF(45.269081f, 131.846853f),
                PointF(45.060837f, 133.061074f),
                PointF(48.448026f, 135.011188f),
                PointF(48.00548f, 131.66288f),
                PointF(50.227074f, 127.689064f),
                PointF(53.351607f, 125.371004f),
                PointF(53.417604f, 119.925404f),
                PointF(47.559081f, 115.142107f),
                PointF(47.133937f, 119.115923f),
                PointF(44.825646f, 111.278675f),
                PointF(42.529356f, 109.254972f),
                PointF(43.259816f, 97.296729f),
                PointF(45.424762f, 90.968059f),
                PointF(47.807557f, 90.673702f),
                PointF(49.150669f, 87.415081f)
            )
        }

        fun isLocationOutOfChina(latitude: Double, longitude: Double): Boolean {
            val point = PointF(latitude.toFloat(), longitude.toFloat())
            var oddFlag = false
            var j = polygonOfChina.size - 1
            for (i in polygonOfChina.indices) {
                val polygonPointi = polygonOfChina[i]
                val polygonPointj = polygonOfChina[j]

                if ((polygonPointi.y < point.y && polygonPointj.y >= point.y) || (polygonPointj.y < point.y && polygonPointi.y >= point.y)) {
                    if (polygonPointi.x <= point.x || polygonPointj.x <= point.x) {
                        oddFlag =
                            oddFlag xor ((polygonPointi.x + (point.y - polygonPointi.y) / (polygonPointj.y - polygonPointi.y) * (polygonPointj.x - polygonPointi.x)) < point.x)
                    }
                }
                j = i
            }
            return !oddFlag
        }

        /**
         * GPS坐标(WGS84)转火星GCJ02坐标
         * @return
         */
        fun convertFromWGS84ToGCJ02(latitude: Double, longitude: Double): DoubleArray {
            //初始化坐标转换工具类，指定源坐标类型和坐标数据
            // sourceLatLng待转换坐标
//            val converter = CoordinateConverter().from(CoordinateConverter.CoordType.GPS)
//                .coord(LatLng(latitude, longitude))
            //desLatLng 转换后的坐标
//            val desLatLng = converter.convert()
            return convert(latitude, longitude)
        }

        /**
         * 火星GCJ02坐标转GPS坐标(WGS84)
         * @return
         */
        fun convertFromGCJ02ToWGS84(lat: Double, lon: Double): DoubleArray {
            val dd = DoubleArray(2)
            val initDelta = 0.01
            val threshold = 0.000001
            var dLat = initDelta
            var dLon = initDelta
            var mLat = lat - dLat
            var mLon = lon - dLon
            var pLat = lat + dLat
            var pLon = lon + dLon
            var wgsLat: Double
            var wgsLon: Double
            var i = 0
            while (true) {
                wgsLat = (mLat + pLat) / 2
                wgsLon = (mLon + pLon) / 2
                val tmp = convertFromWGS84ToGCJ02(wgsLat, wgsLon)
                dLat = tmp[0] - lat
                dLon = tmp[1] - lon
                if ((abs(dLat) < threshold) && (abs(dLon) < threshold)) {
                    break
                }
                if (dLat > 0) {
                    pLat = wgsLat
                } else {
                    mLat = wgsLat
                }
                if (dLon > 0) {
                    pLon = wgsLon
                } else {
                    mLon = wgsLon
                }
                if (++i > 1000) break
            }
            dd[0] = wgsLat
            dd[1] = wgsLon
            return dd
        }

        /**
         * 动态个数参数
         * vararg
         * 数组多个元素传入函数的变长参数需要在数组名前加 * 号
         */
        fun getMinLatOrLon(vararg latOrLonList: Double): Double {
            if (latOrLonList.isNotEmpty()) {
                var minLatOrLon = latOrLonList[0]
                latOrLonList.forEach {
                    if (minLatOrLon > it) minLatOrLon = it
                }
                return minLatOrLon
            }
            return 0.0
        }

        fun getMaxLatOrLon(vararg latOrLonList: Double): Double {
            if (latOrLonList.isNotEmpty()) {
                var maxLatOrLon = latOrLonList[0]
                latOrLonList.forEach {
                    if (maxLatOrLon < it) maxLatOrLon = it
                }
                return maxLatOrLon
            }
            return 0.0
        }

        /**
         * 把公式部分抽取出来
         */
        private fun convert(latitude: Double, longitude: Double): DoubleArray {
            val dd = DoubleArray(2)
            var dLat: Double = convertLat(longitude - 105.0, latitude - 35.0)
            var dLon: Double = convertLon(longitude - 105.0, latitude - 35.0)
            val radLat = latitude / 180.0 * Math.PI
            var magic = sin(radLat)
            magic = 1 - ee * magic * magic
            val sqrtMagic = sqrt(magic)
            dLat = dLat * 180.0 / (a * (1 - ee) / (magic * sqrtMagic) * Math.PI)
            dLon = dLon * 180.0 / (a / sqrtMagic * cos(radLat) * Math.PI)
            dd[0] = latitude + dLat
            dd[1] = longitude + dLon
            return dd
        }

        private fun convertLat(x: Double, y: Double): Double {
            var ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * sqrt(
                if (x > 0) x else -x
            )
            ret += (20.0 * sin(6.0 * x * Math.PI) + 20.0 * sin(2.0 * x * Math.PI)) * 2.0 / 3.0
            ret += (20.0 * sin(y * Math.PI) + 40.0 * sin(y / 3.0 * Math.PI)) * 2.0 / 3.0
            ret += (160.0 * sin(y / 12.0 * Math.PI) + 320 * sin(y * Math.PI / 30.0)) * 2.0 / 3.0
            return ret
        }

        private fun convertLon(x: Double, y: Double): Double {
            var ret =
                300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * sqrt(if (x > 0) x else -x)
            ret += (20.0 * sin(6.0 * x * Math.PI) + 20.0 * sin(2.0 * x * Math.PI)) * 2.0 / 3.0
            ret += (20.0 * Math.sin(x * Math.PI) + 40.0 * sin(x / 3.0 * Math.PI)) * 2.0 / 3.0
            ret += (150.0 * sin(x / 12.0 * Math.PI) + 300.0 * sin(x / 30.0 * Math.PI)) * 2.0 / 3.0
            return ret
        }
    }
}