/*
* This file is part of the TraKERS\Middleware package.
*
* (c) IRI <http://www.iri.centrepompidou.fr/>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/*
 * Projet : TraKERS
 * Module : MIDDLEWARE
 * Sous-Module : Debug
 * Classe : DebugWindow
 * 
 * Auteur : alexandre.bastien@iri.centrepompidou.fr
 * 
 * Fonctionnalités : Reçoit des notifications des sous-modules Tracking, Communication et Exception.
 * Intéragit avec la fenêtre XAML de debug de façon à afficher un rendu visuel.
 */

using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Drawing;
using Microsoft.Kinect;
using System.Resources;
using System.Reflection;
using System.Timers;
using System.Configuration;
using System.IO;
using System.Collections.Specialized;

namespace Trakers.Debug
{
    public partial class DebugWindow : Window
    {
        //Nom du projet, afin de savoir quel menu charger et quel fichier de configuration utiliser (TraKERS ou BBM).
        private String projectName = "BBM";
        //Chemins du fichier de config.
        private String configPath;
        //private String projectName = "BBM";

        //Gestionnaire de ressources.
        private ResourceManager rm;

        //Paramètres du serveur TUIO.
        private OrderedDictionary config;

        //Images
        private String imgLocation;

        //Timer.
        private System.Timers.Timer _timer;
        //Membre permettant d'atteindre la classe KinectMain du sous-module Tracking.
        //private KinectMain kinectMain;
        //Tableau contenant une image en couleurs.
        private byte[] colorPixelData;
        //Indique si la kinect est allumée/éteinte.
        private bool on;
        //Indique si la fenêtre de debug est actuellement en cours de fermeture.
        private bool closing;
        //Indique si l'image doit être raffraichie.
        private Boolean refreshImage;

        //Images des mains.
        BitmapSource right_hand_onBitmap, right_hand_offBitmap, left_hand_onBitmap, left_hand_offBitmap;

