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

namespace Leap.Unity
{
	public class HandPool : HandFactory
	{
		public void ReturnToPool(IHandModel model)
		{
			HandPool.ModelGroup modelGroup;
			bool flag = this.modelGroupMapping.TryGetValue(model, out modelGroup);
			for (int i = 0; i < this.activeHandReps.Count; i++)
			{
				HandProxy handProxy = this.activeHandReps[i];
				if (handProxy.RepChirality == model.Handedness && handProxy.RepType == model.HandModelType)
				{
					bool flag2 = false;
					if (handProxy.handModels != null)
					{
						for (int j = 0; j < modelGroup.modelsCheckedOut.Count; j++)
						{
							IHandModel y = modelGroup.modelsCheckedOut[j];
							for (int k = 0; k < handProxy.handModels.Count; k++)
							{
								if (handProxy.handModels[k] == y)
								{
									flag2 = true;
								}
							}
						}
					}
					if (!flag2)
					{
						handProxy.AddModel(model);
						this.modelToHandRepMapping[model] = handProxy;
						return;
					}
				}
			}
			modelGroup.ReturnToGroup(model);
		}

		public void RemoveHandRepresentation(HandProxy handRep)
		{
			this.activeHandReps.Remove(handRep);
		}

		private void Start()
		{
			if (this.ModelsParent == null)
			{
				Debug.LogWarning("HandPool.ModelsParent needs to reference the parent transform of the hand models.  This transform should be a child of the LMHeadMountedRig transform.");
			}
			foreach (HandPool.ModelGroup modelGroup in this.ModelPool)
			{
				modelGroup._handPool = this;
				IHandModel handModel;
				if (modelGroup.IsLeftToBeSpawned)
				{
					IHandModel leftModel = modelGroup.LeftModel;
					GameObject gameObject = UnityEngine.Object.Instantiate<GameObject>(leftModel.gameObject);
					handModel = gameObject.GetComponent<IHandModel>();
					handModel.transform.parent = this.ModelsParent;
				}
				else
				{
					handModel = modelGroup.LeftModel;
				}
				if (handModel != null)
				{
					modelGroup.modelList.Add(handModel);
					this.modelGroupMapping.Add(handModel, modelGroup);
				}
				IHandModel handModel2;
				if (modelGroup.IsRightToBeSpawned)
				{
					IHandModel rightModel = modelGroup.RightModel;
					GameObject gameObject2 = UnityEngine.Object.Instantiate<GameObject>(rightModel.gameObject);
					handModel2 = gameObject2.GetComponent<IHandModel>();
					handModel2.transform.parent = this.ModelsParent;
				}
				else
				{
					handModel2 = modelGroup.RightModel;
				}
				if (handModel2 != null)
				{
					modelGroup.modelList.Add(handModel2);
					this.modelGroupMapping.Add(handModel2, modelGroup);
				}
			}
		}

		public override HandRepresentation MakeHandRepresentation(Hand hand, ModelType modelType)
		{
			Chirality chirality = (!hand.IsRight) ? Chirality.Left : Chirality.Right;
			HandProxy handProxy = new HandProxy(this, hand, chirality, modelType);
			for (int i = 0; i < this.ModelPool.Count; i++)
			{
				HandPool.ModelGroup modelGroup = this.ModelPool[i];
				if (modelGroup.IsEnabled)
				{
					IHandModel handModel = modelGroup.TryGetModel(chirality, modelType);
					if (handModel != null)
					{
						handProxy.AddModel(handModel);
						if (!this.modelToHandRepMapping.ContainsKey(handModel))
						{
							this.modelToHandRepMapping.Add(handModel, handProxy);
						}
					}
				}
			}
			this.activeHandReps.Add(handProxy);
			return handProxy;
		}

		public void EnableGroup(string groupName)
		{
			base.StartCoroutine(this.enableGroup(groupName));
		}

		private IEnumerator enableGroup(string groupName)
		{
			yield return new WaitForEndOfFrame();
			HandPool.ModelGroup group = null;
			for (int i = 0; i < this.ModelPool.Count; i++)
			{
				if (this.ModelPool[i].GroupName == groupName)
				{
					group = this.ModelPool[i];
					for (int j = 0; j < this.activeHandReps.Count; j++)
					{
						HandProxy handProxy = this.activeHandReps[j];
						IHandModel handModel = group.TryGetModel(handProxy.RepChirality, handProxy.RepType);
						if (handModel != null)
						{
							handProxy.AddModel(handModel);
							this.modelToHandRepMapping.Add(handModel, handProxy);
						}
					}
					group.IsEnabled = true;
				}
			}
			if (group == null)
			{
				Debug.LogWarning("A group matching that name does not exisit in the modelPool");
			}
			yield break;
		}

		public void DisableGroup(string groupName)
		{
			base.StartCoroutine(this.disableGroup(groupName));
		}

