using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace KinectCar
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows;
    using Microsoft.Kinect;
    using uPLibrary.Networking.M2Mqtt;
    using System.Net;
    using uPLibrary.Networking.M2Mqtt.Messages;
    using System.Text;

    /// <summary>       
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : INotifyPropertyChanged
    {
        // 活动的 Kinect 传感器
        private KinectSensor _kinectSensor = null;
        // 坐标映射器将一种类型的点映射到另一种
        private CoordinateMapper _coordinateMapper = null;
        // 身体框架渲染器
        private BodyFrameReader _bodyFrameReader = null;
        // 颜色框架渲染器
        private ColorFrameReader _colorFrameReader = null;
        // 身体的数组
        private Body[] _bodies = null;
        // 骨骼的定义
        private List<Tuple<JointType, JointType>> _bones;
        // 显示宽度，高度（深度空间）
        private int _displayWidth, _displayHeight;
        // 要显示的当前状态文本
        private string _statusText = null;
        // 阈值（1/2框）（单位：米）
        private const float Threshold = 0.15f;
        // 当前状态
        private int _gesture = -1;
        // Bitmap to display
        private WriteableBitmap _colorBitmap;

        private static string MQTT_BROKER_ADDRESS = "123.207.151.92";
        // 创建客户端实例
        MqttClient _client = new MqttClient(IPAddress.Parse(MQTT_BROKER_ADDRESS), 1600, false, null, null, MqttSslProtocols.None); // 主机为IP时

        // INotifyPropertyChangedPropertyChanged 事件允许窗口控件绑定到可更改的数据
        public event PropertyChangedEventHandler PropertyChanged;

        public string StatusText
        {
            get
            {
                return _statusText;
            }

            set
            {
                if (_statusText == value) return;
                _statusText = value;
                // 通知任何绑定元素文本已更改
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("StatusText"));
            }
        }

        public MainWindow()
        {
            // 目前支持一个传感器
            _kinectSensor = KinectSensor.GetDefault();
            // 获取坐标映射器
            _coordinateMapper = _kinectSensor.CoordinateMapper;
            // 获取深度（显示）范围
            var frameDescription = _kinectSensor.DepthFrameSource.FrameDescription;
            // 得到关节空间的大小
            _displayWidth = frameDescription.Width;
            _displayHeight = frameDescription.Height;
            // 打开身体框架的渲染器
            _bodyFrameReader = _kinectSensor.BodyFrameSource.OpenReader();
            // 打开颜色框架的渲染器
            _colorFrameReader = _kinectSensor.ColorFrameSource.OpenReader();
            // 设置数据回调
            if (_bodyFrameReader != null)
            {
                _bodyFrameReader.FrameArrived += Reader_FrameArrived;
            }
            if (_colorFrameReader != null)
            {
                _colorFrameReader.FrameArrived += Reader_ColorFrameArrived;
            }
            // 利用 BGRA 格式创建颜色描述来自颜色来源
            var colorFrameDescription = _kinectSensor.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);
            // 创建要显示的位图
            _colorBitmap = new WriteableBitmap(colorFrameDescription.Width, colorFrameDescription.Height, 96.0, 96.0, PixelFormats.Bgr32, null);

            // 设置 IsAvailableChanged 事件通知程序
            _kinectSensor.IsAvailableChanged += Sensor_IsAvailableChanged;
            // 打开传感器
            _kinectSensor.Open();

            // 骨骼定义为两个关节之间的线
            _bones = new List<Tuple<JointType, JointType>>
            {
                // 躯干
                new Tuple<JointType, JointType>(JointType.Head, JointType.Neck),
                new Tuple<JointType, JointType>(JointType.Neck, JointType.SpineShoulder),
                new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.SpineMid),
                new Tuple<JointType, JointType>(JointType.SpineMid, JointType.SpineBase),
                new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.ShoulderRight),
                new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.ShoulderLeft),
                new Tuple<JointType, JointType>(JointType.SpineBase, JointType.HipRight),
                new Tuple<JointType, JointType>(JointType.SpineBase, JointType.HipLeft),
                // 右臂
                new Tuple<JointType, JointType>(JointType.ShoulderRight, JointType.ElbowRight),
                new Tuple<JointType, JointType>(JointType.ElbowRight, JointType.WristRight),
                new Tuple<JointType, JointType>(JointType.WristRight, JointType.HandRight),
                new Tuple<JointType, JointType>(JointType.HandRight, JointType.HandTipRight),
                new Tuple<JointType, JointType>(JointType.WristRight, JointType.ThumbRight),
                // 左臂
                new Tuple<JointType, JointType>(JointType.ShoulderLeft, JointType.ElbowLeft),
                new Tuple<JointType, JointType>(JointType.ElbowLeft, JointType.WristLeft),
                new Tuple<JointType, JointType>(JointType.WristLeft, JointType.HandLeft),
                new Tuple<JointType, JointType>(JointType.HandLeft, JointType.HandTipLeft),
                new Tuple<JointType, JointType>(JointType.WristLeft, JointType.ThumbLeft),
                // 右腿
                new Tuple<JointType, JointType>(JointType.HipRight, JointType.KneeRight),
                new Tuple<JointType, JointType>(JointType.KneeRight, JointType.AnkleRight),
                new Tuple<JointType, JointType>(JointType.AnkleRight, JointType.FootRight),
                // 左腿
                new Tuple<JointType, JointType>(JointType.HipLeft, JointType.KneeLeft),
                new Tuple<JointType, JointType>(JointType.KneeLeft, JointType.AnkleLeft),
                new Tuple<JointType, JointType>(JointType.AnkleLeft, JointType.FootLeft)
            };
            
            // 设置状态文本
            StatusText = _kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText : Properties.Resources.NoSensorStatusText;
            // 在这个简单的例子中使用window对象作为视图模型
            DataContext = this;
            // 初始化窗口的组件（控件）
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // 注册消息接收处理事件，还可以注册消息订阅成功、取消订阅成功、与服务器断开等事件处理函数
            _client.MqttMsgPublishReceived += ClientMqttMsgPublishReceived;
            //生成客户端 ID 并连接服务器
            var clientId = Guid.NewGuid().ToString();
            _client.Connect(clientId, "yumin", "minbb.cn");
            // 订阅主题"" 消息质量为 2
            _client.Subscribe(new string[] { "iot.time" }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
            // 发布消息到主题 "wifi/car" 消息质量为 2,不保留 
            _client.Publish("iot.all", Encoding.UTF8.GetBytes("I'm C#"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (_bodyFrameReader != null)
            {
                _bodyFrameReader.Dispose();
                _bodyFrameReader = null;
            }

            if (_colorFrameReader != null)
            {
                _colorFrameReader.Dispose();
                _colorFrameReader = null;
            }

            if (_kinectSensor != null)
            {
                _kinectSensor.Close();
                _kinectSensor = null;
            }

            _client?.Disconnect();
        }

        private void ClientMqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
        {
            //处理接收到的消息
            string msg = Encoding.Default.GetString(e.Message);
            Console.WriteLine("收到消息 = " + msg + "\r\n");
        }

        private void Reader_FrameArrived(object sender, BodyFrameArrivedEventArgs e)
        {
            bool dataReceived = false;
            using (BodyFrame bodyFrame = e.FrameReference.AcquireFrame())
            {
                if (bodyFrame != null)
                {
                    if (_bodies == null)
                    {
                        _bodies = new Body[bodyFrame.BodyCount];
                    }
                    // 第一次调用GetAndRefreshBodyData时，Kinect将在数组中分配每个Body。只要这些主体对象没有被释放并且在数组中没有设置为null，那么这些主体对象将被重用。
                    bodyFrame.GetAndRefreshBodyData(_bodies);
                    dataReceived = true;
                }
            }

            if (dataReceived)
            {
                foreach (Body body in _bodies)
                {
                    if (body.IsTracked)
                    {
                        Status.Content = "追踪到Body.";
                        IReadOnlyDictionary<JointType, Joint> joints = body.Joints;

                        Joint jointHandRight = joints[JointType.HandRight], jointShoulderRight = joints[JointType.ShoulderRight];
                        CameraSpacePoint positionHandRight = jointHandRight.Position, positionShoulderRight = jointShoulderRight.Position;
                        if (jointHandRight.TrackingState == TrackingState.Tracked &&
                            jointShoulderRight.TrackingState == TrackingState.Tracked)
                        {
                            float xHandRight = positionHandRight.X, yHandRight = positionHandRight.Y;
                            float xShoulderRight = positionShoulderRight.X, yShoulderRight = positionShoulderRight.Y;
                            // 右手位置判定（基于右肩为原点且无深度检测）
                            if (xHandRight >= 2 * xShoulderRight - Threshold && xHandRight <= 2 * xShoulderRight + Threshold && 
                                yHandRight >= 2 * yShoulderRight - Threshold && yHandRight <= 2 * yShoulderRight + Threshold)
                            {
                                // 中 - 5
                                if(_gesture != 5)
                                {
                                    _gesture = 5;
                                    Console.WriteLine("中");
                                }
                            }
                            else if(xHandRight > 2 * xShoulderRight - Threshold && xHandRight < 2 * xShoulderRight + Threshold && yHandRight > 2 * yShoulderRight + Threshold)
                            {
                                // 上 - 2
                                if (_gesture != 2)
                                {
                                    _gesture = 2;
                                    Console.WriteLine("上");
                                }
                            }
                            else if (xHandRight > 2 * xShoulderRight - Threshold && xHandRight < 2 * xShoulderRight + Threshold && yHandRight < 2 * yShoulderRight + Threshold)
                            {
                                // 下 - 8
                                if (_gesture != 8)
                                {
                                    _gesture = 8;
                                    Console.WriteLine("下");
                                }
                            }
                            else if (xHandRight < 2 * xShoulderRight - Threshold && yHandRight > 2 * yShoulderRight - Threshold && yHandRight < 2 * yShoulderRight + Threshold)
                            {
                                // 左 - 4
                                if (_gesture != 4)
                                {
                                    _gesture = 4;
                                    Console.WriteLine("左");
                                }
                            }
                            else if (xHandRight > 2 * xShoulderRight + Threshold && yHandRight > 2 * yShoulderRight - Threshold && yHandRight < 2 * yShoulderRight + Threshold)
                            {
                                // 右 - 6
                                if (_gesture != 6)
                                {
                                    _gesture = 6;
                                    Console.WriteLine("右");
                                }
                            }
                            else if (xHandRight > 2 * xShoulderRight + Threshold && yHandRight > 2 * yShoulderRight + Threshold)
                            {
                                // 右上 - 3
                                if (_gesture != 3)
                                {
                                    _gesture = 3;
                                    Console.WriteLine("右上");
                                }
                            }
                            else if (xHandRight > 2 * xShoulderRight + Threshold && yHandRight < 2 * yShoulderRight - Threshold)
                            {
                                // 右下 - 9
                                if (_gesture != 9)
                                {
                                    _gesture = 9;
                                    Console.WriteLine("右下");
                                }
                            }
                            else if (xHandRight < 2 * xShoulderRight - Threshold && yHandRight > 2 * yShoulderRight + Threshold)
                            {
                                // 左上 - 1
                                if (_gesture != 1)
                                {
                                    _gesture = 1;
                                    Console.WriteLine("左上");
                                }
                            }
                            else if (xHandRight < 2 * xShoulderRight - Threshold && yHandRight < 2 * yShoulderRight - Threshold)
                            {
                                // 左下 - 7
                                if (_gesture != 7)
                                {
                                    _gesture = 7;
                                    Console.WriteLine("左下");
                                }
                            }
                            //Console.WriteLine("X = " + positionHead.X + ", Y = " + positionHead.Y + ", Z = " + positionHead.Z);
                            //Console.WriteLine("X = " + positionHandRight.X + ", Y = " + positionHandRight.Y + ", Z = " + positionHandRight.Z);
                        }

                        // 将关节点转换为深度（显示）空间
                        //Dictionary<JointType, Point> jointPoints = new Dictionary<JointType, Point>();
                        //foreach (JointType jointType in joints.Keys)
                        //{
                        //    DepthSpacePoint depthSpacePoint = coordinateMapper.MapCameraPointToDepthSpace(positionHead);
                        //    jointPoints[jointType] = new Point(depthSpacePoint.X, depthSpacePoint.Y);
                        //}
                    }
                }
            }
            else
            {
                Status.Content = "无";
            }
        }

        private void Reader_ColorFrameArrived(object sender, ColorFrameArrivedEventArgs e)
        {
            // ColorFrame is IDisposable
            using (var colorFrame = e.FrameReference.AcquireFrame())
            {
                if (colorFrame != null)
                {
                    var colorFrameDescription = colorFrame.FrameDescription;
                    using (var colorBuffer = colorFrame.LockRawImageBuffer())
                    {
                        _colorBitmap.Lock();
                        // verify data and write the new color frame data to the display bitmap
                        if ((colorFrameDescription.Width == _colorBitmap.PixelWidth) && (colorFrameDescription.Height == _colorBitmap.PixelHeight))
                        {
                            colorFrame.CopyConvertedFrameDataToIntPtr(_colorBitmap.BackBuffer,
                                (uint)(colorFrameDescription.Width * colorFrameDescription.Height * 4),
                                ColorImageFormat.Bgra);
                            var rect = new Int32Rect(0, 0, _colorBitmap.PixelWidth, _colorBitmap.PixelHeight);
                            Console.WriteLine(rect == null);
                            _colorBitmap.AddDirtyRect(rect);
                            Console.WriteLine(_colorBitmap == null);
                            Console.WriteLine(Image.Source == null);
                        }
                        _colorBitmap.Unlock();
                    }
                }
            }
        }

        private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e)
        {
            // 如果失败，设置状态文本
            StatusText = _kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText : Properties.Resources.SensorNotAvailableStatusText;
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Escape:
                    ToolBar.Visibility = Visibility.Visible;
                    ViewBox.Margin = new Thickness { Left = 0, Top = 32, Right = 0, Bottom = 0 };
                    WindowState = WindowState.Normal;
                    WindowStyle = WindowStyle.SingleBorderWindow;
                    break;
                case Key.Space:
                    //var bitmapImage = new BitmapImage(new Uri("I:\\图片\\background.jpg", UriKind.Absolute));
                    //_colorBitmap = new WriteableBitmap(bitmapImage);
                    //StatusText = DateTime.Now.ToLongTimeString();
                    break;
            }
        }

        private void Settings_Click(object sender, RoutedEventArgs e)
        {
            new SettingsWindow().ShowDialog();
        }

        private void FullScreen_Click(object sender, RoutedEventArgs e)
        {
            ToolBar.Visibility = Visibility.Hidden;
            ViewBox.Margin = new Thickness { Left = 0, Top = 0, Right = 0, Bottom = 0 };
            Topmost = false;
            WindowStyle = WindowStyle.None;
            WindowState = WindowState.Maximized;
        }

        public ImageSource ImageSource => _colorBitmap;
    }
}
