#region Using Statements
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.GamerServices;
#endregion

namespace Fireball
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        Wizard dWSprite;
        Knight knightSprite;
        Gangster gangsterSprite;
        Sprite mBackgroundOne;
        Sprite mBackgroundTwo;
        Sprite mBackgroundThree;
        Sprite hearts0;
        Sprite hearts1;
        Sprite hearts2;
        Sprite hearts3;
        Sprite hearts4;
        Sprite hearts5;
        Sprite hearts6;
        Sprite arrow;
        Sprite lever;
        SpriteEffects mEffect;

        Texture2D mTitle;
        Texture2D mGameOver;
        Texture2D mVictory;

        List<Gangster> mGangsters = new List<Gangster>();

        enum ScreenState
        {
            Title,
            Level1,
            GameOver,
            Victory
        }

        ScreenState mCurrentScreen;

        /*SoundEffect lightningSound;
        SoundEffectInstance lightningClip;*/

        SoundEffect clashSound;
        SoundEffectInstance clashClip;

        SoundEffect punchSound;
        SoundEffectInstance punchClip;

        SoundEffect groanSound;
        SoundEffectInstance groanClip;

        int health;
        bool cleared;
        int stage;
        bool advanceScreen;
        bool hitCheck;
        int timeToDrawArrow;
        int spawnCount;
        bool leverSwitch;
        int timeToWin;
        int timeSinceHit;

        public Game1()
            : base()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        /// <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
             dWSprite = new Wizard("Dark Wizard.gif", new Vector2(712,250));
            // dWSprite = new Wizard("Dark Wizard.gif", new Vector2(1424, 250));

            knightSprite = new Knight("Knight Stance 1.png", new Vector2(20, 410));
            knightSprite.Scale = 1.25f;

            gangsterSprite = new Gangster("Gangster 3.png", new Vector2(800, 250), true);
            gangsterSprite.Scale = 1.25f;
            mGangsters.Add(gangsterSprite);

            hearts0 = new Sprite("0.png", new Vector2(10, 0));
            hearts1 = new Sprite("1.png", new Vector2(10, 0));
            hearts2 = new Sprite("2.png", new Vector2(10, 0));
            hearts3 = new Sprite("3.png", new Vector2(10, 0));
            hearts4 = new Sprite("4.png", new Vector2(10, 0));
            hearts5 = new Sprite("5.png", new Vector2(10, 0));
            hearts6 = new Sprite("6.png", new Vector2(10, 0));
            hearts0.Scale = 1.2f;
            hearts1.Scale = 1.2f;
            hearts2.Scale = 1.2f;
            hearts3.Scale = 1.2f;
            hearts4.Scale = 1.2f;
            hearts5.Scale = 1.2f;
            hearts6.Scale = 1.2f;

            mEffect = SpriteEffects.None;
            lever = new Sprite("Lever.png", new Vector2(730, 290));
            leverSwitch = false;

            arrow = new Sprite("arrow.png", new Vector2(700, 250));
            arrow.Scale = 0.25f;

            health = 6;
            cleared = false;
            stage = 1;
            advanceScreen = false;
            hitCheck = false;
            timeToDrawArrow = 0;
            spawnCount = 0;
            timeToWin = 0;
            timeSinceHit = 0;

            mBackgroundOne = new Sprite("Dojo.png", new Vector2(0, 0));
            mBackgroundOne.Scale = 2f;

            mBackgroundTwo = new Sprite("Gym.png", new Vector2(900, 0));
            mBackgroundTwo.Scale = 2f;

            mBackgroundThree = new Sprite("Gym2.png", Vector2.Zero);
            mBackgroundThree.Scale = 2f;

            mTitle = Content.Load<Texture2D>("TitleScreen");
            mGameOver = Content.Load<Texture2D>("GameOverScreen");
            mVictory = Content.Load<Texture2D>("VictoryScreen");
            mCurrentScreen = ScreenState.Title;

            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);

            // TODO: use this.Content to load your game content here
            dWSprite.LoadContent(this.Content);
            knightSprite.LoadContent(this.Content);
            foreach (Gangster aGangster in mGangsters)
            {
                aGangster.LoadContent(this.Content);
            }

            hearts0.LoadContent(this.Content);
            hearts1.LoadContent(this.Content);
            hearts2.LoadContent(this.Content);
            hearts3.LoadContent(this.Content);
            hearts4.LoadContent(this.Content);
            hearts5.LoadContent(this.Content);
            hearts6.LoadContent(this.Content);

            arrow.LoadContent(this.Content);
            lever.LoadContent(this.Content);

            mBackgroundOne.LoadContent(this.Content);
            mBackgroundTwo.LoadContent(this.Content);
            mBackgroundThree.LoadContent(this.Content);

            /*lightningSound = this.Content.Load<SoundEffect>("lightning");
            lightningClip = lightningSound.CreateInstance();
            lightningClip.IsLooped = false;*/

            clashSound = this.Content.Load<SoundEffect>("clash");
            clashClip = clashSound.CreateInstance();
            clashClip.IsLooped = false;

            punchSound = this.Content.Load<SoundEffect>("punch");
            punchClip = punchSound.CreateInstance();
            punchClip.IsLooped = false;

            groanSound = this.Content.Load<SoundEffect>("groan");
            groanClip = groanSound.CreateInstance();
            groanClip.IsLooped = false;
        }

        /// <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)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
                Exit();

            // TODO: Add your update logic here

            switch (mCurrentScreen)
            {
                case ScreenState.Level1: 
                {
                    if (health <= 0)
                    {
                        mCurrentScreen = ScreenState.GameOver;
                        // lightningClip.Play();
                    }

                    timeSinceHit++;

                    if (stage >= 5)
                    {
                        dWSprite.Update(gameTime);
                    }

                    knightSprite.Update(gameTime);

                    if (mBackgroundOne.Position.X < -mBackgroundOne.Size.Width)
                    {
                        mBackgroundOne.Position.X = mBackgroundTwo.Position.X + mBackgroundTwo.Size.Width;
                        advanceScreen = false;
                        stage++;
                    }

                    if (mBackgroundTwo.Position.X < -mBackgroundTwo.Size.Width)
                    {
                        mBackgroundTwo.Position.X = mBackgroundOne.Position.X + mBackgroundOne.Size.Width;
                        advanceScreen = false;
                        stage++;
                    }

                    Vector2 aDirection = new Vector2(-1, 0);
                    Vector2 aSpeed = new Vector2(250, 0);

                    if (knightSprite.Position.X >= 650 && advanceScreen)
                    {
                        knightSprite.Position.X = 649; 
                        mBackgroundOne.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
                        mBackgroundTwo.Position += aDirection * aSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds;
                    }

                    if (stage == 5)
                    {
                        mBackgroundOne.Position += aDirection * 350 * (float)gameTime.ElapsedGameTime.TotalSeconds;
                        mBackgroundTwo.Position += aDirection * 350 * (float)gameTime.ElapsedGameTime.TotalSeconds;

                        knightSprite.Position.X -= 450 * (float)gameTime.ElapsedGameTime.TotalSeconds;
                    }

                    foreach (Fireball aFireball in dWSprite.mFireballs)
                    {
                        if (knightSprite.Intersects(aFireball, 10) && aFireball.contact == true && timeSinceHit > 100)
                        {
                            knightSprite.Position.X -= 100;
                            // knightSprite.Position.X = 0;
                            health--;
                            aFireball.contact = false;
                            aFireball.Visible = false;
                            timeSinceHit = 0;
                        }
                    }

                    if (dWSprite.health == 1)
                    {
                        if (stage == 6)
                        {
                            mBackgroundOne.Position += aDirection * 350 * (float)gameTime.ElapsedGameTime.TotalSeconds;
                            mBackgroundTwo.Position += aDirection * 350 * (float)gameTime.ElapsedGameTime.TotalSeconds;

                            knightSprite.Position.X -= 450 * (float)gameTime.ElapsedGameTime.TotalSeconds;
                        }
                    }

                    if (stage == 7)
                    {
                        hitCheck = false;

                        Gangster aGangster = new Gangster("Gangster 3.png", new Vector2(825, 250), true);
                        Gangster aGangster2 = new Gangster("Gangster 3.png", new Vector2(825, 350), true);
                        aGangster.LoadContent(this.Content);
                        aGangster2.LoadContent(this.Content);
                        aGangster.Scale = 1.25f;
                        aGangster2.Scale = 1.25f;

                        mGangsters.Add(aGangster);
                        mGangsters.Add(aGangster2);

                        stage++;
                    }

                    if (dWSprite.health == 0 && stage == 8)
                    {
                        dWSprite.Position.X = -500;
                        stage++;
                        advanceScreen = true;
                    }

                    if (stage == 10)
                    {
                        Gangster aGangster = new Gangster("Gangster 3.png", new Vector2(0, 250), false);
                        Gangster aGangster2 = new Gangster("Gangster 3.png", new Vector2(-25, 350), false);
                        Gangster aGangster3 = new Gangster("Gangster 3.png", new Vector2(-15, 450), false);
                        Gangster aGangster4 = new Gangster("Gangster 3.png", new Vector2(-30, 375), false);
                        aGangster.LoadContent(this.Content);
                        aGangster2.LoadContent(this.Content);
                        aGangster3.LoadContent(this.Content);
                        aGangster4.LoadContent(this.Content);
                        aGangster.Scale = 1.25f;
                        aGangster2.Scale = 1.25f;
                        aGangster3.Scale = 1.25f;
                        aGangster4.Scale = 1.25f;

                        mGangsters.Add(aGangster);
                        mGangsters.Add(aGangster2);
                        mGangsters.Add(aGangster3);
                        mGangsters.Add(aGangster4);

                        stage++;
                    }

                    if (stage == 13)
                    {
                        Gangster aGangster = new Gangster("Gangster 3.png", new Vector2(0, 250 + 2*spawnCount), false);
                        aGangster.LoadContent(this.Content);
                        aGangster.Scale = 1.25f;
                        mGangsters.Add(aGangster);
                        spawnCount++;
                        if (spawnCount > 100)
                        {
                            spawnCount = 0;
                            stage++;
                        }
                    }

                    if (stage == 14)
                    {
                        if (knightSprite.Intersects(lever, 10))
                        {
                            bool swinging = knightSprite.touchEnemy();
                            if (swinging)
                            {
                                mEffect = SpriteEffects.FlipHorizontally;
                                leverSwitch = true;
                                stage++;
                            }
                            else
                            {
                                knightSprite.Position.Y = knightSprite.Position.Y + 5;
                            }
                        }
                    }

                    if (stage == 15)
                    {
                        bool advance = true;
                        foreach (Gangster aGangster in mGangsters)
                        {
                            if (aGangster.Position.X < 400 && aGangster.notFlying())
                            {
                                aGangster.Position.Y += 5;
                            }
                            if (aGangster.Position.Y > 450)
                            {
                                aGangster.health = 0;
                            }
                        }

                        if (knightSprite.Position.X < 400)
                        {
                            knightSprite.Position.X = 400;
                        }

                        foreach (Gangster aGangster in mGangsters)
                        {
                            if (aGangster.health > 0)
                            {
                                advance = false;
                            }
                        }

                        if (advance)
                        {
                            timeToWin++;
                            if (timeToWin > 100)
                            {
                                stage++;
                            }
                        }

                        if (knightSprite.Intersects(lever, 10))
                        {
                            knightSprite.Position.Y = knightSprite.Position.Y + 5;
                        }
                    }

                    if (stage == 16)
                    {
                        mCurrentScreen = ScreenState.Victory;
                    }

                    if (knightSprite.Intersects(dWSprite, 10) && stage >= 5 && !hitCheck)
                    {
                        bool swinging = knightSprite.touchEnemy();
                        if (swinging)
                        {
                            dWSprite.health--;
                            hitCheck = true;
                        }
                        else if (timeSinceHit > 100)
                        {
                            health--;
                            knightSprite.Position.X = knightSprite.Position.X - 200;
                            timeSinceHit = 0;
                        }
                    }

                    foreach (Gangster aGangster in mGangsters)
                    {

                        /*if (aGangster.health > 0)
                        {
                            if (stage != 8)
                            {
                                aGangster.Update(gameTime, knightSprite);
                            }
                            else if (aGangster.Position.X > 150 || knightSprite.Position.X > 150)
                            {
                                aGangster.Update(gameTime, knightSprite);
                            }
                        }*/

                        if (aGangster.health > 0)
                        {
                            aGangster.Update(gameTime, knightSprite);
                        }

                        if (knightSprite.Intersects(aGangster, 0))
                        {
                            bool direction = false;
                            bool swinging = knightSprite.touchEnemy();
                            bool punching = aGangster.touchHero();
                            if (aGangster.Position.X > knightSprite.Position.X)
                            {
                                direction = false;
                            }
                            else
                            {
                                direction = true;
                            }
                            if (swinging && punching)
                            {
                                clashClip.Play();
                                knightSprite.takeHit(120, direction);
                                aGangster.takeHit(120, direction);
                            }
                            else if (swinging)
                            {
                                groanClip.Play();
                                aGangster.health--;
                                aGangster.takeHit(120, direction);
                                aGangster.stun();
                                if (aGangster.health < 1)
                                {
                                    aGangster.Position.X = -200;
                                    cleared = true;
                                }
                            }
                            else if (punching && timeSinceHit > 100)
                            {
                                health--;
                                knightSprite.takeHit(120, direction);
                                punchClip.Play();
                                timeSinceHit = 0;
                            }
                        }

                        foreach (Gangster bGangster in mGangsters)
                        {
                            if (bGangster.health > 0)
                            {
                                cleared = false;
                            }

                            if (aGangster.Intersects(bGangster, 5) && aGangster != bGangster)
                            {
                                if (aGangster.Position.X - bGangster.Position.X > 0)
                                {
                                    aGangster.Position.X = aGangster.Position.X + 5;
                                    aGangster.Position.Y = aGangster.Position.Y + 5;
                                }
                                else 
                                {
                                    aGangster.Position.X = aGangster.Position.X - 5;
                                    aGangster.Position.Y = aGangster.Position.Y - 5;
                                }
                            }
                        }
                    }

                    if (stage == 3)
                    {
                        Gangster aGangster = new Gangster("Gangster 3.png", new Vector2(-25,250), false);
                        Gangster aGangster2 = new Gangster("Gangster 3.png", new Vector2(0, 350), false);
                        aGangster.LoadContent(this.Content);
                        aGangster2.LoadContent(this.Content);
                        aGangster.Scale = 1.25f;
                        aGangster2.Scale = 1.25f;

                        mGangsters.Add(aGangster);
                        mGangsters.Add(aGangster2);

                        stage++;

                        cleared = false;
                    }

                    if (cleared && stage != 2 && (stage < 5 || stage == 11 || stage == 14 || stage == 15))
                    {
                        advanceScreen = true;
                        cleared = false;
                        stage++;
                    }

                    break;
                }
                case ScreenState.Title:
                {
                    if (Keyboard.GetState().IsKeyDown(Keys.Enter))
                    {
                        mCurrentScreen = ScreenState.Level1;
                    }
                    break;
                }
            }

            base.Update(gameTime);
        }

        /// <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);

            // TODO: Add your drawing code here
            spriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);

            switch (mCurrentScreen) {
                case ScreenState.Victory:
                {
                    spriteBatch.Draw(mVictory, Vector2.Zero, Color.White);
                    break;
                }
                case ScreenState.GameOver:
                {
                    spriteBatch.Draw(mGameOver, Vector2.Zero, Color.White);
                    break;
                }
                case ScreenState.Title:
                {
                    spriteBatch.Draw(mTitle, Vector2.Zero, Color.White);
                    break;
                }
                case ScreenState.Level1:
                {
                    mBackgroundOne.Draw(this.spriteBatch, 1f);
                    if (leverSwitch == false)
                    {
                        mBackgroundTwo.Draw(this.spriteBatch, 1f);
                    }
                    else
                    {
                        mBackgroundThree.Draw(this.spriteBatch, 1f);
                    }

                    if (stage >= 13)
                    {
                        lever.Draw(this.spriteBatch, mEffect, 0f);
                    }

                    if (stage == 2 || stage == 9 || stage == 12)
                    {
                        timeToDrawArrow++;
                        if (timeToDrawArrow < 20) {
                            arrow.Draw(this.spriteBatch);
                        }
                        else if (timeToDrawArrow > 40)
                        {
                            timeToDrawArrow = 0;
                        }
                    }

                    if (stage >= 5)
                    {
                        dWSprite.Draw(this.spriteBatch);
                    }

                    knightSprite.Draw(this.spriteBatch);
                    foreach (Gangster aGangster in mGangsters)
                    {
                        if (aGangster.health > 0)
                        {
                            aGangster.Draw(this.spriteBatch);
                        }
                    }

                    switch (health)
                    {
                        default:
                            {
                                hearts0.Draw(this.spriteBatch);
                                break;
                            }
                        case 1:
                            {
                                hearts1.Draw(this.spriteBatch);
                                break;
                            }
                        case 2:
                            {
                                hearts2.Draw(this.spriteBatch);
                                break;
                            }
                        case 3:
                            {
                                hearts3.Draw(this.spriteBatch);
                                break;
                            }
                        case 4:
                            {
                                hearts4.Draw(this.spriteBatch);
                                break;
                            }
                        case 5:
                            {
                                hearts5.Draw(this.spriteBatch);
                                break;
                            }
                        case 6:
                            {
                                hearts6.Draw(this.spriteBatch);
                                break;
                            }
                    }
                break;
                }
            }

            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}