using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Sokoban3D;

namespace Sokoban3D.Screens
{
    /// <summary>
    /// the menu class holds the handlings of menus
    /// </summary>
    public class Menu : DrawableGameComponent
    {
        // graphic variables
        protected SpriteBatch spriteBatch = null;
        protected readonly SpriteFont regularFont, selectedFont;

        protected Color regularColor = Color.White, selectedColor = Color.Red;

        // the position
        protected Vector2 position = new Vector2();

        // variable to tell if the menu should be displayed
        private Boolean active;

        // public setter to switch the actives value
        public Boolean Hide
        {
            set { this.active = value; }
        }

        // menu related variables
        protected int selectedIndex = 0;
        private readonly List<string> menuItems;

        // size variables
        protected int width, height;

        private Sokoban3D game;

        // used for input handling
        protected KeyboardState oldKeyboardState;
        protected GamePadState oldGamePadState;

        public Menu(Sokoban3D game, SpriteFont normalFont,
            SpriteFont selectedFont)
            : base(game)
        {
            this.game = game;

            regularFont = this.game.gameContent.smallFont;
            this.selectedFont = this.game.gameContent.largeFont;
            this.active = true;

            menuItems = new List<string>();

            spriteBatch = (SpriteBatch)
                Game.Services.GetService(typeof(SpriteBatch));

            // Used for input handling
            oldKeyboardState = Keyboard.GetState();
            oldGamePadState = GamePad.GetState(PlayerIndex.One);
        }

        /// <summary>
        /// initializes the menu with the items from the string list
        /// </summary>
        /// <param name="items"></param>
        public void SetMenuItems(string[] items)
        {
            menuItems.Clear();
            menuItems.AddRange(items);
            CalculateBounds();
        }
        /// <summary>
        /// Width of menu in pixels
        /// </summary>
        public int Width
        {
            get { return width; }
        }

        /// <summary>
        /// Height of menu in pixels
        /// </summary>
        public int Height
        {
            get { return height; }
        }

        /// <summary>
        /// Selected menu item index
        /// </summary>
        public int SelectedIndex
        {
            get { return selectedIndex; }
            set { selectedIndex = value; }
        }
        /// <summary>
        /// Position of component in screen
        /// </summary>
        public Vector2 Position
        {
            get { return position; }
            set { position = value; }
        }

        /// <summary>
        /// checks where the boundaries are for drawing the text
        /// </summary>
        protected void CalculateBounds()
        {
            width = 0;
            height = 0;
            foreach (string item in menuItems)
            {
                Vector2 size = selectedFont.MeasureString(item);
                if (size.X > width)
                {
                    width = (int)size.X;
                }
                height += selectedFont.LineSpacing;
            }
        }

        public override void Update(GameTime gameTime)
        {
            if (this.active)
            {
                GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);
                KeyboardState keyboardState = Keyboard.GetState();

                bool down, up;
                // Handle the keyboard
                down = (oldKeyboardState.IsKeyDown(Keys.Down) &&
                    (keyboardState.IsKeyUp(Keys.Down)));
                up = (oldKeyboardState.IsKeyDown(Keys.Up) &&
                    (keyboardState.IsKeyUp(Keys.Up)));
                // Handle the D-Pad
                down |= (oldGamePadState.DPad.Down == ButtonState.Pressed) &&
                        (gamepadState.DPad.Down == ButtonState.Released);
                up |= (oldGamePadState.DPad.Up == ButtonState.Pressed) &&
                    (gamepadState.DPad.Up == ButtonState.Released);

                if (down)
                {
                    selectedIndex++;
                    if (selectedIndex == menuItems.Count)
                    {
                        selectedIndex = 0;
                    }
                }
                if (up)
                {
                    selectedIndex--;
                    if (selectedIndex == -1)
                    {
                        selectedIndex = menuItems.Count - 1;
                    }
                }
            
                oldKeyboardState = keyboardState;
                oldGamePadState = gamepadState;
            }
            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            float y = position.Y;
            for (int i = 0; i < menuItems.Count; i++)
            {
                SpriteFont font;
                Color theColor;
                if (i == SelectedIndex)
                {
                    font = selectedFont;
                    theColor = selectedColor;
                }
                else
                {
                    font = regularFont;
                    theColor = regularColor;
                }

                // Draw the text shadow
                spriteBatch.DrawString(font, menuItems[i],
                    new Vector2(position.X + 1, y + 1), Color.Black);
                // Draw the text item
                spriteBatch.DrawString(font, menuItems[i],
                    new Vector2(position.X, y), theColor);
                y += font.LineSpacing;
            }


            base.Draw(gameTime);

        }
    }
}