using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Threading;
using Microsoft.Kinect;
using System.Windows.Threading;
using System.Threading.Tasks;

namespace TeacherAssitant
{
    /// <summary>
    /// Interaction logic for Cover.xaml
    /// </summary>
    partial class Cover : Window
    {


        /// <summary>
        /// The Kinect.
        /// </summary>
        private KinectSensor sensor;

        /// <summary>
        /// Current skeleton data for all the players.
        /// </summary>
        private Skeleton[] skeletonData;

        /// <summary>
        /// Timer to manage elevation update tasks. 
        /// </summary>
        private readonly DispatcherTimer debounce = new DispatcherTimer { IsEnabled = false, Interval = TimeSpan.FromMilliseconds(200) };

        /// <summary>
        /// Current elevation.
        /// </summary>
        private int elevation;

        /// <summary>
        /// Flag. Helps the management of the elevation update tasks.
        /// </summary>
        private bool backgroundUpdateInProgress = false;

        /// <summary>
        /// Teachers.
        /// </summary>
        private readonly Dictionary<int, Teacher> teachers = new Dictionary<int, Teacher>();

        private Teacher activeTeacher;

        private JointType activeHand;

        #region Images

        private Image actualCursor;

        private Image handCursor;

        private Image[] selectionAni;

        private TextBlock txtMsg;

        #endregion Images

        private PowerPointPresentation selection;
        private PptControls controlSelection;
        private int counter;
        private int secCounter;
        private Image actualSelectionAni;

        public Rectangle pptPreviousSlider;
        public Rectangle pptSliderLeftZone;
        public Rectangle pptSliderRightZone;
        public Rectangle pptNextSlider;
        public Image prevArrow;
        public Image nextArrow;
        public Image pptCerrar;
        public Line sliderPosition;

        private double x;
        private double y;

        private MainWindow principal;

        public Cover(MainWindow principal)
        {
            this.principal = principal;

            //Config
            elevation = 10;
            activeHand = JointType.HandRight;
            principal.uniqueName = "Usuario XYZ";

            InitializeComponent();
            Init();
        }

        private void Init()
        {
            initializeImages();
            txtMsg = new TextBlock { Text = "Status", Foreground = Brushes.White };
            Canvas.SetLeft(txtMsg, 50);
            Canvas.SetTop(txtMsg, 10);
            mainCanvas.Children.Add(txtMsg);
            Canvas.SetZIndex(txtMsg,98);

            //Sets the callback for the debounce clock tick.
            this.debounce.Tick += this.DebounceElapsed;

            //Sets the callback to identify a new Kinect sensor.
            kinectSensorChooser1.KinectSensorChanged += new DependencyPropertyChangedEventHandler(kinectSensorChooser1_KinectSensorChanged);
        }

        private void initializeImages()
        {
            handCursor = new Image();
            handCursor.Source = new BitmapImage(new Uri("data/img/cursor1.png", UriKind.RelativeOrAbsolute));

            selectionAni = new Image[10];
            for (int i = 0; i < 10; i++)
            {
                selectionAni[i] = new Image();
                selectionAni[i].Source = new BitmapImage(new Uri("data/img/selctionAni" + (i + 1) + ".png", UriKind.RelativeOrAbsolute));
            }

            nextArrow = new Image();
            nextArrow.Source = new BitmapImage(new Uri("data/img/nextarrow.png", UriKind.RelativeOrAbsolute));
            prevArrow = new Image();
            prevArrow.Source = new BitmapImage(new Uri("data/img/prevarrow.png", UriKind.RelativeOrAbsolute));
            pptCerrar = new Image();
            pptCerrar.Source = new BitmapImage(new Uri("data/img/cerrar.png", UriKind.RelativeOrAbsolute));
        }
        
        /// <summary>
        /// This callback is invoked each time a new Kinect sensor is identified.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void kinectSensorChooser1_KinectSensorChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            //Stop last sensor.
            KinectSensor oldSensor = (KinectSensor)e.OldValue;
            StopKinect(oldSensor);

