using UnityEngine;
using System.Collections;

/*
 * Utilities for GameObjects and Transforms
 */

namespace com.deeperbeige.lib
{
	public class GameObjects
	{
		// Destroys all children of given GameObject or Transform, optionally filtering by a given start string
		// Note that dynamically created GameObjects tend to have (clone) in their name, hence the StartsWith check.
		//
		public static void DestroyAllChildren(GameObject gameobject)                        { DestroyAllChildren(gameobject.transform, ""); }
		public static void DestroyAllChildren(GameObject gameobject, string nameStartsWith) { DestroyAllChildren(gameobject.transform, nameStartsWith); }
		public static void DestroyAllChildren(Transform  transform)                         { DestroyAllChildren(transform, ""); }
		public static void DestroyAllChildren(Transform  transform,  string nameStartsWith)
		{
			foreach (Transform child in transform)
			{
			    if (! child.gameObject.name.StartsWith(nameStartsWith)) continue;
				MonoBehaviour.Destroy(child.gameObject);
			}
		}
		
		// Finds a named GameObject anywhere in the heirachy, including the root, including inactive objects
		// Recursive, depth-first, fairly expensive call. Cache the results if using repeatedly
		// Returns the first matching object found.
		// Returns null if no match is found.
		public static GameObject FindAnywhere(string named) { return FindAnywhere(named, false); }
		public static GameObject FindAnywhere(string named, bool silent)
		{
			foreach (GameObject obj in Resources.FindObjectsOfTypeAll(typeof(GameObject)))
			{
			    // Root heirachy objects have no parent object
				if (obj.transform.parent != null) continue;
				
				// Looking for a root object?
				if (obj.transform.name == named) return obj;
				
				// Search children
				Transform result = FindInChildren(obj.transform, named);
				if (result != null) return result.gameObject;
			}
			
			if (! silent) DevPanel.Log("GameObjects.FindAnywhere: Could not find \"" + named + "\"");
			return null;
		}
		
		// Finds a named GameObject anywhere below the given point in the heirachy (transform or gameobject)
		// Recursive, depth-first, fairly expensive call. Cache the results if using repeatedly
		// Returns the first matching child found.
		// Returns null if no match is found.
		public static GameObject FindNested(GameObject startFrom, string named) { return FindNested(startFrom, named, false); }
		public static GameObject FindNested(GameObject startFrom, string named, bool silent)
		{
			GameObject result = FindNested(startFrom.transform, named, silent);
			if (result == null) return null;
			return result.gameObject;
		}
		
		public static GameObject FindNested(Transform  startFrom, string named) { return FindNested(startFrom, named, false); }
		public static GameObject FindNested(Transform  startFrom, string named, bool silent)
		{
			if (startFrom == null)
			{
				if (! silent) DevPanel.Log("GameObjects.FindNested: Null startObject supplied while finding \"" + named + "\"");
				return null;
			}
			
			Transform result = FindInChildren(startFrom, named);
			
			if (result == null)
			{
				if (! silent) DevPanel.Log("GameObjects.FindNested: Could not find \"" + named + "\" from startObject \"" + startFrom.gameObject.name + "\"");
				return null;
			}
			
			return result.gameObject;
		}
		
		private static Transform FindInChildren(Transform transform, string named)
		{
			for (int j = 0; j < transform.childCount; j++)
			{
				Transform child = transform.GetChild(j);
				if (child.name == named) return child;
				
				Transform found = FindInChildren(child, named);
				if (found != null) return found;
			}
			
			return null;
		}
		
		
		// Looks for a child game object, only within the immediate children of the start object
		public static GameObject FindInImmediateChildren(GameObject startFrom, string named) { return FindInImmediateChildren(startFrom, named, false); }
		public static GameObject FindInImmediateChildren(GameObject startFrom, string named, bool silent)
		{
			Transform result = FindInImmediateChildren(startFrom.transform, named, silent);
			if (result == null) return null;
			return result.gameObject;
		}
		
		public static Transform FindInImmediateChildren(Transform transform, string named) { return FindInImmediateChildren(transform, named, false); }
		public static Transform FindInImmediateChildren(Transform transform, string named, bool silent)
		{
			for (int j = 0; j < transform.childCount; j++)
			{
				Transform child = transform.GetChild(j);
				if (child.name == named) return child;
			}
			
			if (! silent) DevPanel.Log("GameObjects.FindInImmediateChildren: Could not find \"" + named + "\" from startObject \"" + transform.gameObject.name + "\"");
			
			return null;
		}
		
		// Returns a string showing the full path to a given object. Good for debugging clarity
		public static string FullPath(GameObject gameObject) { return FullPath(gameObject.transform); }
		public static string FullPath(Transform  transform)
		{
			string path = "";
			
			while (transform.parent != null)
			{
				path = "/" + transform.name + path;
				transform = transform.parent;
			}
			
			return path;
		}
		
		// Sets the given gameobject and all its children to a given layer
		// Can supply layer as string or layer number
		public static void SetLayer(GameObject go, string layerName) { SetLayer(go, LayerMask.NameToLayer(layerName)); }
		public static void SetLayer(GameObject go, int layerNumber)
		{
			foreach (Transform transform in go.GetComponentsInChildren<Transform>(true))
			{
				transform.gameObject.layer = layerNumber;
			}
		}
	}
}
