using System;
using System.IO;
using System.Linq;
using System.Reflection;
using BeWo.Data;
using BS.Shared.Core;

namespace BeWo.Service.Plugins
{
	public class PluginLoader
	{
		public static String Tenant
		{
			get
			{
#if DEBUG
				var t = "demo";
				//t = "1"; // Lebenshilfe Würzburg
				//t = "1234567890"; // Präsentationsdatenbank
				//t = "5687373602"; // LH Duisburg
				//t = "5620636022"; // GPZ Biberach
				//t = "8562233401"; // Sozialwirkstatt Schmitz
				//t = "1076891970"; // Assistenza
				//t = "0216265667"; // LH Hannover
				//t = "1774789565"; // LH Essen 
				//t = "9342168675"; // ABC Betreuungen
				//t = "1193188501"; // Aids Hilfe Dortmund
				//t = "7860351957"; // SKF Alsdorf
				//t = "3311520228"; // Die Düne
				//t = "1352143437"; // Sewo
				//t = "7107514623"; // BeWo Neuss
				//t = "9098141768"; // Fib e.V. Marburg
				//t = "1505148718"; // VSD Hamm
				//t = "5926081834"; // Spektrum
				//t = "1378137009"; // BeWo Direkt
				//t = "3010479871"; // Aachener Verein
				//t = "3849764093"; // Club 74
				//t = "7375324044"; // Diakonie KKKleve
				//t = "5805202339"; // Wegweiser Betreuungsdienst
				//t = "2301474784"; // Hauskrankenpflege Leiendecker
				//t = "8243565510"; // Der Karren
				//t = "2499262621"; // HPH Bersenbrück
				//t = "4950382346"; // Holsinger
				//t = "5973016645"; // Verein Lebensgestaltung Hanau
				//t = "7375324044"; // Diakonie KK Kleve
				//t = "1441747891"; // BeWo Mobil Köln
				//t = "5120047701"; // Trialog
				//t = "3629696651"; // Soziale Dienste Niederrhein
				//t = "2918696314"; // Caritas Frankfurt 2
				//t = "6923790936"; // Integra e.V.
				//t = "2392153512"; // Christopherus Haus
				//t = "2918696314"; // Caritas Frankfurt 2
				//t = "9495336024"; // VKMAachen app1
				//t = "5237724939"; // Indro ABW
				//t = "7635986435"; // Köln Ring
				//t = "4074176860"; // Soziale Dienstleistung Gessner
				//t = "2542550178"; // LWVEingliederungshilfe
				//t = "3963982016"; // Convoi
				//t = "1600408120"; // BeWo Amrath
				//t = "3886054624"; // Brücke ABW
				//t = "2028095630"; // Integra Heinsberg
				//t = "5351926758"; // Viva a Vida
				//t = "2215396183"; // Diakonie Remscheid Lennep
				//t = "5157599087"; // SHG Schwerte
				//t = "4526293996"; // Fortis
				//t = "3647969417"; // Caritas Bottrop
				//t = "3963982016"; // Convoi
				//t = "3057313346"; // SBB Mainz
				//t = "6246287823"; // BeWo Alsdorf
				//t = "1420341656"; // Vibb Essen
				//t = "4941141927"; // Signcom
				//t = "8897605322"; // SPZ Ratingen
				//t = "6483870127"; // Wigonetz
				//t = "9482484652"; // Blömeling und Teckhaus
				//t = "8001550599"; // Biallas BeWo
				//t = "7282396774"; // Caritas Unna
				//t = "6884855402"; // IBP
				//t = "4867997795"; // ADiK Kleve
				//t = "3184859776"; // Sergej Becker
				//t = "7752610643"; // BWK Gbr
				//t = "3785623125"; // Betreuwo
				//t = "7130228334"; // LH Borken
				//t = "4209820830"; // VKM Hamm
				//t = "5700328131"; // Betreutes Wohnen St. Ludgerus Essen-Werden
				//t = "1907984777"; // Soziale Dienste Katrin Schmidt
				//t = "9033246467"; // SKM  Menden
				//t = "9290510010"; // BeWo Schilling
				//t = "5251218094"; // KOMO e.V.
				//t = "3529871747"; // Vivat gemeinnützige GmbH
				//t = "8561513464"; // Caritasverband Wuppertal/Solingen
				//t = "2727001973"; // SD Julia Schönberg
				//t = "5653806613"; // Feid und Kollegen
				//t = "3830114427"; // FiZ Familie im Zentrum Hof
				//t = "7138297573"; // Tagwerk betreutes wohnen
				//t = "1008896531"; // BeWo Auxilio
				//t = "9383760246"; // Die Kette
				//t = "5915565037"; // LH Remscheid
				//t = "3350425974"; // BeWo Rückenwind
				//t = "9447917179"; // LH Rodenkirchen
				//t = "4690407894"; // Bleib im Leben
				//t = "2576513996"; // TRIAS
				//t = "2509786400"; // LH Stade
                //t = "8677523325"; // BeWo Richartz
				//t = "1765854593"; // Mein Betreutes Wohnen
				//t = "6802909544"; // Lebenshilfe Coburg
				//t = "9417634361"; // Synprax
				//t = "5761861730"; // Lebenshilfe Warendorf
				//t = "6712648331"; // BeWo Färber
				//t = "4982295287"; // ASB Hamm
				//t = "3890031575"; // Die Wohnhelfer Kuhrau
				//t = "3536719736"; // BeWo Stefanie Schäfer (BeWoKerpen)
				//t = "7739670213"; // SPZ Leverkusen
				//t = "3341456098"; // BeWo Schillinger
				//t = "4271389563"; // Komm Mit
			    //t = "5430005891"; // Marienhospital Eickel
			    //t = "3265049248"; // Gerdas Pflegedienst
			    //t = "1549622397"; // Kontakt und Krisenhilfe
			    //t = "4782194565"; // Skm Rheydt
			    //t = "7535795843"; // Sozialwerk Dürener Christen
			    t = "6388340414"; // Weitblick
                return t;
#else
				if (MultitenancyOperationContextExt.Current != null)
					return MultitenancyOperationContextExt.Current.Tenant;

				return SessionFacade.Tenant;
#endif
			}
		}

