using UnityEditor;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;

[CustomEditor(typeof(PoolController))] 
public class PoolControllerEditor : Editor
{
	#region Pooling Private Members 
	
	// The list for editing pool members
	private List<InspectorPool> m_inspectorPools;
	
	// Make sure we've initialized the pool
	private bool m_initialized;
	
	// The target Pool Controller script  
	private PoolController m_controller;
	
	// The temporary pool object for adding
	private TypePool  m_addPool;
	
	#endregion	
	
	#region Inspector Classes
	
	// Small class for adding a foldout bool per pool only in edit mode
	public class InspectorPool
	{
		public bool Foldout;
		public TypePool Pool;
	}
	
	#endregion
	
	#region GUI Private Members
	
	// Main skin for overriding certain elements
	private GUISkin   m_skin;
	
	// The main style for formatting
	private GUIStyle  m_mainStyle;
	
	// Unused atm
	private Texture2D m_viewIcon;
	
	// Unused atm
	private Texture2D m_editIcon;
	
	// Icon for the pool removal button
	private Texture2D m_removeIcon;
	
	// Icon for the clear button
	private Texture2D m_clearIcon;
	
	// Icon for the add button
	private Texture2D m_addButtonIcon;
	
	// Icon for the settings toolbar button
	private Texture2D m_settingsIcon;
	
	// Icon for the manage toolbar button
	private Texture2D m_manageIcon;
	
	// Icon for the Add toolbar button
	private Texture2D m_addIcon;
	
	// Int for which toolbar we're currently on
	private int  m_modeInt;
	
	// The path this editors' resources
	private const string m_pluginPath = "Assets/PoolController/Editor/Resources/";

	// Whether or not to use the prefab's name when adding
	private bool  m_usePrefabName = true;
	private bool m_overviewFold;
	
	#endregion
	
	#region Init
	
	void OnEnable ()
	{
		ResetAddPool ();
		m_inspectorPools = new List<InspectorPool> ();
		m_initialized = false;
	}

	#endregion
	
	#region Inspector GUI

	public override void OnInspectorGUI ()
	{
		GUI.changed = false;
		m_controller = (PoolController)target;
	
		LoadResources ();
		
		if (!m_initialized) {
			// reload on submit and removal. copy settings from previous to new, with new or /removed entries
			
			foreach (var pool in m_controller.Pools) {
				m_inspectorPools.Add (new InspectorPool{ Foldout = false, Pool = pool});
			}
			
			m_initialized = true;
		}
		
		EditorGUILayout.Space ();
		
		ToolbarGui ();

		if (GUI.changed) {
			EditorUtility.SetDirty (m_controller);
		}
	}
	
	private	void OnInspectorUpdate ()
	{
		Repaint ();	
	}
		
	private void LoadResources ()
	{
		m_clearIcon = (Texture2D)Resources.LoadAssetAtPath (m_pluginPath + "ClearIcon.png", typeof(Texture2D));
		m_addButtonIcon = (Texture2D)Resources.LoadAssetAtPath (m_pluginPath + "AddButtonIcon.png", typeof(Texture2D));	
		m_settingsIcon = (Texture2D)Resources.LoadAssetAtPath (m_pluginPath + "SettingsIcon.png", typeof(Texture2D));	
		m_manageIcon = (Texture2D)Resources.LoadAssetAtPath (m_pluginPath + "ManageIcon.png", typeof(Texture2D));	
		m_addIcon = (Texture2D)Resources.LoadAssetAtPath (m_pluginPath + "AddIcon.png", typeof(Texture2D));
		m_skin = (GUISkin)Resources.LoadAssetAtPath (m_pluginPath + "PoolControllerSkin.guiskin", typeof(GUISkin));	
	}
		
	private void ToolbarGui ()
	{
		var toolbarOptions = new GUIContent[3];

		toolbarOptions [0] = new GUIContent (" Add", m_addIcon, "Add a new pool");
		toolbarOptions [1] = new GUIContent (" Manage", m_manageIcon, "Manage details of pools");
		toolbarOptions [2] = new GUIContent (" Settings", m_settingsIcon, "Pool Controller Settings");		
		
		m_modeInt = GUILayout.Toolbar (m_modeInt, toolbarOptions, GUILayout.Height (30));
		
		EditorGUILayout.Separator ();
		
		switch (m_modeInt) {
		case 0:
			{
				AddPoolGui ();
				break;
			}
		case 1:
			{
			    
				ManageGui ();
				break;
			}
		case 2:
			{
				SettingsGui ();
			   
				break;
			}
		}
	}
	
