package com.abbidot.tracker.util

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

        /**
         * 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
        }
    }
}