        /*
        * Constructeur : Affiche la fenêtre de debug en lui passant en paramètre une instanciation de la
        * classe KinectMain.
        * Au départ, la kinect est éteinte.
        */
        public DebugWindow()
        {
            InitializeComponent();

            imgLocation = "Imgs";

            config = new OrderedDictionary();

            //On fait appel au gestionnaire de ressources.
            rm = new ResourceManager("Trakers.Debug.Properties.Resources", Assembly.GetExecutingAssembly());

            //On charge les éléments relatifs au projet.
            if (projectName.Equals("TraKERS"))
            {
                MiddlewareDebugWindow.Title = "TraKERS - Middleware";
                configPath = ".\\TraKERS - config.txt";
                loadTraKERSMenu();
            }
            else if (projectName.Equals("BBM"))
            {
                MiddlewareDebugWindow.Title = "Browse by Motion - Middleware";
                configPath = ".\\BBM - config.txt";
                loadBBMMenu();
            }

            //On initialise les images des mains.
            right_hand_onBitmap = CreateBitmapSourceFromBitmap(getImage(imgLocation + "\\right_hand_on.png"));
            right_hand_offBitmap = CreateBitmapSourceFromBitmap(getImage(imgLocation + "\\right_hand_off.png"));
            left_hand_onBitmap = CreateBitmapSourceFromBitmap(getImage(imgLocation + "\\left_hand_on.png"));
            left_hand_offBitmap = CreateBitmapSourceFromBitmap(getImage(imgLocation + "\\left_hand_off.png"));

            LeftHand.Source = left_hand_offBitmap;
            RightHand.Source = right_hand_offBitmap;
            //On initialise les images de proximité.
            Bitmap userBitmap = getImage(imgLocation + "\\user.png"), kinectBitmap = getImage(imgLocation + "\\kinect.png");
            UserImage.Source = CreateBitmapSourceFromBitmap(userBitmap);
            KinectImage.Source = CreateBitmapSourceFromBitmap(kinectBitmap);
            //On masque de base l'utilisateur car il est improbable qu'il soit détecté d'office.
            UserImage.Visibility = Visibility.Collapsed;

            //On tente de charger les paramètres du fichier params.ini.
            //Si on n'y arrive pas, on affiche une erreur et on charge les paramètres par défaut.
            if (!loadParameters())
            {
                ExceptionLbl.Content = rm.GetString("loadParametersFail");
                config.Clear();
                //Distances de détection des mains par défaut pour la recherche (ici de 1m à 2m de la Kinect).
                config.Add("minDistHands", 1.0f);
                config.Add("maxDistHands", 1.5f);
                config.Add("minDist", 1.0f);
                config.Add("maxDist", 4.0f);
                config.Add("zeroPoint", 1.7f);
                config.Add("tuioConnexionHost", "127.0.0.1");
                config.Add("tuioConnexionPort", 80);
                config.Add("wsConnexionHost", "127.0.0.1");
                config.Add("wsConnexionPort", 81);
                config.Add("tuioTimerElapsing", 1000);
                config.Add("wsTimerElapsing", 1000);
                config.Add("imagesToShow", 20);
                config.Add("takenPoints", 10);
                config.Add("directionChangeTresholdXY", 10);
                config.Add("directionChangeTresholdZ", 0.01f);

                if (projectName.Equals("TraKERS"))
                {
                    //On charge les paramètres relatifs à TraKERS.
                    //Chemins des readme et doc pour TraKERS.
                    config.Add("readmeTraKERSMiddleware", "..\\readme - TraKERS Middleware.txt");
                    config.Add("readmeTraKERSFrontProcessing", "..\\readme - TraKERS Front Processing.txt");
                    config.Add("docTraKERSFrontProcessing", "..\\tutorial - TraKERS Front Processing.html");
                    config.Add("readmeTraKERSFrontJS", "..\\readme - TraKERS Front Web.txt");
                    config.Add("docTraKERSFrontJS", "..\\tutorial - TraKERS Front JS et Wamp.html");
                    //Chemins des exemples processing.
                    config.Add("exPFMPS", "..\\Front Processing\\src\\Fluid_manipulation\\Fluid_manipulation.pde");
                    config.Add("exPFMExe", "..\\Front Processing\\src\\Fluid_manipulation\\application.windows\\Fluid_manipulation.exe");
                    config.Add("exPSMPS", "..\\Front Processing\\src\\Smoke_manipulation\\Smoke_manipulation.pde");
                    config.Add("exPSMExe", "..\\Front Processing\\src\\Smoke_manipulation\\application.windows\\Smoke_manipulation.exe");
                    config.Add("exPTPS", "..\\Front Processing\\src\\Trakers\\Trakers.pde");
                    config.Add("exPTExe", "..\\Front Processing\\src\\Trakers\\application.windows\\Trakers.exe");
                    config.Add("exPTGPS", "..\\Front Processing\\src\\Trakers_gestures\\Trakers_gestures.pde");
                    config.Add("exPTGExe", "..\\Front Processing\\src\\Trakers_gestures\\application.windows\\Trakers_gestures.exe");
                    config.Add("exPIEHand1DPS", "..\\Front Processing\\src\\Interaction_examples\\Hands_1D\\Hands_1D.pde");
                    config.Add("exPIEHand1DExe", "..\\Front Processing\\src\\Interaction_examples\\Hands_1D\\application.windows\\Hands_1D.exe");
                    config.Add("exPIEHand2DPS", "..\\Front Processing\\src\\Interaction_examples\\Hands_2D\\Hands_2D.pde");
                    config.Add("exPIEHand2DExe", "..\\Front Processing\\src\\Interaction_examples\\Hands_2D\\application.windows\\Hands_2D.exe");
                    config.Add("exPIEHandPressPS", "..\\Front Processing\\src\\Interaction_examples\\Hand_press\\Hand_press.pde");
                    config.Add("exPIEHandPressExe", "..\\Front Processing\\src\\Interaction_examples\\Hand_press\\application.windows\\Hand_press.exe");
                    config.Add("exPIEHandSignalPS", "..\\Front Processing\\src\\Interaction_examples\\Hand_signal\\Hand_signal.pde");
                    config.Add("exPIEHandSignalExe", "..\\Front Processing\\src\\Interaction_examples\\Hand_signal\\application.windows\\Hand_signal.exe");
                    //Chemins des exemples web.
                    config.Add("exWPointersPS", "C:\\wamp\\www\\Front JS\\pointers\\");
                    config.Add("exWPointersExe", "http://localhost/Front%20JS/pointers/");
                    config.Add("exWGesturesPS", "C:\\wamp\\www\\Front JS\\pointers\\");
                    config.Add("exWGesturesExe", "http://localhost/Front%20JS/gestures/");
                }
                else if (projectName.Equals("BBM"))
                {
                    //On charge les paramètres relatifs à BBM.
                    //Chemins des readme et doc pour BBM.
                    config.Add("readmeBBMMiddleware", "..\\readme - BBM Middleware.txt");
                    config.Add("docBBMFrontIDILL", "..\\Front IDILL\\Documentation - Front IDILL.html");
                    //Chemins du Front IDILL pour BBM.
                    config.Add("frontIDILLS", "C:\\wamp\\www\\Front IDILL\\");
                    config.Add("frontIDILLExe", "http://localhost/Front%20IDILL/");
                }
            }

            //On donne les noms des éléments du menu.
            FileMenu.Header = rm.GetString("menuFile");
            ReadmeMiddlewareMenu.Header = rm.GetString("menuReadmeMiddleware");
            
            QuitMenu.Header = rm.GetString("menuQuit");
            ConfigMenu.Header = rm.GetString("menuConfig");
            ParamMenu.Header = rm.GetString("menuParam");
            ParamMenuReboot.Header = rm.GetString("menuParamReboot");

            //kinectMain = main;
            on = true;
            closing = false;
            refreshImage = true;
            try
            {
                //On instancie les timers à N ms.
                _timer = new System.Timers.Timer((int)config["tuioTimerElapsing"]);
                //Dès que le timer est expiré, on appelle _timer_Elapsed.
                _timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
            }
            catch (Exception){}
        }

