using System;
using System.Collections.Generic;
using UnityEngine;

namespace Leap.Unity
{
	public class CapsuleHand : IHandModel
	{
		public override ModelType HandModelType
		{
			get
			{
				return ModelType.Graphics;
			}
		}

		public override Chirality Handedness
		{
			get
			{
				return this.handedness;
			}
			set
			{
			}
		}

		public override bool SupportsEditorPersistence()
		{
			return true;
		}

		public override Hand GetLeapHand()
		{
			return this.hand_;
		}

		public override void SetLeapHand(Hand hand)
		{
			this.hand_ = hand;
		}

		private void OnValidate()
		{
			this._cylinderResolution = Mathf.Max(3, this._cylinderResolution);
			if (this._armRenderers != null)
			{
				this.updateArmVisibility();
			}
		}

		public override void InitHand()
		{
			if (this._material != null)
			{
				this.jointMat = new Material(this._material);
				this.jointMat.hideFlags = HideFlags.DontSaveInEditor;
			}
			if (this._serializedTransforms != null)
			{
				for (int i = 0; i < this._serializedTransforms.Count; i++)
				{
					Transform transform = this._serializedTransforms[i];
					if (transform != null)
					{
						UnityEngine.Object.DestroyImmediate(transform.gameObject);
					}
				}
				this._serializedTransforms.Clear();
			}
			else
			{
				this._serializedTransforms = new List<Transform>();
			}
			this._jointSpheres = new Transform[20];
			this._armRenderers = new List<Renderer>();
			this._cylinderTransforms = new List<Transform>();
			this._sphereATransforms = new List<Transform>();
			this._sphereBTransforms = new List<Transform>();
			this.createSpheres();
			this.createCylinders();
			this.updateArmVisibility();
			this._hasGeneratedMeshes = false;
		}

		public override void BeginHand()
		{
			base.BeginHand();
			if (this.hand_.IsLeft)
			{
				this.jointMat.color = CapsuleHand._leftColorList[CapsuleHand._leftColorIndex];
				CapsuleHand._leftColorIndex = (CapsuleHand._leftColorIndex + 1) % CapsuleHand._leftColorList.Length;
			}
			else
			{
				this.jointMat.color = CapsuleHand._rightColorList[CapsuleHand._rightColorIndex];
				CapsuleHand._rightColorIndex = (CapsuleHand._rightColorIndex + 1) % CapsuleHand._rightColorList.Length;
			}
		}

		public override void UpdateHand()
		{
			this.updateSpheres();
			if (this._showArm)
			{
				this.updateArm();
			}
			this.updateCylinders();
		}

		private void updateSpheres()
		{
			List<Finger> fingers = this.hand_.Fingers;
			for (int i = 0; i < fingers.Count; i++)
			{
				Finger finger = fingers[i];
				for (int j = 0; j < 4; j++)
				{
					int fingerJointIndex = this.getFingerJointIndex((int)finger.Type, j);
					Transform transform = this._jointSpheres[fingerJointIndex];
					transform.position = finger.Bone((Bone.BoneType)j).NextJoint.ToVector3();
				}
			}
			this.palmPositionSphere.position = this.hand_.PalmPosition.ToVector3();
			Vector3 position = this.hand_.PalmPosition.ToVector3();
			this.wristPositionSphere.position = position;
			Transform transform2 = this._jointSpheres[0];
			Vector3 inDirection = transform2.position - this.hand_.PalmPosition.ToVector3();
			this.mockThumbJointSphere.position = this.hand_.PalmPosition.ToVector3() + Vector3.Reflect(inDirection, this.hand_.Basis.xBasis.ToVector3());
		}

		private void updateArm()
		{
			Arm arm = this.hand_.Arm;
			Vector3 b = arm.Basis.xBasis.ToVector3() * arm.Width * 0.7f * 0.5f;
			Vector3 a = arm.WristPosition.ToVector3();
			Vector3 vector = arm.ElbowPosition.ToVector3();
			float d = Vector3.Distance(a, vector);
			a -= arm.Direction.ToVector3() * d * 0.05f;
			this.armFrontRight.position = a + b;
			this.armFrontLeft.position = a - b;
			this.armBackRight.position = vector + b;
			this.armBackLeft.position = vector - b;
		}

