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

namespace CompassSample
{
    public partial class MainPage : PhoneApplicationPage
    {
        // Aufzaehlung für den Sensorstatus
        enum SensorStatus
        {
            Stopped, Started
        }

        // Instanz des Kompasssensors
        private Compass myCompass;

        // Kenner fuer aktive Kalibrierung
        private bool calibrating;

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

            // Sensorstatus in Schaltflaeche ablegen
            btn_Launch.Tag = SensorStatus.Stopped;

            // pruefen, ob der Kompass vom Geraet unterstuetzt wird
            if (!Compass.IsSupported)
            {
                // Kompass wird vom Geraet nicht unterstuetzt
                btn_Launch.IsEnabled = false;
                MessageBox.Show("Ihr Gerät unterstützt den Kompass nicht!", "Hinweis", MessageBoxButton.OK);
            }           
        }

        // Ereignismethode der Schaltflaeche
        private void btn_Launch_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            // pruefen des intern gepflegten Sensorstatus
            if (btn_Launch.Tag.Equals(SensorStatus.Stopped))
            {
                if (myCompass == null)
                {
                    // Kompassobjekt instanzieren
                    myCompass = new Compass();
                    // Abfrageintervall in Millisekunden festlegen
                    myCompass.TimeBetweenUpdates = TimeSpan.FromMilliseconds(Convert.ToDouble(sld_Interval.Value));
                    // Aenderungsereignis hinzufuegen
                    myCompass.CurrentValueChanged += new EventHandler<SensorReadingEventArgs<CompassReading>>(myCompass_CurrentValueChanged);
                    // Ereignis, wenn der Kompass kalibriert werden muss hinzufuegen
                    myCompass.Calibrate += new EventHandler<CalibrationEventArgs>(myCompass_Calibrate);
                }

                try
                {
                    // Kompasssensor starten
                    myCompass.Start();
                    // Schaltflaeche umbenennen
                    btn_Launch.Content = "Stoppen";
                    // Sensorstatus als Hilfe im Tag der Schaltflaeche ablegen
                    btn_Launch.Tag = SensorStatus.Started;
                }
                catch (InvalidOperationException)
                {
                    MessageBox.Show("Ihr Kompass konnte nich gestartet werden!", "Fehler", MessageBoxButton.OK);
                }
            }
            else
            {
                if (myCompass != null)
                {
                    // Kompasssensor stoppen
                    myCompass.Stop();
                    // manged und unmanged Resourcen, welche vom Sensorobjekt verwendet wurden, wieder freigeben
                    myCompass.Dispose();
                    myCompass = null;
                    // Schaltflaeche umbenennen
                    btn_Launch.Content = "Starten";
                    // Sensorstatus als Hilfe im Tag der Schaltflaeche ablegen
                    btn_Launch.Tag = SensorStatus.Stopped;
                }
            }
        }

        // Ereignismethode, insofern der Sensor die kalibriert werden muss
        // bei HeadingAccuracy +/- 30 Grad
        void myCompass_Calibrate(object sender, CalibrationEventArgs e)
        {
            if (!calibrating)
            {
                // Oberflaeche zur Kalibrierung anzeigen
                Dispatcher.BeginInvoke(() => { CalibrationStackPanel.Visibility = Visibility.Visible; ContentPanel.Visibility = Visibility.Collapsed; });
                // Kenner fuer aktive Kalibrierung auf wahr setzen
                calibrating = true;
            }
        }

        // Ereignismethode, insofern der Sensor gestartet wurde
        void myCompass_CurrentValueChanged(object sender, SensorReadingEventArgs<CompassReading> e)
        {
            // Unterscheidung, ob die Werteaenderung waehrend der Kalibrierung ausgeloest wurde
            if (calibrating)
            {
                // pruefen, ob die Genauigkeit kleiner gleich 10 Grad betraegt
                if (e.SensorReading.HeadingAccuracy <= 10)
                {
                    // Kalibierungskenner auf unwahr setzen
                    calibrating = false;
                    // Schaltflaeche zum Schliessen des Kalibrierungsdialogs aktivieren
                    Dispatcher.BeginInvoke(() => { btn_Calibration.IsEnabled = true; });
                }

                // interne Methode zum Aktualisieren der grafischen Kalibrierungsoberfläche mit Hilfe des Dispatcher aufrufen und den Paramter der Kompassdaten uebergeben
                Dispatcher.BeginInvoke(() => RefreshCalibrationGUI(e.SensorReading));
            }
            else
            {
                // interne Methode zum Aktualisieren der grafischen Oberfläche mit Hilfe des Dispatcher aufrufen und den Paramter der Kompassdaten 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(CompassReading p_CompassReading)
        {
            // Zeitstempel anzeigen, wann die Daten gemessen wurden
            tbx_TimeStamp.Text = p_CompassReading.Timestamp.ToString("HH:mm:ss dd.MM.yyyy");

            // Genauigkeit der Kompassdaten in Grad
            tbx_HeadingAccuracy.Text = p_CompassReading.HeadingAccuracy.ToString("0.00");

            // Peilung in Grad, gemessen im Uhrzeigersinn anhand des magnetischen Nordpols
            tbx_MagneticHeading.Text = p_CompassReading.MagneticHeading.ToString("0.00");

            // Peilung in Grad, gemessen im Uhrzeigersinn anhand des geographischen Nordpols
            tbx_TrueHeading.Text = p_CompassReading.TrueHeading.ToString("0.00");

            // Rohdaten des Magnetometer zum Auslesen der Werte der X,Y,Z Achsen
            tbx_X.Text = p_CompassReading.MagnetometerReading.X.ToString("0.00");
            tbx_Y.Text = p_CompassReading.MagnetometerReading.Y.ToString("0.00");
            tbx_Z.Text = p_CompassReading.MagnetometerReading.Z.ToString("0.00");

            // Kompasswerte grafisch im Koordinatensystem anzeigen
            magneticLine.X2 = magneticLine.X1 - 200 * Math.Sin(MathHelper.ToRadians((float)p_CompassReading.MagneticHeading));
            magneticLine.Y2 = magneticLine.Y1 - 200 * Math.Cos(MathHelper.ToRadians((float)p_CompassReading.MagneticHeading));

            trueLine.X2 = trueLine.X1 - 200 * Math.Sin(MathHelper.ToRadians((float)p_CompassReading.TrueHeading));
            trueLine.Y2 = trueLine.Y1 - 200 * Math.Cos(MathHelper.ToRadians((float)p_CompassReading.TrueHeading));

            xLine.X2 = xLine.X1 - p_CompassReading.MagnetometerReading.X * 4;
            yLine.Y2 = yLine.Y1 + p_CompassReading.MagnetometerReading.Y * 4;
            zLine.X2 = zLine.X1 - p_CompassReading.MagnetometerReading.Z * 4;
            zLine.Y2 = zLine.Y1 + p_CompassReading.MagnetometerReading.Z * 4;
        }

        // Ereignsmethode der "Fertig"-Schaltflaeche
        private void btn_Calibration_Click(object sender, RoutedEventArgs e)
        {
            // Kalibrierungdialog verbergen
            CalibrationStackPanel.Visibility = Visibility.Collapsed;
            // Hauptdialog anzeigen
            ContentPanel.Visibility = Visibility.Visible;
            // Schaltflaeche zum Schliessen des Kalibrierungsdialogs deaktivieren
            btn_Calibration.IsEnabled = false;
        }
    }
}