using Google.Protobuf;
using Message;
using parkMonitor.LOG;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace parkspace_manager
{
    public partial class FormParkSpaceStatus : Form
    {
        public static int s_spacesInRow = 15;
        public static int s_floors = 11;
        public static int s_rows = 1;
        public static bool s_isClosing;
        private static object s_map_update_lock;
        private static object s_parkspace_force_update_queue_lock;
        private static object s_parkspace_status_lock;
        /// <summary>
        /// 车位id与车位信息映射
        /// </summary>
        private Dictionary<int, Parkspace_info> m_idPssMap;
        /// <summary>
        /// 提示信息管理器
        /// </summary>
        private ToolTip m_toolTip_parkspace_info;
        ///// <summary>
        ///// 按钮与对应提示信息映射
        ///// </summary>
        //private Dictionary<Button, ToolTip> m_btnToolTipMap;
        /// <summary>
        /// 强制更新反馈消息队列，用于处理同时收到多个反馈消息的情况
        /// </summary>
        private Queue<Parkspace_force_update_response_msg> m_parkspace_force_update_response_queue;
        /// <summary>
        /// 当前所有车位状态，由界面更新线程主动更新
        /// </summary>
        Parkspace_allocation_status_msg m_parkspace_status;
        Thread m_update_display_thread;

        public FormParkSpaceStatus()
        {
            m_parkspace_status = new Parkspace_allocation_status_msg();
            s_map_update_lock = new object();
            s_parkspace_force_update_queue_lock = new object();
            s_parkspace_status_lock = new object();
            m_parkspace_force_update_response_queue = new Queue<Parkspace_force_update_response_msg>();
            m_idPssMap = new Dictionary<int, Parkspace_info>();

            m_toolTip_parkspace_info = new ToolTip();
            // 设置显示样式
            m_toolTip_parkspace_info.AutoPopDelay = 20000;//提示信息的可见时间
            m_toolTip_parkspace_info.InitialDelay = 500;//事件触发多久后出现提示
            m_toolTip_parkspace_info.ReshowDelay = 500;//指针从一个控件移向另一个控件时，经过多久才会显示下一个提示框
            m_toolTip_parkspace_info.ShowAlways = false;//是否显示提示框

            //m_btnToolTipMap = new Dictionary<Button, ToolTip>();
            s_isClosing = false;

            InitializeComponent();

            Communicator.Instance.Init();
            Communicator.Instance.Bind("tcp://192.168.2.144:20000");
            Communicator.Instance.Connect("tcp://192.168.2.125:20000");
            Communicator.Instance.SetParkspaceForceUpdateResponseDelegate(ParkspaceForceUpdateResponseCallback);

            // 库位显示
            m_update_display_thread = new Thread(new ThreadStart(UpdateParkingSpaceView));
            m_update_display_thread.Start();
        }

        public void Uninit()
        {
            s_isClosing = true;
            Communicator.Instance.Uninit();
            //if(m_update_display_thread!=null)
            //{
            //    m_update_display_thread.Join();
            //}
        }

        /// <summary>
        /// 接收到强制更新车位反馈消息回调
        /// </summary>
        /// <param name="response"></param>
        void ParkspaceForceUpdateResponseCallback(Parkspace_force_update_response_msg response)
        {
            lock (s_parkspace_force_update_queue_lock)
            {
                if (m_parkspace_force_update_response_queue != null)
                {
                    m_parkspace_force_update_response_queue.Enqueue(response);
                }
            }
        }

        /// <summary>
        /// 更新立体停车位显示
        /// </summary>
        private void UpdateParkingSpaceView()
        {
            while (!s_isClosing)
            {
                bool needUpdate = false;
                List<Parkspace_info> psList = null;
                Thread.Sleep(1000);
                bool get_status_result = Communicator.Instance.Get_parkspace_status(ref m_parkspace_status);
                lock (s_parkspace_status_lock)
                {
                    if (get_status_result && (m_parkspace_status == null || m_parkspace_status.ParkspaceInfo == null))
                    {
                        get_status_result = false;
                    }
                }
                if (!get_status_result)
                {
                    lock (s_map_update_lock)
                    {
                        m_idPssMap.Clear();
                    }
                    continue;
                }
                else
                {
                    lock (s_parkspace_status_lock)
                    {
                        psList = m_parkspace_status.ParkspaceInfo.ToList();
                    }
                }
                if (psList == null || psList.Count <= 0)
                {
                    Thread.Sleep(1000);
                    continue;
                }
                //更新映射表
                try
                {
                    lock (s_map_update_lock)
                    {
                        if (m_idPssMap.Count != psList.Count)
                        {
                            m_idPssMap.Clear();
                            for (int i = 0; i < psList.Count; i++)
                            {
                                m_idPssMap.Add(psList[i].ParkspaceId, psList[i]);
                            }
                        }
                        else
                        {
                            for (int i = 0; i < psList.Count; i++)
                            {
                                m_idPssMap[psList[i].ParkspaceId] = psList[i];
                            }
                        }
                    }
                }
                catch (Exception e) { Console.WriteLine(e.StackTrace); /*Log.WriteLog(LogType.process, LogFile.WARNING, "实时更新所有库位异常");*/ }
                Action action = () =>
                {
                    int blockSize = s_spacesInRow * s_floors * s_rows;
                    int offset = (s_rows + 1 - ((blockSize / s_spacesInRow) % s_rows)) * s_spacesInRow;
                    //创建控件
                    if (ParkingSpaceMonitorPanel != null && ParkingSpaceMonitorPanel.Controls.Count == 0 || needUpdate)
                    {
                        TableLayoutPanel tlp = new TableLayoutPanel();
                        tlp.Name = "tlp_ParkingSpace";
                        tlp.ColumnCount = s_rows;
                        tlp.RowCount = 1;
                        tlp.Dock = DockStyle.Fill;
                        tlp.AutoScroll = true;
                        tlp.BackColor = SystemColors.GradientActiveCaption;

                        for (int i = 0; i < s_rows; i++)
                        {
                            TableLayoutPanel temp = new TableLayoutPanel();
                            temp.Name = "tlp_ParkingSpaceSection" + (i + 1).ToString();
                            temp.RowCount = s_floors;
                            temp.ColumnCount = s_spacesInRow;
                            temp.Dock = DockStyle.Fill;
                            temp.AutoSize = true;
                            temp.BackColor = SystemColors.GradientActiveCaption;
                            temp.Margin = new Padding(1, 2, 1, 2);
                            for (int j = Math.Max(psList.Count, blockSize) - 1; j >= 0; j--)
                            {
                                Button btn = new Button();
                                btn.Anchor = (AnchorStyles.Top | AnchorStyles.Left);
                                btn.AutoSize = true;
                                btn.Location = new Point(5, 5);
                                btn.Margin = new Padding(1, 2, 1, 2);
                                btn.Padding = new Padding(5);
                                btn.Name = "lb_parkingSpace" + j;
                                btn.TextAlign = ContentAlignment.MiddleCenter;
                                btn.MouseClick += new MouseEventHandler(Btnvalue_Click);
                                btn.MouseHover += new EventHandler(Btnvalue_Mouse_Hover);
                                if (((j + offset) / s_spacesInRow) % s_rows == i)
                                {
                                    if (j > psList.Count - 1)
                                    {
                                        btn.Text = "#####";
                                        temp.Controls.Add(btn);
                                        btn.BackColor = GetPSColor(Parkspace_status.EParkspaceError);
                                    }
                                    else
                                    {
                                        try
                                        {
                                            btn.Text = "车位" + psList[j].ParkspaceId;
                                            btn.BackColor = GetPSColor(psList[j].ParkspaceStatus);
                                            temp.Controls.Add(btn);
                                        }
                                        catch { Log.WriteLog(LogType.process, LogFile.WARNING, "实时更新单一库位异常"); }
                                    }
                                }
                            }
                            tlp.Controls.Add(temp);
                            //tlpList.Add(temp);
                        }
                        ParkingSpaceMonitorPanel.Controls.Clear();
                        ParkingSpaceMonitorPanel.Controls.Add(tlp);
                        needUpdate = false;
                    }
                    //更新控件
                    else
                    {
                        Control.ControlCollection psCC = ParkingSpaceMonitorPanel.Controls;
                        foreach (Control segment in psCC)
                        {
                            Control.ControlCollection segmentCC = segment.Controls;
                            //Console.WriteLine("seg::"+segmentCC.Count);
                            foreach (Control spaces in segmentCC)
                            {
                                Control.ControlCollection spaceCC = spaces.Controls;
                                //Console.WriteLine("spaces::"+spaceCC.Count);
                                foreach (Control space in spaceCC)
                                {
                                    if (space.GetType() == typeof(Button))
                                    {
                                        int index = -1;
                                        bool result = int.TryParse(space.Text.Substring(2), out index);
                                        lock (s_map_update_lock)
                                        {
                                            //Console.WriteLine("text is :" + space.Text+", index:"+index);
                                            if (m_idPssMap.ContainsKey(index))
                                            {
                                                //Console.WriteLine("index:" + index+", status:"+ idPssMap[index].spaceStatus);
                                                space.BackColor = GetPSColor(m_idPssMap[index].ParkspaceStatus);
                                            }
                                            else if (result)
                                            {
                                                needUpdate = true;
                                                //Console.WriteLine("need update:"+index);
                                                break;
                                            }
                                        }
                                    }
                                }
                            }
                            if (needUpdate)
                            {
                                break;
                            }
                        }
                    }
                };
                if (this != null && this.IsHandleCreated)
                {
                    this.Invoke(action);
                }
            }
        }

        /// <summary>
        /// 按钮点击事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Btnvalue_Click(object sender, MouseEventArgs e)
        {
            Button btn = (Button)sender;
            //实例化窗口，选择待修改状态
            FormStatusSelect formStatusSelect = new FormStatusSelect(btn);
            formStatusSelect.Location = Control.MousePosition;
            formStatusSelect.StartPosition = FormStartPosition.Manual;
            formStatusSelect.SetCallback(ForceUpdateStatusCallback);
            formStatusSelect.ShowDialog();
        }

        private void Btnvalue_Mouse_Hover(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            // 创建the ToolTip 
            if (m_toolTip_parkspace_info == null)
            {
                m_toolTip_parkspace_info = new ToolTip();
                // 设置显示样式
                m_toolTip_parkspace_info.AutoPopDelay = 20000;//提示信息的可见时间
                m_toolTip_parkspace_info.InitialDelay = 500;//事件触发多久后出现提示
                m_toolTip_parkspace_info.ReshowDelay = 500;//指针从一个控件移向另一个控件时，经过多久才会显示下一个提示框
                m_toolTip_parkspace_info.ShowAlways = false;//是否显示提示框
            }

            // 获取车位信息，处理后显示
            int parkspaceID = GetParkspaceIdFromButton(btn);
            Parkspace_info space_info = null;
            lock (s_parkspace_status_lock)
            {
                if (parkspaceID <= 0 || m_parkspace_status == null || m_parkspace_status.ParkspaceInfo == null)
                    return;
                for (int i = 0; i < m_parkspace_status.ParkspaceInfo.Count; i++)
                {
                    if (m_parkspace_status.ParkspaceInfo[i].ParkspaceId == parkspaceID)
                    {
                        space_info = m_parkspace_status.ParkspaceInfo[i];
                        break;
                    }
                }
            }
            if (space_info == null)
                return;
            //  设置伴随的对象
            m_toolTip_parkspace_info.SetToolTip(btn, space_info.ToString().Replace(",", "\n"));//设置提示按钮和提示内容
        }

        /// <summary>
        /// 定义用于发送修改请求，以及修改button状态的回调函数
        /// </summary>
        /// <param name="status"></param>
        private void ForceUpdateStatusCallback(Parkspace_status status, Button btn)
        {
            int parkspaceID = GetParkspaceIdFromButton(btn);
            lock(s_parkspace_status_lock)
            {
                if (parkspaceID <= 0 || m_parkspace_status == null || m_parkspace_status.ParkspaceInfo == null)
                    return;
            }

            // 遍历强制更新反馈队列，清除对应车位已存在的反馈消息，即将非对应车位的消息放回队列
            lock (s_parkspace_force_update_queue_lock)
            {
                for (int i = 0; i < m_parkspace_force_update_response_queue.Count; i++)
                {
                    Parkspace_force_update_response_msg response = m_parkspace_force_update_response_queue.Dequeue();
                    if (response.UpdateSpaceInfo != null && response.UpdateSpaceInfo.ParkspaceId != parkspaceID)
                    {
                        m_parkspace_force_update_response_queue.Enqueue(response);
                    }
                }
            }
            // 发送强制更新请求
            Parkspace_info space_info = null;
            lock (s_parkspace_status_lock)
            {
                for (int i = 0; i < m_parkspace_status.ParkspaceInfo.Count; i++)
                {
                    if (m_parkspace_status.ParkspaceInfo[i].ParkspaceId == parkspaceID)
                    {
                        space_info = m_parkspace_status.ParkspaceInfo[i];
                        break;
                    }
                }
            }
            DateTime startTime = DateTime.Now;
            string commandKey = startTime.ToString("yyyy-MM-dd_HH:mm:ss:ffff");
            try
            {
                space_info.ParkspaceStatus = status;
                Parkspace_force_update_request_msg parkspace_force_update_request_msg = new Parkspace_force_update_request_msg();
                Base_info base_Info = new Base_info();
                base_Info.MsgType = Message_type.EParkspaceForceUpdateRequestMsg;
                base_Info.TimeoutMs = 2000;
                base_Info.Sender = Message.Communicator.EParkspace;
                base_Info.Receiver = Message.Communicator.EParkspace;
                parkspace_force_update_request_msg.BaseInfo = base_Info;
                parkspace_force_update_request_msg.CommandKey = commandKey;
                parkspace_force_update_request_msg.UpdateSpaceInfo = space_info;
                Communicator.Instance.Send_msg(parkspace_force_update_request_msg.ToByteString());
            }
            catch (Exception ex) { Console.WriteLine(ex.StackTrace); }

            // 遍历强制更新反馈队列，寻找对应反馈消息
            bool get_result = false;
            while ((DateTime.Now - startTime).TotalMilliseconds < Communicator.Instance.m_timeout_milli)
            {
                lock (s_parkspace_force_update_queue_lock)
                {
                    for (int i = 0; i < m_parkspace_force_update_response_queue.Count; i++)
                    {
                        Parkspace_force_update_response_msg response = m_parkspace_force_update_response_queue.Dequeue();
                        if (response.UpdateSpaceInfo != null && response.CommandKey == commandKey && response.UpdateSpaceInfo.ParkspaceId == parkspaceID)
                        {
                            get_result = true;
                            if (response.ErrorManager != null)
                            {
                                if (response.ErrorManager.ErrorCode != 0)
                                {
                                    //btn.BackColor = GetPSColor(status);
                                    Console.WriteLine("force update failed, code: " + response.ErrorManager.ErrorCode + ", description: " + response.ErrorManager.ErrorDescription);
                                }
                            }
                            break;
                        }
                        else
                        {
                            m_parkspace_force_update_response_queue.Enqueue(response);
                        }
                    }
                }
                if (get_result)
                    break;
                Thread.Sleep(50);
            }
        }

        /// <summary>
        /// 通过按钮信息截取车位id，失败返回-1
        /// </summary>
        /// <param name="btn"></param>
        /// <returns></returns>
        private int GetParkspaceIdFromButton(Button btn)
        {
            if (btn == null || btn.Text.Length < 3)
                return -1;
            int parkspaceID = -1;
            bool parse_result = int.TryParse(btn.Text.Substring(2), out parkspaceID);
            if (parse_result)
            {
                return parkspaceID;
            }
            else
            {
                return -1;
            }
        }

        /// <summary>
        /// 获取状态对应颜色
        /// </summary>
        /// <param name="status"></param>
        /// <returns></returns>
        private Color GetPSColor(Parkspace_status status)
        {
            switch (status)
            {
                case Parkspace_status.EParkspaceEmpty: return Color.White;
                case Parkspace_status.EParkspaceOccupied: return Color.Yellow;
                case Parkspace_status.EParkspaceReserved: return Color.SkyBlue;
                case Parkspace_status.EParkspaceLocked: return Color.LightGreen;
                case Parkspace_status.EParkspaceError: return Color.Red;
                default: return Color.Violet;
            }
        }

        private void FormParkSpaceStatus_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            this.Visible = false;
        }

        private void FormParkSpaceStatus_FormClosed(object sender, FormClosedEventArgs e)
        {
            try
            {
                if (m_update_display_thread != null)
                {
                    m_update_display_thread.Abort();
                }
            }
            catch { Console.WriteLine("线程退出"); }
            //s_isClosing = true;
            ////if (m_update_display_thread != null)
            ////{
            ////    m_update_display_thread.Join();
            ////}
            //Communicator.Instance.Uninit();
        }
    }
}