		private void updateCylinders()
		{
			for (int i = 0; i < this._cylinderTransforms.Count; i++)
			{
				Transform transform = this._cylinderTransforms[i];
				Transform transform2 = this._sphereATransforms[i];
				Transform transform3 = this._sphereBTransforms[i];
				Vector3 vector = transform2.position - transform3.position;
				if (!this._hasGeneratedMeshes)
				{
					MeshFilter component = transform.GetComponent<MeshFilter>();
					component.sharedMesh = this.generateCylinderMesh(vector.magnitude / base.transform.lossyScale.x);
				}
				transform.position = transform2.position;
				if (vector.sqrMagnitude > Mathf.Epsilon)
				{
					transform.LookAt(transform3);
				}
			}
			this._hasGeneratedMeshes = true;
		}

		private void updateArmVisibility()
		{
			for (int i = 0; i < this._armRenderers.Count; i++)
			{
				this._armRenderers[i].enabled = this._showArm;
			}
		}

		private void createSpheres()
		{
			List<Finger> fingers = this.hand_.Fingers;
			for (int i = 0; i < fingers.Count; i++)
			{
				Finger finger = fingers[i];
				for (int j = 0; j < 4; j++)
				{
					int fingerJointIndex = this.getFingerJointIndex((int)finger.Type, j);
					this._jointSpheres[fingerJointIndex] = this.createSphere("Joint", 0.008f, false);
				}
			}
			this.mockThumbJointSphere = this.createSphere("MockJoint", 0.008f, false);
			this.palmPositionSphere = this.createSphere("PalmPosition", 0.015f, false);
			this.wristPositionSphere = this.createSphere("WristPosition", 0.008f, false);
			this.armFrontLeft = this.createSphere("ArmFrontLeft", 0.008f, true);
			this.armFrontRight = this.createSphere("ArmFrontRight", 0.008f, true);
			this.armBackLeft = this.createSphere("ArmBackLeft", 0.008f, true);
			this.armBackRight = this.createSphere("ArmBackRight", 0.008f, true);
		}

		private void createCylinders()
		{
			for (int i = 0; i < 5; i++)
			{
				for (int j = 0; j < 3; j++)
				{
					int fingerJointIndex = this.getFingerJointIndex(i, j);
					int fingerJointIndex2 = this.getFingerJointIndex(i, j + 1);
					Transform jointA = this._jointSpheres[fingerJointIndex];
					Transform jointB = this._jointSpheres[fingerJointIndex2];
					this.createCylinder("Finger Joint", jointA, jointB, false);
				}
			}
			for (int k = 0; k < 4; k++)
			{
				int fingerJointIndex3 = this.getFingerJointIndex(k, 0);
				int fingerJointIndex4 = this.getFingerJointIndex(k + 1, 0);
				Transform jointA2 = this._jointSpheres[fingerJointIndex3];
				Transform jointB2 = this._jointSpheres[fingerJointIndex4];
				this.createCylinder("Hand Joints", jointA2, jointB2, false);
			}
			Transform jointA3 = this._jointSpheres[0];
			Transform jointA4 = this._jointSpheres[16];
			this.createCylinder("Hand Bottom", jointA3, this.mockThumbJointSphere, false);
			this.createCylinder("Hand Side", jointA4, this.mockThumbJointSphere, false);
			this.createCylinder("ArmFront", this.armFrontLeft, this.armFrontRight, true);
			this.createCylinder("ArmBack", this.armBackLeft, this.armBackRight, true);
			this.createCylinder("ArmLeft", this.armFrontLeft, this.armBackLeft, true);
			this.createCylinder("ArmRight", this.armFrontRight, this.armBackRight, true);
		}

		private int getFingerJointIndex(int fingerIndex, int jointIndex)
		{
			return fingerIndex * 4 + jointIndex;
		}

		private Transform createSphere(string name, float radius, bool isPartOfArm = false)
		{
			GameObject gameObject = new GameObject(name);
			this._serializedTransforms.Add(gameObject.transform);
			gameObject.AddComponent<MeshFilter>().mesh = this._sphereMesh;
			gameObject.AddComponent<MeshRenderer>().sharedMaterial = this.jointMat;
			gameObject.transform.parent = base.transform;
			gameObject.transform.localScale = Vector3.one * radius * 2f;
			gameObject.hideFlags = (HideFlags.HideInHierarchy | HideFlags.HideInInspector | HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild | HideFlags.DontUnloadUnusedAsset);
			gameObject.layer = base.gameObject.layer;
			if (isPartOfArm)
			{
				this._armRenderers.Add(gameObject.GetComponent<Renderer>());
			}
			return gameObject.transform;
		}

