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.Media;
using Blindfold.Managers;
using Blindfold.Objects;

namespace Blindfold
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Main : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;


        ObjManager objectManager;
        SoundManager soundManager;
        InputManager inputManager;

        Player player;
        private SpriteFont testFont;
        private Texture2D objectTexture;

        private Texture2D screenTexture;
        private bool debug;

        private bool playing;

        private SoundEffectInstance ambient1;
        private SoundEffectInstance narrator;
        private Monster monster;
        private Guider guider;

        private List<Checkpoint> cpList;
        private Checkpoint finish;
        private  bool introduced;
        private int level;


        #region PROPERTIES
        public InputManager INPUTMANAGER
        {
            get
            {
                return inputManager;
            }
        }
        public ObjManager OBJECTMANAGER
        {
            get
            {
                return objectManager;
            }
        }
        public SoundManager SOUNDMANAGER
        {
            get
            {
                return soundManager;
            }
        }
        public Player PLAYER
        {
            get
            {
                return player;
            }
            set
            {
                player = value;
            }
        }
        public Monster MONSTER
        {
            get
            {
                return monster;
            }
            set
            {
                monster = value;
            }
        }
        public Guider GUIDER
        {
            get
            {
                return guider;
            }
            set
            {
                guider = value;
            }
        }
        public List<Checkpoint> CPList
        {
            get
            {
                return cpList;
            }
        }
        public Checkpoint FINISH
        {
            get
            {
                return finish;
            }
            set
            {
                finish = value;
            }
        }
        public Texture2D OBJTEX
        {
            get
            {
                return objectTexture;
            }
        }
        #endregion


        public Main()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 640;
            graphics.PreferredBackBufferHeight = 480;
            graphics.ApplyChanges();
            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

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

            cpList = new List<Checkpoint>();

            objectManager = new ObjManager(this);
            Components.Add(objectManager);

            inputManager = new InputManager(this);
            Components.Add(inputManager);

            objectTexture = Content.Load<Texture2D>(@"Assets/Gfx/object");
            screenTexture = Content.Load<Texture2D>(@"Assets/Gfx/title");
            testFont = Content.Load<SpriteFont>(@"Assets/Fonts/MenuFont");

            LoadSounds();

            narrator = soundManager.getEffectInstance("narrator_welcome");

            SoundEffect.MasterVolume = 1.0f;

            // 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 (inputManager.buttonHit(Buttons.Back, 0))
                {
                    this.Exit();
                }
            if(!introduced && gameTime.TotalGameTime.Milliseconds > 500)
            {
                if (GamePad.GetState(PlayerIndex.One).IsConnected)
                {
                    narrator.Stop();
                    introduced = true;
                    narrator = soundManager.getEffectInstance("narrator_welcome");
                    narrator.Play();
                }
                else
                {
                    if (!narrator.State.Equals(SoundState.Playing))
                    {
                        narrator = soundManager.getEffectInstance("narrator_plug");
                        narrator.Play();
                    }
                }
            }
            if (!narrator.State.Equals(SoundState.Playing))
            {
                if (!playing)
                {
                    if (inputManager.buttonHit(Buttons.Start, 0))
                    {
                        playing = true;
                        startUp(gameTime);
                    }
                    if (inputManager.buttonHit(Buttons.A, 0) || inputManager.buttonHit(Buttons.B, 0) || inputManager.buttonHit(Buttons.X, 0) || inputManager.buttonHit(Buttons.Y, 0))
                    {
                        narrator = soundManager.getEffectInstance("narrator_controls");
                        narrator.Play();
                    }
                    ambient1.Stop();
                }
                else
                {
                    //Enable Debug Mode
                    if (inputManager.keyHit(Keys.F12))
                    {
                        debug = !debug;
                    }
                    if (ambient1.State != SoundState.Playing)
                    {
                        ambient1.Play();
                    }
                }
            }

            // TODO: Add your update logic here

            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.Black);
            spriteBatch.Begin();
            if (debug && playing)
            {
                spriteBatch.DrawString(testFont, player.POSITION.ToString(), new Vector2(10, 10), Color.White);
                spriteBatch.DrawString(testFont, player.LOOK.ToString(), new Vector2(10, 50), Color.White);
                objectManager.drawAll(spriteBatch);
            }
            else
            {
                spriteBatch.Draw(screenTexture, new Rectangle(0, 0, 640, 480), Color.White);
            }
            spriteBatch.End();

            base.Draw(gameTime);
        }

        public void gameOver()
        {
            narrator = soundManager.getEffectInstance("narrator_gameover");
            narrator.Play();
            while (narrator.State.Equals(SoundState.Playing))
            {
                if (inputManager.buttonHit(Buttons.A, 0) || inputManager.buttonHit(Buttons.Start, 0))
                {
                    narrator.Stop();
                }
            }
            level--;
            nextLevel();
        }

        public void startUp(GameTime gameTime)
        {
            level = 0;
            cpList.Clear();
            narrator = soundManager.getEffectInstance("kat_scene_0");
            narrator.Play();
            int curtime = gameTime.TotalGameTime.Milliseconds;
            while (narrator.State.Equals(SoundState.Playing))
            {
            }             
            LevelManager.loadImage(this, @"Assets/Levels/", "Intro", 16, 16);
            Vector3 l = guider.POSITION - player.POSITION;
            l.Normalize();
            player.LOOK = l;
        }

        public void nextLevel()
        {
            cpList.Clear();
            objectManager.Clear();
            level++;
            narrator = soundManager.getEffectInstance("kat_scene_" + level);
            narrator.Play();
            while(narrator.State.Equals(SoundState.Playing))
            {
                if (inputManager.buttonHit(Buttons.A, 0) || inputManager.buttonHit(Buttons.Start, 0))
                {
                    narrator.Stop();
                }
            }
            if (level < 6)
            {
                LevelManager.loadImage(this, @"Assets/Levels/", "Level" + level, 16, 16);
                Vector3 l = guider.POSITION - player.POSITION;
                l.Normalize();
                player.LOOK = l;
            }
            else
            {
                playing = false;
                introduced = false;
            }
        }

        public void LoadSounds()
        {
            soundManager = new SoundManager(this);

            this.soundManager.add(new SoundEffectInfo(this, "step_l", @"Assets/Audio/SE/Footsteps 1", 0.4f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "step_r", @"Assets/Audio/SE/Footsteps 2", 0.4f, 0f, 0.5f, false));

            this.soundManager.add(new SoundEffectInfo(this, "breath1", @"Assets/Audio/SE/Normal Breathing", 0.1f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "breath2", @"Assets/Audio/SE/Hard Breathing", 0.1f, 0f, 0.5f, false));

            this.soundManager.add(new SoundEffectInfo(this, "monsterstep_l", @"Assets/Audio/SE/Monster Stomp 1", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "monsterstep_r", @"Assets/Audio/SE/Monster Stomp 2", 1, 0f, 0.5f, false));

            //Vocals
            this.soundManager.add(new SoundEffectInfo(this, "kat_run", @"Assets/Audio/Vocals/Kat/Run!", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_follow_0", @"Assets/Audio/Vocals/Kat/Come On!", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_follow_1", @"Assets/Audio/Vocals/Kat/I'm Over Here 1", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_follow_2", @"Assets/Audio/Vocals/Kat/I'm Over Here 2", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_follow_3", @"Assets/Audio/Vocals/Kat/This Way! 1", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_follow_4", @"Assets/Audio/Vocals/Kat/This Way 2", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_follow_5", @"Assets/Audio/Vocals/Kat/Hurry!", 1, 0f, 0.5f, false));

            this.soundManager.add(new SoundEffectInfo(this, "monster_0", @"Assets/Audio/Vocals/Monster/Soft Growl 1", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "monster_1", @"Assets/Audio/Vocals/Monster/Soft Growl 2", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "monster_2", @"Assets/Audio/Vocals/Monster/Soft Growl 3", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "monster_3", @"Assets/Audio/Vocals/Monster/Strong Growl 1", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "monster_4", @"Assets/Audio/Vocals/Monster/Strong Growl 2", 1, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "monster_5", @"Assets/Audio/Vocals/Monster/Strong Growl 3", 1, 0f, 0.5f, false));

            //Narrator
            this.soundManager.add(new SoundEffectInfo(this, "narrator_welcome", @"Assets/Audio/Vocals/Narrator/Narrator 1", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "narrator_controls", @"Assets/Audio/Vocals/Narrator/Narrator 2", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "narrator_plug", @"Assets/Audio/Vocals/Narrator/Please Plug In", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "narrator_gameover", @"Assets/Audio/Vocals/Narrator/Game Over", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_scene_0", @"Assets/Audio/Vocals/Kat/Intro Scene", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_scene_1", @"Assets/Audio/Vocals/Kat/Kate 2", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_scene_2", @"Assets/Audio/Vocals/Kat/Kate 4", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_scene_3", @"Assets/Audio/Vocals/Kat/Kate 6", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_scene_4", @"Assets/Audio/Vocals/Kat/Kate 8", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_scene_5", @"Assets/Audio/Vocals/Kat/Kate 10", 0.3f, 0f, 0.5f, false));
            this.soundManager.add(new SoundEffectInfo(this, "kat_scene_6", @"Assets/Audio/SE/Ending Scene", 0.3f, 0f, 0.5f, false));

            this.soundManager.add(new SoundEffectInfo(this, "easteregg", @"Assets/Audio/SE/Guard Easter Egg", 1, 0f, 0.5f, true));
            this.soundManager.add(new SoundEffectInfo(this, "ambient1", @"Assets/Audio/SE/Room Tone", 1, 0f, 0.5f, true));
            ambient1 = soundManager.getEffectInstance("ambient1");
        }
    }
}
