using System;
using System.Text;
using MessagePack;

namespace GameMessage
{
    /// <summary>
    /// 设备信息
    /// </summary>
    [MessagePackObject]
    public class DeviceInfo
    {
        /// <summary>
        /// 玩家所在的平台 0pc 1安卓 2IOS 3miniGame 4webgl
        /// </summary>
        [Key(0)]
        public int plat;

        /// <summary>
        /// 玩家类型 0正常 1虚拟机 
        /// </summary>
        [Key(1)]
        public int wmsty;

        /// <summary>
        /// 登录类型 -1未知  0普通  1微信  2QQ
        /// </summary>
        [Key(2)]
        public int loginsty;

        /// <summary>
        /// 维度
        /// </summary>
        [Key(3)]
        public double weidu;

        /// <summary>
        /// 经度
        /// </summary>
        [Key(4)]
        public double jingdu;

        /// <summary>
        /// wifi 名称
        /// </summary>
        [Key(5)]
        public string wifissd;

        /// <summary>
        /// wifi mac 地址
        /// </summary>
        [Key(6)]
        public string wifimac;

        /// <summary>
        /// 手机的IMEI
        /// </summary>
        [Key(7)]
        public string phone_imei;

        /// <summary>
        /// ip地址
        /// </summary>
        [Key(8)]
        public string ip;

        /// <summary>
        /// 省
        /// </summary>
        [Key(9)]
        public string province;

        /// <summary>
        /// 市
        /// </summary>
        [Key(10)]
        public string city;

        /// <summary>
        /// 区
        /// </summary>
        [Key(11)]
        public string district;

        /// <summary>
        /// 地址名称
        /// </summary>
        [Key(12)]
        public string address;

        /// <summary>
        /// 作弊程度   0"正常", 1 "无法定位",   2"低",   3"中",  4"高"
        /// </summary>
        [Key(13)]
        public int zuobichengdu;

        /// <summary>
        /// 
        /// </summary>
        public DeviceInfo()
        {
        }

        /// <summary>
        /// 无定位信息
        /// </summary>
        [IgnoreMember]
        public bool isEmpty
        {
            get { return Math.Abs(jingdu) < 0.01f && Math.Abs(weidu) < 0.01; }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("plat:" + plat);
            sb.AppendLine("wmsty:" + wmsty);
            sb.AppendLine("loginsty:" + loginsty);
            sb.AppendLine("weidu:" + weidu);
            sb.AppendLine("jingdu" + jingdu);
            sb.AppendLine("wifissd:" + wifissd);
            sb.AppendLine("wifimac:" + wifimac);
            sb.AppendLine("phone_imei:" + phone_imei);
            sb.AppendLine("ip:" + ip);
            sb.AppendLine("province:" + province);
            sb.AppendLine("city:" + city);
            sb.AppendLine("district:" + district);
            sb.AppendLine("address:" + address);

            return sb.ToString();
        }

        /// <summary>
        /// 获取用户坐标
        /// </summary>
        /// <returns></returns>
        public WorldPosition GetPosition()
        {
            return new WorldPosition() { weidu = weidu, jingdu = jingdu };
        }
    }
    
    /// <summary>
    /// 定位信息
    /// </summary>
    public struct WorldPosition
    {
        /// <summary>
        /// 经度
        /// </summary>
        public double jingdu;

        /// <summary>
        /// 纬度
        /// </summary>
        public double weidu;

        /// <summary>
        /// 无定位信息
        /// </summary>
        public bool isEmpty {
            get {
                return Math.Abs(jingdu) < 0.01f && Math.Abs(weidu) < 0.01;
            }
        }

        /// <summary>
        /// 是否属于安全距离
        /// </summary>
        /// <param name="pos0"></param>
        /// <param name="pos1"></param>
        /// <param name="sefeDistance">安全距离</param>
        /// <returns></returns>
        public static bool CheckSafeDistance(WorldPosition pos0, WorldPosition pos1, int sefeDistance) {
            if (pos0.isEmpty || pos1.isEmpty)
                return false;

            double safeSegment = sefeDistance / 100000f;

            double latbetween = Math.Abs(pos0.weidu - pos1.weidu);
            double lngbetween = Math.Abs(pos0.jingdu - pos1.jingdu);

            if (latbetween + lngbetween > safeSegment)
                return true;

            var dis = GetDistance(pos0, pos1);

            return dis > sefeDistance;
        }

        /// <summary>
        /// 获取两个位置的坐标距离
        /// </summary>
        /// <param name="pos0">坐标0</param>
        /// <param name="pos1">坐标1</param>
        /// <returns>坐标距离</returns>
        public static double GetDistance(WorldPosition pos0, WorldPosition pos1) {
            if (pos0.isEmpty || pos1.isEmpty)
                return 0;

            return GetDistance(pos0.jingdu, pos0.weidu, pos1.jingdu, pos1.weidu);
        }
        
        /// <summary>
        /// 计算地球上两点之间的距离_单位是米  
        /// 经纬度相差一个单位大约是 10000米  如果是比较两点是否小于 2000米 应该使用估算方法 只要两个点 经各经度 纬度 之间的差值 之后大于0.5应该就不需要计算了,肯定是大于2000米 减小运算 运算费时
        /// </summary>
        /// <param name="lng1">第一点的经度</param>
        /// <param name="lat1">第一点的纬度</param>
        /// <param name="lng2">第二点的经度</param>
        /// <param name="lat2">第二点的维度</param>
        /// <returns></returns>
        public static double GetDistance(double lng1, double lat1, double lng2, double lat2)
        {
            double ralat1 = Rad(lat1);
            double ralng1 = Rad(lng1);
            double ralat2 = Rad(lat2);
            double ralng2 = Rad(lng2);

            double a = ralat1 - ralat2;
            double b = ralng1 - ralng2;

            double result = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + Math.Cos(ralat1) * Math.Cos(ralat2) * Math.Pow(Math.Sin(b / 2), 2))) * Earth_Radius;

            return result;
        }
        
        /// <summary>
        /// 地球的半径
        /// </summary>
        public const double Earth_Radius = 6378137;
        
        /// <summary>
        /// 经纬度转弧度
        /// </summary>
        /// <returns>弧度</returns>
        public static double Rad(double d)
        {
            return (double)d * Math.PI / 180d;
        }
    }
}