context: using UnityEngine;
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using Frontiers.World;
  using Frontiers.World.Gameplay;
  using Frontiers.GUI;
  using Frontiers.Data;
  using Frontiers.World.WIScripts;
  
  namespace Frontiers
  {
  	public class PlayerInventory : PlayerScript, IInventory
  	{
  		public PlayerInventoryState State = new PlayerInventoryState ();
  		public List <IWIBase> LastAddedItems = new List <IWIBase> ();
  		public double LastAddedTime = Mathf.NegativeInfinity;
  		public WIStack SelectedStack = null;
  		public WIStackEnabler QuickslotEnabler = null;
  		public List <WIStackEnabler> InventoryEnablers = new List <WIStackEnabler> ();
  		public List <string> NoSpaceNeededItems = new List <string> { "BookAvatar", "Currency", "Purse", "Key" };
  
  		public override void Initialize ()
  		{
  			base.Initialize ();
  			enabled = true;
  		}
  
  		public override bool LockQuickslots {
  			get {
  				return mChangingAqi;
  			}
  		}
  
  		public WorldItem ActiveQuickslotItem {
  			get {
  				return mActiveQuickslotItem;
  			}
  		}
  
  		public WorldItem ActiveCarryItem {
  			get {
  				return mActiveCarryItem;
  			}
  		}
  
  		#region has this, has that
  
  		public bool HasActiveQuickslotItem {
  			get {//this will cover our asses a bit if we don't
  				//get around to updating the quickslot status enough
  				return 	!(mActiveQuickslotItem == null || !mActiveQuickslotItem.Is (WILoadState.Initialized));
  			}
  		}
  
  		public bool HasActiveCarryItem { 
  			get { 
  				return !(mActiveCarryItem == null || !mActiveCarryItem.Is (WILoadState.Initialized));
  			}
  		}
  
  		public bool HasItem (IWIBase item, out WIStack stack)
  		{
  			stack = null;
  			return false;
  		}
  
  		public void AcquireStructure (MobileReference ownedStructure, bool announceOwnership)
  		{
  			if (State.OwnedStructures.SafeAdd (ownedStructure)) {
  				//if we don't already own it
  				//announce that we gained a thing
  				Player.Get.AvatarActions.ReceiveAction (AvatarAction.LocationAquire, WorldClock.AdjustedRealTime);
  				if (announceOwnership) {
  					GUIManager.PostGainedItem (ownedStructure);
  				}
  			}
  		}
  
  		public bool HasKey (string keyType, string keyTag, out string keyName)
  		{
  			keyName = string.Empty;
  			for (int i = 0; i < State.PlayerKeyChain.Keys.Count; i++) {
  				KeyState keyState = State.PlayerKeyChain.Keys [i];
  				if (keyState.KeyType == keyType && keyState.KeyTag == keyTag) {
  					keyName = keyState.KeyName;
  					return true;
  				}
  			}
  			return false;
  		}
  
  		#endregion
  
  		//used for searching - use sparingly
  		public Dictionary <int,IWIBase>	QuickslotItems {
  			get {
  				Dictionary <int,IWIBase> quickslotItems = new Dictionary <int, IWIBase> ();
  				if (QuickslotsEnabled) {
  					List <WIStack> stacks = QuickslotEnabler.EnablerStacks;
  					for (int i = 0; i < stacks.Count; i++) {
  						if (i == State.ActiveQuickslot && HasActiveQuickslotItem) {	//if it's the active quickslot then the item will be equipped as a tool
  							//so get the tool's worlditem instead of the stack's
  							quickslotItems.Add (i, ActiveQuickslotItem);
  						} else if (stacks [i].HasTopItem) {
  							quickslotItems.Add (i, stacks [i].TopItem);
  						}
  					}
  				}
  				return quickslotItems;
  			}
  		}
  
  		public bool QuickslotsEnabled {
  			get {	//we're initialized, updated, we have an enabler
  				//and that enabler has a compatible stack container with stacks
  				return State.ActiveQuickslot >= 0
  				&& QuickslotEnabler != null
  				&& QuickslotEnabler.IsEnabled;
  			}
  		}
  
  		#region initialization
  
  		public override void OnStateLoaded ()
  		{
  			try {
  				if (State.QuickslotsStack.Group == null) {
  					State.QuickslotsStack.Group = WIGroups.Get.Player;
  				}
  				Stacks.Convert.UnloadedItemsToWorldItems (State.QuickslotsStack);
  				for (int i = 0; i < State.InventoryStacks.Count; i++) {
  					Stacks.Convert.UnloadedItemsToWorldItems (State.InventoryStacks [i]);
  				}
  			} catch (Exception e) {
  				Debug.LogError ("Exception when loading state in inventory, proceeding normally: " + e.ToString ());
  			}
  		}
  
  		public void FillInventory (string inventoryFillCategory)
  		{
  			StartCoroutine (FillInventoryOverTime (inventoryFillCategory));
  		}
  
  		protected IEnumerator FillInventoryOverTime (string inventoryFillCategory)
  		{
  			yield return null;
  			WICategory startupCategory = null;
  			WIStackError error = WIStackError.None;
  			if (WorldItems.Get.Category (inventoryFillCategory, out startupCategory)) {
  				for (int i = 0; i < startupCategory.GenericWorldItems.Count; i++) {
  					for (int j = 0; j < startupCategory.GenericWorldItems [i].InstanceWeight; j++) {
  						WorldItem worlditem = null;
  						if (WorldItems.CloneWorldItem (startupCategory.GenericWorldItems [i], STransform.zero, false, WIGroups.Get.Player, out worlditem)) {
  							if (!AddItems (worlditem, ref error)) {
  								Debug.Log ("PLAYERINVENTORY: Couldn't add item, error: " + error.ToString ());
  							}
  						}
  					}
  					yield return null;
  				}
  			}
  		}
  
  		public override void OnGameLoadStart ()
  		{
  			if (State.InventoryStacks == null || State.InventoryStacks.Count != Globals.NumInventoryStackContainers) {	//if it's null after setting state then we haven't created it before
  				State.QuickslotsStack = Stacks.Create.Stack (WIGroups.Get.Player);
  				State.QuickslotsStackCarry = Stacks.Create.Stack (WIGroups.Get.Player);
  				State.InventoryStacks = Stacks.Create.Stacks (Globals.NumInventoryStackContainers, WIGroups.Get.Player);
  			} else {
  				State.QuickslotsStack.Group = WIGroups.Get.Player;
  				State.QuickslotsStackCarry.Group = WIGroups.Get.Player;
  				for (int i = 0; i < State.InventoryStacks.Count; i++) {
  					State.InventoryStacks [i].Group = WIGroups.Get.Player;
  				}
  			}
  			for (int i = 0; i < State.InventoryStacks.Count; i++) {
  				State.InventoryStacks [i].Bank = State.PlayerBank;
  			}
  			State.QuickslotsStackCarry.Bank = State.PlayerBank;
  			State.QuickslotsStack.Bank = State.PlayerBank;
  			//always create enablers
  			QuickslotEnabler = Stacks.Create.StackEnabler (State.QuickslotsStack, WIGroups.Get.Player);
  			InventoryEnablers = Stacks.Create.StackEnablers (State.InventoryStacks, WIGroups.Get.Player);
  
  			SelectedStack = Stacks.Create.Stack (WIGroups.Get.Player);
  			SelectedStack.StackMaxSize = WISize.NoLimit;
  			SelectedStack.Bank = State.PlayerBank;
  
  			//make sure the curreny interface is using our actual inventory bank
  			GUIInventoryInterface.Get.Initialize ();
  
  			GUIStackContainerDisplay display = GUIInventoryInterface.Get.QuickslotsDisplay;
  			display.name = "Quickslots";
  			display.SetEnabler (QuickslotEnabler);
  
  			GUIInventoryInterface.Get.QuickslotsCarrySquare.SetStack (State.QuickslotsStackCarry);
  
  			for (int i = 0; i < InventoryEnablers.Count; i++) {
  				display = GUIInventoryInterface.Get.StackContainerDisplays [i];
  				display.name = "Inventory enabler " + i.ToString ();
  				display.SetEnabler (InventoryEnablers [i]);
  			}
  
  			State.PlayerBank.RefreshAction += OnBankChange;
  			GUIInventoryInterface.Get.CurrencyInterface.SetBank (State.PlayerBank);
  
  			if (State.ActiveQuickslot < 0) {
  				State.ActiveQuickslot = 0;
  			}
  			GUIInventoryInterface.Get.SetActiveQuickslots (State.ActiveQuickslot);
  		}
  
  		public override void OnLocalPlayerDespawn ()
  		{
  			mLastRelevantStack = null;
  			if (State.ActiveQuickslot < 0) {
  				SelectionNext (WorldClock.RealTime);
  			}
  		}
  
  		public override void OnGameStartFirstTime ()
  		{
  			ClearInventory (false);//this will add a container
  		}
  
  		public override void OnGameStart ()
  		{
  			GUIInventoryInterface.Get.Subscribe (InterfaceActionType.SelectionNext, new ActionListener (SelectionNext));
  			GUIInventoryInterface.Get.Subscribe (InterfaceActionType.SelectionPrev, new ActionListener (SelectionPrev));
  			GUIInventoryInterface.Get.Subscribe (InterfaceActionType.SelectionNumeric, new ActionListener (SelectionNumeric));
  			GUIInventoryInterface.Get.UserActions.Subscribe (UserActionType.ToolSwap, new ActionListener (ToolSwap));
  
  			StartCoroutine (CheckQuickslotStatus ());
  			StartCoroutine (CheckCarryItemStatus ());
  			if (State.ActiveQuickslot < 0) {
  				SelectionNext (WorldClock.AdjustedRealTime);
  			}
  		}
  
  		#endregion
  
  		public bool PopAQIIntoWorld (out WorldItem aqi, WIGroup toGroup, ref WIStackError error)
  		{
  			if (HasActiveQuickslotItem) {
  				IWIBase aqiBase = null;
  				player.Tool.UnlockWorldItem ();//in case the tool has locked it
  				if (Stacks.Pop.Top (QuickslotEnabler.EnablerStacks [State.ActiveQuickslot], out aqiBase, toGroup, ref error)) {
  					aqi = aqiBase.worlditem;
  					aqi.SetMode (WIMode.World);
  					return true;
  				}
  			}
  			aqi = null;
  			return false;
  		}
  
  		public void TryToEquip (IWIBase item)
  		{
  			//this specifically looks for a spot in our quickslot bar
  			//then adds it to that stack
  			//if it can't find an empty quickslot bar, it just adds it normally
  			WIStackError error = WIStackError.None;
  			int selection = -1;
  			if (!player.ItemPlacement.PlacementModeEnabled) {
  				List <WIStack> quickslotStacks = QuickslotEnabler.EnablerStacks;
  				for (int i = 0; i < quickslotStacks.Count; i++) {
  					if (Stacks.Push.Item (quickslotStacks [i], item, ref error)) {
  						selection = i;
  						break;
  					}
  				}
  			} else {
  				Debug.Log ("Couldn't equip, placement mode enabled");
  			}
  
  			if (selection >= 0) {
  				Debug.Log ("Added to quickslot, selecting now");
  				State.ActiveQuickslot = selection;
  				if (State.ActiveQuickslot >= Globals.MaxStacksPerContainer) {	//quickslots will always cap at MaxStacksPerContainer
  					State.ActiveQuickslot = 0;
  				} else if (State.ActiveQuickslot < 0) {
  					State.ActiveQuickslot = 0;
  				}
  				GUIInventoryInterface.Get.SetActiveQuickslots (State.ActiveQuickslot);
  			} else {
  				Debug.Log ("Couldn't equip directly, adding to inventory normally");
  				AddItems (item, ref error);
  			}
  		}
  
  		public void ClearInventory (bool destroyItems)
  		{
  			for (int i = 0; i < InventoryEnablers.Count; i++) {
  				Stacks.Clear.Items (InventoryEnablers [i], destroyItems);
  			}
  			Stacks.Clear.Items (QuickslotEnabler, destroyItems);
  			Stacks.Clear.Items (State.QuickslotsStackCarry, destroyItems);
  			mActiveQuickslotItem = null;
  			mActiveCarryItem = null;
  			Player.Get.AvatarActions.ReceiveAction (AvatarAction.ItemAQIChange, WorldClock.AdjustedRealTime);
  			Player.Get.AvatarActions.ReceiveAction (AvatarAction.ItemACIChange, WorldClock.AdjustedRealTime);
  			//always add a single sack, even if we've cleared everything else
  			WorldItem containerItem = null;
  			WIStackError error = WIStackError.None;
  			mLastRelevantStack = null;
  			if (WorldItems.CloneWorldItem ("Containers", "Sack 1", STransform.zero, false, WIGroups.Get.Player, out containerItem)) {
  				AddItems (containerItem, ref error);
  			}
  			mLastRelevantStack = null;
  		}
  
  		public bool AddQuestItem (string questItem)
  		{
  			if (State.QuestItemsAcquired.SafeAdd (questItem)) {
  				Player.Get.AvatarActions.ReceiveAction (AvatarAction.ItemQuestItemAddToInventory, WorldClock.AdjustedRealTime);
  				return true;
  			}
  			return false;
  		}
  
  		#region user / interface actions / actions in general
  
  		public bool SelectionNumeric (double timeStamp)
  		{
  			if (player.LockQuickslots)
  				return true;
  
  			if (!GameManager.Is (FGameState.InGame)) {
  				return true;
  			}
  			int selection = -1;
  
  			switch (InterfaceActionManager.LastKey) {
  			case KeyCode.None:
  			default:
  				return true;
  
  			case KeyCode.Alpha1:
  				selection = 0;
  				break;
  
  			case KeyCode.Alpha2:
  				selection = 1;
  				break;
  
  			case KeyCode.Alpha3:
  				selection = 2;
  				break;
  
  			case KeyCode.Alpha4:
  				selection = 3;
  				break;
  
  			case KeyCode.Alpha5:
  				selection = 4;
  				break;
  
  			case KeyCode.Alpha6:
  				selection = 5;
  				break;
  
  			case KeyCode.Alpha7:
  				selection = 6;
  				break;
  
  			case KeyCode.Alpha8:
  				selection = 7;
  				break;
  
  			case KeyCode.Alpha9:
  				selection = 8;
  				break;
  
  			case KeyCode.Alpha0:
  				selection = 9;
  				break;
  			}
  
  			if (selection >= 0) {
  				State.ActiveQuickslot = selection;
  				if (State.ActiveQuickslot >= Globals.MaxStacksPerContainer) {	//quickslots will always cap at MaxStacksPerContainer
  					State.ActiveQuickslot = 0;
  				} else if (State.ActiveQuickslot < 0) {
  					State.ActiveQuickslot = 0;
  				}
  				GUIInventoryInterface.Get.SetActiveQuickslots (State.ActiveQuickslot);
  			}
  			return true;
  		}
  
  		public bool SelectionNext (double timeStamp)
  		{
  			if (player.LockQuickslots)
  				return true;
  
  			if (GameManager.Is (FGameState.InGame)) {
  				State.ActiveQuickslot++;
  				if (State.ActiveQuickslot >= Globals.MaxStacksPerContainer) {	//quickslots will always cap at MaxStacksPerContainer
  					State.ActiveQuickslot = 0;
  				}
  				GUIInventoryInterface.Get.SetActiveQuickslots (State.ActiveQuickslot);
  			}
  			return true;
  		}
  
  		public bool SelectionPrev (double timeStamp)
  		{
  			if (player.LockQuickslots)
  				return true;
  
  			if (GameManager.Is (FGameState.InGame)) {
  				State.ActiveQuickslot--;
  				if (State.ActiveQuickslot < 0) {	//quickslots will always cap at MaxStacksPerContainer
  					State.ActiveQuickslot = Globals.MaxStacksPerContainer - 1;
  				}
  				GUIInventoryInterface.Get.SetActiveQuickslots (State.ActiveQuickslot);
  			}
  			return true;
  		}
  
  		public bool ToolSwap (double timeStamp)
  		{
  			if (player.LockQuickslots)
  				return true;
  
  			//swap the carry item with the active quickslot item
  			WIStackError error = WIStackError.None;
  			Stacks.Swap.Stacks (State.QuickslotsStack, State.QuickslotsStackCarry, ref error);
  			return true;
  		}
  
  		public void OnBankChange ()
  		{
  			Player.Get.AvatarActions.ReceiveAction (AvatarAction.ItemCurrencyExchange, WorldClock.AdjustedRealTime);
  		}
  
  		#endregion
  
  		#region adding items
  
  		//the main add item function
  		//this is where all other 'add' functions eventually filter down to
  		public bool AddItems (IWIBase item, ref WIStackError error)
  		{
  			if (item == null) {
  				error = WIStackError.InvalidOperation;
  				Debug.Log ("Item was null on add to inventory");
  				return false;
  			}
  
  			if (!mInitialized) {
  				mItemsToAddOnInitialization.Add (item);
  				Debug.Log ("Not initialized so not adding item " + item.DisplayName);
  				return true;
  			}
  
  			if (player.LockQuickslots) {
  				//we'll add this once our quickslots aren't locked any more
  				mItemsToAddOnQuickslotsUnlocked.SafeEnqueue (item);
  				Debug.Log ("Quickslots are locked so adding item to temporary queue " + item.DisplayName);
  				return true;
  			}
  
  			if (!item.Is <Stackable> ()) {
  				//can't add non-stackable items, dummy
  				Debug.Log ("Not stackable");
  				return false;
  			}
  
  			//-----SPECIAL CASES-----//
  			if (item.Is <Purse> ()) {
  				PurseState purseState = null;
  				if (item.IsWorldItem) {	
  					Purse purse = item.worlditem.Get <Purse> ();
  					purseState = purse.State;
  					//book avatars inform their owner that they've been picked up
  					//then they are discarded - they are never added to inventory
  					//item.worlditem.SetMode (WIMode.RemovedFromGame);
  				} else {
  					System.Object purseStateObject = null;
  					if (item.GetStateOf <Purse> (out purseStateObject)) {
  						//get state using generic method since it may be a stackitem
  						purseState = (PurseState)purseStateObject;
  					}
  				}
  				GUIManager.PostGainedItem (purseState);
  				//add the contents of our purse to the bank, then destroy the item
  				State.PlayerBank.Add (purseState.Bronze, WICurrencyType.A_Bronze);
  				State.PlayerBank.Add (purseState.Silver, WICurrencyType.B_Silver);
  				State.PlayerBank.Add (purseState.Gold, WICurrencyType.C_Gold);
  				State.PlayerBank.Add (purseState.Lumen, WICurrencyType.D_Luminite);
  				State.PlayerBank.Add (purseState.Warlock, WICurrencyType.E_Warlock);
  				item.RemoveFromGame ();
  				return true;
  			}
  
  			if (item.Is <Currency> ()) {
  				GUIManager.PostGainedItem (Mathf.Max (Mathf.FloorToInt (item.BaseCurrencyValue), 1), item.CurrencyType);
  				State.PlayerBank.Add (Mathf.Max (Mathf.FloorToInt (item.BaseCurrencyValue), 1), item.CurrencyType);
  				item.RemoveFromGame ();
  				return true;
  			}
  
  			if (item.Is <Key> ()) {
  				KeyState keyState = null;
  				if (item.IsWorldItem) {
  					Key key = item.worlditem.Get <Key> ();
  					keyState = key.State;
  				} else {
  					StackItem keyItem = item.GetStackItem (WIMode.Unloaded);
  					keyItem.GetStateData <KeyState> (out keyState);
  				}
  				if (State.PlayerKeyChain.AddKey (keyState)) {
  					GUIManager.PostSuccess ("Added key to log");
  				}
  				if (keyState.DisappearFromInventory) {
  					item.RemoveFromGame ();
  					return true;
  				}
  			}
  
  			if (item.Is <BookAvatar> ()) {
  				if (item.IsWorldItem) {	
  					BookAvatar avatar = item.worlditem.Get <BookAvatar> ();
  					Books.AquireBook (avatar.State.BookName);
  					//book avatars inform their owner that they've been picked up
  					//then they are discarded - they are never added to inventory
  					//item.worlditem.SetMode (WIMode.RemovedFromGame);
  				} else {
  					System.Object bookAvatarStateObject = null;
  					if (item.GetStateOf <BookAvatar> (out bookAvatarStateObject)) {
  						//get state using generic method since it may be a stackitem
  						BookAvatarState bookAvatarState = (BookAvatarState)bookAvatarStateObject;
  						Books.AquireBook (bookAvatarState.BookName);
  					} else {
  						Debug.Log ("Couldn't get state of book avatar");
  					}
  				}
  				//never put books in our inventory
  				item.RemoveFromGame ();
  				return true;
  			}
  
  			//-----GENERAL CASE-----//
  			mAddingItem = true;
  			bool addResult = false;
  
  			//this may have been set by CanItemFit
  			//or it may have been set the last time we added something
  			//try to use it again
  			if (FindMostRelevantStack (ref mLastRelevantStack, item, true, true, ref error)) {
  				addResult = Stacks.Push.Item (mLastRelevantStack, item, true, StackPushMode.Manual, ref error);
  				#if UNITY_EDITOR
  				if (!addResult) {
  					Debug.Log ("Found most relevant stack but couldn't push item");
  				}
  				#endif
  			}
  
  			if (!addResult) {
  				//whoops! drop it at our feed
  				GUIManager.PostInfo (item.DisplayName + " wouldn't fit.");
  				if (!item.Is <OwnedByPlayer> ()) {
  					item.Add ("OwnedByPlayer");
  				}
  				player.ItemPlacement.ItemDropAtFeet (item);
  				return true;
  			} else {
  				mRefreshCurrency = true;
  				if (item.IsWorldItem) {
  					item.worlditem.OnAddedToPlayerInventory.SafeInvoke ();
  					item.worlditem.SetMode (WIMode.Stacked);
  					LastAddedItems.Add (item);
  					LastAddedTime = WorldClock.AdjustedRealTime;
  					Player.Get.AvatarActions.ReceiveAction ((AvatarAction.ItemAddToInventory), WorldClock.AdjustedRealTime);
  				}
  				if (item.IsQuestItem) {
  					if (State.QuestItemsAcquired.SafeAdd (item.QuestName)) {
  						Player.Get.AvatarActions.ReceiveAction ((AvatarAction.ItemQuestItemAddToInventory), WorldClock.AdjustedRealTime);
  						QuestItemState questItemState = null;
  						if (item.IsWorldItem) {
  							QuestItem questItem = item.worlditem.Get <QuestItem> ();
  							questItemState = questItem.State;
  						} else {
  							StackItem questItem = item.GetStackItem (WIMode.Unloaded);
  							questItem.GetStateData <QuestItemState> (out questItemState);
  						}
  						GUIManager.PostGainedItem (questItemState);
  					}
  				}
  				Player.Get.AvatarActions.ReceiveAction ((AvatarAction.ItemAddToInventory), WorldClock.AdjustedRealTime);
  				GUIManager.PostInfo ("Added " + item.DisplayName + " to inventory.");
  			}
  			mAddingItem = false;
  
  			return addResult;
  		}
  		//this is where we find the best stack to put something when it's added to the inventory
  		public bool FindMostRelevantStack (ref WIStack mostRelevantStack, IWIBase item, bool enablerStacksOk, bool compatibleOK, ref WIStackError error)
  		{
  			if (WorldClock.RealTime > mTimeSinceLastRelevantStackSearch + mRelevantStackSearchInterval) {
  				#if UNITY_EDITOR
  				//Debug.Log ("Most relevant stack was out of date, clearing");
  				#endif
  				mostRelevantStack = null;
  			}
  			//first see if the stack we have will fit it
  			if (mostRelevantStack != null && mostRelevantStack.Mode == WIStackMode.Generic) {
  				if (mostRelevantStack.Group == WIGroups.Get.Player) {
  					if (!mostRelevantStack.IsFull && Stacks.Can.Stack (mostRelevantStack, item)) {
  						#if UNITY_EDITOR
  						//Debug.Log ("Most relevant was NOT out of date, returning relevant stack");
  						#endif
  						return true;
  					}
  				}
  			}
  
  			#if UNITY_EDITOR
  			//Debug.Log ("Most relevant stack was null, searching from scratch");
  			#endif
  
  			mTimeSinceLastRelevantStackSearch = WorldClock.RealTime;
  			mostRelevantStack = null;
  			bool checkedQuickslots = false;
  			bool foundFirstEmpty = false;
  			bool foundFirstCompatible = false;
  			WIStack firstEmpty = null;
  			WIStack firstCompatible = null;
  
  			if (item.IsStackContainer) {	
  				if (!QuickslotEnabler.HasEnablerTopItem) {	//if quickslots are empty
  					//always fill the quickslots stack first
  					//don't bother to check for stack size, it'll be NoLimit
  					mostRelevantStack = QuickslotEnabler.EnablerStack;
  					return true;
  				}
  
  				//we can use anything for the quickslot enabler
  				//but for other enablers, check this first
  				if (item.UseAsContainerInInventory || item.StackContainer.NumItems > 0) {
  					//if we've gotten this far then quickslots are full
  					//so check the remaining enablers to see if they need containers
  					for (int i = 0; i < InventoryEnablers.Count; i++) {
  						WIStackEnabler enabler = InventoryEnablers [i];
  						if (!enabler.HasEnablerTopItem) {//fill enabler stacks before adding items to existing containers
  							//don't bother to check for size, it'll be NoLimit
  							mostRelevantStack = enabler.EnablerStack;
  							return true;
  						}
  					}
  				}
  
  				if (QuickslotEnabler.IsEnabled
  				        && Stacks.Can.Fit (item.Size, QuickslotEnabler.EnablerContainer.Size)) {	//if quickslots have a stack and they're enabled
  					//and the item will fit in a container that size
  					//fill quickslots first
  					checkedQuickslots = true;
  					List <WIStack> quickslotStacks = QuickslotEnabler.EnablerStacks;
  					for (int i = 0; i < quickslotStacks.Count; i++) {
  						WIStack stack = quickslotStacks [i];
  						if (!foundFirstEmpty && stack.IsEmpty) {
  							foundFirstEmpty = true;
  							firstEmpty = stack;
  						}
  						if (!foundFirstCompatible && compatibleOK && !stack.IsFull && Stacks.Can.Stack (stack, item)) {
  							foundFirstCompatible = true;
  							firstCompatible = stack;
  						}
  						if (foundFirstCompatible && compatibleOK) {//that's all we need
  							break;
  						}
  					}
  				}
  			}
  
  			//if quickslots enabler is filled and
  			//our other enablers are filled, start looking for
  			//other compatible stacks
  			if (!checkedQuickslots && QuickslotEnabler.IsEnabled) {
  				List <WIStack> quickslotStacks = QuickslotEnabler.EnablerStacks;
  				for (int i = 0; i < quickslotStacks.Count; i++) {
  					WIStack stack = quickslotStacks [i];
  					if (!foundFirstEmpty && stack.IsEmpty) {
  						foundFirstEmpty = true;
  						firstEmpty = stack;
  					}
  					if (!foundFirstCompatible && compatibleOK && !stack.IsFull && Stacks.Can.Stack (stack, item)) {
  						foundFirstCompatible = true;
  						firstCompatible = stack;
  					}
  
  					if (foundFirstCompatible && compatibleOK) {//that's all we need
  						break;
  					}
  				}
  			}
  
  			if (!foundFirstCompatible || (!compatibleOK && !foundFirstEmpty)) {
  				//we've already searched in quickslots so now search in the rest
  				//next search in each of the other containers
  				foreach (WIStackEnabler enabler in InventoryEnablers) {	//don't bother to check the enabler stack we already did that
  					//just check the enabler's container stacks
  					if (enabler.IsEnabled) {
  						if (Stacks.Can.Fit (item.Size, enabler.EnablerContainer.Size)) {
  							foreach (WIStack stack in enabler.EnablerStacks) {
  								if (!foundFirstEmpty
  								            && stack.IsEmpty) {
  									foundFirstEmpty = true;
  									firstEmpty = stack;
  								}
  								if (!foundFirstCompatible && compatibleOK && !stack.IsFull && Stacks.Can.Stack (stack, item)) {
  									foundFirstCompatible = true;
  									firstCompatible = stack;
  								}
  
  								if (foundFirstCompatible && compatibleOK) {
  									//that's all we need
  									break;
  								}
  							}
  						}
  					}
  
  
gt: 					if (foundFirstCompatible && compatibleOK) {//that's all we need