using System;
using System.Collections;
using System.Collections.Specialized;
using System.IO;
using System.Reflection;
using Medivators.Common.Enums;

namespace Medivators.Common
{
	public class TextSettings : IDisposable
	{
		#region declarations

		private static Hashtable _app		= null;
		private static Hashtable _user		= null;
		private static Hashtable _default	= null;

		private string AppSettingPath		= string.Empty;
		private string DefaultSettingPath	= string.Empty;
		private string UserSettingPath		= string.Empty;

		private static bool _init = false;

		#endregion

		#region singleton construct/instance/dispose

		private static TextSettings _instance = null;

		private TextSettings()
		{
			_app = new Hashtable();
			_user = new Hashtable();
			_default = new Hashtable();
		}

		public static TextSettings GetInstance()
		{
			if ( _instance == null )
				_instance = new TextSettings();
			return _instance;
		}

		public void Dispose()
		{
			Save();
			_app.Clear();
			_user.Clear();
			_default.Clear();
		}

		#endregion

		#region file IO (save/load)

		public void Save()
		{
			TextSettingsFile file = null;

			if ( _app != null )
				if ( _app.Count > 0 )
				{
					file = new TextSettingsFile (AppSettingPath);
					file.Save(_app);
				}
			if ( _default != null )
				if ( _default.Count > 0 )
				{
					file = new TextSettingsFile (DefaultSettingPath);
					file.Save(_default);
				}
			if ( _user != null )
				if ( _user.Count > 0 )
				{
					// insure the users local app data folder exists
					if ( ! Directory.Exists(Path.GetDirectoryName(UserSettingPath)))
						Directory.CreateDirectory(Path.GetDirectoryName(UserSettingPath));

					file = new TextSettingsFile (UserSettingPath);
					file.Save(_user);
				}
		}

		public void Load(string SettingsFileFolder,
						 string SettingsFileName)
		{
			if (!_init)
			{
				AppSettingPath = Utilities.PathSlash(SettingsFileFolder) +
								 SettingsFileName +
								 Constants.TextSettingsExtension;
				DefaultSettingPath = Utilities.PathSlash(SettingsFileFolder) +
								 SettingsFileName +
								 ".default" +
								 Constants.TextSettingsExtension;
				UserSettingPath = Utilities.PathSlash(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData)) +
								  Utilities.PathSlash(SettingsFileName) + 
								 SettingsFileName +
								 Constants.TextSettingsExtension;
				LoadHashtables();
			}
		}

		public void Load()		
		{
			// make sure we only do this once
			if ( ! _init )
			{
				// establish file paths
				string appPath = Assembly.GetEntryAssembly().GetName().CodeBase.Remove(0,8); 
				string appName = Assembly.GetEntryAssembly().GetName().Name;
				appPath = appPath.Replace("/", "\\");
				appPath = Utilities.PathSlash(Path.GetDirectoryName(appPath));
			
				AppSettingPath = appPath + appName + Constants.TextSettingsExtension;
				DefaultSettingPath = appPath + appName + ".default" + Constants.TextSettingsExtension;

				UserSettingPath = Utilities.PathSlash(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData)) +
					Utilities.PathSlash(appName) + 
					appName + Constants.TextSettingsExtension;

				LoadHashtables();
			}
		}

		private void LoadHashtables()
		{
			if (! _init)
			{
				TextSettingsFile file = null;

				file = new TextSettingsFile(AppSettingPath);
				_app = file.Load();
				file = new TextSettingsFile(UserSettingPath);
				_user = file.Load();
				file = new TextSettingsFile(DefaultSettingPath);
				_default = file.Load();
				_init = true;
			}
		}

