using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace FarseerPhysics.SamplesFramework
{
    /// 
    /// Base class for screens that contain a menu of options. The user can
    /// move up and down to select an entry, or cancel to back out of the screen.
    /// 
    public class MenuScreen : GameScreen
    {
#if WINDOWS || XBOX
        protected const float NumEntries = 15;
#elif WINDOWS_PHONE
        protected const float NumEntries = 9;
#endif
        protected List _menuEntries = new List();
        protected string _menuTitle;
        protected Vector2 _titlePosition;
        protected Vector2 _titleOrigin;
        protected int _selectedEntry;
        protected float _menuBorderTop;
        protected float _menuBorderBottom;
        protected float _menuBorderMargin;
        protected float _menuOffset;
        protected float _maxOffset;
        protected Texture2D _texScrollButton;
        protected Texture2D _texSlider;
        protected MenuButton _scrollUp;
        protected MenuButton _scrollDown;
        protected MenuButton _scrollSlider;
        protected bool _scrollLock;
        /// 
        /// Constructor.
        /// 
        public MenuScreen(string menuTitle)
        {
            _menuTitle = menuTitle;
            TransitionOnTime = TimeSpan.FromSeconds(0.7);
            TransitionOffTime = TimeSpan.FromSeconds(0.7);
            HasCursor = true;
        }
        public void AddMenuItem(string name, EntryType type, GameScreen screen)
        {
            MenuEntry entry = new MenuEntry(this, name, type, screen);
            _menuEntries.Add(entry);
        }
        public void AddMenuItem(MenuEntry me)
        {
            _menuEntries.Add(me);
        }
        public override void LoadContent()
        {
            base.LoadContent();
            
            _texScrollButton = ScreenManager.Content.Load("Common/arrow");
            _texSlider = ScreenManager.Content.Load("Common/slider");
            //Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
            //float scrollBarPos = viewport.Width / 2f;
            //scrollBarPos -= _texScrollButton.Width + 2f;
            
            InitMenu();
            
            
        }
        public void InitMenu()
        {
            Viewport viewport = ScreenManager.GraphicsDevice.Viewport;
            SpriteFont font = ScreenManager.Fonts.MenuSpriteFont;
            float scrollBarPos = viewport.Width / 2f;
            
            for (int i = 0; i < _menuEntries.Count; ++i)
            {
                _menuEntries[i].Initialize();
                scrollBarPos = Math.Min(scrollBarPos,
                                         (viewport.Width - _menuEntries[i].GetWidth()) / 2f);
            }
            _titleOrigin = font.MeasureString(_menuTitle) / 2f;
            _titlePosition = new Vector2(viewport.Width / 2f, font.MeasureString("M").Y / 2f + 10f);
            _menuBorderMargin = font.MeasureString("M").Y * 0.8f;
            _menuBorderTop = (viewport.Height - _menuBorderMargin * (NumEntries - 1)) / 2f;
            _menuBorderBottom = (viewport.Height + _menuBorderMargin * (NumEntries - 1)) / 2f;
            _menuOffset = 0f;
            _maxOffset = Math.Max(0f, (_menuEntries.Count - NumEntries) * _menuBorderMargin);
            _scrollUp = new MenuButton(_texScrollButton, false,
                                       new Vector2(scrollBarPos, _menuBorderTop - _texScrollButton.Height), this);
            _scrollDown = new MenuButton(_texScrollButton, true,
                                         new Vector2(scrollBarPos, _menuBorderBottom + _texScrollButton.Height), this);
            _scrollSlider = new MenuButton(_texSlider, false, new Vector2(scrollBarPos, _menuBorderTop), this);
            _scrollLock = false;
        }
        /// 
        /// Returns the index of the menu entry at the position of the given mouse state.
        /// 
        /// Index of menu entry if valid, -1 otherwise
        private int GetMenuEntryAt(Vector2 position)
        {
            if (this.TransitionPosition == 0f && this.ScreenState == SamplesFramework.ScreenState.Active)
            {
                int index = 0;
                foreach (MenuEntry entry in _menuEntries)
                {
                    float width = entry.GetWidth();
                    float height = entry.GetHeight();
                    Rectangle rect = new Rectangle((int)(entry.Position.X - width / 2f),
                                                   (int)(entry.Position.Y - height / 2f),
                                                   (int)width, (int)height);
                    if (rect.Contains((int)position.X, (int)position.Y) && entry.Alpha > 0.1f)
                    {
                        return index;
                    }
                    ++index;
                }
            }
            return -1;
        }
        /// 
        /// Responds to user input, changing the selected entry and accepting
        /// or cancelling the menu.
        /// 
        public override void HandleInput(InputHelper input, GameTime gameTime)
        {
            // Mouse or touch on a menu item
            int hoverIndex = GetMenuEntryAt(input.Cursor);
            if (hoverIndex > -1 && _menuEntries[hoverIndex].IsSelectable() && !_scrollLock)
            {
                _selectedEntry = hoverIndex;
            }
            else
            {
                _selectedEntry = -1;
            }
            _scrollSlider.Hover = false;
            if (input.IsCursorValid)
            {
                _scrollUp.Collide(input.Cursor);
                _scrollDown.Collide(input.Cursor);
                _scrollSlider.Collide(input.Cursor);
            }
            else
            {
                _scrollUp.Hover = false;
                _scrollDown.Hover = false;
                _scrollLock = false;
            }
            // Accept or cancel the menu? 
            if (input.IsMenuSelect() && _selectedEntry != -1)
            {
                if (_menuEntries[_selectedEntry].IsExitItem())
                {
                    ScreenManager.Game.Exit();
                } 
                else if (_menuEntries[_selectedEntry].IsBackItem())
                {
                    this.ExitScreen();
                }
                else if (_menuEntries[_selectedEntry].Screen != null)
                {
                    ScreenManager.AddScreen(_menuEntries[_selectedEntry].Screen);
                    if (_menuEntries[_selectedEntry].Screen is IDemoScreen)
                    {
                        ScreenManager.AddScreen(
                            new MessageBoxScreen((_menuEntries[_selectedEntry].Screen as IDemoScreen).GetDetails()));
                    }
                }
            }
            else if (input.IsMenuCancel())
            {
                if (this.ScreenState == SamplesFramework.ScreenState.Active && this.TransitionPosition == 0 && this.TransitionAlpha == 1)
                {
                    //GameScreen[] screens = ScreenManager.GetScreens();
                    //if (screens[screens.Length - 1] is BackgroundScreen ||| screens.Length )
                    //    ScreenManager.Game.Exit();
                    //if (ScreenManager.GetScreens().Length == 2)
                    //    ScreenManager.Game.Exit();
                    //else
                    this.ExitScreen();
                }
                //ScreenManager.Game.Exit();
            }
            if (input.IsMenuPressed())
            {
                if (_scrollUp.Hover)
                {
                    _menuOffset = Math.Max(_menuOffset - 200f * (float)gameTime.ElapsedGameTime.TotalSeconds, 0f);
                    _scrollLock = false;
                }
                if (_scrollDown.Hover)
                {
                    _menuOffset = Math.Min(_menuOffset + 200f * (float)gameTime.ElapsedGameTime.TotalSeconds, _maxOffset);
                    _scrollLock = false;
                }
                if (_scrollSlider.Hover)
                {
                    _scrollLock = true;
                }
            }
            if (input.IsMenuReleased())
            {
                _scrollLock = false;
            }
            if (_scrollLock)
            {
                _scrollSlider.Hover = true;
                _menuOffset = Math.Max(Math.Min(((input.Cursor.Y - _menuBorderTop) / (_menuBorderBottom - _menuBorderTop)) * _maxOffset, _maxOffset), 0f);
            }
        }
        /// 
        /// Allows the screen the chance to position the menu entries. By default
        /// all menu entries are lined up in a vertical list, centered on the screen.
        /// 
        protected virtual void UpdateMenuEntryLocations()
        {
            // Make the menu slide into place during transitions, using a
            // power curve to make things look more interesting (this makes
            // the movement slow down as it nears the end).
            float transitionOffset = (float)Math.Pow(TransitionPosition, 2);
            Vector2 position = Vector2.Zero;
            position.Y = _menuBorderTop - _menuOffset;
            // update each menu entry's location in turn
            for (int i = 0; i < _menuEntries.Count; ++i)
            {
                position.X = ScreenManager.GraphicsDevice.Viewport.Width / 2f;
                if (ScreenState == ScreenState.TransitionOn)
                {
                    position.X -= transitionOffset * 256;
                }
                else
                {
                    position.X += transitionOffset * 256;
                }
                // set the entry's position
                _menuEntries[i].Position = position;
                if (position.Y < _menuBorderTop)
                {
                    _menuEntries[i].Alpha = 1f -
                                            Math.Min(_menuBorderTop - position.Y, _menuBorderMargin) / _menuBorderMargin;
                }
                else if (position.Y > _menuBorderBottom)
                {
                    _menuEntries[i].Alpha = 1f -
                                            Math.Min(position.Y - _menuBorderBottom, _menuBorderMargin) /
                                            _menuBorderMargin;
                }
                else
                {
                    _menuEntries[i].Alpha = 1f;
                }
                // move down for the next entry the size of this entry
                position.Y += _menuEntries[i].GetHeight();
            }
            Vector2 scrollPos = _scrollSlider.Position;
            scrollPos.Y = MathHelper.Lerp(_menuBorderTop, _menuBorderBottom, _menuOffset / _maxOffset);
            _scrollSlider.Position = scrollPos;
        }
        /// 
        /// Updates the menu.
        /// 
        public override void Update(GameTime gameTime, bool otherScreenHasFocus,
                                    bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);
            // Update each nested MenuEntry object.
            for (int i = 0; i < _menuEntries.Count; ++i)
            {
                bool isSelected = IsActive && (i == _selectedEntry);
                _menuEntries[i].Update(isSelected, gameTime);
            }
            _scrollUp.Update(gameTime);
            _scrollDown.Update(gameTime);
            _scrollSlider.Update(gameTime);
        }
        /// 
        /// Draws the menu.
        /// 
        public override void Draw(GameTime gameTime)
        {
            // make sure our entries are in the right place before we draw them
            UpdateMenuEntryLocations();
            SpriteBatch spriteBatch = ScreenManager.SpriteBatch;
            SpriteFont font = ScreenManager.Fonts.MenuSpriteFont;
            spriteBatch.Begin();
            // Draw each menu entry in turn.
            for (int i = 0; i < _menuEntries.Count; ++i)
            {
                bool isSelected = IsActive && (i == _selectedEntry);
                _menuEntries[i].Draw();
            }
            // Make the menu slide into place during transitions, using a
            // power curve to make things look more interesting (this makes
            // the movement slow down as it nears the end).
            Vector2 transitionOffset = new Vector2(0f, (float)Math.Pow(TransitionPosition, 2) * 100f);
            spriteBatch.DrawString(font, _menuTitle, _titlePosition - transitionOffset + Vector2.One * 2f, Color.Black, 0,
                                   _titleOrigin, 1f, SpriteEffects.None, 0);
            spriteBatch.DrawString(font, _menuTitle, _titlePosition - transitionOffset, new Color(255, 210, 0), 0,
                                   _titleOrigin, 1f, SpriteEffects.None, 0);
            _scrollUp.Draw();
            _scrollSlider.Draw();
            _scrollDown.Draw();
            spriteBatch.End();
        }
    }
}