        /*
         Charge la partie du menu de TraKERS.
         */
        public void loadTraKERSMenu()
        {
            //On rend visible la partie du menu des readme et doc de TraKERS.
            ReadmeFrontProcessingMenu.Visibility = Visibility.Visible;
            DocumentationFrontProcessingMenu.Visibility = Visibility.Visible;
            ReadmeFrontJSMenu.Visibility = Visibility.Visible;
            DocumentationFrontJSMenu.Visibility = Visibility.Visible;
            //On rend visible la partie du menu des exemples Processing et Web de TraKERS.
            ExamplesMenu.Visibility = Visibility.Visible;

            //On cache la partie du menu des readme et doc de BBM.
            DocumentationFrontIDILLMenu.Visibility = Visibility.Collapsed;
            FrontIDILLMenu.Visibility = Visibility.Collapsed;

            //Readme et doc de TraKERS.
            ReadmeFrontProcessingMenu.Header = rm.GetString("menuReadmeFrontProcessing");
            DocumentationFrontProcessingMenu.Header = rm.GetString("menuDocFrontP");
            ReadmeFrontJSMenu.Header = rm.GetString("menuReadmeFrontJS");
            DocumentationFrontJSMenu.Header = rm.GetString("menuDocFrontJS");
            //Exemples de TraKERS.
            ExamplesMenu.Header = rm.GetString("menuEx");
            ProcessingMenu.Header = rm.GetString("menuExP");
            ProcessingMenuFM.Header = rm.GetString("menuExPFluid");
            ProcessingMenuFMPS.Header = rm.GetString("menuExSource");
            ProcessingMenuFMExe.Header = rm.GetString("menuExExe");
            ProcessingMenuSM.Header = rm.GetString("menuExPSmoke");
            ProcessingMenuSMPS.Header = rm.GetString("menuExSource");
            ProcessingMenuSMExe.Header = rm.GetString("menuExExe");
            ProcessingMenuIE.Header = rm.GetString("menuExPIE");
            ProcessingMenuIEHand1D.Header = rm.GetString("menuExPIEHand1D");
            ProcessingMenuIEHand1DPS.Header = rm.GetString("menuExSource");
            ProcessingMenuIEHand1DExe.Header = rm.GetString("menuExExe");
            ProcessingMenuIEHand2D.Header = rm.GetString("menuExPIEHand2D");
            ProcessingMenuIEHand2DPS.Header = rm.GetString("menuExSource");
            ProcessingMenuIEHand2DExe.Header = rm.GetString("menuExExe");
            ProcessingMenuIEHandPress.Header = rm.GetString("menuExPIEHandPress");
            ProcessingMenuIEHandPressPS.Header = rm.GetString("menuExSource");
            ProcessingMenuIEHandPressExe.Header = rm.GetString("menuExExe");
            ProcessingMenuIEHandSignal.Header = rm.GetString("menuExPIEHandSignal");
            ProcessingMenuIEHandSignalPS.Header = rm.GetString("menuExSource");
            ProcessingMenuIEHandSignalExe.Header = rm.GetString("menuExExe");
            ProcessingMenuT.Header = rm.GetString("menuExPT");
            ProcessingMenuTPS.Header = rm.GetString("menuExSource");
            ProcessingMenuTExe.Header = rm.GetString("menuExExe");
            ProcessingMenuTG.Header = rm.GetString("menuExPTG");
            ProcessingMenuTGPS.Header = rm.GetString("menuExSource");
            ProcessingMenuTGExe.Header = rm.GetString("menuExExe");
            WebMenu.Header = rm.GetString("menuExW");
            WebMenuPointers.Header = rm.GetString("menuExWPointers");
            WebMenuPointersPS.Header = rm.GetString("menuExSource");
            WebMenuPointersExe.Header = rm.GetString("menuExExe");
            WebMenuGestures.Header = rm.GetString("menuExWGestures");
            WebMenuGesturesPS.Header = rm.GetString("menuExSource");
            WebMenuGesturesExe.Header = rm.GetString("menuExExe");
        }

        /*
         Charge la partie du menu de BBM.
         */
        public void loadBBMMenu()
        {
            //On rend visible la partie du menu des readme et doc de BBM.
            DocumentationFrontIDILLMenu.Visibility = Visibility.Visible;
            //On rend visible la partie du menu du Front IDILL pour BBM.
            FrontIDILLMenu.Visibility = Visibility.Visible;
            
            //On cache la partie du menu des readme et doc de TraKERS.
            ReadmeFrontProcessingMenu.Visibility = Visibility.Collapsed;
            DocumentationFrontProcessingMenu.Visibility = Visibility.Collapsed;
            ReadmeFrontJSMenu.Visibility = Visibility.Collapsed;
            DocumentationFrontJSMenu.Visibility = Visibility.Collapsed;
            //On cache la partie du menu des exemples Processing et Web de TraKERS.
            menu.Items.Remove(ExamplesMenu);
            
            //Readme et doc de BBM.
            DocumentationFrontIDILLMenu.Header = rm.GetString("menuDocFrontIDILL");
            //Exemples de BBM.
            FrontIDILLMenu.Header = rm.GetString("menuFrontIDILL");
            FrontIDILLMenuS.Header = rm.GetString("menuFrontIDILLS");
            FrontIDILLMenuExe.Header = rm.GetString("menuFrontIDILLExe");
        }

        /*
         * Méthode d'effacement du label d'exceptions.
         */
        public void NoException()
        {
            ExceptionLbl.Content = "";
        }

        /*
         * Méthode d'affichage des exceptions dans le label d'exceptions.
         */
        public void ShowException(String reference)
        {
            ExceptionLbl.Content = rm.GetString(reference);
        }

        /*
         * Méthode de fermeture de l'interface.
         */
        public void ShutDownInterface()
        {
            DebugImage.Source = null;
            ExceptionLbl.Content = "";
        }

        /*
         * Méthode appelée à l'expiration du timer ws pour les gestures et modes.
         */
        public void _timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            //On débloque le raffraichissement de l'image.
            refreshImage = true;
            //On arrête le timer.
            _timer.Stop();
        }

        /*
        * Getter pour le membre indiquant la fermeture de la fenêtre de debug.
        */
        public bool isClosing()
        {
            return closing;
        }

        /*
         * Est appelé lors de la fermeture du Middleware par le menu.
         */
        private void QuitMenu_Click(object sender, RoutedEventArgs e)
        {
            closing = true;
            Application.Current.Shutdown();
        }

        /*
        * Est appelée à la fermeture de la fenêtre.
        */
        public void Window_Closed(object sender, EventArgs e)
        {
            closing = true;
        }

