context: //#define DEBUG_SKILLS
  using UnityEngine;
  using System.Collections;
  using System.Collections.Generic;
  using Frontiers.World.Gameplay;
  using Frontiers.World;
  using System;
  
  namespace Frontiers
  {
  	public class Skills : Manager
  	{
  		//the skills manager makes it easier to look up skills by name etc.
  		//it also does the work of associating worlditems with skills
  		//and provides some convenience functions like LearnSkill
  		public static Skills Get;
  		public List <Skill> SkillList = new List <Skill> ();
  		public List <Skill> SkillsInUse = new List <Skill> ();
  		public List <SkillStartupSetting> DefaultSkillStartupSettings = new List<SkillStartupSetting> ();
  		public List <CredentialLevel> CredentialLevels = new List <CredentialLevel> ();
  		public static Skill MostRecentlyLearnedSkill;
  		public GameObject EffectSpherePrefab;
  		public bool DebugSkills = true;
  
  		public int Credentials (string flagSet)
  		{
  			int credentials = 0;
  			Dictionary <int,int> lookup = new Dictionary <int, int> ();
  			if (mCredentialLevelsLookup.TryGetValue (flagSet, out lookup)) {
  				int experience = Profile.Get.CurrentGame.Character.Exp.ExpByFlagset (flagSet);
  				int greatestExperience = 0;
  				foreach (KeyValuePair <int,int> credExpPair in lookup) {
  					if (experience >= credExpPair.Value && credExpPair.Value > greatestExperience) {
  						credentials = credExpPair.Key;
  						greatestExperience = credExpPair.Value;
  					}
  				}
  			}
  			return credentials;
  		}
  
  		public bool HasCredentials (int credentials, string flagSet)
  		{
  			int experience = Profile.Get.CurrentGame.Character.Exp.ExpByFlagset (flagSet);
  			int requiredExperience = Int32.MaxValue;
  			Dictionary <int,int> lookup = null;
  			if (mCredentialLevelsLookup.TryGetValue (flagSet, out lookup)) {
  				lookup.TryGetValue (credentials, out requiredExperience);
  			}
  			return experience >= requiredExperience;
  		}
  
  		public float NormalizedExpToNextCredentials (string flagSet)
  		{
  			float exp = 0f;
  			if (!mNormalizedExpToNextCredentials.TryGetValue (flagSet, out exp)) {
  				exp = 1f;
  			}
  			return exp;
  		}
  
  		public bool HasMasteredSkill (string skillName)
  		{
  			Skill learnedSkill = null;
  			if (SkillByName (skillName, out learnedSkill)) {
  				return learnedSkill.HasBeenMastered;
  			}
  			return false;
  		}
  
  		public bool HasLearnedSkill (string skillName, out Skill learnedSkill)
  		{
  			//TEMP
  			learnedSkill = null;
  			if (SkillByName (skillName, out learnedSkill)) {
  				SkillKnowledgeState state = learnedSkill.KnowledgeState;
  				return (state == SkillKnowledgeState.Enabled || state == SkillKnowledgeState.Learned) || GameManager.Get.EnableAllSkills;
  			}
  			return false | GameManager.Get.EnableAllSkills;
  		}
  
  		public bool HasLearnedSkill (string skillName, out float skillUsageLevel)
  		{
  			//TEMP
  			skillUsageLevel = 0f;
  			Skill learnedSkill = null;
  			if (SkillByName (skillName, out learnedSkill)) {
  				SkillKnowledgeState state = learnedSkill.KnowledgeState;
  				skillUsageLevel = learnedSkill.State.NormalizedUsageLevel;
  				return (state == SkillKnowledgeState.Enabled || state == SkillKnowledgeState.Learned) || GameManager.Get.EnableAllSkills;
  			}
  			return false | GameManager.Get.EnableAllSkills;
  		}
  
  		public bool HasLearnedSkill (string skillName)
  		{
  			//TEMP
  			Skill learnedSkill = null;
  			if (SkillByName (skillName, out learnedSkill)) {
  				SkillKnowledgeState state = learnedSkill.KnowledgeState;
  				return (state == SkillKnowledgeState.Enabled || state == SkillKnowledgeState.Learned) || GameManager.Get.EnableAllSkills;
  			}
  			return false | GameManager.Get.EnableAllSkills;
  		}
  
  		public override void WakeUp ()
  		{
  			base.WakeUp ();
  
  			Get = this;
  		}
  
  		public override void OnModsLoadFinish ()
  		{
  			LoadSkills ();
  			RefreshSkills ();
  			mModsLoaded = true;
  		}
  
  		public override void OnGameUnload ()
  		{
  			for (int i = 0; i < SkillList.Count; i++) {
  				GameObject.Destroy (SkillList [i].gameObject);
  			}
  			SkillList.Clear ();
  			SkillsInUse.Clear ();
  			mSkillsLookup.Clear ();
  			mSkillsLookupByWIScript.Clear ();
  			mSkillsLookupByWorldItem.Clear ();
  		}
  
  		public override void OnGameSave ()
  		{
  			for (int i = 0; i < SkillList.Count; i++) {
  				SkillList [i].Save ();
  			}
  			mGameSaved = true;
  		}
  
  		public override void OnGameStartFirstTime ()
  		{
  			for (int j = 0; j < SkillList.Count; j++) {
  				Skill skill = SkillList [j];
  				//see if we have a startup setting
  				for (int i = 0; i < DefaultSkillStartupSettings.Count; i++) {
  					SkillStartupSetting ss = DefaultSkillStartupSettings [i];
  					if (DefaultSkillStartupSettings [i].SkillName == skill.name) {
  						if (ss.Mastered) {
  							skill.HasBeenMastered = true;
  						} else {
  							skill.State.KnowledgeState = ss.KnowledgeState;
  						}
  						break;
  					}
  				}
  			}
  		}
  
  		public override void OnGameStart ()
  		{
  			Player.Get.AvatarActions.Subscribe (AvatarAction.SkillExperienceGain, new ActionListener (SkillExperienceGain));
  			StartCoroutine (UpdateSkillsInUse ());
  		}
  
  		public RemoveItemSkill RemoveItemSkillFromName (string skillName)
  		{
  			return null;
  		}
  
  		public bool SkillExperienceGain (double timeStamp)
  		{
  			if (!mCheckingCredentials) {
  				StartCoroutine (CheckCredentials ());
  			}
  			return true;
  		}
  
  		public List <Skill> SkillsAssociatedWith (WorldItem targetObject)
  		{
  			HashSet <Skill> skills = new HashSet <Skill> ();
  			Skill examineSkill = null;
  			Skill reverseEngineerSkill = null;
  			if (mSkillsLookup.TryGetValue ("Examine", out examineSkill)) {
  				skills.Add (examineSkill);
  			}
  			if (mSkillsLookup.TryGetValue ("ReverseEngineer", out reverseEngineerSkill)) {
  				skills.Add (reverseEngineerSkill);
  			}
  			
  			List <Skill> associatedNameSkills;
  			if (mSkillsLookupByWorldItem.TryGetValue (targetObject.StackName, out associatedNameSkills)) {
  				var enumerator = associatedNameSkills.GetEnumerator ();
  				while (enumerator.MoveNext ()) {
  					skills.Add (enumerator.Current);
  				}
  			}
  			WorldItem worlditem = targetObject.GetComponent <WorldItem> ();
  			if (worlditem != null) {
  				#if DEBUG_SKILLS
  				Debug.Log ("Skills associated with " + targetObject.name);
  				#endif
  				var enumerator = worlditem.ScriptNames.GetEnumerator ();
  				while (enumerator.MoveNext ()) {
  					List <Skill> associatedScriptSkills = null;
  					#if DEBUG_SKILLS
  					Debug.Log (" - Checking " + enumerator.Current);
  					#endif
  					if (mSkillsLookupByWIScript.TryGetValue (enumerator.Current, out associatedScriptSkills)) {
  						var associatedEnumerator = associatedScriptSkills.GetEnumerator ();
  						while (associatedEnumerator.MoveNext ()) {
  							#if DEBUG_SKILLS
  							Debug.Log (" - Adding " + associatedEnumerator.Current.name);
  							#endif
  							skills.Add (associatedEnumerator.Current);
  						}
  					}
  				}
  			}
  
  			List <Skill> finalSkillList = new List<Skill> (skills);
  			finalSkillList.Sort ();
  			return finalSkillList;
  		}
  
  		public List <Skill> SkillsByGroup (string skillGroup)
  		{
  			List <Skill> skills = new List<Skill> ();
  			for (int i = 0; i < SkillList.Count; i++) {
  				Skill skill = SkillList [i];
  				if (skill.Info.SkillGroup == skillGroup && skill.HasBeenDiscovered) {
  					skills.Add (skill);
  				}
  			}
  			return skills;
  		}
  
  		public string SkillDisplayName (string skillName)
  		{
  			Skill skill = null;
  			if (mSkillsLookup.TryGetValue (skillName, out skill)) {
  				return skill.DisplayName;
  			}
  			return string.Empty;
  		}
  
  		public List <Skill> SkillsByName (IEnumerable <string> names)
  		{
  			List <Skill> skills = new List <Skill> ();
  			foreach (string skillName in names) {
  				Skill skillByName = null;
  				if (mSkillsLookup.TryGetValue (skillName, out skillByName)) {
  					skills.Add (skillByName);
  				}
  			}
  			return skills;
  		}
  
  		public List <T> SkillsByType <T> () where T : Skill
  		{
  			List <T> skillsByType = new List <T> ();
  			foreach (Skill skill in SkillList) {
  				T skillAsType = skill as T;
  				if (skillAsType != null) {
  					skillsByType.Add (skillAsType);
  				}
  			}
  			return skillsByType;
  		}
  
  		public int SkillLevelByName (string skillName)
  		{
  			Skill skill = null;
  			if (mSkillsLookup.TryGetValue (skillName, out skill)) {
  				return skill.Info.SkillLevel;
  			}
  			return 0;
  		}
  
  		public static void OnSkillMastered ()
  		{		//here's where we see if it's been learned
  			for (int i = 0; i < Get.SkillList.Count; i++) {
  				Get.SkillList [i].Refresh ();
  			}
  			//here's where we see if it's been replaced
  			for (int i = 0; i < Get.SkillList.Count; i++) {
  				Get.SkillList [i].RefreshPrerequisites ();
  			}
  		}
  
  		public void MasterSkill (string skillName)
  		{
  			Skill skillToMaster = null;
  			if (Get.mSkillsLookup.TryGetValue (skillName, out skillToMaster)) {
  				skillToMaster.MasterSkill ();
  			}
  		}
  
  		public static void MarkSkill (string skillName)
  		{
  			Skill skillToLearn = null;
  			if (Get.mSkillsLookup.TryGetValue (skillName, out skillToLearn)) {
  				skillToLearn.State.GetPlayerAttention = true;
  			}
  		}
  
  		public static void LearnSkill (string skillName)
  		{
  			Skill skillToLearn = null;
  			if (Get.mSkillsLookup.TryGetValue (skillName, out skillToLearn)) {
  				skillToLearn.LearnSkill ();
  			}
  		}
  
  		public static void RevealSkill (string skillName)
  		{
  			Skill skillToLearn = null;
  			if (Get.mSkillsLookup.TryGetValue (skillName, out skillToLearn)) {
  				skillToLearn.DiscoverSkill ();
  			}
  		}
  
  		public bool SkillByName (string skillName, out Skill skill)
  		{
  			return mSkillsLookup.TryGetValue (skillName, out skill);
  		}
  
  		protected void RefreshSkills ()
  		{
  			for (int i = 0; i < SkillList.Count; i++) {
  				Skill newSkill = SkillList [i];
  				newSkill.Initialize ();
  
  				#if DEBUG_SKILLS
  				Debug.Log ("Refreshing skill " + newSkill.name);
  				#endif
  
  				mSkillsLookup.Add (newSkill.name, newSkill);
  
  				List <string> associatedWorldItems = new List <string> ();
  				List <string> associatedWIScripts = new List <string> ();
  				associatedWorldItems.AddRange (newSkill.Requirements.RequiredEquippedWorldItems);
  				associatedWorldItems.AddRange (newSkill.Requirements.RequiredWorldItemNames);
  				associatedWorldItems.Add (newSkill.Requirements.RequiredPlayerFocusItemName);
  
  				associatedWIScripts.AddRange (newSkill.Usage.TargetWIScriptNames);
  				associatedWIScripts.AddRange (newSkill.Requirements.RequiredWIScriptNames);
  				associatedWIScripts.AddRange (newSkill.Requirements.RequiredEquippedWIScriptNames);
  				associatedWIScripts.AddRange (newSkill.Requirements.RequiredPlayerFocusWIScriptNames);
  
  				if (newSkill.RequiresPlayerFocusItem) {
  					associatedWorldItems.Add (newSkill.Requirements.RequiredPlayerFocusItemName);
  				}
  
  				var associatedWorldItemNameEnum = associatedWorldItems.GetEnumerator ();
  				while (associatedWorldItemNameEnum.MoveNext( )) {
  					//using an enumerator so we can modify string
  					string associatedWorldItemName = associatedWorldItemNameEnum.Current;
  
gt: 					if (!string.IsNullOrEmpty (associatedWorldItemName)) {