		private IEnumerator disableGroup(string groupName)
		{
			yield return new WaitForEndOfFrame();
			HandPool.ModelGroup group = null;
			for (int i = 0; i < this.ModelPool.Count; i++)
			{
				if (this.ModelPool[i].GroupName == groupName)
				{
					group = this.ModelPool[i];
					for (int j = 0; j < group.modelsCheckedOut.Count; j++)
					{
						IHandModel handModel = group.modelsCheckedOut[j];
						HandProxy handProxy;
						if (this.modelToHandRepMapping.TryGetValue(handModel, out handProxy))
						{
							handProxy.RemoveModel(handModel);
							group.ReturnToGroup(handModel);
							j--;
						}
					}
					group.IsEnabled = false;
				}
			}
			if (group == null)
			{
				Debug.LogWarning("A group matching that name does not exisit in the modelPool");
			}
			yield break;
		}

		public void ToggleGroup(string groupName)
		{
			base.StartCoroutine(this.toggleGroup(groupName));
		}

		private IEnumerator toggleGroup(string groupName)
		{
			yield return new WaitForEndOfFrame();
			HandPool.ModelGroup modelGroup = this.ModelPool.Find((HandPool.ModelGroup i) => i.GroupName == groupName);
			if (modelGroup != null)
			{
				if (modelGroup.IsEnabled)
				{
					this.DisableGroup(groupName);
					modelGroup.IsEnabled = false;
				}
				else
				{
					this.EnableGroup(groupName);
					modelGroup.IsEnabled = true;
				}
			}
			else
			{
				Debug.LogWarning("A group matching that name does not exisit in the modelPool");
			}
			yield break;
		}

		public void AddNewGroup(string groupName, IHandModel leftModel, IHandModel rightModel)
		{
			HandPool.ModelGroup modelGroup = new HandPool.ModelGroup();
			modelGroup.LeftModel = leftModel;
			modelGroup.RightModel = rightModel;
			modelGroup.GroupName = groupName;
			modelGroup.CanDuplicate = false;
			modelGroup.IsEnabled = true;
			this.ModelPool.Add(modelGroup);
		}

		public void RemoveGroup(string groupName)
		{
			while (this.ModelPool.Find((HandPool.ModelGroup i) => i.GroupName == groupName) != null)
			{
				HandPool.ModelGroup modelGroup = this.ModelPool.Find((HandPool.ModelGroup i) => i.GroupName == groupName);
				if (modelGroup != null)
				{
					this.ModelPool.Remove(modelGroup);
				}
			}
		}

		[SerializeField]
		[Tooltip("Reference for the transform that is a child of the camera rig's root and is a parent to all hand models")]
		private Transform ModelsParent;

		[SerializeField]
		private List<HandPool.ModelGroup> ModelPool;

		private List<HandProxy> activeHandReps = new List<HandProxy>();

		private Dictionary<IHandModel, HandPool.ModelGroup> modelGroupMapping = new Dictionary<IHandModel, HandPool.ModelGroup>();

		private Dictionary<IHandModel, HandProxy> modelToHandRepMapping = new Dictionary<IHandModel, HandProxy>();

		[Serializable]
		public class ModelGroup
		{
			public IHandModel TryGetModel(Chirality chirality, ModelType modelType)
			{
				for (int i = 0; i < this.modelList.Count; i++)
				{
					if (this.modelList[i].HandModelType == modelType && this.modelList[i].Handedness == chirality)
					{
						IHandModel handModel = this.modelList[i];
						this.modelList.RemoveAt(i);
						this.modelsCheckedOut.Add(handModel);
						return handModel;
					}
				}
				if (this.CanDuplicate)
				{
					for (int j = 0; j < this.modelsCheckedOut.Count; j++)
					{
						if (this.modelsCheckedOut[j].HandModelType == modelType && this.modelsCheckedOut[j].Handedness == chirality)
						{
							IHandModel original = this.modelsCheckedOut[j];
							IHandModel handModel2 = UnityEngine.Object.Instantiate<IHandModel>(original);
							handModel2.transform.parent = this._handPool.ModelsParent;
							this._handPool.modelGroupMapping.Add(handModel2, this);
							this.modelsCheckedOut.Add(handModel2);
							return handModel2;
						}
					}
				}
				return null;
			}

			public void ReturnToGroup(IHandModel model)
			{
				this.modelsCheckedOut.Remove(model);
				this.modelList.Add(model);
				this._handPool.modelToHandRepMapping.Remove(model);
			}

			public string GroupName;

			[HideInInspector]
			public HandPool _handPool;

			public IHandModel LeftModel;

			[HideInInspector]
			public bool IsLeftToBeSpawned;

			public IHandModel RightModel;

			[HideInInspector]
			public bool IsRightToBeSpawned;

			[HideInInspector]
			public List<IHandModel> modelList;

			[HideInInspector]
			public List<IHandModel> modelsCheckedOut;

			public bool IsEnabled = true;

			public bool CanDuplicate;
		}
	}
}