        /*
        * Bouton ON/OFF.
        */
        private void Switch_Click(object sender, RoutedEventArgs e)
        {
            //S'il valait faux, il vaut vrai maintenant et inversement.
            on = !on;
            //Si la kinect est allumée.
            if (on)
            {
                //Il affiche OFF (pour éteindre la kinect).
                Switch.Content = "OFF";
                //On vide le label des exceptions.
                ExceptionLbl.Content = "";
            }
            else
            {
                //Il affiche ON (pour allumer la kinect).
                Switch.Content = "ON";
                Bitmap rightHandBitmap = getImage(imgLocation + "\\right_hand_off.png"), leftHandBitmap = getImage(imgLocation + "\\left_hand_off.png");
                LeftHand.Source = CreateBitmapSourceFromBitmap(leftHandBitmap);
                RightHand.Source = CreateBitmapSourceFromBitmap(rightHandBitmap);
                DebugCanvas.Children.RemoveRange(1, DebugCanvas.Children.Count - 1);
            }
        }

        /*
        *  Récupère le flux video et met à jour le rendu visuel de debug.
        */
        public void RefreshVideo(AllFramesReadyEventArgs e)
        {
            if (refreshImage)
            {
                bool receivedData = false;
                ColorImageFrame colorImageFrameData;
                using (colorImageFrameData = e.OpenColorImageFrame())
                {
                    //Si on ne reçoit pas de trames de la kinect.
                    if (colorImageFrameData == null)
                    {
                        //L'image est supprimée.
                        DebugImage.Source = null;
                    }
                    //Si le tableau stockant l'image en cours est nul.
                    if (colorPixelData == null)
                        //On alloue un nouveau tableau.
                        colorPixelData = new byte[colorImageFrameData.PixelDataLength];
                    else
                    {
                        try
                        {
                            //Sinon on met à jour le tableau en copiant le contenu de la trame dans le tableau.
                            colorImageFrameData.CopyPixelDataTo(colorPixelData);
                            receivedData = true;
                        }
                        catch (Exception) { }
                    }
                }
                //Si on a des données dans le tableau et que la kinect est allumée.
                if (receivedData && on)
                {
                    //On met à jour l'image de la caméra.
                    DebugImage.Source = BitmapSource.Create(colorImageFrameData.Width, colorImageFrameData.Height, 96, 96, PixelFormats.Bgr32, null, colorPixelData, colorImageFrameData.Width * colorImageFrameData.BytesPerPixel);
                    DebugImage.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
                    DebugImage.VerticalAlignment = System.Windows.VerticalAlignment.Center;
                    DebugImage.Stretch = Stretch.Fill;
                    //On annule l'image associée aux gestures.
                    Gestures.Source = null;
                }
            }
        }

        /*
        * Affiche la distance de l'utilisateur dans le rendu visuel.
        * Sous forme de nombre en m et de rectangles changeant de couleur en fonction de la distance.
        */
        public void showDistance(float proximity)
        {
            UserImage.Margin = new System.Windows.Thickness(552, 350 - 350 / 100 * proximity, 0, 0);
        }

        /*
        * Affiche la détection de la main droite via un label.
        */
        public void showRightHandRect(bool show)
        {
            BitmapSource source = null;

            if (show)
                source = right_hand_onBitmap;
            else
                source = right_hand_offBitmap;

            RightHand.Source = source;
        }

        /*
        * Affiche la détection de la main gauche via un label.
        */
        public void showLeftHandRect(bool show)
        {
            BitmapSource source = null;

            if (show)
                source = left_hand_onBitmap;
            else
                source = left_hand_offBitmap;

            LeftHand.Source = source;
        }

        /*
        * Dessine les noeuds du squelette dans le rendu visuel.
        */
        public void drawJoints(JointCollection joints, Skeleton first)
        {
            if (refreshImage)
            {
                //On enlève tout élément du Canvas à part l'image, de manière à mettre à jour la position du squelette. 
                DebugCanvas.Children.RemoveRange(1, DebugCanvas.Children.Count - 1);

                //Pour chaque noeud.
                foreach (Joint joint in first.Joints)
                {
                    //On crée une ellipse de taille 20 et de largeur 20.
                    Ellipse node = new Ellipse();
                    node.Height = 20;
                    node.Width = 20;

                    //S'il s'agit d'un noeud de tête, on le colorie en rouge, sinon en bleu.
                    if (joint.JointType == JointType.Head)
                        node.Fill = System.Windows.Media.Brushes.Red;
                    else if (joint.JointType == JointType.ShoulderCenter)
                        node.Fill = System.Windows.Media.Brushes.Green;
                    else if (joint.JointType == JointType.HipCenter)
                        node.Fill = System.Windows.Media.Brushes.Green;
                    else if (joint.JointType == JointType.HandRight)
                        node.Fill = System.Windows.Media.Brushes.Red;
                    else
                        node.Fill = System.Windows.Media.Brushes.Blue;

                    //On met à la bonne échelle les coordonnées des positions des noeuds.
                    Joint scaledJoint = Coding4Fun.Kinect.Wpf.SkeletalExtensions.ScaleTo(joint, 600, 400, 0.75f, 0.75f);

                    //On positionne le noeud dans le Canvas, et on l'ajoute.
                    Canvas.SetLeft(node, scaledJoint.Position.X);
                    Canvas.SetTop(node, scaledJoint.Position.Y);
                    DebugCanvas.Children.Add(node);
                }
            }
        }

        /*
        * Dessine un os, en ayant en paramètres deux noeuds.
        */
        public void drawBone(Joint j1, Joint j2)
        {
            //On crée une nouvelle ligne verte d'épaisseur 8 entre les deux noeuds et on l'ajoute au Canvas.
            Line line = new Line();
            line.Stroke = System.Windows.Media.Brushes.Green;
            line.X1 = j1.Position.X;
            line.X2 = j2.Position.X;
            line.Y1 = j1.Position.Y;
            line.Y2 = j2.Position.Y;
            line.StrokeThickness = 8;
            DebugCanvas.Children.Add(line);
        }

