#region File Description
//-----------------------------------------------------------------------------
// GameplayScreen.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion

#region Using Statements
using System;
using System.Threading;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using TiledLib;
#endregion

namespace Snake
{
    /// <summary>
    /// This screen implements the actual game logic. It is just a
    /// placeholder to get the idea across: you'll probably want to
    /// put some more interesting gameplay in here!
    /// </summary>
    class GameplayScreen : GameScreen
    {
        #region Fields

        ContentManager content;
        SpriteFont gameFont;

        Texture2D life;
        SpriteBatch spriteBatch;
        Snake snake;
        Direction currentDir;
        int time = 0;
        Map map;
        Level level;
        int lives = 3;
        int score = 0;
        int levelNum = 1;
        bool needTitle = true;

        public int Lives
        {
            get { return lives; }
        }

        public int Score
        {
            get { return score; }
        }

        public int Level
        {
            get { return levelNum; }
        }

        float pauseAlpha;

        #endregion

        #region Initialization


        /// <summary>
        /// Constructor.
        /// </summary>
        public GameplayScreen(int num = 0, int score = 0, int lives = 3)
        {
            this.levelNum = num;
            this.score = score;
            this.lives = lives;
            TransitionOnTime = TimeSpan.FromSeconds(1.5);
            TransitionOffTime = TimeSpan.FromSeconds(0.5);
        }


        /// <summary>
        /// Load graphics content for the game.
        /// </summary>
        public override void LoadContent()
        {
            if (content == null)
                content = new ContentManager(ScreenManager.Game.Services, "Content");
            spriteBatch = new SpriteBatch(ScreenManager.GraphicsDevice);

            gameFont = content.Load<SpriteFont>("gamefont");
            Snake.Load(content);
            Bonus.Load(content);
            Wormhole.Load(content);
            life = content.Load<Texture2D>("life");
            map = content.Load<Map>(string.Format("level{0}", levelNum + 1));
            StartGame();
            ScreenManager.Game.ResetElapsedTime();
        }


        /// <summary>
        /// Unload graphics content used by the game.
        /// </summary>
        public override void UnloadContent()
        {
            content.Unload();
        }


        #endregion

        #region Update and Draw


        /// <summary>
        /// Updates the state of the game. This method checks the GameScreen.IsActive
        /// property, so the game will stop updating when the pause menu is active,
        /// or if you tab away to a different application.
        /// </summary>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                                       bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, false);

            // Gradually fade in or out depending on whether we are covered by the pause screen.
            if (coveredByOtherScreen)
                pauseAlpha = Math.Min(pauseAlpha + 1f / 32, 1);
            else
                pauseAlpha = Math.Max(pauseAlpha - 1f / 32, 0);

            level.Update(gameTime);
            if (IsActive)
            {
                if (needTitle)
                {
                    ScreenManager.AddScreen(new StartLevelScreen(levelNum, level.Title, level.Description), ControllingPlayer);
                    needTitle = false;
                    currentDir = level.Direction;
                    return;
                }
                time += gameTime.ElapsedGameTime.Milliseconds;
                if (time >= 300)
                {
                    time -= 300;
                    Point next = snake.NextMove(currentDir);
                    if (!level.CanMove(next) || snake.CheckSuicide(next))
                    {
                        KillSnake();
                    }
                    else
                    {
                        snake.Move(currentDir);
                        level.Update(gameTime, snake);
                        if (snake.Length >= level.Goal)
                        {
                            ScreenManager.AddScreen(new LevelCompleteScreen(levelNum, score + snake.Score, lives), ControllingPlayer);
                        }
                    }
                }
            }
        }

        void KillSnake()
        {
            ScreenManager.PlaySound("die");
            if (lives <= 1)
            {
                // Кончились жизни
                ScreenManager.AddScreen(new GameOverScreen(), ControllingPlayer);
            }
            else
            {
                // Умерли - с начала
                // TODO: Запоминаем очки
                lives -= 1;
                needTitle = true;
                StartGame();
            }
        }


        /// <summary>
        /// Lets the game respond to player input. Unlike the Update method,
        /// this will only be called when the gameplay screen is active.
        /// </summary>
        public override void HandleInput(InputState input)
        {
            if (input == null)
                throw new ArgumentNullException("input");

            // Look up inputs for the active player profile.
            int playerIndex = (int)ControllingPlayer.Value;

            KeyboardState keyboardState = input.CurrentKeyboardStates[playerIndex];
            GamePadState gamePadState = input.CurrentGamePadStates[playerIndex];

            // The game pauses either if the user presses the pause button, or if
            // they unplug the active gamepad. This requires us to keep track of
            // whether a gamepad was ever plugged in, because we don't want to pause
            // on PC if they are playing with a keyboard and have no gamepad at all!
            bool gamePadDisconnected = !gamePadState.IsConnected &&
                                       input.GamePadWasConnected[playerIndex];

            if (input.IsPauseGame(ControllingPlayer) || gamePadDisconnected)
            {
                ScreenManager.AddScreen(new PauseMenuScreen(), ControllingPlayer);
            }
            else
            {
                // Otherwise move the player position.
                if (keyboardState.IsKeyDown(Keys.Down))
                {
                    currentDir = Direction.Down;
                }
                if (keyboardState.IsKeyDown(Keys.Up))
                {
                    currentDir = Direction.Up;
                }
                if (keyboardState.IsKeyDown(Keys.Left))
                {
                    currentDir = Direction.Left;
                }
                if (keyboardState.IsKeyDown(Keys.Right))
                {
                    currentDir = Direction.Right;
                }
            }
        }


        /// <summary>
        /// Draws the gameplay screen.
        /// </summary>
        public override void Draw(GameTime gameTime)
        {
            spriteBatch.Begin();
            level.Draw(spriteBatch);
            snake.Draw(spriteBatch);
            spriteBatch.End();

            // HUD
            GraphicsDevice graphics = ScreenManager.GraphicsDevice;
            SpriteBatch hud = ScreenManager.SpriteBatch;
            hud.Begin();
            string scoreText = string.Format("Очки: {0}", score + snake.Score);
            hud.DrawString(gameFont, scoreText, new Vector2(5, 5), Color.White);
            for (int i = 1; i < lives; ++i)
            {
                Rectangle rect = new Rectangle(graphics.Viewport.Width - i * life.Width - 15, 15, life.Width, life.Height);
                hud.Draw(life, rect, Color.White);
            }
            string goal = string.Format("{0}/{1}", snake.Length, level.Goal);
            Vector2 position = new Vector2(graphics.Viewport.Width / 2, 5);
            Vector2 origin = gameFont.MeasureString(goal) / 2;
            position.Y += origin.Y;

            hud.DrawString(gameFont, goal, position, Color.White, 0,
                                   origin, 1.0f, SpriteEffects.None, 0);

            hud.End();

            // If the game is transitioning on or off, fade it out to black.
            if (TransitionPosition > 0 || pauseAlpha > 0)
            {
                float alpha = MathHelper.Lerp(1f - TransitionAlpha, 1f, pauseAlpha / 2);

                ScreenManager.FadeBackBufferToBlack(alpha);
            }
        }

        void StartGame()
        {
            level = new Level(map, ScreenManager);
            snake = new Snake(Game1.CELL_SIZE);
            snake.Spawn(level.Start);
            currentDir = level.Direction;
        }

        #endregion
    }
}
