using Microsoft.Xna.Framework;
using System.ComponentModel;

namespace Innovation
{
    // Represents a 3D object. These objects will be drawn before 
    // 2D objects, and will have modifiers automatically provided 
    // in the editor.
    public interface I3DComponent
    {
        // Position in the Cartesian system (X, Y, Z)
        [Category("3D Component")]
        Vector3 Position { get; set; }

        // Rotation represented as a Vector3. This shouldn't
        // be used for calculations, it is left in so that
        // the rotation can be more easily modified by hand
        [DisplayName("Rotation")]
        [Category("3D Component")]
        Vector3 EulerRotation { get; set; }
        // Rotation as a Matrix. This will give much smoother
        // and cleaner calculations that a Vector3
        [Browsable(false)]
        Matrix Rotation { get; set; }

        // Scale for each axis (X, Y, Z)
        [Category("3D Component")]
        Vector3 Scale { get; set; }

        // BoundingBox to use for picking and pre-collision
        [Browsable(false)]
        BoundingBox BoundingBox { get; }
    }

    // Represents a 2D object. These objects will be drawn after
    // 3D objects, and will have modifiers automatically provided
    // in the editor.
    public interface I2DComponent
    {
        [Category("2D Component")]
        Rectangle Rectangle { get; set; }
    }

    public enum ComponentType
    {
        // Represents all 2D components (I2DComponent)
        Component2D,
        // Represents all 3D components (I3DComponent)
        Component3D,
        // Represents all components that are either 2D or 3D
        // components
        Both,
        // Represents all components regardless of type
        All
    }

    // Provides a way for the engine to let the game tell it what to
    // draw, instead of the somewhat limited ComponentType
    public abstract class ComponentPredicate
    {
        // Decides whether the specified component is eligible for the
        // action being done
        public abstract bool IsComponentEligible(Component Component);
    }

    // Basic ComponentPredicate that uses ComponentType to determine
    // what components to use
    public class ComponentTypePredicate : ComponentPredicate
    {
        // The type of component to accept
        ComponentType Type;

        // Accepts a ComponentType to use to determine what
        // components will be accepted
        public ComponentTypePredicate(ComponentType Type)
        {
            this.Type = Type;
        }

        public override bool IsComponentEligible(Component Component)
        {
            if (Type == ComponentType.Both)
            {
                // If the render type is both, we will use all 2D or
                // 3D components
                if (Component is I2DComponent || Component is I3DComponent)
                    return true;
            }
            else if (Type == ComponentType.Component2D)
            {
                // If the render type is 2D, we will only use 2D
                // components
                if (Component is I2DComponent)
                    return true;
            }
            else if (Type == ComponentType.Component3D)
            {
                // If the render type is 3D, we will only use 3D
                // components
                if (Component is I3DComponent)
                    return true;
            }
            else
            {
                // Otherwise, we will use every component regardless of type
                return true;
            }

            // If the conditions have not been met, we will not use the
            // component
            return false;
        }
    }
}