	private void AddPoolGui ()
	{
		Header ("Create a new Pool");
		
		if (!m_usePrefabName) {
			m_addPool.PoolName = EditorGUILayout.TextField ("Name", m_addPool.PoolName);
		} else {
			if (m_addPool.Prefab != null) {
				PrefixLabel ("Name", m_addPool.Prefab.name);
			} else {
				PrefixLabel ("Name", "");
			}
		}
		
		m_usePrefabName = EditorGUILayout.Toggle ("Use Prefab Name", m_usePrefabName);
		
		PoolEditGui ();
		
		EditorGUILayout.Separator ();	
		Seperator ();
		EditorGUILayout.Separator ();	
		
		EditorGUILayout.BeginHorizontal ();
		
		if (GUILayout.Button (new GUIContent (" Reset", m_clearIcon, "Clear the settings"), GUILayout.Width (80), GUILayout.Height (36))) {
			ResetAddPool ();
			
			Repaint ();
		}

		if (GUILayout.Button (new GUIContent (" Add", m_addButtonIcon, "Add a new pool"), GUILayout.Width (80), GUILayout.Height (36))) {
			SubmitPool ();
		}
		
		EditorGUILayout.EndHorizontal ();
		EditorGUILayout.Separator ();
	}
	
	private void ManageGui ()
	{	
		OverviewGui ();
		ManagePoolsGui ();
	}
	
	private void OverviewGui ()
	{
		Header ("Overview");

		EditorGUI.indentLevel++;
		
		int count = 0;

		count = GetPoolCount (PoolType.ParticleEffect);
		PrefixLabel ("# Shuriken", count.ToString ());
		
		count = GetPoolCount (PoolType.GameItem);
		PrefixLabel ("# Object ", count.ToString ());

		EditorGUILayout.Space ();
		Seperator ();
		EditorGUILayout.Space ();
		EditorGUI.indentLevel--;
	}
	
	private void ManagePoolsGui ()
	{
		
		Header ("Manage Pools");
		
		if (m_controller.Pools.Count <= 0) {
			Seperator ();
			EditorGUILayout.Space ();
			return;
		}
				
		foreach (var inspectorPool in m_inspectorPools.ToList()) {
			EditorGUILayout.BeginHorizontal ();
			inspectorPool.Foldout = EditorGUILayout.Foldout (inspectorPool.Foldout, " " + inspectorPool.Pool.PoolName);

			
			EditorGUILayout.EndHorizontal ();
			EditorGUILayout.Space ();
		
			if (inspectorPool.Foldout) {
				Seperator ();
				EditorGUILayout.Space ();
				
				EditorGUILayout.BeginVertical ();
				inspectorPool.Pool.PoolName = EditorGUILayout.TextField ("Name", inspectorPool.Pool.PoolName);
				inspectorPool.Pool.Prefab = (GameObject)EditorGUILayout.ObjectField ("Prefab", inspectorPool.Pool.Prefab, typeof(GameObject), true);
				inspectorPool.Pool.ResourcePath = EditorGUILayout.TextField ("Resource Path", inspectorPool.Pool.ResourcePath);	
				inspectorPool.Pool.PooledType = (PoolType)EditorGUILayout.EnumPopup ("Type", inspectorPool.Pool.PooledType);
				m_addPool.Layer = EditorGUILayout.LayerField ("Layer", m_addPool.Layer);		

				EditorGUI.indentLevel++;
				
				PrefixSection ("Size");
				
				inspectorPool.Pool.PoolSize = EditorGUILayout.IntField ("Max Size", inspectorPool.Pool.PoolSize);	
				inspectorPool.Pool.LimitToSize = EditorGUILayout.Toggle ("Limit To Size", inspectorPool.Pool.LimitToSize);
				inspectorPool.Pool.PopulatePool = EditorGUILayout.Toggle ("Populate", inspectorPool.Pool.PopulatePool);
				inspectorPool.Pool.PopulateCount = EditorGUILayout.IntSlider ("Populate Count", inspectorPool.Pool.PopulateCount, 1, inspectorPool.Pool.PoolSize);			
				
				PrefixSection ("Spawning");
				inspectorPool.Pool.ResourcesLoad = EditorGUILayout.Toggle ("Resources Load", inspectorPool.Pool.ResourcesLoad);
				inspectorPool.Pool.AutoDespawn = EditorGUILayout.Toggle ("Auto Despawn", inspectorPool.Pool.AutoDespawn);
				inspectorPool.Pool.DespawnTime = EditorGUILayout.FloatField ("Despawn Time", inspectorPool.Pool.DespawnTime);
				inspectorPool.Pool.SpawnNotifications = EditorGUILayout.Toggle ("Spawn Notification", inspectorPool.Pool.SpawnNotifications);
			    
				/*
				PrefixSection("Environment Pool");
				inspectorPool.Pool.IsScenery     = EditorGUILayout.Toggle("Is Environment", inspectorPool.Pool.IsScenery);
				inspectorPool.Pool.XmlLoad       = EditorGUILayout.Toggle("XML Load", inspectorPool.Pool.XmlLoad);
				inspectorPool.Pool.XmlFile       = (TextAsset)EditorGUILayout.ObjectField("XML File", inspectorPool.Pool.XmlFile, typeof(TextAsset), true);
				*/
				
				inspectorPool.Pool.LogMessages = EditorGUILayout.Toggle ("Debug Messages", inspectorPool.Pool.LogMessages);				
				
				if (GUILayout.Button ("Remove Pool")) {
					RemovePool (inspectorPool.Pool.PoolName);
				}
				
				EditorGUILayout.EndVertical ();
			}

		}
		
		EditorGUILayout.Space ();
		Seperator ();
		EditorGUILayout.Space ();		
		EditorGUILayout.Space ();
	}
	
