using UnityEngine;
using System.Collections;

namespace CharacterEngine.Primitives
{
    public sealed class CECollider
    {
        public static int[,] edges = new int[,]
        {
            {0, 4}, {0, 2}, {0, 6},
            {1, 7}, {1, 5}, {1, 3},
            {3, 4}, {3, 2}, {6, 5},
            {6, 7}, {7, 2}, {5, 4}
        };

        public static int[,] faces = new int[,]
        {
            {0, 3}, {0, 5}, {0, 7},
            {1, 6}, {1, 4}, {1, 2}
        };

        private Collider collider;
        public Collider Coll
        {
            get { return collider; }
        }

        public Vector3 position
        {
            get { return collider.bounds.center; }
        }

        public readonly Vector3[] localPoints;     

        public CECollider (Collider coll)
        {
            collider = coll;

            ///COLLIDER CONSTANT RELATIVE POINTS
            localPoints = new Vector3[]
            {
            coll.bounds.size * 0.5f, //max
            -coll.bounds.size * 0.5f, //min
            new Vector3(-coll.bounds.extents.x, coll.bounds.extents.y, coll.bounds.extents.z),
            new Vector3(-coll.bounds.extents.x, coll.bounds.extents.y, -coll.bounds.extents.z),
            new Vector3(coll.bounds.extents.x, coll.bounds.extents.y, -coll.bounds.extents.z),
            new Vector3(coll.bounds.extents.x, -coll.bounds.extents.y, -coll.bounds.extents.z),
            new Vector3(coll.bounds.extents.x, -coll.bounds.extents.y, coll.bounds.extents.z),
            new Vector3(-coll.bounds.extents.x, -coll.bounds.extents.y, coll.bounds.extents.z)
            };
        }
        
        public Vector3 GetPoint (int index)
        {
            return position + localPoints[index];
        }

        /// <summary>
        /// Collision test along a path
        /// </summary>
        public RaycastHit SweepTest(Vector3 dir, float distance, float skinWidth = 1.0f)
        {
            RaycastHit hit = new RaycastHit();

            for (int i = 0; i <= CEPrimitives.sweepResolution; i++)
            {
                Vector3 currentDistance = dir.normalized * (distance * (i / CEPrimitives.sweepResolution));
                hit = BoxCast(position + currentDistance, skinWidth);

                if (hit.distance != 0.0f) break;
            }

            return hit;
        }

        /// <summary>
        /// Collision test in an specific point
        /// </summary>
        public RaycastHit BoxCast(Vector3 position, float skinWidth = 1.0f)
        {
            int mask = LayerMask.GetMask("Default");

            RaycastHit outHit = new RaycastHit();

            ///FACE CAST
            for (int i = 0; i < faces.GetLength(0); i++)
            {
                //Debug.DrawLine(points[faces[i, 0]], points[faces[i, 1]], Color.blue);

                if (!Physics.Linecast(position + localPoints[faces[i, 0]] * skinWidth, position + localPoints[faces[i, 1]] * skinWidth, out outHit, mask, QueryTriggerInteraction.Ignore))
                {
                    continue;
                }

                ///RETURN DISTANCE FROM CENTER
                return outHit;
            }

            ///EDGE CAST  
            for (int i = 0; i < CECollider.edges.GetLength(0); i++)
            {
                //Debug.DrawLine(points[edges[i, 0]], points[edges[i, 1]], Color.red);

                if (!Physics.Linecast(position + localPoints[edges[i, 0]] * skinWidth, position + localPoints[edges[i, 1]] * skinWidth, out outHit, mask, QueryTriggerInteraction.Ignore))
                {
                    if (!Physics.Linecast(position + localPoints[edges[i, 1]] * skinWidth, position + localPoints[edges[i, 0]] * skinWidth, out outHit, mask, QueryTriggerInteraction.Ignore))
                    {
                        continue;
                    }
                }

                ///RETURN DISTANCE FROM CENTER
                return outHit;
            }

            ///IF REACH HERE DIDNT FOUND SHIT
            return outHit;
        }
    }
}
