using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Data.Common;
using Howest.SchemaDiscovery.Configuration;
using System.Configuration;

using Config = System.Configuration.Configuration;
using Howest.SchemaDiscovery.CommonHelpers;

namespace Howest.SchemaDiscovery
{
	public static class DbSchemaProviderFactory
	{
		static Dictionary<string, Type> _types;
		static Type _default;
		static object _lock = new object();

		static DbSchemaProviderFactory()
		{
			InitializeProviders();
		}

		static void InitializeProviders()
		{
			lock (_lock)
			{
				AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
				_types = new Dictionary<string, Type>();
				Config config = ConfigurationManager.OpenExeConfiguration(typeof(DbSchemaProviderFactory).Assembly.Location);
				try
				{
					SchemaDiscoverySectionGroup grp = SchemaDiscoverySectionGroup.GetSectionGroup(config);
					if (grp != null)
					{
						DbSchemaProvidersSection providerSection = grp.DbSchemaProviders;
						_default = null;

						foreach (DbSchemaProviderElement prov in providerSection.DbSchemaProviders)
						{
							try
							{
								Type dbSchemaProviderType = ReflectionHelper.LoadType(prov.Type);
								_types.Add(prov.Name, dbSchemaProviderType);
								if (prov.IsDefault && _default == null)
									_default = dbSchemaProviderType;
							}
							catch (Exception ex)
							{
								System.Diagnostics.Debug.WriteLine("Message: " + ex.Message);
								System.Diagnostics.Debug.WriteLine("StackTrace: " + ex.StackTrace);
							}
						}
					}

				}
				catch (Exception)
				{
				}
			}
		}

		public static DbSchemaProvider CreateProvider(string providerName)
		{
			return CreateProvider(providerName, true);
		}

		public static DbSchemaProvider CreateProvider(string providerName, bool useDefault)
		{
			//Assembly asm = Assembly.LoadFile(Environment.CurrentDirectory + "\\Howest.SchemaDiscovery.SqlServer.dll");
			//return (DbSchemaProvider)asm.CreateInstance("Howest.SchemaDiscovery.SqlServer.SqlServerSchemaProvider");

			if (string.IsNullOrEmpty(providerName))
				throw new ArgumentException("String argument cannot by null or empty", "providerName");

			Type type = null;
			lock (_lock)
			{
				type = _types[providerName];


				if (useDefault)
				{
					type = _default;
				}
			}

			if (type == null)
				throw new ArgumentException("The provider is not available in the list", "providerName");

			return (DbSchemaProvider)Activator.CreateInstance(type);
		}

		static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			AppDomain.CurrentDomain.AssemblyResolve -= new ResolveEventHandler(CurrentDomain_AssemblyResolve);
			Assembly asm = null;
			try
			{
				 asm = Assembly.Load(args.Name);
			}
			finally
			{
				AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
			}
			return asm;
		}
	}
}