		private void createCylinder(string name, Transform jointA, Transform jointB, bool isPartOfArm = false)
		{
			GameObject gameObject = new GameObject(name);
			this._serializedTransforms.Add(gameObject.transform);
			gameObject.AddComponent<MeshFilter>();
			gameObject.AddComponent<MeshRenderer>().sharedMaterial = this._material;
			gameObject.transform.parent = base.transform;
			this._cylinderTransforms.Add(gameObject.transform);
			this._sphereATransforms.Add(jointA);
			this._sphereBTransforms.Add(jointB);
			gameObject.gameObject.layer = base.gameObject.layer;
			gameObject.hideFlags = (HideFlags.HideInHierarchy | HideFlags.HideInInspector | HideFlags.DontSaveInEditor | HideFlags.DontSaveInBuild | HideFlags.DontUnloadUnusedAsset);
			if (isPartOfArm)
			{
				this._armRenderers.Add(gameObject.GetComponent<Renderer>());
			}
		}

		private Mesh generateCylinderMesh(float length)
		{
			Mesh mesh = new Mesh();
			mesh.name = "GeneratedCylinder";
			mesh.hideFlags = HideFlags.DontSave;
			List<Vector3> list = new List<Vector3>();
			List<Color> list2 = new List<Color>();
			List<int> list3 = new List<int>();
			Vector3 zero = Vector3.zero;
			Vector3 a = Vector3.forward * length;
			for (int i = 0; i < this._cylinderResolution; i++)
			{
				float f = 6.28318548f * (float)i / (float)this._cylinderResolution;
				float x = 0.006f * Mathf.Cos(f);
				float y = 0.006f * Mathf.Sin(f);
				Vector3 b = new Vector3(x, y, 0f);
				list.Add((zero + b) * base.transform.lossyScale.x);
				list.Add((a + b) * base.transform.lossyScale.x);
				list2.Add(Color.white);
				list2.Add(Color.white);
				int count = list.Count;
				int num = this._cylinderResolution * 2;
				list3.Add(count % num);
				list3.Add((count + 2) % num);
				list3.Add((count + 1) % num);
				list3.Add((count + 2) % num);
				list3.Add((count + 3) % num);
				list3.Add((count + 1) % num);
			}
			mesh.SetVertices(list);
			mesh.SetIndices(list3.ToArray(), MeshTopology.Triangles, 0);
			mesh.RecalculateBounds();
			mesh.RecalculateNormals();
			mesh.UploadMeshData(true);
			return mesh;
		}

		private const int THUMB_BASE_INDEX = 0;

		private const int PINKY_BASE_INDEX = 16;

		private const float SPHERE_RADIUS = 0.008f;

		private const float CYLINDER_RADIUS = 0.006f;

		private const float PALM_RADIUS = 0.015f;

		private static int _leftColorIndex = 0;

		private static int _rightColorIndex = 0;

		private static Color[] _leftColorList = new Color[]
		{
			new Color(0f, 0f, 1f),
			new Color(0.2f, 0f, 0.4f),
			new Color(0f, 0.2f, 0.2f)
		};

		private static Color[] _rightColorList = new Color[]
		{
			new Color(1f, 0f, 0f),
			new Color(1f, 1f, 0f),
			new Color(1f, 0.5f, 0f)
		};

		[SerializeField]
		private Chirality handedness;

		[SerializeField]
		private bool _showArm = true;

		[SerializeField]
		private Material _material;

		[SerializeField]
		private Mesh _sphereMesh;

		[SerializeField]
		private int _cylinderResolution = 12;

		private bool _hasGeneratedMeshes;

		private Material jointMat;

		[SerializeField]
		[HideInInspector]
		private List<Transform> _serializedTransforms;

		private Transform[] _jointSpheres;

		private Transform mockThumbJointSphere;

		private Transform palmPositionSphere;

		private Transform wristPositionSphere;

		private List<Renderer> _armRenderers;

		private List<Transform> _cylinderTransforms;

		private List<Transform> _sphereATransforms;

		private List<Transform> _sphereBTransforms;

		private Transform armFrontLeft;

		private Transform armFrontRight;

		private Transform armBackLeft;

		private Transform armBackRight;

		private Hand hand_;
	}
}
