using System;
using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
[RequireComponent(typeof(VelocityTracker))]
public class WfGrabbableObject : VRGrabbable
{
	public Rigidbody rigidBody { get; private set; }

	public VelocityTracker velocityTrack { get; private set; }

	protected override void Awake()
	{
		base.Awake();
		this.rigidBody = base.GetComponent<Rigidbody>();
		this.velocityTrack = base.GetComponent<VelocityTracker>();
	}

	public override void GrabBegin(VRGrabber hand, Collider grabPoint)
	{
		base.GrabBegin(hand, grabPoint);
	}

	public override void GrabEnd(Vector3 linearVelocity, Vector3 angularVelocity)
	{
		float magnitude = linearVelocity.magnitude;
		if (this.throwForceThreshold <= magnitude)
		{
			if (this.onThrowObjectCorrectionVelocityEvent != null)
			{
				this.onThrowObjectCorrectionVelocityEvent(ref linearVelocity, ref angularVelocity);
			}
			base.GrabEnd(linearVelocity * this.throwForceRate, angularVelocity);
			if (this.isThrowCorrection)
			{
				this.PlayLookRotationAnime(Quaternion.LookRotation(linearVelocity.normalized * -1f));
			}
		}
		else
		{
			base.GrabEnd(linearVelocity * Mathf.Max(1f, magnitude / this.throwForceThreshold * this.throwForceRate), angularVelocity);
		}
		if (this.onThrowObjectEvent != null)
		{
			this.onThrowObjectEvent(this, this.throwForceThreshold > magnitude);
		}
	}

	public void PlayLookRotationAnime(Quaternion targetRotation)
	{
		this.backupRotation = base.transform.rotation;
		this.targetRotation = targetRotation;
		this.isRotationAnime = true;
		this.animeValue = (this.animeValue2 = 0f);
		this.lastY = 0f;
		this.rigidBody.freezeRotation = true;
	}

	public void StopLookRotationAnime()
	{
		this.isRotationAnime = false;
		this.rigidBody.freezeRotation = false;
	}

	public void Update()
	{
		if (this.isRotationAnime)
		{
			this.animeValue += ((this.trackedLinearCorrectionTime != 0f) ? (1f / this.trackedLinearCorrectionTime * Time.deltaTime) : 1f);
			Mathf.Clamp(this.animeValue, 0f, 1f);
			if (1f <= this.animeValue)
			{
				Vector3 trackedLinearVelocity = this.velocityTrack.TrackedLinearVelocity;
				float num = Vector3.Dot(Vector3.down, trackedLinearVelocity);
				if (0f < num)
				{
					if (this.animeValue2 == 0f)
					{
						this.backupRotation = base.transform.rotation;
					}
					this.animeValue2 += ((this.fallDownCorrectionTime != 0f) ? (1f / this.fallDownCorrectionTime * Time.deltaTime) : 1f);
					Mathf.Clamp(this.animeValue2, 0f, 1f);
					Vector3 forward = (trackedLinearVelocity.normalized * -1f + new Vector3(0f, -0.65f, 0f)).normalized;
					float y = (forward.y >= this.lastY) ? forward.y : this.lastY;
					forward = new Vector3(forward.x, y, forward.z);
					base.transform.rotation = Quaternion.Lerp(this.backupRotation, Quaternion.LookRotation(forward), this.animeValue2);
				}
				else
				{
					Vector3 forward = trackedLinearVelocity.normalized * -1f;
					this.lastY = forward.y;
				}
			}
			else
			{
				base.transform.rotation = Quaternion.Lerp(this.backupRotation, this.targetRotation, this.animeValue);
			}
		}
	}

	private void OnCollisionEnter(Collision collision)
	{
		this.StopLookRotationAnime();
		this.rigidBody.velocity = Vector3.zero;
		if (this.onCollisionEnter != null)
		{
			this.onCollisionEnter(this, collision);
		}
	}

	[SerializeField]
	protected bool isThrowCorrection;

	[SerializeField]
	protected float trackedLinearCorrectionTime;

	[SerializeField]
	protected float fallDownCorrectionTime;

	[SerializeField]
	protected float throwForceThreshold = 3f;

	[SerializeField]
	protected float throwForceRate = 1f;

	public WfGrabbableObject.OnThrowObjectEvent onThrowObjectEvent;

	public Action<WfGrabbableObject, Collision> onCollisionEnter;

	public WfGrabbableObject.OnThrowObjectCorrectionVelocityEvent onThrowObjectCorrectionVelocityEvent;

	private Quaternion backupRotation;

	private Quaternion targetRotation;

	private bool isRotationAnime;

	private float animeValue;

	private float animeValue2;

	private float lastY;

	public delegate void OnThrowObjectEvent(WfGrabbableObject throwObject, bool mistakeThrow);

	public delegate void OnThrowObjectCorrectionVelocityEvent(ref Vector3 linearVelocity, ref Vector3 angularVelocity);
}
