using System;
using System.Windows;
using Microsoft.Phone.Controls;
using Microsoft.Devices.Sensors;
using Microsoft.Xna.Framework;

namespace SimpleMotionSample
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Instanz der Bewegungssensorik
        private Motion myMotion;

        // Instanz des Kompasssensors, welcher fuer die Kalibrierung benoetigt wird
        private Compass myCompass;

        // Kenner fuer aktive Kalibrierung
        private bool calibrating = false;

        // Hauptkonstruktor
        public MainPage()
        {
            InitializeComponent();

            // pruefen, ob Bewegungssensorik vom Geraet unterstuetzt wird
            if (!Motion.IsSupported)
            {
                // Bewegungssensorik wird vom Geraet nicht unterstuetzt
                btn_Start.IsEnabled = false;

                MessageBox.Show("Ihr Gerät unterstützt die Bewegungssensorik nicht!");
            }
        }

        // Ereignismethode der Start Schaltflaeche
        private void btn_Start_Click(object sender, RoutedEventArgs e)
        {
            if (myMotion == null)
            {
                // Bewegungssensorik instanzieren
                myMotion = new Motion();
                // Abfrageintervall in Millisekunden festlegen
                myMotion.TimeBetweenUpdates = TimeSpan.FromMilliseconds(Convert.ToDouble(sld_Interval.Value));
                // Aenderungsereignis hinzufuegen
                myMotion.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<MotionReading>>(myMotion_CurrentValueChanged);
                // Ereignis, wenn der Kompass kalibriert werden muss
                myMotion.Calibrate += new EventHandler<CalibrationEventArgs>(myMotion_Calibrate);
            }

            try
            {
                // Bewegungssensorik starten
                myMotion.Start();
                // Konfiguartionsoberflaeche ausblenden, Werteflaeche einblenden
                ContentPanel.Visibility = Visibility.Collapsed;
                TitlePanel.Visibility = Visibility.Collapsed;
                ValuePanel.Visibility = Visibility.Visible;
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show("Die Bewegungssensorik konnte nicht gestartet werden!", "Fehler", MessageBoxButton.OK);
            }
        }

        // Ereignismethode der Stop Schaltflaeche 
        private void btn_Stop_Click(object sender, RoutedEventArgs e)
        {
            // Konfiguartionsoberflaeche einblenden, Werteflaeche ausblenden
            ContentPanel.Visibility = Visibility.Visible;
            TitlePanel.Visibility = Visibility.Visible;
            ValuePanel.Visibility = Visibility.Collapsed;

            if (myMotion != null)
            {
                // Bewegungssensorik stoppen
                myMotion.Stop();
                // manged und unmanged Resourcen, welche vom Sensorobjekt verwendet wurden, wieder freigeben
                myMotion.Dispose();
                myMotion = null;
            }
        }

        // Verarbeitungsmethode zum Calibrate-Ereignis, wird für die Kalibrierung des Kompass benoetigt
        void myMotion_Calibrate(object sender, CalibrationEventArgs e)        
        {
            if (!calibrating)
            {
                // Bewegungssensorik stoppen
                myMotion.Stop();

                if (myCompass == null && Compass.IsSupported)
                {
                    // Kompassobjekt instanzieren
                    myCompass = new Compass();
                    // Werteaenderungsereignis hinzufuegen
                    myCompass.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<CompassReading>>(myCompass_CurrentValueChanged);
                }

                try
                {
                    // Kompasssensor fuer die Kalibrierung starten
                    myCompass.Start();
                }
                catch (InvalidOperationException)
                {
                        MessageBox.Show("Der Kompasssensor konnte nicht zur Kalibrierung gestartet werden!", "Fehler", MessageBoxButton.OK);                   
                }

                // Oberflaeche zur Kalibrierung anzeigen
                Dispatcher.BeginInvoke(() => { CalibrationStackPanel.Visibility = Visibility.Visible; ValuePanel.Visibility = Visibility.Collapsed; });
                // Kenner fuer aktive Kalibrierung auf wahr setzen
                calibrating = true;
            }
        }

        // Ereignismethode, insofern der Kompasssensor gestartet wurde
        void myCompass_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
        {
            // interne Methode zum Aktualisieren der grafischen Kalibrierungsoberfläche mit Hilfe des Dispatcher aufrufen und den Paramter der Kompassdaten uebergeben
            Dispatcher.BeginInvoke(() => RefreshCalibrationGUI(e.SensorReading));

            // pruefen, ob die Genauigkeit kleiner gleich 10 Grad betraegt
            if (e.SensorReading.HeadingAccuracy <= 10)
            {
                if (myCompass != null)
                {
                    // Kompasssensor stoppen
                    myCompass.Stop();
                    // manged und unmanged Resourcen, welche vom Sensorobjekt verwendet wurden, wieder freigeben
                    myCompass.Dispose();
                    myCompass = null;
                }

                // Kalibierungskenner auf unwahr setzen
                calibrating = false;
                // Schaltflaeche zum Schliessen des Kalibrierungsdialogs aktivieren
                Dispatcher.BeginInvoke(() => { btn_Calibration.IsEnabled = true; });
            }
        }

        // Ereignismethode, insofern die Bewegungssensorik gestartet wurde
        void myMotion_CurrentValueChanged(object sender, SensorReadingEventArgs<MotionReading> e)
        {
            if (myMotion.IsDataValid)
                // interne Methode zum Aktualisieren der grafischen Oberfläche mit Hilfe des Dispatcher aufrufen und den Paramter der Bewegungsdaten uebergeben
                Dispatcher.BeginInvoke(() => RefreshGUI(e.SensorReading));
        }

        // interne Methode zum Aktualisieren der grafischen Oberfläche der Kalibrierung
        private void RefreshCalibrationGUI(CompassReading p_CompassReading)
        {
            // Messgenauigkeit anzeigen
            tbx_calibration.Text = p_CompassReading.HeadingAccuracy.ToString("0.00");
        }

        // interne Methode zum Aktualisieren der grafischen Oberfläche
        private void RefreshGUI(MotionReading p_MotionReading)
        {
            // Zeitstempel anzeigen, wann die Daten gemessen wurden
            tbx_TimeStamp.Text = p_MotionReading.Timestamp.ToString("HH:mm:ss dd.MM.yyyy");

            // Werte für das Rollen, Nicken und Gieren
            tbx_Roll.Text = p_MotionReading.Attitude.Roll.ToString();
            tbx_Pitch.Text = p_MotionReading.Attitude.Pitch.ToString();
            tbx_Yaw.Text = p_MotionReading.Attitude.Yaw.ToString();

            // Werte der linearen Beschleunigung des Geraetes als Vector3
            tbl_DeviceAccelerationX.Text = p_MotionReading.DeviceAcceleration.X.ToString();
            tbl_DeviceAccelerationY.Text = p_MotionReading.DeviceAcceleration.Y.ToString();
            tbl_DeviceAccelerationZ.Text = p_MotionReading.DeviceAcceleration.Z.ToString();

            // Werte der Rotationsgeschwindigkeit des Geraetes als Vector3
            tbl_DeviceRotationRateX.Text = p_MotionReading.DeviceRotationRate.X.ToString();
            tbl_DeviceRotationRateY.Text = p_MotionReading.DeviceRotationRate.Y.ToString();
            tbl_DeviceRotationRateZ.Text = p_MotionReading.DeviceRotationRate.Z.ToString();

            // Werte zum Gravitätsvektor
            tbl_GravityX.Text = p_MotionReading.Gravity.X.ToString();
            tbl_GravityY.Text = p_MotionReading.Gravity.Y.ToString();
            tbl_GravityZ.Text = p_MotionReading.Gravity.Z.ToString();
        }

        // Ereignismethode der Kalibrierungsschaltflaeche
        private void btn_Calibration_Click(object sender, RoutedEventArgs e)
        {
            // Kalibrierungdialog verbergen
            CalibrationStackPanel.Visibility = Visibility.Collapsed;
            // Wertedialog wieder anzeigen
            ValuePanel.Visibility = Visibility.Visible;
            // Schaltflaeche zum Schliessen des Kalibrierungsdialogs deaktivieren
            btn_Calibration.IsEnabled = false;

            try
            {
                // Bewegungssensorik wieder starten
                myMotion.Start();
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show("Die Bewegungssensorik konnte nicht gestartet werden!", "Fehler", MessageBoxButton.OK);
            }
        }
    }
}