using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using Microsoft.Xna.Framework.Media;
//Virtuelle Thumbsticks
using TouchThumbsticks;
//Tombstoning
using Microsoft.Phone.Shell;

namespace XNAPaddleGame
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        //Textur für den Ball
        Texture2D texBall;
        //Texturen für die Paddle
        Texture2D textLinkesPaddel;
        Texture2D texRechtesPaddel;
        //Textur für den Hintergrund
        Texture2D texHintergrund;
        //Textur für den "CPU" Spieler
        Texture2D texCPU;
        //Textur für den "Benutzer" Spieler
        Texture2D texSpieler;
        //Die Ball Position
        Vector2 positionBall;
        //Paddle Positionen
        Vector2 positionLinkesPaddel;
        Vector2 positionRechtesPad;
        //Maximaler Y-Achsen Wert der Paddle
        int iMaximalY;
        //Richtungswerte des Balls
        bool boBallnachRechts;
        bool boBallnachOben;
        //Spielstatus
        bool boSpielLaeuft;
        //Ballbewegung
        int iBallBewegung = 6;
        //Schwellwert für die virtuellen Thumbsticks
        float fThumbStickTrigger = 0.2f;
        //Spielstände
        int iLinksTreffer;
        int iRechtsTreffer;
        //Schriftart
        SpriteFont fntStatus;
        //Automodi
        bool boLinkerAutomodus;
        bool boRechterAutomodus;
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            //Tombstoning
            PhoneApplicationService.Current.Activated += new EventHandler<ActivatedEventArgs>(Current_Activated);
            PhoneApplicationService.Current.Deactivated += new EventHandler<DeactivatedEventArgs>(Current_Deactivated);
            // Frame rate is 30 fps by default for Windows Phone.
            TargetElapsedTime = TimeSpan.FromTicks(333333);
        }

        //Spielinformationen speichern
        void Current_Deactivated(object sender, DeactivatedEventArgs e)
        {
            //Punkte speichern
            PhoneApplicationService.Current.State.Add("PunkteLinks", iLinksTreffer);
            PhoneApplicationService.Current.State.Add("PunkteRechts", iRechtsTreffer);
            //Automodus speichern
            PhoneApplicationService.Current.State.Add("AutoLinks",boLinkerAutomodus);
            PhoneApplicationService.Current.State.Add("AutoRechts",boRechterAutomodus);
            //Ballposition
            PhoneApplicationService.Current.State.Add("BallX",positionBall.X);
            PhoneApplicationService.Current.State.Add("BallY",positionBall.Y);
            //Ballrichtung
            PhoneApplicationService.Current.State.Add("BallOben",boBallnachOben);
            PhoneApplicationService.Current.State.Add("BallRechts",boBallnachRechts);
            //Spielstatus
            PhoneApplicationService.Current.State.Add("Laeuft", boSpielLaeuft);
        }

        //Spielinformationen auslesen
        void Current_Activated(object sender, ActivatedEventArgs e)
        {
            //Kein Auslesen im Dormant Status
            if (e.IsApplicationInstancePreserved)
                return;
            //Punkte auslesen
            if (PhoneApplicationService.Current.State.ContainsKey("PunkteLinks"))
            {
                iLinksTreffer = (int)PhoneApplicationService.Current.State["PunkteLinks"];
                PhoneApplicationService.Current.State.Remove("PunkteLinks");
            }
            if (PhoneApplicationService.Current.State.ContainsKey("PunkteRechts"))
            {
                iRechtsTreffer = (int)PhoneApplicationService.Current.State["PunkteRechts"];
                PhoneApplicationService.Current.State.Remove("PunkteRechts");
            }
            //Automodus
            if (PhoneApplicationService.Current.State.ContainsKey("AutoLinks"))
            {
                boLinkerAutomodus = (bool)PhoneApplicationService.Current.State["AutoLinks"];
                PhoneApplicationService.Current.State.Remove("AutoLinks");
            }
            if (PhoneApplicationService.Current.State.ContainsKey("AutoRechts"))
            {
                boRechterAutomodus = (bool)PhoneApplicationService.Current.State["AutoRechts"];
                PhoneApplicationService.Current.State.Remove("AutoRechts");
            }
            //Ballposition
            if (PhoneApplicationService.Current.State.ContainsKey("BallX"))
            {
                positionBall.X = (float)PhoneApplicationService.Current.State["BallX"];
                PhoneApplicationService.Current.State.Remove("BallX");
            }
            if (PhoneApplicationService.Current.State.ContainsKey("BallY"))
            {
                positionBall.Y = (float)PhoneApplicationService.Current.State["BallY"];
                PhoneApplicationService.Current.State.Remove("BallY");
            }
            //Ballrichtung
            if (PhoneApplicationService.Current.State.ContainsKey("BallOben"))
            {
                boBallnachOben = (bool)PhoneApplicationService.Current.State["BallOben"];
                PhoneApplicationService.Current.State.Remove("BallOben");
            }
            if (PhoneApplicationService.Current.State.ContainsKey("BallRechts"))
            {
                boBallnachRechts = (bool)PhoneApplicationService.Current.State["BallRechts"];
                PhoneApplicationService.Current.State.Remove("BallRechts");
            }
            //Spielstatus
            if (PhoneApplicationService.Current.State.ContainsKey("Laeuft"))
            {
                boSpielLaeuft = (bool)PhoneApplicationService.Current.State["Laeuft"];
                PhoneApplicationService.Current.State.Remove("Laeuft");
            }
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            //Vollbildmodus
            graphics.IsFullScreen = true;
            //Ball nach rechts
            boBallnachRechts = false;
            //Spiel läuft nicht, 2xCPU
            boSpielLaeuft = false;
            //Keine Treffer
            iLinksTreffer = 0;
            iRechtsTreffer = 0;
            //Automodus beide Seiten
            boRechterAutomodus = true;
            boLinkerAutomodus = true;
            //DoubleTap Geste registrieren
            TouchPanel.EnabledGestures = GestureType.DoubleTap;
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            //Spielfeld-Hintergrund laden
            texHintergrund = Content.Load<Texture2D>("background");
            //Ball laden
            texBall = Content.Load<Texture2D>("ball");
            //Paddle laden, beide verwenden die selbe Textur
            textLinkesPaddel = Content.Load<Texture2D>("paddle");
            texRechtesPaddel = Content.Load<Texture2D>("paddle");
            //Schrift laden
            fntStatus = Content.Load<SpriteFont>("SpriteFont1");
            //"CPU" Spieler Icon laden
            texCPU = Content.Load<Texture2D>("CPU");
            //"Benutzer" Spieler Icon laden
            texSpieler = Content.Load<Texture2D>("Benutzer");
            //Initiale Werte setzen, jetzt da Textur-Eigenschaften vorliegen
            //Paddle zentrieren
            positionLinkesPaddel.Y = (graphics.GraphicsDevice.Viewport.Height / 2) - (textLinkesPaddel.Height / 2);
            //Seitenabstand
            positionLinkesPaddel.X = 30;
            //Paddle zentrieren
            positionRechtesPad.Y = (graphics.GraphicsDevice.Viewport.Height / 2) - (texRechtesPaddel.Height / 2);
            //Seitenabstand
            positionRechtesPad.X = graphics.GraphicsDevice.Viewport.Width - 30 - texRechtesPaddel.Width;
            //Ball zentrieren
            positionBall.Y = (graphics.GraphicsDevice.Viewport.Height / 2) - (texBall.Height / 2);
            positionBall.X = (graphics.GraphicsDevice.Viewport.Width / 2) - (texBall.Width / 2);
            //Maximale Y Achse berechnen
            iMaximalY = graphics.GraphicsDevice.Viewport.Height - textLinkesPaddel.Height;
            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            // TODO: Add your update logic here
            //Virtuelle Thumbsticks Updaten
            VirtualThumbsticks.Update();
            //Gesten
            GestenHandler(gameTime);
            //Steuerung
            SteuerungsHandler(gameTime);
            //Ball bewegen
            BallHandler(gameTime);
            //Kollisionsprüfung
            KollisionsHandler(gameTime);
            base.Update(gameTime);
        }

        //Behandelt alle verwendeten Gesten
        protected void GestenHandler(GameTime gameTime)
        {
            //Prüfen ob Gesten vorhanden sind
            while (TouchPanel.IsGestureAvailable)
            {
                //Die aktuelle Geste auslesen
                GestureSample curGesture = TouchPanel.ReadGesture();
                //Gestentyp prüfen
                switch (curGesture.GestureType)
                {
                    //Double Tap Geste auswerten
                    case GestureType.DoubleTap:
                        //Auswertunge muss nur erfolgen wenn noch ein "Automodus" aktiv ist
                        if (boRechterAutomodus || boLinkerAutomodus)
                        {
                            //Prüfen ob Geste auf linker oder rechter Seite erfolgte
                            if (curGesture.Position.X < graphics.GraphicsDevice.Viewport.Width / 2)
                            {
                                //Bei Geste auf linker Seite prüfen ob linker Automodus noch aktiv ist
                                if (boLinkerAutomodus)
                                {
                                    //Automodus beenden
                                    boLinkerAutomodus = false;
                                    //Spiel "neu" starten
                                    InitialisiereSpiel();
                                }
                            }
                            else
                            {
                                //Bei Geste auf rechter Seite prüfen ob rechter Automodus noch aktiv ist
                                if (boRechterAutomodus)
                                {
                                    //Automodus beenden
                                    boRechterAutomodus = false;
                                    //Spiel "neu" starten
                                    InitialisiereSpiel();
                                }
                            }
                        }
                        break;
                }
            }
        }

        //Steuerungsbehandlung: Paddle bewegen
        protected void SteuerungsHandler(GameTime gameTime)
        {
            //Auf den linken Thumbstick nur reagieren wenn ein "linker" Spieler vorhanden ist
            if (VirtualThumbsticks.LeftThumbstickCenter.HasValue && !boLinkerAutomodus)
            {
                //"linker" Spieler beginnt, Also Ball nach rechts
                if (!boSpielLaeuft)
                {
                    boSpielLaeuft = true;
                    boBallnachRechts = true;
                }
                //Nur die Y Achse des Thumbsticks auswerten
                //Bei Bewegung nach unten wird Y positiv
                if (VirtualThumbsticks.LeftThumbstick.Y > fThumbStickTrigger)
                {
                    //Paddle bewegen
                    positionLinkesPaddel.Y += 10;
                    //Die Spielfeldbeschränkung beachten
                    if (positionLinkesPaddel.Y > iMaximalY)
                        positionLinkesPaddel.Y = iMaximalY;
                }
                //Bei Bewegung nach oben wird Y negativ
                if (VirtualThumbsticks.LeftThumbstick.Y < -fThumbStickTrigger)
                {
                    //Paddle bewegen
                    positionLinkesPaddel.Y -= 10;
                    //Die Spielfeldbeschränkung beachten
                    if (positionLinkesPaddel.Y < 0)
                        positionLinkesPaddel.Y = 0;
                }
            }
            else
            {
                //"linker" Automodus nur wenn der Ball auch nach links bewegt wird
                if (boLinkerAutomodus && !boBallnachRechts)
                {
                    //Position des Balls mit der Mitte des Paddles vergleichen und ggf. nach unten bewegen
                    if (positionBall.Y > positionLinkesPaddel.Y + (textLinkesPaddel.Height / 2))
                    {
                        positionLinkesPaddel.Y += 10;
                        //Die Spielfeldbeschränkung beachten
                        if (positionLinkesPaddel.Y > iMaximalY)
                            positionLinkesPaddel.Y = iMaximalY;
                    }
                    //Position des Balls mit der Mitte des Paddles vergleichen und ggf. nach oben bewegen
                    if (positionBall.Y < positionLinkesPaddel.Y + (textLinkesPaddel.Height / 2))
                    {
                        positionLinkesPaddel.Y -= 10;
                        //Die Spielfeldbeschränkung beachten
                        if (positionLinkesPaddel.Y < 0)
                            positionLinkesPaddel.Y = 0;
                    }
                }
            }
            //Auf den rechten Thumbstick nur reagieren wenn ein "rechter" Spieler vorhanden ist
            if (VirtualThumbsticks.RightThumbstickCenter.HasValue && !boRechterAutomodus)
            {
                //"rechter" Spieler beginnt, Also Ball nach links
                if (!boSpielLaeuft)
                {
                    boSpielLaeuft = true;
                    boBallnachRechts = false;
                }
                //Nur die Y Achse des Thumbsticks auswerten
                //Bei Bewegung nach unten wird Y positiv
                if (VirtualThumbsticks.RightThumbstick.Y > fThumbStickTrigger)
                {
                    //Paddle bewegen
                    positionRechtesPad.Y += 10;
                    //Die Spielfeldbeschränkung beachten
                    if (positionRechtesPad.Y > iMaximalY)
                        positionRechtesPad.Y = iMaximalY;
                }
                //Bei Bewegung nach oben wird Y negativ
                if (VirtualThumbsticks.RightThumbstick.Y < -fThumbStickTrigger)
                {
                    //Paddle bewegen
                    positionRechtesPad.Y -= 10;
                    //Die Spielfeldbeschränkung beachten
                    if (positionRechtesPad.Y < 0)
                        positionRechtesPad.Y = 0;
                }
            }
            else
            {
                //"rechter" Automodus nur wenn der Ball auch nach rechts bewegt wird
                if (boRechterAutomodus && boBallnachRechts)
                {
                    //Position des Balls mit der Mitte des Paddles vergleichen und ggf. nach unten bewegen
                    if (positionBall.Y > positionRechtesPad.Y + (texRechtesPaddel.Height / 2))
                    {
                        positionRechtesPad.Y += 10;
                        //Die Spielfeldbeschränkung beachten
                        if (positionRechtesPad.Y > iMaximalY)
                            positionRechtesPad.Y = iMaximalY;
                    }
                    //Position des Balls mit der Mitte des Paddles vergleichen und ggf. nach oben bewegen
                    if (positionBall.Y < positionRechtesPad.Y + (texRechtesPaddel.Height / 2))
                    {
                        positionRechtesPad.Y -= 10;
                        //Die Spielfeldbeschränkung beachten
                        if (positionRechtesPad.Y < 0)
                            positionRechtesPad.Y = 0;
                    }
                }
            }
        }
        
        //Ball bewegen & Punktvergabe
        protected void BallHandler(GameTime gameTime)
        {
            //Simple Ballbewegung nach rechts oder links
            if (boBallnachRechts)
            {
                //Ball auf der X-Achse nach rechts verschieben
                positionBall.X += iBallBewegung;
                //Kollision mit rechter Seitenwand prüfen
                if (positionBall.X > graphics.GraphicsDevice.Viewport.Width - texBall.Width)
                {
                    //Treffer: Punkt zählen und Richtung wehcseln
                    boBallnachRechts = false;
                    //Punkt nur werten wenn das Spiel wirklich läuft
                    if (boSpielLaeuft)
                        iRechtsTreffer++;
                }
            }
            else
            {
                //Ball auf der X-Achse nach links verschieben
                positionBall.X -= iBallBewegung;
                //Kollision mit linker Seitenwand prüfen
                if (positionBall.X < 0)
                {
                    //Treffer: Punkt zählen und Richtung wehcseln
                    boBallnachRechts = true;
                    //Punkt nur werten wenn das Spiel wirklich läuft
                    if (boSpielLaeuft)
                        iLinksTreffer++;
                }
            }
            //Simple Ballbewegung nach oben oder unten
            if (boBallnachOben)
            {
                //Ball auf der Y-Achse nach oben verschieben
                positionBall.Y -= iBallBewegung;
                //Kollision mit oberer Seitenwand prüfen
                if (positionBall.Y < 0)
                    boBallnachOben = false;
            }
            else
            {
                //Ball auf der Y-Achse nach unten verschieben
                positionBall.Y += iBallBewegung;
                //Kollision mit unterer Seitenwand prüfen
                if (positionBall.Y > graphics.GraphicsDevice.Viewport.Height - texBall.Height)
                    boBallnachOben = true;
            }
        }
        
        //Ball/Paddle Kollision prüfen
        protected void KollisionsHandler(GameTime gameTime)
        {
            //Paddle Kollision überprüfen
            Rectangle rcBall = new Rectangle((int)positionBall.X, (int)positionBall.Y, texBall.Width, texBall.Height);
            Rectangle rcPaddle;
            if (boBallnachRechts)
                rcPaddle = new Rectangle((int)positionRechtesPad.X, (int)positionRechtesPad.Y, texRechtesPaddel.Width, texRechtesPaddel.Height);
            else
                rcPaddle = new Rectangle((int)positionLinkesPaddel.X, (int)positionLinkesPaddel.Y, textLinkesPaddel.Width, textLinkesPaddel.Height);
            //Bei Kollision die Richtung ändern
            if (rcBall.Intersects(rcPaddle))
                    boBallnachRechts = !boBallnachRechts;
        }
        //Positionen & Spielstand initialisieren
        protected void InitialisiereSpiel()
        {
            //Treffer Anzahl zurücksetzten
            iRechtsTreffer = 0;
            iLinksTreffer = 0;
            //Paddel zurücksetzen
            positionLinkesPaddel.Y = (graphics.GraphicsDevice.Viewport.Height / 2) - (textLinkesPaddel.Height / 2);
            positionRechtesPad.Y = (graphics.GraphicsDevice.Viewport.Height / 2) - (texRechtesPaddel.Height / 2);
            //Ball zurücksetzen
            positionBall.Y = (graphics.GraphicsDevice.Viewport.Height / 2) - (texBall.Height / 2);
            positionBall.X = (graphics.GraphicsDevice.Viewport.Width / 2) - (texBall.Width / 2);
        }
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
            spriteBatch.Begin();
            //Zeichnen
            //1. Hintergrund
            spriteBatch.Draw(texHintergrund, new Vector2(0, 0), Color.White);
            //2. Spielstand
            string strStatus = "Links: " + iRechtsTreffer.ToString() + " Rechts: " + iLinksTreffer.ToString();
            Vector2 vStatus = fntStatus.MeasureString(strStatus);
            spriteBatch.DrawString(fntStatus, 
                strStatus, new Vector2((graphics.GraphicsDevice.Viewport.Width / 2) - (vStatus.X/2), 10), Color.LightGray);
            //3. Spieler/CPU Symbole
            if (boLinkerAutomodus)
                spriteBatch.Draw(texCPU, new Vector2(8, 8), Color.White);
            else
                spriteBatch.Draw(texSpieler, new Vector2(8, 8), new Color(64, 64, 64, 128));
            if(boRechterAutomodus)
                spriteBatch.Draw(texCPU, new Vector2(graphics.GraphicsDevice.Viewport.Width - texCPU.Width - 8, 8), Color.White);
            else
                spriteBatch.Draw(texSpieler, new Vector2(graphics.GraphicsDevice.Viewport.Width - texSpieler.Width - 8, 8), new Color(64, 64, 64, 128));
            //4. Linkes Paddle
            spriteBatch.Draw(textLinkesPaddel, positionLinkesPaddel, Color.Yellow);
            //5. Rechtes Paddle
            spriteBatch.Draw(texRechtesPaddel, positionRechtesPad, Color.Blue);
            //6. Ball
            spriteBatch.Draw(texBall, positionBall, Color.White);
            //7. Wenn noch nicht gestartet Infotext
            if(!boSpielLaeuft)
            {
                strStatus = "Double-Tap in einer\nSpielhälfte um einzusteigen";
                vStatus = fntStatus.MeasureString(strStatus);
                spriteBatch.DrawString(fntStatus,
                    strStatus, new Vector2(
                        (graphics.GraphicsDevice.Viewport.Width / 2) - (vStatus.X / 2),
                        (graphics.GraphicsDevice.Viewport.Height / 2) - (vStatus.Y / 2)),
                        Color.Green);
            }
            //Zeichen Ende
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}