	private void SettingsGui ()
	{
		Header ("Pool Controller Settings");
		m_controller.DontDestroy = EditorGUILayout.Toggle ("Don't Destroy On Load", m_controller.DontDestroy);
		m_controller.DebugMessages = EditorGUILayout.Toggle ("Debug Messages", m_controller.DebugMessages);			
		m_controller.NotifyOnLoad = EditorGUILayout.Toggle ("Notify On Load", m_controller.NotifyOnLoad);			   
		m_controller.NotifyTarget = (GameObject)EditorGUILayout.ObjectField ("Notify Target", m_controller.NotifyTarget, typeof(GameObject), true); 
		m_controller.NotifyMethod = EditorGUILayout.TextField ("Notify Method", m_controller.NotifyMethod);
		m_controller.RootName = EditorGUILayout.TextField ("Root Name", m_controller.RootName);

		EditorGUILayout.Separator ();
	}
	
	private void PoolEditGui ()
	{
		m_addPool.Prefab = (GameObject)EditorGUILayout.ObjectField ("Prefab", m_addPool.Prefab, typeof(GameObject), true);
		m_addPool.ResourcePath = EditorGUILayout.TextField ("Resource Path", m_addPool.ResourcePath);			
		m_addPool.PooledType = (PoolType)EditorGUILayout.EnumPopup ("Type", m_addPool.PooledType);
		m_addPool.Layer = EditorGUILayout.LayerField ("Layer", m_addPool.Layer);
		
		EditorGUI.indentLevel++;
		
		PrefixSection ("Size");
		
		m_addPool.PoolSize = EditorGUILayout.IntField ("Max Size", m_addPool.PoolSize);	
		m_addPool.LimitToSize = EditorGUILayout.Toggle ("Limit To Size", m_addPool.LimitToSize);
		m_addPool.PopulatePool = EditorGUILayout.Toggle ("Populate", m_addPool.PopulatePool);
		m_addPool.PopulateCount = EditorGUILayout.IntSlider ("Populate Count", m_addPool.PopulateCount, 1, m_addPool.PoolSize);			
		
		PrefixSection ("Spawning");
		m_addPool.ResourcesLoad = EditorGUILayout.Toggle ("Resources Load", m_addPool.ResourcesLoad);		
		m_addPool.AutoDespawn = EditorGUILayout.Toggle ("Auto Despawn", m_addPool.AutoDespawn);
		m_addPool.DespawnTime = EditorGUILayout.FloatField ("Despawn Time", m_addPool.DespawnTime);
		m_addPool.SpawnNotifications = EditorGUILayout.Toggle ("Spawn Notification", m_addPool.SpawnNotifications);
	
		/*
		PrefixSection("Environment Pool");
		m_addPool.IsScenery     = EditorGUILayout.Toggle("Is Environment", m_addPool.IsScenery);
		m_addPool.XmlLoad       = EditorGUILayout.Toggle("XML Load", m_addPool.XmlLoad);
		m_addPool.XmlFile       = (TextAsset)EditorGUILayout.ObjectField("XML File", m_addPool.XmlFile, typeof(TextAsset), true);
				*/
		m_addPool.LogMessages = EditorGUILayout.Toggle ("Debug Messages", m_addPool.LogMessages);

	}
	