		private static String CustomerPluginPath()
		{
#if DEBUG
			return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"bin\" + Tenant + "_reports.dll");
#else
			return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Customer\" + Tenant + "_reports.dll");
#endif
		}


		public static T FindClass<T>() where T : new()
		{
			
			var t = FindClass<T>(null, null);
			if (t == null)
			{
				t = new T();
			}
			return t;
		}

		public static T FindClass<T>(string specificId)
		{
			return FindClass<T>(specificId, null);
		}

		public static T FindClass<T>(string specificId, string typename)
		{
			Type[] lAllTypes = null;

			if (Tenant != null)
			{
				if (File.Exists(CustomerPluginPath()))
					lAllTypes = Assembly.LoadFrom(CustomerPluginPath()).GetTypes();
			}

			T result = default(T);
			if (lAllTypes != null)
				result = FindClass<T>(lAllTypes, specificId, typename);
			
			return result;
		}

		public static T FindClass<T>(Type[] lAllTypes, string specificId, string typename)
		{
			T result = default(T);

			if (!string.IsNullOrEmpty(specificId) && !string.IsNullOrEmpty(typename))
			{
				var cbSpecific = lAllTypes
					.Where(i => typeof(T).IsAssignableFrom(i))
					.FirstOrDefault(t => t.GetCustomAttributes(typeof(IDSpecificClassAttribute), true)
											 .ToList()
											 .Exists(i =>
											 {
												 var attr = (IDSpecificClassAttribute)i;
												 if (attr.Identifiers != null)
													 return attr.Identifiers.Contains(specificId);
												 if (!String.IsNullOrEmpty(attr.Identifier))
													 return attr.Identifier.Equals(specificId);
												 return false;

											 }
											 ) && t.FullName == typename);
				if (cbSpecific != null)
					result = (T)Activator.CreateInstance(cbSpecific);
			}

			if (!string.IsNullOrEmpty(typename))
			{
				var cbSpecific = lAllTypes.FirstOrDefault(t => t.FullName == typename);
				if (cbSpecific != null)
					result = (T)Activator.CreateInstance(cbSpecific);
			}

			if (!string.IsNullOrEmpty(specificId))
			{
				var cbSpecific = lAllTypes
					.Where(i => typeof(T).IsAssignableFrom(i))
					.FirstOrDefault(t => t.GetCustomAttributes(typeof(IDSpecificClassAttribute), true)
											 .ToList()
											 .Exists(i =>
											 {
												 var attr = (IDSpecificClassAttribute)i;
												 if (attr.Identifiers != null)
													 return attr.Identifiers.Contains(specificId);
												 if (!String.IsNullOrEmpty(attr.Identifier))
													 return attr.Identifier.Equals(specificId);
												 return false;

											 }
											 ));
				if (cbSpecific != null)
					result = (T)Activator.CreateInstance(cbSpecific);

				if (result == null)
				{
					foreach (var iType in lAllTypes)
						if (typeof(T).IsAssignableFrom(iType))
							if (iType.Name == specificId)
								result = (T)Activator.CreateInstance(iType);
				}
			}

			

			if (result == null)
			{
				var list = lAllTypes.Where(t => typeof(T).IsAssignableFrom(t)).ToList();

				if (list.Count == 1)
					result = (T)Activator.CreateInstance(list[0]);
				else if (list.Count > 1)
				{
					foreach (var type in list)
					{
						var attrs = type.GetCustomAttributes(typeof(IDSpecificClassAttribute), true);
						if (attrs.Length == 0)
							return (T)Activator.CreateInstance(type);
					}

					result = (T)Activator.CreateInstance(list[0]);
				}

			}

			return result;
		}
	}
}

