using System;
using System.Drawing;
using System.Xml.Serialization;

namespace Icarus.Logic.Physics
{
	/// <summary>
	/// Summary description for CollisionBox.
	/// </summary>
    // Instruct the XmlSerializer to accept other types of boxes as well.
    [XmlInclude(typeof(Physics.CollisionBoxFloor))]
    [XmlInclude(typeof(Physics.CollisionBoxWall))]
    [XmlInclude(typeof(Physics.CollisionBoxSlopeTL))]
    [XmlInclude(typeof(Physics.CollisionBoxSlopeTR))]
    [XmlInclude(typeof(Physics.CollisionBoxSlopeBR))]
    [XmlInclude(typeof(Physics.CollisionBoxSlopeBL))]
    [XmlInclude(typeof(Physics.CollisionBoxTransition))]
    [XmlInclude(typeof(Physics.CollisionBoxMobile))]
    [XmlInclude(typeof(Physics.CollisionBoxRobotTuxHand))]
    [XmlInclude(typeof(Physics.CollisionBoxEnemyDefault))]
    [XmlInclude(typeof(Physics.CollisionBoxWhip))]
    [XmlInclude(typeof(Physics.CollisionBoxZoom))]
	public class CollisionBox
	{

        #region Declarations

        /// <summary>
        /// The amount of damage this collisionbox does.
        /// </summary>
        private int iDamage;

        /// <summary>
        /// Rectangular bounding box of this collision box
        /// </summary>
        private PhysicsRectangle rectBoundingBox;

        /// <summary>
        /// Array of rectangles for more precise collisions within
        /// this collision box
        /// </summary>
        private PhysicsRectangle[] rectArray = null;


        /// <summary>
        /// Array of triangles for more precise collisions within
        /// this collision box
        /// </summary>
        private Triangle[] triArray = null;

        /// <summary>
        /// Original width of bounding box that does not change
        /// </summary>
        private int iBoundingBoxWidth;

        /// <summary>
        /// Orgiginal height of bounding box that does not change
        /// </summary>
        private int iBoundingBoxHeight;

        /// <summary>
        /// Text Description of this object for level editing
        /// </summary>
        private string strDescription = "";

        #endregion

        #region Properties/Feilds

        /// <summary>
        /// Gets or sets the damage this collision box does to merc
        /// </summary>
        public int Damage 
        {
            get { return this.iDamage; }
            set { this.iDamage = value; }
        }

        /// <summary>
        /// Rectangular bounding box of this collision box
        /// </summary>
        public PhysicsRectangle BoundingBox
        {
            get {return this.rectBoundingBox; }
            set {this.rectBoundingBox = value; }
        }

        /// <summary>
        /// Array of rectangles for more precise collisions within
        /// this collision box
        /// </summary>
        public PhysicsRectangle[] RectArray
        {
            //TODO: These need to be recalculated when needed so they up to date
            //      and represent the current velocity, etc.
            get { return this.rectArray; }
            set {this.rectArray = value;}
        }

        /// <summary>
        /// Array of triangles for more precise collisions within
        /// this collision box
        /// </summary>
        public Triangle[] TriArray
        {
            //TODO: These need to be recalculated when needed so they up to date
            //      and represent the current velocity, etc.
            get { return this.triArray; }
            set { this.triArray = value; }
        }

        /// <summary>
        /// Original width of bounding box that does not change with vel
        /// </summary>
        public int BoundingBoxHeight
        {
            get { return this.iBoundingBoxHeight; }
            set { this.iBoundingBoxHeight = value;}
        }

        /// <summary>
        /// Original height of bounding box that does not change with vel
        /// </summary>
        public int BoundingBoxWidth
        {
            get {return this.iBoundingBoxWidth; }
            set {this.iBoundingBoxWidth = value;}
        }

        /// <summary>
        /// A text Description of this object for level editing
        /// </summary>
        public string Description
        {
            get { return this.strDescription; }
            set { this.strDescription = value; }
        }

        #endregion

        #region Contruction

		public CollisionBox()
		{
            this.rectBoundingBox = new PhysicsRectangle();
            this.RectArray = new PhysicsRectangle[Icarus.Logic.GameEngine.GameSettings.Instance.sv_maxInternalRects];
            this.TriArray = new Triangle[Icarus.Logic.GameEngine.GameSettings.Instance.sv_maxInternalTris];
            this.strDescription = "Collision Box";
		}

        #endregion 

        #region Methods

        public int checkAndCollide(PhysicsObject po)
        {

            //Check for collision with this box
            if(po.CollisionBox.BoundingBox.IntersectsWith(this.BoundingBox))
            {
 
                if(this.RectArray[0] == null && this.TriArray[0] == null)
                {
                    //Collided but had no interal rectangles or triangles to collide with
                    return this.handleRectCollision(this.BoundingBox, po);
                }
                
                //Check for internal, more precise collisions
                //Check Rectangles
                foreach (PhysicsRectangle pr in this.RectArray)
                {
                    if(pr == null) break;

                    if(pr.IntersectsWith(po.CollisionBox.BoundingBox))
                    {
                        return this.handleRectCollision(pr, po);
                    }
                }

                //Check Triangles
                foreach (Triangle tri in this.TriArray)
                {
                    if (tri == null) break;

                    if(tri.IntersectsWith(po.CollisionBox.BoundingBox))
                    {
                        return this.handleTriCollision(tri, po);
                    }
                }
                
            }
            
            return (int)PhysicsSettings.enumActions.DoNothing;
        }

        /// <summary>
        /// -Performs actions on a PO/WO specific to this collision box.
        /// -Basic functionality only stops the PO/WO where the collision
        ///  took place.
        /// -This function should be overridden for specific collision boxes
        ///  such as teleporters, jump pads, ice...
        /// </summary>
        /// <param name="rect">The collision rect that was hit</param>
        /// <param name="po">The PO/WO that hit the rect</param>
        /// <returns>An action represented in PhysicsSettings.enumActions</returns>
        public virtual int handleRectCollision(PhysicsRectangle rect, PhysicsObject po)
        {
            
            return rect.intersectionAction(po);
            //Vector.ScalarMultVector(po.Velocity, po.Velocity, 0.0f); 
            //return (int)PhysicsSettings.enumActions.DoNothing;
        }

        public virtual int handleTriCollision(Triangle tri, PhysicsObject po)
        {
            return tri.intersectionAction(po);
            //Vector.ScalarMultVector(po.Velocity, po.Velocity, 0.0f); 
            //return (int)PhysicsSettings.enumActions.DoNothing;
        }

        /// <summary>
        /// This can be called to set properties specifically when making
        /// a prefab collision box. i.e: CollisionBoxFloor, CollisionBoxWall, etc
        /// </summary>
        public virtual void setSpecial()
        {

        }

        #endregion
	}
}
