// (c) Copyright HutongGames, LLC 2010-2013. All rights reserved.
// Added Ignore Owner option. Thanks Nueral Echo: http://hutonggames.com/playmakerforum/index.php?topic=71.0

using UnityEngine;

namespace HutongGames.PlayMaker.Actions
{
	[ActionCategory(ActionCategory.GameObject)]
	[Tooltip("Finds the closest object to the specified Game Object.\nOptionally filter by Tag and Visibility.")]
	public class FindClosest : FsmStateAction
	{
		[RequiredField]
		[Tooltip("The GameObject to measure from.")]
		public FsmOwnerDefault gameObject;
		
		[RequiredField]
		[UIHint(UIHint.Tag)]
		[Tooltip("Only consider objects with this Tag. NOTE: It's generally a lot quicker to find objects with a Tag!")]
		public FsmString withTag;
		
		[Tooltip("If checked, ignores the object that owns this FSM.")]
		public FsmBool ignoreOwner;

		[Tooltip("Only consider objects visible to the camera.")]
		public FsmBool mustBeVisible;
		
		[UIHint(UIHint.Variable)]
		[Tooltip("Store the closest object.")]
		public FsmGameObject storeObject;
		
		[UIHint(UIHint.Variable)]
		[Tooltip("Store the distance to the closest object.")]
		public FsmFloat storeDistance;
		
		[Tooltip("Repeat every frame")]
		public bool everyFrame;

		
		public override void Reset()
		{
			gameObject = null;	
			withTag = "Untagged";
			ignoreOwner = true;
			mustBeVisible = false;
			storeObject = null;
			storeDistance = null;
			everyFrame = false;
		}

		public override void OnEnter()
		{
			DoFindClosest();
			
			if (!everyFrame)
			{
				Finish();
			}
		}
		
		public override void OnUpdate()
		{
			DoFindClosest();
		}

		void DoFindClosest()
		{
			var go = gameObject.OwnerOption == OwnerDefaultOption.UseOwner ? Owner : gameObject.GameObject.Value;

			GameObject[] objects; // objects to consider

			if (string.IsNullOrEmpty(withTag.Value) || withTag.Value == "Untagged")
			{
				objects = (GameObject[])GameObject.FindObjectsOfType(typeof(GameObject));
			}
			else
			{
				objects = GameObject.FindGameObjectsWithTag(withTag.Value);
			}	
			
			GameObject closestObj = null;
			var closestDist = Mathf.Infinity;

			foreach (var obj in objects)
			{
				if (ignoreOwner.Value && obj == Owner)
				{
					continue;
				}
				
				if (mustBeVisible.Value && !ActionHelpers.IsVisible(obj))
				{
					continue;
				}
				
				var dist = (go.transform.position - obj.transform.position).sqrMagnitude;
				if (dist < closestDist)
				{
					closestDist = dist;
					closestObj = obj;
				}
			}

			storeObject.Value = closestObj;
			
			if (!storeDistance.IsNone)
			{
				storeDistance.Value = Mathf.Sqrt(closestDist);
			}
		}
	}
}