        /*
        * Dessine le squelette (ensemble des os), en ayant en paramètres tous les noeuds.
        */
        public void showSkeleton(Joint hipCenter, Joint spine, Joint shoulderCenter, Joint head, Joint shoulderLeft, Joint elbowLeft, Joint wristLeft, Joint handLeft, Joint shoulderRight, Joint elbowRight, Joint wristRight, Joint handRight, Joint hipLeft, Joint kneeLeft, Joint ankleLeft, Joint footLeft, Joint hipRight, Joint kneeRight, Joint ankleRight, Joint footRight)
        {
            if (refreshImage)
            {
                //On met les noeuds deux par deux en fonction de leur position dans le squelette.
                drawBone(head, shoulderCenter);
                drawBone(shoulderCenter, shoulderLeft);
                drawBone(shoulderLeft, elbowLeft);
                drawBone(elbowLeft, wristLeft);
                drawBone(wristLeft, handLeft);
                drawBone(shoulderCenter, shoulderRight);
                drawBone(shoulderRight, elbowRight);
                drawBone(elbowRight, wristRight);
                drawBone(wristRight, handRight);
                drawBone(shoulderCenter, spine);
                drawBone(spine, hipCenter);
                drawBone(hipCenter, hipLeft);
                drawBone(hipLeft, kneeLeft);
                drawBone(kneeLeft, ankleLeft);
                drawBone(ankleLeft, footLeft);
                drawBone(hipCenter, hipRight);
                drawBone(hipRight, kneeRight);
                drawBone(kneeRight, ankleRight);
                drawBone(ankleRight, footRight);
            }

            //On affiche la silhouette sur la droite de l'écran si elle a été masquée.
            if (UserImage.Visibility.Equals(Visibility.Collapsed))
            {
                UserImage.Visibility = Visibility.Visible;
            }
        }

        /*
        * Cache le squelette et le reste de l'interface à part l'image.
        */
        public void hideSkeleton()
        {
            //On vide le canvas mais en gardant l'image.
            if(DebugCanvas.Children.Count > 1)
                DebugCanvas.Children.RemoveRange(1, DebugCanvas.Children.Count - 1);
            //On efface la silhouette sur la droite de l'écran.
            UserImage.Visibility = Visibility.Collapsed;
        }

        /*
        * Affiche la position de la main gauche dans le rendu visuel.
        */
        public void showLeftHandCoord(String coord)
        {
            //LeftHand.Content = coord;
        }

        /*
        * Affiche la position de la main gauche dans le rendu visuel.
        */
        public void showRightHandCoord(String coord)
        {
            //RightHand.Content = coord;
        }

        /*
         * Méthode associée à l'événement : Quitter via le menu.
         */
        public void Quit_Click(object sender, RoutedEventArgs e)
        {
            closing = true;
            //On éteint la Kinect (pour éviter qu'elle reste allumée même lorsque le programme est éteint).
 
            Application.Current.Shutdown();
        }

