using UnityEngine;

public delegate void Action();

public class Utils
{
	const uint defaultPixelToUnit = 108;

	public static T Create<T>(Transform parent, Vector3 position, string name = "") where T : Component
	{
		GameObject gameObject = new GameObject();
		if (name == "")
		{
			gameObject.name = typeof(T).Name;
		}
		else
		{
			gameObject.name = name;
		}
		if (parent != null)
		{
			gameObject.transform.parent = parent;
		}
		gameObject.transform.localPosition = position;
		
		T component = gameObject.AddComponent<T>(); 
		return component;
	}
	
	public static T Create<T>(Transform parent, string name = "") where T : Component
	{
		return Create<T>(parent, Vector3.zero, name);
	}

	public static T Create<T>(string name = "") where T : Component
	{
		return Create<T>(null, Vector3.zero, name);
	}

	public static GameObject LoadPrefab(string resourceName, Transform parent = null)
	{
		GameObject prefab = (GameObject)GameObject.Instantiate(Resources.Load(resourceName));
		if (prefab != null) {
			prefab.transform.parent = parent;
		}
		return prefab;
	}

	public static GameObject LoadPrefab(string resourceName, Vector3 position, Transform parent = null)
	{
		GameObject prefab = LoadPrefab(resourceName, parent);
		if (prefab != null) {
			prefab.transform.localPosition = position;
		}
		return prefab;
	}
	
	public static T LoadPrefab<T>(string resourceName, Vector3 position, Transform parent = null) where T : Component
	{
		return LoadPrefab(resourceName, position, parent).GetComponent<T>();
	}

	public static T LoadPrefab<T>(string resourceName, Transform parent = null) where T : Component
	{
		return LoadPrefab(resourceName, parent).GetComponent<T>();
	}

	public static SpriteRenderer AddSprite(GameObject obj, Texture2D texture, Rect rect, Vector3 pivot, uint pixelToUnit = defaultPixelToUnit)
	{
		SpriteRenderer spriteRenderer = obj.AddComponent<SpriteRenderer>();
		spriteRenderer.sprite = UnityEngine.Sprite.Create(texture, rect, pivot, pixelToUnit);
		return spriteRenderer;
	}

	public static SpriteRenderer AddSprite(GameObject obj, UnityEngine.Sprite sprite)
	{
		SpriteRenderer spriteRenderer = obj.AddComponent<SpriteRenderer>();
		spriteRenderer.sprite = sprite;
		return spriteRenderer;
	}
	
	public static GameObject CreateGameObject(Transform parent, string name = "")
	{
		return CreateGameObject(parent, Vector3.zero, name);
	}
	
	public static GameObject CreateGameObject(Transform parent, Vector3 position, string name = "")
	{
		GameObject gameObject = new GameObject();
		if (name == "")
		{
			gameObject.name = "GameObject";
		}
		else
		{
			gameObject.name = name;
		}
		gameObject.transform.parent = parent;
		gameObject.transform.localPosition = position;
		return gameObject;
	}
	
	public static T GetOrCreateComponent<T>(GameObject gameObject) where T : Component
	{
		T component = gameObject.GetComponent<T>();
		if (component == null)
		{
			component = gameObject.AddComponent<T>();
		}
		return component;
	}
	
	public static float GetAngle(Vector3 m, Vector3 n)
	{
		float angle = Vector3.Angle((m - n), Vector3.up);
		if (m.x < n.x)
		{
			angle = 360 - angle;
		}
		return angle;
	}
	
	public static float GetAngle(Vector2 m, Vector2 n)
	{
		float angle = Vector2.Angle((m - n), Vector2.up);
		if (m.x < n.x)
		{
			angle = 360 - angle;
		}
		return angle;
	}
	
	public static float GetAngle(Vector2 m)
	{
		return GetAngle(m, Vector2.zero);
	}
	
	public static float RotateToAngle(float sourceAngle, float destAngle, float speed)
	{
		float angle = destAngle;
		if (sourceAngle < destAngle)
		{
			if (destAngle - sourceAngle <= 180f)
			{
				angle = sourceAngle + speed;
				if (angle > destAngle)
				{
					angle = destAngle;
				}
			}
			else
			{
				angle = sourceAngle - speed;
				if (angle < 0)
				{
					angle = angle + 360f;
					if (angle < destAngle)
					{
						angle = destAngle;
					}
				}
			}
		}
		else if (sourceAngle > destAngle)
		{
			if (sourceAngle - destAngle <= 180f)
			{
				angle = sourceAngle - speed;
				if (angle < destAngle)
				{
					angle = destAngle;
				}
			}
			else
			{
				angle = sourceAngle + speed;
				if (angle > 360f)
				{
					angle = angle - 360f;
					if (angle > destAngle)
					{
						angle = destAngle;
					}
				}				
			}			
		}
		return angle;
	}
	
	public static Rect ScreenQuadRect(float x, float y, float w = 1f, float h = 1f)
	{
		if (Screen.width > Screen.height)
		{
			float xShift = (float)(Screen.width - Screen.height) / 2f;
			float basePixels = (float)Screen.height / 10f;
			return new Rect(xShift + x * basePixels, y * basePixels, w * basePixels, h * basePixels);
		}
		else
		{
			float yShift = (float)(Screen.height - Screen.width) / 2f;
			float basePixels = (float)Screen.width / 10f;
			return new Rect(x * basePixels, yShift + y * basePixels, w * basePixels, h * basePixels);
		}
	}
}