	private int GetPoolCount (PoolType type)
	{
		return m_controller.Pools.Count (c => c.PooledType == type);
	}

	#endregion
	
	#region GUI Helpers
	
	private void PrefixSection (string text)
	{
		EditorGUILayout.Space ();
		EditorGUI.indentLevel--;
		EditorGUILayout.PrefixLabel (text);
		EditorGUI.indentLevel++;
	}
	
	private void Seperator ()
	{
		GUILayout.Box ("", new GUILayoutOption[]{GUILayout.ExpandWidth (true), GUILayout.Height (2)}); 
	}
	
	private void Header (string title)
	{
		GUI.skin = m_skin;
		GUILayout.Label (title);
		GUI.skin = null;
		Seperator ();
		EditorGUILayout.Separator ();
		EditorGUILayout.Space ();
	}
	
	private void PrefixLabel (string prefix, string label)
	{
		EditorGUILayout.BeginHorizontal ();
		EditorGUILayout.PrefixLabel (prefix);
		EditorGUILayout.LabelField (label);
		EditorGUILayout.EndHorizontal ();
	}
	
	#endregion
	
	#region Pool Methods
	
	private void SubmitPool ()
	{
		if (m_addPool.Prefab == null) {
			EditorUtility.DisplayDialog ("Add Pool Error", "The Prefab field is empty", "Close");
			return;
		}		
		
		if (m_usePrefabName) {
			m_addPool.PoolName = m_addPool.Prefab.name;
		}
		
		if (m_addPool.PoolName.Length == 0) {
			EditorUtility.DisplayDialog ("Add Pool Error", "The Name field is empty", "Close");
			return;
		}
		
		if (m_controller.Pools.Any (p => p.PoolName == m_addPool.PoolName)) {
			EditorUtility.DisplayDialog ("Add Pool Error", "A pool with this name already exists", "Close");
			return;
		}
		

		m_controller.Pools.Add (m_addPool);
		m_inspectorPools.Add (new InspectorPool{ Foldout = false, Pool = m_addPool});
		EditorUtility.DisplayDialog ("Add Pool", "A " + m_addPool.PooledType.ToString () + " pool with the name " + m_addPool.PoolName + " was successfully added", "Close"); 
		ResetAddPool ();   
	}
	
	public void RemovePool (string poolName)
	{
		if (EditorUtility.DisplayDialog ("Pool Removal", "Remove the pool " + poolName + "?", "yes", "no")) {
			var targetPool = m_controller.Pools.FirstOrDefault (p => p.PoolName == poolName);
			
			if (targetPool == null) {
				EditorUtility.DisplayDialog ("Remove Pool Error", "A Pool with this name does not exist", "Close");
				return;
			}		
	
			m_controller.Pools.Remove (targetPool);
			
			var targetInspectorPool = m_inspectorPools.FirstOrDefault (p => p.Pool.PoolName == poolName);
			
			if (targetPool == null) {
				Debug.Log ("Remove Pool Error. A Pool with this name does not exist in the Custom Inpector pool list");
				return;
			}	
			
			m_inspectorPools.Remove (targetInspectorPool);
		}
	}
	
	private void ResetAddPool ()
	{
		m_addPool = new TypePool{PoolName = string.Empty, PooledType = PoolType.ParticleEffect};
		m_usePrefabName = true;
	}
	
	#endregion
}