            //Enable depth, skeleton and color stream.
            KinectSensor newSensor = (KinectSensor)e.NewValue;
            sensor = newSensor;
            newSensor.DepthStream.Enable();
            newSensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);
            newSensor.SkeletonStream.Enable(new TransformSmoothParameters()
            {
                Smoothing = 0.5f,
                Correction = 0.3f,
                Prediction = 0.3f,
                JitterRadius = 1.0f,
                MaxDeviationRadius = 1.0f
            });

            //Add callbacks for depth frame and skeleton frame.
            newSensor.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(skeletonFrameReady);

            //Add the Kinect to the skeleton viewer.
            kinectSkeletonViewer1.Kinect = newSensor;
            kinectColorViewer1.Kinect = newSensor;

            try
            {
                //Start the stream nad reset the elevation angle.
                newSensor.Start();
                ElevationAngleChanged();
                updateStatus("started");
            }
            catch (System.IO.IOException)
            {
                kinectSensorChooser1.AppConflictOccurred();
                return;
            }
        }


        public void updateCursorPosition(double[] position)
        {
            if (position != null)
            {
                if (actualCursor == null)
                {
                    actualCursor = handCursor;
                    mainCanvas.Children.Add(actualCursor); 
                    Canvas.SetZIndex(actualCursor,99);
                }

                x = position[0];
                y = position[1];
                Canvas.SetLeft(actualCursor, position[0] - (actualCursor.ActualWidth / 2));
                Canvas.SetTop(actualCursor, position[1] - (actualCursor.ActualHeight / 2));

                if (actualSelectionAni != null)
                {
                    Canvas.SetLeft(actualSelectionAni, x - (actualSelectionAni.ActualWidth / 2));
                    Canvas.SetTop(actualSelectionAni, y - (actualSelectionAni.ActualHeight / 2));
                }
            }
            else
            {
                if (actualCursor != null)
                {
                    mainCanvas.Children.Remove(actualCursor);
                    actualCursor = null;
                }
            }
        }

        public void updateStatus(string txt)
        {
            txtMsg.Text = txt;
        }

        public void advanceSelection(PowerPointPresentation ppt, Func<PowerPointPresentation, int> retreive)
        {
            if (ppt == selection)
            {
                secCounter++;
                if (secCounter == 5)
                {
                    secCounter = 0;

                    counter++;
                    if (counter == 11)
                    {
                        retreive(selection);
                        selection = null;
                        counter = 0;
                    }
                    else
                    {
                        if (actualSelectionAni != null)
                        {
                            mainCanvas.Children.Remove(actualSelectionAni);
                        }

                        actualSelectionAni = selectionAni[counter - 1];
                        Canvas.SetLeft(actualSelectionAni, x - (actualSelectionAni.ActualWidth / 2));
                        Canvas.SetTop(actualSelectionAni, y - (actualSelectionAni.ActualHeight / 2));
                        mainCanvas.Children.Add(actualSelectionAni);
                        Canvas.SetZIndex(actualSelectionAni,99);
                    }
                }
            }
            else
            {
                selection = ppt;
                counter = 1;
                secCounter = 0;

                if (actualSelectionAni != null)
                {
                    mainCanvas.Children.Remove(actualSelectionAni);
                }

                actualSelectionAni = selectionAni[counter - 1];
                Canvas.SetLeft(actualSelectionAni, x - (actualSelectionAni.ActualWidth / 2));
                Canvas.SetTop(actualSelectionAni, y - (actualSelectionAni.ActualHeight / 2));
                mainCanvas.Children.Add(actualSelectionAni); 
                Canvas.SetZIndex(actualSelectionAni,99);
            }
        }

        public void noSelection()
        {
            selection = null;
            counter = 1;
            secCounter = 0;

            if (actualSelectionAni != null)
            {
                mainCanvas.Children.Remove(actualSelectionAni);
            }
        }

        public void loadPresentationControls()
        {
            pptPreviousSlider = new Rectangle
            {
                Width = mainCanvas.ActualWidth - 400,
                Height = 300,
                Fill = new LinearGradientBrush(Color.FromArgb(200, 0, 250, 250), Color.FromArgb(50, 0, 250, 250), 0)
            };
            pptSliderRightZone = new Rectangle
            {
                Width = 100,
                Height = 300,
                Stroke = new SolidColorBrush(Color.FromArgb(200, 0, 250, 250)),
                StrokeThickness = 2
            };
            pptNextSlider = new Rectangle
            {
                Width = mainCanvas.ActualWidth - 400,
                Height = 300,
                Fill = new LinearGradientBrush(Color.FromArgb(50, 0, 250, 250), Color.FromArgb(200, 0, 250, 250), 0)
            };
            pptSliderLeftZone = new Rectangle
            {
                Width = 100,
                Height = 300,
                Stroke = new SolidColorBrush(Color.FromArgb(200, 0, 250, 250)),
                StrokeThickness = 2
            };

            pptPreviousSlider.Opacity = 0;
            mainCanvas.Children.Add(pptPreviousSlider);
            Canvas.SetLeft(pptPreviousSlider, 200);
            Canvas.SetTop(pptPreviousSlider, mainCanvas.ActualHeight - 350);
            Canvas.SetZIndex(pptPreviousSlider,1);

            pptSliderRightZone.Opacity = 0;
            mainCanvas.Children.Add(pptSliderRightZone);
            Canvas.SetLeft(pptSliderRightZone, mainCanvas.ActualWidth - 300);
            Canvas.SetTop(pptSliderRightZone, mainCanvas.ActualHeight - 350);
            Canvas.SetZIndex(pptSliderRightZone,2);

            prevArrow.Opacity = 0;
            mainCanvas.Children.Add(prevArrow);
            Canvas.SetLeft(prevArrow, mainCanvas.ActualWidth / 2 - 80);
            Canvas.SetTop(prevArrow, mainCanvas.ActualHeight - 300 - 20);
            Canvas.SetZIndex(prevArrow,2);

            pptNextSlider.Opacity = 0;
            mainCanvas.Children.Add(pptNextSlider);
            Canvas.SetLeft(pptNextSlider, 200);
            Canvas.SetTop(pptNextSlider, mainCanvas.ActualHeight - 350);
            Canvas.SetZIndex(pptNextSlider,1);

            pptSliderLeftZone.Opacity = 0;
            mainCanvas.Children.Add(pptSliderLeftZone);
            Canvas.SetLeft(pptSliderLeftZone, 200);
            Canvas.SetTop(pptSliderLeftZone, mainCanvas.ActualHeight - 350);
            Canvas.SetZIndex(pptSliderLeftZone,2);

            nextArrow.Opacity = 0;
            mainCanvas.Children.Add(nextArrow);
            Canvas.SetLeft(nextArrow, mainCanvas.ActualWidth / 2 - 80);
            Canvas.SetTop(nextArrow, mainCanvas.ActualHeight - 300 - 20);
            Canvas.SetZIndex(nextArrow,2);

            //pptCerrar.Opacity = 0;
            mainCanvas.Children.Add(pptCerrar);
            Canvas.SetLeft(pptCerrar, 1000);
            Canvas.SetTop(pptCerrar, 20);
            Canvas.SetZIndex(pptCerrar,1);
        }

        public void unloadPresentationControls()
        {
            mainCanvas.Children.Remove(pptPreviousSlider);
            mainCanvas.Children.Remove(pptSliderRightZone);
            mainCanvas.Children.Remove(prevArrow);
            mainCanvas.Children.Remove(pptNextSlider);
            mainCanvas.Children.Remove(pptSliderLeftZone);
            mainCanvas.Children.Remove(nextArrow);
            mainCanvas.Children.Remove(pptCerrar);
        }

        public void notSelected(PptControls control)
        {
            if (control == PptControls.Cerrar && pptCerrar.Opacity > 0)
            {
                pptCerrar.Opacity -= 0.01;
            }
            else if (control == PptControls.NextSlider)
            {
                pptNextSlider.Opacity = 0;
                nextArrow.Opacity = 0;
                pptSliderLeftZone.Opacity = 0;
            }
            else if (control == PptControls.PrevSlider)
            {
                pptPreviousSlider.Opacity = 0;
                prevArrow.Opacity = 0;
                pptSliderRightZone.Opacity = 0;
            }
        }

        public bool isIn(double x, double y, PptControls control)
        {
            if (control == PptControls.Cerrar)
            {
                return x >= Canvas.GetLeft(pptCerrar) && x <= Canvas.GetLeft(pptCerrar) + pptCerrar.ActualWidth && y >= Canvas.GetTop(pptCerrar) && y <= Canvas.GetTop(pptCerrar) + pptCerrar.ActualHeight;
            }
            else if (control == PptControls.LeftSliderZone)
            {
                return x >= Canvas.GetLeft(pptSliderLeftZone) && x <= Canvas.GetLeft(pptSliderLeftZone) + pptSliderLeftZone.ActualWidth && y >= Canvas.GetTop(pptSliderLeftZone) && y <= Canvas.GetTop(pptSliderLeftZone) + pptSliderLeftZone.ActualHeight;
            }
            else if (control == PptControls.RightSliderZone)
            {
                return x >= Canvas.GetLeft(pptSliderRightZone) && x <= Canvas.GetLeft(pptSliderRightZone) + pptSliderRightZone.ActualWidth && y >= Canvas.GetTop(pptSliderRightZone) && y <= Canvas.GetTop(pptSliderRightZone) + pptSliderRightZone.ActualHeight;
            }
            else if (control == PptControls.NextSlider)
            {
                return x >= Canvas.GetLeft(pptNextSlider) && x <= Canvas.GetLeft(pptNextSlider) + pptNextSlider.ActualWidth && y >= Canvas.GetTop(pptNextSlider) && y <= Canvas.GetTop(pptNextSlider) + pptNextSlider.ActualHeight;
            }
            else if (control == PptControls.PrevSlider)
            {
                return x >= Canvas.GetLeft(pptPreviousSlider) && x <= Canvas.GetLeft(pptPreviousSlider) + pptPreviousSlider.ActualWidth && y >= Canvas.GetTop(pptPreviousSlider) && y <= Canvas.GetTop(pptPreviousSlider) + pptPreviousSlider.ActualHeight;
            }

            return false;
        }

        public bool isIn2(double x, double y, PptControls control)
        {
            if (control == PptControls.LeftSliderZone)
            {
                return x <= Canvas.GetLeft(pptSliderLeftZone) + pptSliderLeftZone.ActualWidth && y >= Canvas.GetTop(pptSliderLeftZone) && y <= Canvas.GetTop(pptSliderLeftZone) + pptSliderLeftZone.ActualHeight;
            }
            else if (control == PptControls.RightSliderZone)
            {
                return x >= Canvas.GetLeft(pptSliderRightZone) && y >= Canvas.GetTop(pptSliderRightZone) && y <= Canvas.GetTop(pptSliderRightZone) + pptSliderRightZone.ActualHeight;
            }

            return false;
        }

        public void advanceSelection(PptControls control, Func<int> retreive)
        {
            if (control == PptControls.Cerrar && pptCerrar.Opacity < 1)
            {
                pptCerrar.Opacity += 0.1;
            }

            if (control == controlSelection)
            {
                secCounter++;
                if (secCounter == 5)
                {
                    secCounter = 0;

                    counter++;
                    if (counter == 11)
                    {
                        retreive();
                        selection = null;
                        counter = 0;
                    }
                    else
                    {
                        if (actualSelectionAni != null)
                        {
                            mainCanvas.Children.Remove(actualSelectionAni);
                        }

                        actualSelectionAni = selectionAni[counter - 1];
                        Canvas.SetLeft(actualSelectionAni, x - (actualSelectionAni.ActualWidth / 2));
                        Canvas.SetTop(actualSelectionAni, y - (actualSelectionAni.ActualHeight / 2));
                        mainCanvas.Children.Add(actualSelectionAni);
                        Canvas.SetZIndex(actualSelectionAni,99);
                    }
                }
            }
            else
            {
                controlSelection = control;
                counter = 1;
                secCounter = 0;

                if (actualSelectionAni != null)
                {
                    mainCanvas.Children.Remove(actualSelectionAni);
                }

                actualSelectionAni = selectionAni[counter - 1];
                Canvas.SetLeft(actualSelectionAni, x - (actualSelectionAni.ActualWidth / 2));
                Canvas.SetTop(actualSelectionAni, y - (actualSelectionAni.ActualHeight / 2));
                mainCanvas.Children.Add(actualSelectionAni);
                Canvas.SetZIndex(actualSelectionAni,99);
            }
        }

        public void showNextSlider()
        {
            pptNextSlider.Opacity = 1;
            nextArrow.Opacity = 1;
            pptSliderLeftZone.Opacity = 1;
        }

        public void showPrevSlider()
        {
            pptPreviousSlider.Opacity = 1;
            prevArrow.Opacity = 1;
            pptSliderRightZone.Opacity = 1;
        }

        public void showSlider(double x)
        {
            if (sliderPosition != null)
            {
                mainCanvas.Children.Remove(sliderPosition);
                sliderPosition = null;
            }
            sliderPosition = new Line { X1 = x, X2 = x, Y1 = mainCanvas.ActualHeight - 350, Y2 = mainCanvas.ActualHeight - 50, Stroke = Brushes.LightGreen, StrokeThickness = 8 };
            mainCanvas.Children.Add(sliderPosition);
            Canvas.SetZIndex(sliderPosition, 98);
        }

        public void hideSlider()
        {
            if (sliderPosition != null)
            {
                mainCanvas.Children.Remove(sliderPosition);
                sliderPosition = null;
            }
        }

        public enum PptControls
        {
            NextSlider,
            PrevSlider,
            LeftSliderZone,
            RightSliderZone,
            Cerrar
        }

        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            kinectSkeletonViewer1.Kinect = null;
            kinectColorViewer1.Kinect = null;
            StopKinect(kinectSensorChooser1.Kinect);
            principal.Close();
        }

        /// <summary>
        /// Stops the Kinect services.
        /// </summary>
        /// <param name="sensor"></param>
        void StopKinect(KinectSensor sensor)
        {
            if (sensor != null)
            {
                sensor.Stop();
                //sensor.AudioSource.Stop();
                //this.mySpeechRecognizer.Stop();
                //this.mySpeechRecognizer.SaidSomething -= this.RecognizerSaidSomething;
                //this.mySpeechRecognizer.Dispose();
                //this.mySpeechRecognizer = null;
            }
        }


        /// <summary>
        /// Callback called every skeleton update.
        /// </summary>
        /// <param name="sender">object that sent the event</param>
        /// <param name="e">Skeletons information</param>
        public void skeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
        {
            using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
            {
                if (skeletonFrame != null)
                {
                    int skeletonSlot = 0;

                    if ((this.skeletonData == null) || (this.skeletonData.Length != skeletonFrame.SkeletonArrayLength))
                    {
                        this.skeletonData = new Skeleton[skeletonFrame.SkeletonArrayLength];
                    }

                    skeletonFrame.CopySkeletonDataTo(this.skeletonData);

                    double minDist = 100;
                    foreach (Skeleton skeleton in this.skeletonData)
                    {
                        if (SkeletonTrackingState.Tracked == skeleton.TrackingState)
                        {
                            //Identify if it is a new player.
                            Teacher teacher;
                            if (this.teachers.ContainsKey(skeletonSlot))
                            {
                                teacher = this.teachers[skeletonSlot];
                            }
                            else
                            {
                                teacher = new Teacher(skeletonSlot);
                                this.teachers.Add(skeletonSlot, teacher);
                            }

                            // Update player's bone and joint positions
                            if (skeleton.Joints.Count > 0)
                            {
                                teacher.LastUpdated = DateTime.Now;
                                teacher.IsAlive = true;
                                
                                double center = skeleton.Joints[JointType.HipCenter].Position.Z;
                                if (center < minDist)
                                {
                                    minDist = center;
                                    activeTeacher = teacher;

                                    JointType hand1 = activeHand;
                                    JointType hand2 = activeHand == JointType.HandRight ? JointType.HandLeft : JointType.HandRight;
                                    JointType elbow2 = activeHand == JointType.HandRight ? JointType.ElbowLeft : JointType.ElbowRight;

                                    bool fHC = skeleton.Joints[JointType.HipCenter].TrackingState == JointTrackingState.Tracked;
                                    bool fSC = skeleton.Joints[JointType.ShoulderCenter].TrackingState == JointTrackingState.Tracked || skeleton.Joints[JointType.ShoulderCenter].TrackingState == JointTrackingState.Inferred;
                                    bool fE2 = skeleton.Joints[elbow2].TrackingState == JointTrackingState.Tracked || skeleton.Joints[elbow2].TrackingState == JointTrackingState.Inferred;
                                    bool fh2 = skeleton.Joints[hand2].TrackingState == JointTrackingState.Tracked || skeleton.Joints[hand2].TrackingState == JointTrackingState.Inferred;
                                    bool fh1 = skeleton.Joints[hand1].TrackingState == JointTrackingState.Tracked || skeleton.Joints[hand1].TrackingState == JointTrackingState.Inferred;

                                    //updateStatus("before Tracked: " + fHC + "&&" + fSC + " &&" + fE2 + "&&" + fh2 + "&&" + fh1);
                                    if (fHC && fSC && fE2 && fh2 && fh1)
                                    {
                                        //vector 1
                                        double x1 = skeleton.Joints[hand2].Position.X - skeleton.Joints[elbow2].Position.X;
                                        double y1 = skeleton.Joints[hand2].Position.Y - skeleton.Joints[elbow2].Position.Y;
                                        double z1 = skeleton.Joints[hand2].Position.Z - skeleton.Joints[elbow2].Position.Z;

                                        //vector 2
                                        double x2 = skeleton.Joints[JointType.ShoulderCenter].Position.X - skeleton.Joints[JointType.HipCenter].Position.X;
                                        double y2 = skeleton.Joints[JointType.ShoulderCenter].Position.Y - skeleton.Joints[JointType.HipCenter].Position.Y;
                                        double z2 = skeleton.Joints[JointType.ShoulderCenter].Position.Z - skeleton.Joints[JointType.HipCenter].Position.Z;

                                        double bigScale = Math.Sqrt(x2 * x2 + y2 * y2 + z2 * z2);
                                        double cosAlpha = (x1 * x2 + y1 * y2 + z1 * z2) / (Math.Sqrt(x1 * x1 + y1 * y1 + z1 * z1) * bigScale);
                                        //updateStatus("cosalpha: " + cosAlpha);
                                        if (cosAlpha >= -0.5 && cosAlpha <= 0.5)
                                        {
                                            double scaleX = 1000;
                                            double scaleY = 2000;

                                            double p1X = skeleton.Joints[hand2].Position.X;
                                            double p1Y = skeleton.Joints[hand2].Position.Y;
                                            double p1Z = skeleton.Joints[hand2].Position.Z;

                                            double p2X = skeleton.Joints[hand1].Position.X;
                                            double p2Y = skeleton.Joints[hand1].Position.Y;
                                            double p2Z = skeleton.Joints[hand1].Position.Z;

                                            double A = y1*z2-z1*y2;
                                            double B = z1*x2-x1*z2;
                                            double C = x1*y2-y1*x2;
                                            double D = (z1*y2-y1*z2)*p1X+(x1*z2-z1*x2)*p1Y-(x1*y2-y1*x2)*p1Z;

                                            double mult = activeHand == JointType.HandRight ? 1 : -1;

                                            double distX = (mult*(A*p2X+B*p2Y+C*p2Z+D)/Math.Sqrt(A*A+B*B+C*C))/bigScale;
                                            //updateStatus("distX: " + distX);

                                            //vector 3
                                            double x3 = y1 * z2 - y2 * z1;
                                            double y3 = x2 * z1 - x1 * z2;
                                            double z3 = x1 * y2 - x2 * y1;

                                            double A2 = y2 * z3 - z2 * y3;
                                            double B2 = z2 * x3 - x2 * z3;
                                            double C2 = x2 * y3 - y2 * x3;
                                            double D2 = (z2 * y3 - y2 * z3) * p1X + (x2 * z3 - z2 * x3) * p1Y - (x2 * y3 - y2 * x3) * p1Z;

                                            double distY = ((-1) * (A2 * p2X + B2 * p2Y + C2 * p2Z + D2) / Math.Sqrt(A2 * A2 + B2 * B2 + C2 * C2)) / bigScale;
                                            //updateStatus("distY: " + distY);

                                            if(activeHand == JointType.HandRight)
                                                teacher.activeHandX = -300 + distX * scaleX;
                                            else
                                                teacher.activeHandX = 1500-distX * scaleX;
                                            teacher.activeHandY = distY*scaleY;
                                            teacher.hasActiveHand = true;
                                        }
                                        else
                                        {
                                            teacher.hasActiveHand = false;
                                        }
                                    }
                                    else
                                    {
                                        teacher.hasActiveHand = false;
                                    }
                                }
                            }

                        }

                        skeletonSlot++;
                    }
                }
            }
        }

        public double[] getCursorPosition()
        {
            if (activeTeacher != null && activeTeacher.hasActiveHand)
            {
                double[] position = { activeTeacher.activeHandX, activeTeacher.activeHandY };
                return position;
            }
            else
                return null;
        }


        # region Elevation Angle

        /// <summary>
        /// This method is called when a command to change the elevation is a call.
        /// </summary>
        private void ElevationAngleChanged()
        {
            this.debounce.Stop();
            this.debounce.Start();
        }


        /// <summary>
        /// Updates the elevation angle. 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DebounceElapsed(object sender, EventArgs e)
        {
            // The time has elapsed.  We may start it again later.
            this.debounce.Stop();
            int angleToSet = elevation;

            // Is there an update in progress?
            if (this.backgroundUpdateInProgress)
            {
                // Try again in a few moments.
                this.debounce.Start();
            }
            else
            {
                this.backgroundUpdateInProgress = true;

                Task.Factory.StartNew(
                    () =>
                    {
                        try
                        {
                            // Check for not null and running
                            if ((this.sensor != null) && this.sensor.IsRunning)
                            {
                                // We must wait at least 1 second, and call no more frequently than 15 times every 20 seconds
                                // So, we wait at least 1350ms afterwards before we set backgroundUpdateInProgress to false.
                                this.sensor.ElevationAngle = angleToSet;
                                Thread.Sleep(1350);
                            }
                        }
                        finally
                        {
                            this.backgroundUpdateInProgress = false;
                        }
                    }).ContinueWith(
                            results =>
                            {
                                // This can happen if the Kinect transitions from Running to not running
                                // after the check above but before setting the ElevationAngle.
                                if (results.IsFaulted)
                                {
                                    var exception = results.Exception;
                                }
                            });
            }
        }
        #endregion Elevation Angle

        #region steps

        private Rectangle rect;

        public Rectangle drawRect(double x, double y)
        {
            rect = new Rectangle
            {
                Width = 100,
                Height = 100,
                Fill = new SolidColorBrush(Color.FromArgb(200, 0, 250, 250)),
                Stroke = new SolidColorBrush(Color.FromArgb(250, 0, 250, 250)),
                StrokeThickness = 2
            };

            mainCanvas.Children.Add(rect);
            Canvas.SetLeft(rect, x);
            Canvas.SetTop(rect, y);
            Canvas.SetZIndex(rect, 97);
            return rect;
        }

        public void removeRect()
        {
            if (rect != null)
            {
                mainCanvas.Children.Remove(rect);
                rect = null;
            }
        }

        public Boolean isInRect(double x, double y)
        {
            return x >= Canvas.GetLeft(rect) && x <= Canvas.GetLeft(rect) + rect.ActualWidth && y >= Canvas.GetTop(rect) && y <= Canvas.GetTop(rect) + rect.ActualHeight;
        }

        #endregion steps


    }

}
