//>>> _using
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SharpDX;
using SharpDX.Direct3D11;
using SharpDX.Windows;
//<<< _using
using System.Dynamic;
using Microsoft.Kinect;
using Framefield.Core.Inputs;

namespace Framefield.Core.ID17235625_8f38_49ab_be49_f564cbb5bcfa
{
    public class Class_KinectBodyFor1 : OperatorPart.Function, Framefield.Core.OperatorPartTraits.IAsyncDependend
    {
        public bool AsyncChanged { get { return _asyncChanged; } }

        //>>> _outputids
        private enum OutputId
        {
            PositionX = 0,
            PositionY = 1,
            PositionZ = 2,
            RotationX = 3,
            RotationY = 4,
            RotationZ = 5,
            RotationW = 6,
            Tracked = 7
        }
        //<<< _outputids

        //>>> _inputids
        private enum InputId
        {
            Skeletons = 0,
            Joint = 1,
            InputRangeXMin = 2,
            InputRangeXMax = 3,
            InputRangeYMin = 4,
            InputRangeYMax = 5,
            InputRangeZMin = 6,
            InputRangeZMax = 7,
            FallbackPositionX = 8,
            FallbackPositionY = 9,
            FallbackPositionZ = 10,
            EnableMouse = 11
        }
        //<<< _inputids

        public override void Dispose()
        {
            Input.Mouse.MouseInputEvent -= HandleMouseInputEvent;
        }

        void HandleMouseInputEvent(object o, MouseInput.MouseEventArgs e)
        {
            _lastEventArgs = e;
            _asyncChanged = true;

            if (e.ButtonFlags.HasFlag(MouseInput.ButtonFlags.MiddleButtonDown))
            {
                _dragX = 0;
                _dragY = 0;
            }
            if (e.ButtonFlags.HasFlag(MouseInput.ButtonFlags.LeftButtonDown))
            {
                _pressed = true;
            }
            if (e.ButtonFlags.HasFlag(MouseInput.ButtonFlags.LeftButtonUp))
            {
                _pressed = false;
                _dragX = 0;
                _dragY = 0;
            }
            if (_pressed)
            {
                _dragX += e.X;
                _dragY += e.Y;
            }            
        }

        public Class_KinectBodyFor1()
        {
            Input.Mouse.MouseInputEvent += HandleMouseInputEvent;   
        }

        public override OperatorPartContext Eval(OperatorPartContext context, List<OperatorPart> inputs, int outputIdx)
        {
            // params
            var Skeletons = inputs[(int)InputId.Skeletons].Eval(context).Dynamic; 
            var Joint = (int) inputs[(int)InputId.Joint].Eval(context).Value;
            var InputRangeXMin = inputs[(int)InputId.InputRangeXMin].Eval(context).Value;
            var InputRangeXMax = inputs[(int)InputId.InputRangeXMax].Eval(context).Value;
            var InputRangeX = new Vector2(InputRangeXMin, InputRangeXMax);
            var InputRangeYMin = inputs[(int)InputId.InputRangeYMin].Eval(context).Value;
            var InputRangeYMax = inputs[(int)InputId.InputRangeYMax].Eval(context).Value;
            var InputRangeY = new Vector2(InputRangeYMin, InputRangeYMax);
            var InputRangeZMin = inputs[(int)InputId.InputRangeZMin].Eval(context).Value;
            var InputRangeZMax = inputs[(int)InputId.InputRangeZMax].Eval(context).Value;
            var InputRangeZ = new Vector2(InputRangeZMin, InputRangeZMax);
            var FallbackPositionX = inputs[(int)InputId.FallbackPositionX].Eval(context).Value;
            var FallbackPositionY = inputs[(int)InputId.FallbackPositionY].Eval(context).Value;
            var FallbackPositionZ = inputs[(int)InputId.FallbackPositionZ].Eval(context).Value;
            var FallbackPosition = new Vector3(FallbackPositionX, FallbackPositionY, FallbackPositionZ);
            var EnableMouse = inputs[(int)InputId.EnableMouse].Eval(context).Value;
            // params

            SkeletonPoint position = new SkeletonPoint {X = FallbackPosition.X, Y = FallbackPosition.Y, Z = FallbackPosition.Z};
            Microsoft.Kinect.Vector4 rotation = new Microsoft.Kinect.Vector4 {X = 0.0f, Y = 0.0f, Z = 0.0f, W = 1.0f};
            bool isTracked = false;

            var skeletonMembers = Skeletons as IDictionary<String, object>;
            if (skeletonMembers != null && skeletonMembers.ContainsKey("TrackedSkeletons"))
            {
                Skeleton skeleton = null;
                float minSkeletonValue = 99999;
                foreach (var s in Skeletons.TrackedSkeletons)
                {
                    float skeletonValue = s.Position.Z + Math.Abs(s.Position.X);
                    if (s.TrackingState == SkeletonTrackingState.Tracked && skeletonValue < minSkeletonValue)
                    {
                        skeleton = s;
                        minSkeletonValue = skeletonValue;
                    }
                }

                if (skeleton != null)
                {
                    BoneOrientation orientation = skeleton.BoneOrientations[(JointType)Joint];
                    Joint startJoint = skeleton.Joints[orientation.StartJoint];
                    Joint endJoint = skeleton.Joints[orientation.EndJoint];
    
                    //uncomment the lines to only use position and orientation if at least on joint
                    //was tracked.
                    if (startJoint.TrackingState != JointTrackingState.NotTracked && endJoint.TrackingState != JointTrackingState.NotTracked)// &&
                        //(startJoint.TrackingState != JointTrackingState.Inferred || endJoint.TrackingState != JointTrackingState.Inferred))
                    {
                        position = endJoint.Position;
                        rotation = orientation.AbsoluteRotation.Quaternion;
                        isTracked = true;
                    }
                }
            }

            context.Value = 0;
            if (EnableMouse < 0.5)
            {
                _dragX = 0.0;
                _dragY = 0.0;
            }
            
            switch (outputIdx)
            {
                case (int)OutputId.PositionX: context.Value = ((position.X + (float)_dragX*0.002f) - InputRangeXMin) / (InputRangeXMax-InputRangeXMin); break;
                case (int)OutputId.PositionY: context.Value = ((position.Y - (float)_dragY*0.002f) - InputRangeYMin) / (InputRangeYMax-InputRangeYMin); break;
                case (int)OutputId.PositionZ: context.Value = ( position.Z                         - InputRangeZMin) / (InputRangeZMax-InputRangeZMin); break;
                case (int)OutputId.RotationX: context.Value = rotation.X; break;
                case (int)OutputId.RotationY: context.Value = rotation.Y; break;
                case (int)OutputId.RotationZ: context.Value = rotation.Z; break;
                case (int)OutputId.RotationW: context.Value = rotation.W; break;
                case (int)OutputId.Tracked: context.Value = isTracked ? 1.0f : 0.0f; break;
            }

            _asyncChanged = false;
            return context;
        }

        MouseInput.MouseEventArgs _lastEventArgs;
        bool _pressed = false;
        double _dragX;
        double _dragY;
        bool _asyncChanged = false;
    }
}