        /*
         * Permet d'initialiser la Kinect dès que la fenêtre est lancée.
         */
        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            //kinectMain.KinectInitialization();
        }

        /*
         * Permet d'obtenir l'image associée à l'emplacement des images si celle-ci existe.
         */
        public Bitmap getImage(String location)
        {
            try
            {
                return new Bitmap(location);
            }
            catch (Exception)
            {
                return (Bitmap)rm.GetObject("_404");
            }
        }

        /*
         * Méthode d'affichage des gestures.
         */
        public void showGesture(String gesture)
        {
            if (refreshImage)
            {
                refreshImage = false;
                _timer.Start();
                Bitmap bitmap = null;
                //S'il s'agit de telle ou telle gesture, on prend l'image correspondante dans les ressources,
                //on la convertit et on l'affiche.

                switch (gesture)
                {
                    case "SWIPE-LEFT": bitmap = getImage(imgLocation + "\\swipe_left.png");
                        break;
                    case "SWIPE-RIGHT": bitmap = getImage(imgLocation + "\\swipe_right.png");
                        break;
                    case "PUSH-RIGHT": bitmap = getImage(imgLocation + "\\push_right.png");
                        break;
                    case "PUSH-LEFT": bitmap = getImage(imgLocation + "\\push_left.png");
                        break;
                    case "PUSH-BOTH": bitmap = getImage(imgLocation + "\\push_both.png");
                        break;
                    case "PULL-RIGHT": bitmap = getImage(imgLocation + "\\pull_right.png");
                        break;
                    case "PULL-LEFT": bitmap = getImage(imgLocation + "\\pull_left.png");
                        break;
                    case "PULL-BOTH": bitmap = getImage(imgLocation + "\\pull_both.png");
                        break;
                    case "WAVE": bitmap = getImage(imgLocation + "\\hello.png");
                        break;
                    case "BEND": bitmap = getImage(imgLocation + "\\bend.png");
                        break;
                    case "KNEE-UP": bitmap = getImage(imgLocation + "\\knee_up.png");
                        break;
                    case "JUMP": bitmap = getImage(imgLocation + "\\jump.png");
                        break;
                    case "FALL": bitmap = getImage(imgLocation + "\\fall.png");
                        break;
                }
                Gestures.Source = CreateBitmapSourceFromBitmap(bitmap);
            }

            DebugImage.Source = null;
            hideSkeleton();
        }

        /*
         * Méthode d'indication de raffraichissement de l'image ("on la raffraichit ou pas ?").
         */
        public void setRefreshImage(bool refresh)
        {
            refreshImage = refresh;
        }

        /*
         * Méthode de conversion de Bitmap (des ressources) en BitmapSource (du debug).
         */
        public static BitmapSource CreateBitmapSourceFromBitmap(Bitmap bitmap)
        {
            if (bitmap == null)
                return null;

            try
            {
                return System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                bitmap.GetHbitmap(),
                IntPtr.Zero,
                Int32Rect.Empty,
                BitmapSizeOptions.FromEmptyOptions());
            }
            catch (Exception)
            {
                return null;
            }
        }

        /*
         * Méthode de chargement des paramètres via le fichier de configuration.
         */
        public bool loadParameters()
        {
            try
            {
                //On lit le fichier de config.
  
                    String[] lines = System.IO.File.ReadAllLines(configPath);

                //On repère les paramètres supposés être des int ou float de manière à les parser.
                String[] ints = { "tuioConnexionPort", "wsConnexionPort", "takenPoints", "tuioTimerElapsing", "wsTimerElapsing", "directionChangeTresholdXY", "imagesToShow" };
                String[] floats = { "minDistHands", "minDist", "maxDistHands", "maxDist", "zeroPoint", "directionChangeTresholdZ" };

                //Indique si on a affecté le paramètre actuel.
                bool goToNextParam = false;

                //Pour chaque ligne du fichier de config.
                for (int i = 0 ; i < lines.Length ; i++)
                {
                    //On récupère la clé et la valeur.
                    String key = lines[i].Split(':')[0];
                    int keyLength = key.Length;
                    String value = lines[i].Substring((keyLength + 1), (lines[i].Length - keyLength - 1));
                    //String value = lines[i].Substring(keyLength, lines[i].Length - keyLength - 1);

                    Console.WriteLine("PARAMS ======= " + key + " " + value);

                    //Si c'est un int on le parse.
                    for (int j = 0 ; j < ints.Length ; j++)
                    {
                        if (ints[j] == key)
                        {
                            config.Add(key, int.Parse(value));
                            goToNextParam = true;
                        }
                    }

                    //Si il n'était pas un int.
                    if (!goToNextParam)
                    {
                        //Si c'est un float on le parse.
                        for (int j = 0; j < floats.Length; j++)
                        {
                            if (floats[j] == key)
                            {
                                config.Add(key, float.Parse(value));
                                goToNextParam = true;
                            }
                        }

                        //Si c'était en fait un string.
                        if (!goToNextParam)
                        {
                            config.Add(key, value);
                        }
                    }
                    goToNextParam = false;
                }
            }
            //S'il s'est passé un problème durant la lecture du fichier de config.
            catch (Exception e)
            {
                //On génère un fichier qui va afficher l'erreur.
                StreamWriter SW;
                try
                {
                    SW = File.CreateText("ErrorFile.txt");
                    SW.WriteLine(e.Message);
                    SW.Close();
                }
                catch { }

                return false;
            }

            //Si l'extraction s'est bien passé mais que les paramètres sont incohérents.
            if ((float)config["maxDistHands"] <= 0f || (float)config["minDistHands"] <= 0f || (float)config["maxDistHands"] > (float)config["maxDist"] || (float)config["minDistHands"] > (float)config["maxDist"] ||
                (float)config["minDistHands"] >= (float)config["maxDistHands"] || (float)config["zeroPoint"] < (float)config["maxDistHands"] || (float)config["minDistHands"] > (float)config["minDist"] ||
                (float)config["zeroPoint"] >= (float)config["maxDist"] || (int)config["tuioConnexionPort"] < 0 || (int)config["wsConnexionPort"] < 0 || (int)config["tuioTimerElapsing"] < 0 || (int)config["wsTimerElapsing"] < 0 || (int)config["imagesToShow"] < 1 ||
                (int)config["takenPoints"] <= 0 || (int)config["directionChangeTresholdXY"] < 0 || (float)config["directionChangeTresholdZ"] < 0)
            {
                ExceptionLbl.Content = rm.GetString("loadParametersIncorrect");

                StreamWriter SW;
                try
                {
                    //On indique les incohérences trouvées dans le fichier.
                    SW = File.CreateText("ErrorFile.txt");
                    if ((float)config["maxDistHands"] <= 0f) { SW.WriteLine("searchMaxDistance <= 0"); }
                    if ((float)config["minDistHands"] <= 0f) { SW.WriteLine("minDistance <= 0"); }
                    if ((float)config["maxDistHands"] > (float)config["maxDist"]) { SW.WriteLine("searchMaxDistance > maxDistance"); }
                    if ((float)config["minDistHands"] > (float)config["maxDist"]) { SW.WriteLine("searchMinDistance > maxDistance"); }
                    if ((float)config["minDistHands"] >= (float)config["maxDistHands"]) { SW.WriteLine("searchMinDistance >= searchMaxDistance"); }
                    if ((float)config["zeroPoint"] < (float)config["maxDistHands"]) { SW.WriteLine("zeroPoint < searchMaxDistance"); }
                    if ((float)config["minDistHands"] > (float)config["minDist"]) { SW.WriteLine("searchMinDistance > minDistance"); }
                    if ((float)config["zeroPoint"] >= (float)config["maxDist"]) { SW.WriteLine("zeroPoint >= maxDistance"); }
                    if ((int)config["tuioConnexionPort"] < 0) { SW.WriteLine("tuioConnexionPort < 0"); }
                    if ((int)config["wsConnexionPort"] < 0) { SW.WriteLine("wsConnexionPort < 0"); }
                    if ((int)config["tuioTimerElapsing"] < 0) { SW.WriteLine("tuioTimerElapsing < 0"); }
                    if ((int)config["wsTimerElapsing"] < 0) { SW.WriteLine("wsTimerElapsing < 0"); }
                    if ((int)config["imagesToShow"] < 1) { SW.WriteLine("imagesToShow < 1"); }
                    if ((int)config["takenPoints"] <= 0) { SW.WriteLine("takenPoints <= 0"); }
                    if ((int)config["directionChangeTresholdXY"] < 0) { SW.WriteLine("directionChangeTresholdXY < 0"); }
                    if ((float)config["directionChangeTresholdZ"] < 0) { SW.WriteLine("directionChangeTresholdZ < 0"); }
                    SW.Close();
                    Console.WriteLine("Error File Created SucacessFully");
                }
                catch (Exception){}

                return false;
            }
            return true;
        }

        /*
         * Getters et setters des paramètres du Middleware.
         */
        public void setMinDistHands(float min)
        {
            config["minDistHands"] = min;
        }
        public void setMaxDistHands(float max)
        {
            config["maxDistHands"] = max;
        }
        public void setMinDist(float min)
        {
            config["minDist"] = min;
        }
        public void setMaxDist(float max)
        {
            config["maxDist"] = max;
        }
        public void setZeroPoint(float zero)
        {
            config["zeroPoint"] = zero;
        }
        public void setTuioConnexionHost(String host)
        {
            config["tuioConnexionHost"] = host;
        }
        public void setTuioConnexionPort(int port)
        {
            config["tuioConnexionPort"] = port;
        }
        public void setWsConnexionHost(String host)
        {
            config["wsConnexionHost"] = host;
        }
        public void setWsConnexionPort(int port)
        {
            config["wsConnexionPort"] = port;
        }
        public void setTuioTimerElapsing(int time)
        {
            config["tuioTimerElapsing"] = time;
        }
        public void setWsTimerElapsing(int time)
        {
            config["wsTimerElapsing"] = time;
        }
        public void setImagesToShow(int _imagesToShow)
        {
            config["imagesToShow"] = _imagesToShow;
        }
        public void setTakenPoints(int _takenPoints)
        {
            config["takenPoints"] = _takenPoints;
        }
        public void setDirectionChangeTresholdXY(int _directionChangeTresholdXY)
        {
            config["directionChangeTresholdXY"] = _directionChangeTresholdXY;
        }
        public void setDirectionChangeTresholdZ(float _directionChangeTresholdZ)
        {
            config["directionChangeTresholdZ"] = _directionChangeTresholdZ;
        }
        public void setSwitch(Button _switch)
        {
            Switch = _switch;
        }
        public void setOn(bool _on)
        {
            on = _on;
        }
        
        public float getMinDistHands()
        {
            return (float)config["minDistHands"];
        }
        public float getMaxDistHands()
        {
            return (float)config["maxDistHands"];
        }
        public float getMinDist()
        {
            return (float)config["minDist"];
        }
        public float getMaxDist()
        {
            return (float)config["maxDist"];
        }
        public float getZeroPoint()
        {
            return (float)config["zeroPoint"];
        }
        public String getTuioConnexionHost()
        {
            return (String)config["tuioConnexionHost"];
        }
        public int getTuioConnexionPort()
        {
            return (int)config["tuioConnexionPort"];
        }
        public int getTuioTimerElapsing()
        {
            return (int)config["tuioTimerElapsing"];
        }
        public String getWsConnexionHost()
        {
            return (String)config["wsConnexionHost"];
        }
        public int getWsConnexionPort()
        {
            return (int)config["wsConnexionPort"];
        }
        public int getWsTimerElapsing()
        {
            return (int)config["wsTimerElapsing"];
        }
        public int getImagesToShow()
        {
            return (int)config["imagesToShow"];
        }
        public int getTakenPoints()
        {
            return (int)config["takenPoints"];
        }
        public int getDirectionChangeTresholdXY()
        {
            return (int)config["directionChangeTresholdXY"];
        }
        public float getDirectionChangeTresholdZ()
        {
            return (float)config["directionChangeTresholdZ"];
        }
        public Button getSwitch()
        {
            return Switch;
        }
        public MenuItem getQuitMenu()
        {
            return QuitMenu;
        }
        
        public bool getOn()
        {
            return on;
        }

        public void onR0(bool b)
        {
            if(b)
                R0.Fill = System.Windows.Media.Brushes.Blue;
            else
                R0.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR1(bool b)
        {
            if (b)
                R1.Fill = System.Windows.Media.Brushes.Blue;
            else
                R1.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR2(bool b)
        {
            if (b)
                R2.Fill = System.Windows.Media.Brushes.Blue;
            else
                R2.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR3(bool b)
        {
            if (b)
                R3.Fill = System.Windows.Media.Brushes.Blue;
            else
                R3.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR4(bool b)
        {
            if (b)
                R4.Fill = System.Windows.Media.Brushes.Blue;
            else
                R4.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR5(bool b)
        {
            if (b)
                R5.Fill = System.Windows.Media.Brushes.Blue;
            else
                R5.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR6(bool b)
        {
            if (b)
                R6.Fill = System.Windows.Media.Brushes.Blue;
            else
                R6.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR7(bool b)
        {
            if (b)
                R7.Fill = System.Windows.Media.Brushes.Blue;
            else
                R7.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR8(bool b)
        {
            if (b)
                R8.Fill = System.Windows.Media.Brushes.Blue;
            else
                R8.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR9(bool b)
        {
            if (b)
                R9.Fill = System.Windows.Media.Brushes.Blue;
            else
                R9.Fill = System.Windows.Media.Brushes.DarkGray;
        }
        public void onR10(bool b)
        {
            if (b)
                R10.Fill = System.Windows.Media.Brushes.Blue;
            else
                R10.Fill = System.Windows.Media.Brushes.DarkGray;
        }

        /*
         * Ouvre un fichier selon son chemin.
         */
        public void OpenFile(String filePath)
        {
            try
            {
                System.Diagnostics.Process.Start(@filePath);
            }
            catch (Exception)
            {
                ExceptionLbl.Content = filePath + " : " + rm.GetString("fileNotFound");
            }
        }

        public void OpenFile(String program, String filePath)
        {
            try
            {
                System.Diagnostics.Process.Start(program, @filePath);
            }
            catch (Exception)
            {
                ExceptionLbl.Content = filePath + " : " + rm.GetString("fileNotFound");
            }
        }

        /*
         * Ouvre le readme du Middleware.
         */
        private void MiddlewareReadmeMenu_Click(object sender, RoutedEventArgs e)
        {
            if (projectName.Equals("TraKERS"))
            {
                OpenFile((String)config["readmeTraKERSMiddleware"]);
            }
            else if (projectName.Equals("BBM"))
            {
                OpenFile((String)config["readmeBBMMiddleware"]);
            }
        }

        /*
         * Ouvre le readme du Front Processing.
         */
        private void FrontProcessingReadmeMenu_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["readmeTraKERSFrontProcessing"]);
        }

        /*
         * Ouvre la documentation du Front Processing.
         */
        private void FrontProcessingDocumentationMenu_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["docTraKERSFrontProcessing"]);
        }
        
        /*
         * Ouvre le readme du Front JS.
         */
        private void FrontJSReadmeMenu_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["readmeTraKERSFrontJS"]);
        }

        /*
         * Ouvre la documentation du Front JS.
         */
        private void FrontJSDocumentationMenu_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["docTraKERSFrontJS"]);
        }

        /*
         * Ouvre la documentation du Front IDILL.
         */
        private void FrontIDILLDocumentationMenu_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["docBBMFrontIDILL"]);
        }

        /*
         * Ouvre le fichier des paramètres.
         */
        private void ParamMenu_Click(object sender, RoutedEventArgs e)
        {
            OpenFile(configPath);
        }

        /*
         * Code de l'exemple processing de manipulation de fluide.
         */
        private void ProcessingMenuFMPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPFMPS"]);
        }
        
        //Exemple processing de manipulation de fluide.
        private void ProcessingMenuFMExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPFMExe"]);
        }

        /*
         * Code de l'exemple processing de manipulation de fumée.
         */
        private void ProcessingMenuSMPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPSMPS"]);
        }

        /*
         * Exemple processing de manipulation de fumée.
         */
        private void ProcessingMenuSMExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPSMExe"]);
        }

        /*
         * Code de l'exemple processing d'affichage des gestures.
         */
        private void ProcessingMenuTGPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPTGPS"]);
        }

        /*
         * Exemple processing d'affichage des gestures.
         */
        private void ProcessingMenuTGExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPTGExe"]);
        }

        /*
         * Code de l'exemple processing d'affichage des pointeurs.
         */
        private void ProcessingMenuTPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPTPS"]);
        }

        /*
         * Exemple processing d'affichage des pointeurs.
         */
        private void ProcessingMenuTExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPTExe"]);
        }

        /*
         * Code de l'exemple processing du press de la main.
         */
        private void ProcessingMenuIEHandPressPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPIEHandPressPS"]);
        }

        /*
         * Exemple processing du press de la main.
         */
        private void ProcessingMenuIEHandPressExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPIEHandPressExe"]);
        }

        /*
         * Code de l'exemple processing du signal de la main.
         */
        private void ProcessingMenuIEHandSignalPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPIEHandSignalPS"]);
        }

        /*
         * Exemple processing du signal de la main.
         */
        private void ProcessingMenuIEHandSignalExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPIEHandSignalExe"]);
        }

        /*
         * Code de l'exemple processing de la manipulation 1D de la main.
         */
        private void ProcessingMenuIEHand1DPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPIEHand1DPS"]);
        }

        /*
         * Exemple processing de la manipulation 1D de la main.
         */
        private void ProcessingMenuIEHand1DExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPIEHand1DExe"]);
        }

        /*
         * Code de l'exemple processing de la manipulation 2D de la main.
         */
        private void ProcessingMenuIEHand2DPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPIEHand2DPS"]);
        }

        /*
         * Exemple processing de la manipulation 2D de la main.
         */
        private void ProcessingMenuIEHand2DExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exPIEHand2DExe"]);
        }

        /*
         * Code de l'exemple web de l'affichage des pointeurs.
         */
        private void WebMenuPointersPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exWPointersPS"]);
        }

        /*
         * Exemple web de l'affichage des pointeurs.
         */
        private void WebMenuPointersExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exWPointersExe"]);
        }

        /*
         * Code de l'exemple web de l'affichage des gestures.
         */
        private void WebMenuGesturesPS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exWGesturesPS"]);
        }

        /*
         * Exemple web de l'affichage des gestures.
         */
        private void WebMenuGesturesExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["exWGesturesExe"]);
        }

        /*
         * Ouvre la source du Front IDILL.
         */
        private void FrontIDILLMenuS_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["frontIDILLS"]);
        }

        /*
         * Ouvre le Front IDILL.
         */
        private void FrontIDILLMenuExe_Click(object sender, RoutedEventArgs e)
        {
            OpenFile((String)config["frontIDILLExe"]);
        }
    }
}