#endregion

		#region indexers

		public string this[SettingTypes SettingType, string Section, string Name]
		{
			get{ return GetSettingValue(SettingType, Section, Name); }
			set{ SetSettingValue(SettingType, Section, Name, value); }
		}
		public string this[SettingTypes SettingType, string Name]
		{
			get{ return GetSettingValue(SettingType, Constants.DefaultSectionName, Name); }
			set{ SetSettingValue(SettingType, Constants.DefaultSectionName, Name, value); }
		}

		#endregion
	
		#region public methods
		
		#region *	getting setting collections

		public StringCollection GetSectionNames (SettingTypes SettingType)
		{
			Hashtable source = null;
			StringCollection rtn = new StringCollection();

			if ( SettingType == SettingTypes.Application )
				source = _app;
			else
				source = _user;

			foreach (TextSetting ts in source.Values)
			{
				if ( ! rtn.Contains(ts.Section) )
					rtn.Add(ts.Section);
			}

			//	now add any default sections of the appropriate type
			//	(although it seems unlikely that there would be any)

			foreach (TextSetting ts in _default.Values)
			{
				if ( ts.SettingType == SettingType )
					if ( ! rtn.Contains(ts.Section) )
						rtn.Add(ts.Section);
			}
			return rtn;
		}
		public NameValueCollection GetSettings (SettingTypes SettingType, string Section) 
		{
			Hashtable source = null;
			NameValueCollection rtn = new NameValueCollection();

			if ( SettingType == SettingTypes.Application )
				source = _app;
			else
				source = _user;

			foreach (TextSetting ts in source.Values)
			{
				if ( ts.Section.Equals(Section) )
					rtn.Add(ts.Name, ts.Value);
			}

			//	now add any default values from the appropriate type
			//	of defaults - if any 
			foreach (TextSetting ts in _default.Values)
				if ( ts.SettingType == SettingType )
					if ( ts.Section.Equals(Section) )
					{
						//	don't add a default value if there is already
						//	an actual value in the return 
						bool found = false;
						for ( int idx = 0; idx < rtn.Count; idx++ )
						{
							if ( ts.Name.Equals(rtn.Keys[idx]) )
							{
								found = true;
								break;
							}
						}
						if ( ! found )
							rtn.Add(ts.Name, ts.Value);
					}
			return rtn;
		}

		#endregion

		#region *	removing settings
		
		public void Remove (SettingTypes SettingType, string Section, string Name)
		{
			TextSetting ts = new TextSetting(SettingType, Section, Name, string.Empty);
			if ( SettingType == SettingTypes.Application )
				_app.Remove(ts.Key);
			else
				_user.Remove(ts.Key);
		}
		public void Remove (SettingTypes SettingType, string Name)
		{
			Remove (SettingType, Constants.DefaultSectionName, Name);
		}


		#endregion

		#region *	managing default values

		public void AddDefaultValue (SettingTypes SettingType, string Section, string Name, string DefaultValue )
		{
			//	first add to the defaults.
			TextSetting ts = new TextSetting(SettingType, Section, Name, DefaultValue);
			_default[ts.Key] = ts;
		}
		public void RemoveDefaultValue (SettingTypes SettingType, string Section, string Name)
		{
			TextSetting ts = new TextSetting(SettingType, Section, Name, string.Empty);
			_default.Remove(ts.Key);
		}		
		public StringCollection GetDefaultValueSectionNames (SettingTypes SettingType)
		{
			StringCollection rtn = new StringCollection();
			foreach (TextSetting ts in _default.Values)
			{
				if ( ts.SettingType == SettingType )
					if ( ! rtn.Contains(ts.Section) )
						rtn.Add(ts.Section);
			}
			return rtn;
		}
		public NameValueCollection GetDefaultValues (SettingTypes SettingType, string Section) 
		{
			NameValueCollection rtn = new NameValueCollection();

			foreach (TextSetting ts in _default.Values)
			{
				if ( ts.Section.Equals(Section) )
					rtn.Add(ts.Name, ts.Value);
			}
			return rtn;
		}
		
		#endregion 

		#endregion

		#region private helpers

		private string GetSettingValue ( SettingTypes Type, string Section, string Name )
		{
			if (_init)
			{
				Hashtable source = null;
				string key = Type + Constants.KeyDelimiter + Section + Constants.KeyDelimiter + Name;

				if (Type == SettingTypes.Application)
					source = _app;
				else
					source = _user;

				if (source.ContainsKey(key))
					return ((TextSetting)source[key]).Value;
				else if (_default.ContainsKey(key))
					return ((TextSetting)_default[key]).Value;
				else
					return string.Empty;
			}
			else
				return string.Empty;
		}
		private static void SetSettingValue (SettingTypes Type, string Section, string Name, string Value )
		{
			if (_init)
			{
				TextSetting ts = new TextSetting(Type, Section, Name, Value);

				if (Type == SettingTypes.Application)
					_app[ts.Key] = ts;
				else
					_user[ts.Key] = ts;
			}
		}

		#endregion
	}
}

