using System;
using Microsoft.Xna.Framework;
using Jitter.Collision;
using Jitter.Dynamics.Constraints.SingleBody;
using Jitter.LinearMath;

namespace KinPortal {
	public class GrabStrategy : TargetingStrategy {
		private PointOnPoint m_leftGrabConstraint = null;
		private PointOnPoint m_rightGrabConstraint = null;
		private float m_leftHitDistance;
		private float m_rightHitDistance;
		private float m_leftHandHitDepth;
		private float m_rightHandHitDepth;

		public void Update(DynamicObject obj, GameTime gameTime) {
			KinPortal.Game game = (KinPortal.Game) obj.Game;

			if(game.HandsTracker.LeftHand.IsClosed) {
				Vector3 ray = obj.Scene.Camera.Unproject(game.HandsTracker.LeftHand.Pos.X, game.HandsTracker.LeftHand.Pos.Y);
				ray.Normalize();
				if(m_leftGrabConstraint != null) {
					float hitDistance = m_leftHitDistance * (1.0f + (float) game.HandsTracker.LeftHand.Depth - m_leftHandHitDepth);
					m_leftGrabConstraint.Anchor = Geometry.GetJitterVector(obj.Scene.Camera.Pos + ray * hitDistance);
					obj.PhysicModel.IsActive = true;
					obj.PhysicModel.LinearVelocity *= 0.98f;
					obj.PhysicModel.AngularVelocity *= 0.98f;
				}
			} else {
				if(m_leftGrabConstraint != null) {
					obj.Scene.PhysicWorld.RemoveConstraint(m_leftGrabConstraint);
					m_leftGrabConstraint = null;
				}
			}

			if(game.HandsTracker.RightHand.IsClosed) {
				Vector3 ray = obj.Scene.Camera.Unproject(game.HandsTracker.RightHand.Pos.X, game.HandsTracker.RightHand.Pos.Y);
				ray.Normalize();
				if(m_rightGrabConstraint != null) {
					float hitDistance = m_rightHitDistance * (1.0f + (float) game.HandsTracker.RightHand.Depth - m_rightHandHitDepth);
					m_rightGrabConstraint.Anchor = Geometry.GetJitterVector(obj.Scene.Camera.Pos + ray * hitDistance);
					obj.PhysicModel.IsActive = true;
					obj.PhysicModel.LinearVelocity *= 0.98f;
					obj.PhysicModel.AngularVelocity *= 0.98f;
				}
			} else {
				if(m_rightGrabConstraint != null) {
					obj.Scene.PhysicWorld.RemoveConstraint(m_rightGrabConstraint);
					m_rightGrabConstraint = null;
				}
			}
		}

		public void Target(DynamicObject obj, HandsProjection leftHand, HandsProjection rightHand) {
			KinPortal.Game game = (KinPortal.Game) obj.Game;

			if(leftHand.IsProjected && game.HandsTracker.LeftHand.IsClosed && !game.HandsTracker.LeftHand.PrevIsClosed) {
				if(m_leftGrabConstraint != null) {
					obj.Scene.PhysicWorld.RemoveConstraint(m_leftGrabConstraint);
				}

				if(m_rightGrabConstraint != null) {
					return;
				}

				JVector lanchor = Geometry.GetJitterVector(leftHand.HitPoint - obj.Pos);
				lanchor = JVector.Transform(lanchor, JMatrix.Transpose(obj.PhysicModel.Orientation));

				m_leftGrabConstraint = new PointOnPoint(obj.PhysicModel, lanchor);
				m_leftGrabConstraint.Softness = 0.004f;
				m_leftGrabConstraint.BiasFactor = 0.1f;

				obj.Scene.PhysicWorld.AddConstraint(m_leftGrabConstraint);
				m_leftHitDistance = (leftHand.HitPoint - obj.Scene.Camera.Pos).Length();
				m_leftGrabConstraint.Anchor = Geometry.GetJitterVector(leftHand.HitPoint);
				m_leftHandHitDepth = (float) game.HandsTracker.LeftHand.Depth;
			}

			if(rightHand.IsProjected && game.HandsTracker.RightHand.IsClosed && !game.HandsTracker.RightHand.PrevIsClosed) {
				if(m_rightGrabConstraint != null) {
					obj.Scene.PhysicWorld.RemoveConstraint(m_rightGrabConstraint);
				}

				if(m_leftGrabConstraint != null) {
					return;
				}

				JVector lanchor = Geometry.GetJitterVector(rightHand.HitPoint - obj.Pos);
				lanchor = JVector.Transform(lanchor, JMatrix.Transpose(obj.PhysicModel.Orientation));

				m_rightGrabConstraint = new PointOnPoint(obj.PhysicModel, lanchor);
				m_rightGrabConstraint.Softness = 0.004f;
				m_rightGrabConstraint.BiasFactor = 0.1f;

				obj.Scene.PhysicWorld.AddConstraint(m_rightGrabConstraint);
				m_rightHitDistance = (rightHand.HitPoint - obj.Scene.Camera.Pos).Length();
				m_rightGrabConstraint.Anchor = Geometry.GetJitterVector(rightHand.HitPoint);
				m_rightHandHitDepth = (float) game.HandsTracker.RightHand.Depth;
			}
		}
	}
}
