using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using RecrownedAthenaeum.Render;

namespace RecrownedAthenaeum.UI.Modular
{

    /// <summary>
    /// Contains a group of modules and has its own relative coordinate system.
    /// </summary>
    public class UIModuleGroup : UIModule
    {
        List<UIModule> modules = new List<UIModule>();

        /// <summary>
        /// Set this to crop anything that flows out of the boundaries of this group. Will not crop if this is null.
        /// </summary>
        public BasicScissor basicScissor;

        /// <summary>
        /// Instantiates the UI module group.
        /// </summary>
        /// <param name="basicScissor">Sets the <see cref="basicScissor"/> field.</param>
        public UIModuleGroup(BasicScissor basicScissor = null)
        {
            this.basicScissor = basicScissor;
        }

        /// <summary>
        /// Draws this group of modules. If scissoring, will use the matrix and effect designated in the <see cref="BasicScissor"/> to begin the batch normally again.
        /// </summary>
        /// <param name="spriteBatch">Batch used to draw the group.</param>
        public override void Draw(ConsistentSpriteBatch spriteBatch)
        {
            if (basicScissor != null)
            {
                spriteBatch.End();
                basicScissor.Begin(Boundaries, spriteBatch);
            }

            foreach (UIModule module in modules)
            {
                int offsetX = module.X;
                int offsetY = module.Y;
                module.X = X + offsetX;
                module.Y = Y + offsetY;
                module.Draw(spriteBatch);
                module.X = offsetX;
                module.Y = offsetY;
            }

            if (basicScissor != null)
            {
                basicScissor.End();
                spriteBatch.Begin();
            }
        }

        /// <summary>
        /// Updates the group of modules.
        /// </summary>
        /// <param name="gameTime">Game time used.</param>
        public override void Update(GameTime gameTime)
        {
            foreach (UIModule module in modules)
            {
                module.Update(gameTime);
            }
        }

        /// <summary>
        /// Adds module(s) to this group.
        /// </summary>
        /// <param name="addModules">The module(s) to add.</param>
        public virtual void AddModules(params UIModule[] addModules)
        {
            foreach (UIModule module in addModules)
            {
                if (modules.Contains(module))
                {
                    throw new InvalidOperationException(module.ToString() + " already exists in " + this.ToString());
                }
                module.parent = this;
                modules.Add(module);
            }
        }

        /// <summary>
        /// Removes given module from group.
        /// </summary>
        /// <param name="module">module to remove.</param>
        public virtual void RemoveModule(UIModule module)
        {
            module.parent = null;
            modules.Remove(module);
        }
        
        /// <summary>
        /// Obtains an array snapshot of all the modules.
        /// </summary>
        public UIModule[] GetCopyOfModules()
        {
            return modules.ToArray();
        }

        /// <summary>
        /// Updates the keyboard state of the modules in this group.
        /// </summary>
        /// <param name="state">The new state.</param>
        /// <returns>Whether or not to continue updating the other listeners.</returns>
        public override bool KeyboardStateChanged(KeyboardState state)
        {
            foreach (UIModule module in modules)
            {
                module.KeyboardStateChanged(state);
            }
            return base.KeyboardStateChanged(state);
        }

        /// <summary>
        /// Updates the moues state of the modules in this group.
        /// </summary>
        /// <param name="state">The new state.</param>
        /// <returns>Whether or not to continue updating other listeners.</returns>
        public override bool MouseStateChanged(MouseState state)
        {
            foreach (UIModule module in modules)
            {
                module.MouseStateChanged(state);
            }
            return base.MouseStateChanged(state);
        }
    }
}
