using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Net.NetworkInformation;
using System.Threading;
using Ursa.Controls;
using 常用工具集.Base;

namespace 常用工具集.ViewModel._02网络相关
{
    public class 网络状态检测ViewModel : ViewModelBase
    {
        #region 数据 
        public ObservableCollection<MyPingStatus> PingStatus { get; set; }

        private int ip1 { get; set; } = 172;
        public int IP1 { get { return ip1; } set { ip1 = value; SetTip(); NotifyPropertyChanged(); } }
        private int ip2 { get; set; } = 16;
        public int IP2 { get { return ip2; } set { ip2 = value; SetTip(); NotifyPropertyChanged(); } }
        private int ip3 { get; set; } = 0;
        public int IP3 { get { return ip3; } set { ip3 = value; SetTip(); NotifyPropertyChanged(); } }
        #endregion

        public DelegateCommand Button1Cmd { get; set; }
        public DelegateCommand Button2Cmd { get; set; }
        public 网络状态检测ViewModel()
        {
            lock (_lock)
            {
                PingStatus = new ObservableCollection<MyPingStatus>();
                for (int i = 1; i <= 255; i++)
                {
                    PingStatus.Add(new MyPingStatus
                    {
                        Index = i,
                        IpAddress = $"{IP1}.{IP2}.{IP3}.{i}",
                        Color = "#FFFF80",
                        Tip = $"{IP1}.{IP2}.{IP3}.{i}",
                        Status = false
                    });
                }
            }
            threadList = new List<MyThread>();
            SetTip();
            Button1Cmd = new DelegateCommand(Button1CmdFunc);
            Button2Cmd = new DelegateCommand(Button2CmdFunc);
        }


        private List<MyThread> threadList;
        private void Button1CmdFunc(object obj)
        {
            lock (pingLock)
            {
                if (IPPool.Count > 0)
                {
                    MessageBox.ShowAsync("上一次操作还没结束,请等待完成后继续");
                    return;
                }
            }
            lock (_lock)
            {
                SetColor("#FFFF80");//开始之前清除一下
            }
            foreach (MyThread myThread in threadList)
            {
                myThread.Stop();
                myThread.OnSendResult -= Thread_OnSendResult;
            }
            threadList.Clear();
            lock (_lock)
            {
                for (int i = 1; i <= 255; i++)
                {
                    IPPool.Add(i);
                }
            }
            string ip = $"{IP1}.{IP2}.{IP3}.";
            for (int i = 0; i < 10; i++)
            {
                MyThread thread = new MyThread(ip);
                thread.OnSendResult += Thread_OnSendResult;
                thread.Start();
                threadList.Add(thread);
            }
        }

        private void Thread_OnSendResult(int endIndex, bool state)
        {
            if (state)
            {
                SetColor(endIndex, "#00FF00");
            }
            else
            {
                SetColor(endIndex, "#FF0000");
            }
        }


        private void Button2CmdFunc(object obj)
        {
            lock (pingLock)
            {
                if (IPPool.Count > 0)
                {
                    MessageBox.ShowAsync("上一次操作还没结束,请等待完成后继续");
                    return;
                }
            }
            lock (_lock)
            {
                SetColor("#FFFF80");
            }
        }


        /// <summary>
        /// 设置提示
        /// </summary>
        private void SetTip()
        {
            foreach (MyPingStatus status in PingStatus)
            {
                status.Tip = $"{IP1}.{IP2}.{IP3}.{status.Index}";
            }
        }

        /// <summary>
        /// 设置提示
        /// </summary>
        private void SetColor(string color)
        {
            foreach (MyPingStatus status in PingStatus)
            {
                status.Color = color;
            }
        }
        internal static List<int> IPPool = new List<int>();
        internal static object pingLock = new object();
        internal object _lock = new object();
        private void SetColor(int index, string color)
        {
            lock (_lock)
            {
                foreach (MyPingStatus status in PingStatus)
                {
                    if (status.Index == index)
                    {
                        status.Color = color;
                        break;
                    }
                }
            }
        }
    }


    public class MyPingStatus : ViewModelBase
    {
        public int Index { get; set; }
        public string Color { get; set; }
        public string Tip { get; set; }

        public string IpAddress { get; set; }

        public bool Status { get; set; }
    }


    internal class MyThread
    {
        public delegate void SendResult(int endIndex, bool state);
        public event SendResult OnSendResult;
        private Thread thread;
        private string ipAddress;
        private bool stop;
        public MyThread(string ip)
        {
            this.ipAddress = ip;
        }

        public MyThread Start()
        {
            thread = new Thread(() =>
            {
                while (true)
                {
                    try
                    {
                        if (stop)
                            break;
                        //从IP池取出一个
                        int ipIndex = 0;
                        lock (网络状态检测ViewModel.pingLock)
                        {
                            if (网络状态检测ViewModel.IPPool.Count > 0)
                            {
                                ipIndex = 网络状态检测ViewModel.IPPool[0];
                                网络状态检测ViewModel.IPPool.RemoveAt(0);
                            }
                        }
                        if (ipIndex == 0)
                            break;
                        bool flag = Ping($"{ipAddress}{ipIndex}");
                        OnSendResult?.Invoke(ipIndex, flag);
                    }
                    catch (Exception ex)
                    {
                        if (ex is ThreadInterruptedException)
                            break;
                    }
                }
            });
            thread.Start();
            return this;
        }

        public void Stop()
        {
            stop = true;
            thread.Interrupt();
        }

        private bool Ping(string ip)
        {
            byte[] bytes = new byte[32];
            for (int i = 0; i < bytes.Length; i++)
            {
                bytes[i] = (byte)(i + 1);
            }

            Ping ping = new Ping();
            if (ping.Send(ip, 300, bytes, new PingOptions { Ttl = 255 }).Status == IPStatus.Success)
            {
                return true;
            }
            return false;
        }
    }
}
