using System;
using System.Collections.Generic;
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.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace WindowsGame1.Scene {
    public class GamePlay : GameScene {
        #region ×Ö¶Î        
        SpriteBatch spriteBatch;
        SpriteFont font;
        Rectangle viewportRect;

        AudioEngine audioEngine;
        WaveBank waveBank;
        SoundBank soundBank;

        MouseState prevMouseState;
        KeyboardState prevKeyboardState;
        int score = 0;
        int totalscore = 0;
        string strMsg;

        GameObject stars;
        GameObject ball;
        float ballspeed = 1.0f;
        int level = 1;
        GameObject bar;
        GameObject[,] blocks;
        List<GameObject> cannonBalls;
        const int firemode = 25;
        const int maxCannonBalls = 1;
        const int blocksColumns = 6;
        const int blocksRows = 5;
        #endregion
        public GamePlay(Game game)
            : base(game, "GamePlay")
        {
        }

        public override void Initialize()
        {
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            viewportRect = new Rectangle(0, 0,
                GraphicsDevice.Viewport.Width,
                GraphicsDevice.Viewport.Height);
            prevMouseState = Mouse.GetState();

            font = Game.Content.Load<SpriteFont>("Fonts\\SpriteFont1");
            strMsg = "Please Enter 'P' To Start.";
            stars = new GameObject(Game.Content.Load<Texture2D>("Images\\stars"));
            ball = new GameObject(Game.Content.Load<Texture2D>("Images\\ball"));
            bar = new GameObject(Game.Content.Load<Texture2D>("Images\\bar"));
            blocks = new GameObject[blocksRows, blocksColumns];
            for (int i = 0; i < blocksRows; i++)
            {
                for (int j = 0; j < blocksColumns; j++)
                {
                    blocks[i, j] = new GameObject(Game.Content.Load<Texture2D>("Images\\block"));
                }
            }
            cannonBalls = new List<GameObject>();
            ResetGame();
            audioEngine = new AudioEngine("Content\\new Project2.xgs");
            waveBank = new WaveBank(audioEngine, "Content\\Wave Bank.xwb");
            soundBank = new SoundBank(audioEngine, "Content\\Sound Bank.xsb");
            BeginPause();
        }

        private void ResetGame()
        {
            ball.position = new Vector2(
                (viewportRect.Width / 2) - ball.center.X,
                viewportRect.Height - ball.sprite.Height - bar.sprite.Height);
            ball.velocity = new Vector2(
                (DateTime.Now.Millisecond % 2 == 0) ? -3.0f : 3.0f,
                -3.0f);
            bar.position = new Vector2(
                (viewportRect.Width / 2) - bar.center.X,
                viewportRect.Height - bar.sprite.Height);
            bar.velocity = new Vector2(6.0f, 0.0f);
            for (int i = 0; i < blocksRows; i++)
            {
                for (int j = 0; j < blocksColumns; j++)
                {
                    blocks[i, j].position = new Vector2(
                        (j + 0.4f) * (blocks[i, j].sprite.Width * 1.2f),
                        (i + 1) * (blocks[i, j].sprite.Height * 1.2f));
                    blocks[i, j].alive = true;
                }
            }
            foreach (GameObject cannonball in cannonBalls)
            {
                cannonball.alive = false;
                cannonball.position = bar.position + bar.center;
                cannonball.velocity = Vector2.Zero;
            }
        }

        protected override void UnloadContent()
        {
        }

        public override void Update(GameTime gameTime)
        {
            KeyboardState keyboardState = Keyboard.GetState();
            // Allows the game to exit
            //if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
              //  keyboardState.IsKeyDown(Keys.Escape))
             //   this.Exit();

            checkPauseKey(keyboardState);
            // If the user hasn't paused, Update normally
            if (!paused)
            {
                UpdateBall();
                UpdateBlock();
                UpdateBar(keyboardState);
                UpdateCannonBalls();
                if (score >= firemode)
                {
                    if (Mouse.GetState().LeftButton == ButtonState.Pressed ||
                                (keyboardState.IsKeyDown(Keys.Space) &&
                                prevKeyboardState.IsKeyUp(Keys.Space)))
                    {
                        FireCannonBall();
                    }
                }
                if (score >= 30)
                {
                    strMsg = "You Won... Please Press 'P' to continue.";
                    soundBank.PlayCue("victory");
                    BeginPause();
                }
                prevKeyboardState = keyboardState;
                audioEngine.Update();
            }
            base.Update(gameTime);
        }

        private void UpdateCannonBalls()
        {
            foreach (GameObject cannonball in cannonBalls)
            {
                if (cannonball.alive)
                {
                    cannonball.position += cannonball.velocity;
                    if (!viewportRect.Contains(new Point(
                        (int)cannonball.position.X,
                        (int)cannonball.position.Y)))
                    {
                        cannonball.alive = false;
                        continue;
                    }

                    foreach (GameObject block in blocks)
                    {
                        if (block.alive && Collide(block, cannonball))
                        {
                            cannonball.alive = false;
                            block.alive = false;
                            score += 1;
                            soundBank.PlayCue("BreakoutBlockKill");
                            break;
                        }
                    }
                }
            }
        }

        private void FireCannonBall()
        {
            foreach (GameObject cannonball in cannonBalls)
            {
                if (!cannonball.alive)
                {
                    cannonball.alive = true;
                    cannonball.position = bar.position + bar.center;
                    cannonball.velocity = new Vector2(0, -10.0f);
                    return;
                }
            }
            if (maxCannonBalls < 1 || cannonBalls.Count < maxCannonBalls)
            {
                GameObject newBall = new GameObject(Game.Content.Load<Texture2D>("Images\\cannonball"));
                newBall.alive = true;
                newBall.position = bar.position + bar.center;
                newBall.velocity = new Vector2(0, -10.0f);
                cannonBalls.Add(newBall);
            }
        }

        private void UpdateBlock()
        {
            foreach (var block in blocks)
            {
                if (block.alive && Collide(block, ball))
                {
                    soundBank.PlayCue("BreakoutBlockKill");
                    if (Math.Abs(Vector2.Distance(
                        block.position + block.center, ball.position + ball.center)) <
                        ball.center.X + block.center.X)
                    {
                        ball.velocity.Y *= -1;
                    }
                    else
                    {
                        ball.velocity.X *= -1;
                    }
                    block.alive = false;
                    score++;
                }
            }
        }

        private void UpdateBar(KeyboardState keyboardState)
        {
            if (keyboardState.IsKeyDown(Keys.Left))
                bar.position.X -= bar.velocity.X;
            if (keyboardState.IsKeyDown(Keys.Right))
                bar.position.X += bar.velocity.X;

            MouseState mouseState = Mouse.GetState();
            if (mouseState.X != prevMouseState.X)
                bar.position.X = mouseState.X;
            prevMouseState = mouseState;

            if (bar.position.X < 0)
                bar.position.X = 0;
            if (bar.position.X > viewportRect.Width - bar.sprite.Width)
                bar.position.X = viewportRect.Width - bar.sprite.Width;
        }

        private void UpdateBall()
        {
            ball.position += ball.velocity * ballspeed;
            if (ball.position.X + ball.sprite.Width > viewportRect.Width || ball.position.X < 0)
            {
                soundBank.PlayCue("PongBallHit");
                ball.velocity.X *= -1;
            }
            if (ball.position.Y < 0)
            {
                soundBank.PlayCue("PongBallHit");
                ball.velocity.Y *= -1;
            }
            if (ball.position.Y + ball.sprite.Height > viewportRect.Height - bar.sprite.Height)
            {
                if (Collide(bar, ball))
                {
                    soundBank.PlayCue("PongBallHit");
                    ball.velocity.X += ((ball.position.X + ball.center.X) - (bar.position.X + bar.center.X)) / 10.0f;
                    ball.velocity.X =
                        ball.velocity.X > 6.0f ? 6.0f :
                        ball.velocity.X < -6.0f ? -6.0f :
                        ball.velocity.X;
                    ball.velocity.Y *= -1;
                }
                else
                {
                    Game1.SceneManager.AddScene(new GameOver(Game));
                    soundBank.PlayCue("lose");
                    //strMsg = "You Lost... Please Enter 'P' To Continue.";
                    BeginPause();
                }
            }
        }

        private bool Collide(GameObject objA, GameObject objB)
        {
            Rectangle rectA = new Rectangle((int)objA.position.X,
                (int)objA.position.Y, objA.sprite.Width, objA.sprite.Height);
            Rectangle rectBall = new Rectangle((int)objB.position.X,
                (int)objB.position.Y, objB.sprite.Width, objB.sprite.Height);
            return rectA.Intersects(rectBall);
        }

        #region pause game fun
        private bool paused = false;
        private bool pauseKeyDown = false;

        private void BeginPause()
        {
            paused = true;
            //TODO: Pause audio playback
            //TODO: Pause controller vibration
        }

        private void EndPause()
        {
            //TODO: Resume audio
            //TODO: Resume controller vibration
            if ((score >= 30) ||
                (ball.position.Y + ball.sprite.Height >
                viewportRect.Height - bar.sprite.Height && !Collide(bar, ball)))
            {
                if (score >= 30)
                {
                    totalscore += 30;
                    ballspeed += 0.25f;
                    level++;
                }
                score = 0;
                ResetGame();
                BeginPause();
            }
            paused = false;
        }

        private void checkPauseKey(KeyboardState keyboardState)
        {
            bool pauseKeyDownThisFrame = keyboardState.IsKeyDown(Keys.P);
            // If key was not down before, but is down now, we toggle the
            // pause setting
            if (!pauseKeyDown && pauseKeyDownThisFrame)
            {
                if (!paused)
                {
                    strMsg = "PAUSED... Please Enter 'P' To Continue.";
                    BeginPause();
                }
                else
                    EndPause();
            }
            pauseKeyDown = pauseKeyDownThisFrame;
        }
        #endregion

        public override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            spriteBatch.Begin();
            spriteBatch.Draw(stars.sprite, viewportRect, Color.White);
            spriteBatch.Draw(ball.sprite, ball.position, Color.White);
            foreach (GameObject cannonball in cannonBalls)
            {
                if (cannonball.alive)
                {
                    spriteBatch.Draw(cannonball.sprite, cannonball.position, Color.White);
                }
            }
            spriteBatch.Draw(bar.sprite, bar.position, Color.White);
            foreach (var block in blocks)
            {
                if (block.alive)
                {
                    spriteBatch.Draw(block.sprite, block.position, Color.White);
                }
            }
            if (score >= firemode)
            {
                spriteBatch.DrawString(font, "Fire Mode", new Vector2(viewportRect.Width - 100, 5), Color.Red);
            }
            spriteBatch.DrawString(font, "Level : " + level + "   Score : " + (totalscore + score), new Vector2(10, 5), Color.Red);
            if (paused)
            {
                spriteBatch.DrawString(font, strMsg,
                    new Vector2(viewportRect.Center.X, viewportRect.Center.Y),
                    Color.Yellow, 0.0f, font.MeasureString(strMsg) / 2, 1.0f,
                    SpriteEffects.None, 0.0f);
            }
            spriteBatch.End();

            base.Draw(gameTime);
        }
    }

}
