#region Copyright and GPL
/*************************************************************************
 * dataMagus - The open source database learning software
 * Copyright (C) 2007 by all authors
 * Authors: Monika Schwitter (monsy@gmx.ch)
 *          Jürg Zgraggen (j.zgraggen@ejaz.net)
 *          HSLU (Hochschule Luzern - Technik+Architektur)
 * 
 *     This program is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     This program is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU General Public License for more details.
 * 
 *     You should have received a copy of the GNU General Public License
 *     along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *************************************************************************/
#endregion
#region Using
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Reflection;
using System.Diagnostics;
using dataMagus.Common;
#endregion

namespace dataMagus.Common
{
	/// <summary>
	/// Generic class for creating instances of a specified type
	/// </summary>
    internal class InterfaceLoadManager<T>
    {
        #region Members
		/// <summary>
		/// Holds a list of all instances loaded by an interface type.
		/// </summary>
		/// <returns>Enumerator to parse.</returns>
        private List<T> _loadedInterfaces = new List<T>();
        #endregion

        #region Constructors / Destructors
        /// <summary>
        /// Default constructor.
        /// </summary>
        public InterfaceLoadManager()
        {
        }
        #endregion

        #region Properties
		/// <summary>
		/// Holds a list of all instances loaded by an interface type.
		/// </summary>
		/// <returns>Enumerator to parse.</returns>
		public List<T> LoadedInterfaces
		{
			get { return this._loadedInterfaces; }
		}
        #endregion

        #region Methodes
        /// <summary>
        /// Creates instances of all found interface types T on a specified path with a specified
        /// search pattern.
        /// </summary>
        /// <remarks>Only types containing a default constructor will be loaded.</remarks>
        /// <param name="path">Path to search in.</param>
        /// <param name="searchPattern">Pattern to search with.</param>
        /// <param name="skipLoaded">Indicates if already loaded types should be skipped.</param>
        /// <returns>List of loaded interfaces.</returns>
        public List<T> LoadInterfaces(string path, string searchPattern, bool skipLoaded)
        {
        	return this.LoadInterfaces(path, searchPattern, Type.EmptyTypes, new object[0], true);
        }
        
        /// <summary>
        /// Creates instances of all found interface types T on a specified path with a specified
        /// search pattern.
        /// </summary>
        /// <param name="path">Path to search in.</param>
        /// <param name="searchPattern">Pattern to search with.</param>
        /// <param name="constructorTypes">Constructor types to be found.</param>
        /// <param name="constructurObjects">Object types to feed the constructor.</param>
        /// <param name="skipLoaded">Indicates if already loaded types should be skipped.</param>
        /// <returns>List of loaded interfaces.</returns>
        public List<T> LoadInterfaces(string path, string searchPattern, 
        	Type[] constructorTypes, object[] constructurObjects, bool skipLoaded)
		{
        	// load all assemblies implementing the T interface
        	List<T> loadedItems = new List<T>();
        	string[] assemblyFiles = Directory.GetFiles(path, searchPattern);
        	foreach (string file in assemblyFiles)
        	{
        		Assembly assembly = Assembly.LoadFile(file);
        		foreach (Type type in assembly.GetTypes())
        		{
        			Type ifType = type.GetInterface(typeof(T).FullName);
        			if (null == ifType)
        			{
        				continue;
        			}

					if (skipLoaded)
					{
						bool skipItem = false;
						foreach (T item in _loadedInterfaces)
						{
							if (item.GetType().Equals(type))
							{
								skipItem = true;
								break;
							}
						}
						if (skipItem)
						{
							continue;
						}
					}
        			
    				ConstructorInfo ci = type.GetConstructor(constructorTypes);
    				if (null != ci)
    				{
    					T instance = (T)ci.Invoke(constructurObjects);
						loadedItems.Add(instance);
    				}
    				else
    				{
    					Trace.TraceWarning(String.Format("Found an assembly {0} containging a type implementing the interface {1}. Load will be skipped, because the needed constructor is not available", 
							file, typeof(T).FullName));
    				}
        		}
        	}
        	// add new loaded items
        	_loadedInterfaces.AddRange(loadedItems);
        	return loadedItems;
		}
        
        /// <summary>
		/// Find all loaded interfaces implementing a specified type.
        /// </summary>
		/// <param name="type">Type to be found.</param>
		/// <returns>List of found items.</returns>
		public List<T> FindType(Type type)
		{
			List<T> results = new List<T>();
			if (null != type)
			{
				foreach (T item in this._loadedInterfaces)
				{
					if (item.GetType() == type)
					{
						results.Add(item);
					}
				}
			}
			return results;
		}

        /// <summary>
		/// Find all loaded interfaces implementing a specified type by its FQN.
        /// </summary>
		/// <param name="fullname">Full qualified name of the type to be found.</param>
		/// <returns>List of found items.</returns>
        public List<T> FindType(string fullname)
        {
            List<T> results = new List<T>();
            foreach (T item in this._loadedInterfaces)
            {
                if (item.GetType().FullName.Equals(fullname))
                {
                    results.Add(item);
                }
            }
            return results;
        }
		
		/// <summary>
		/// Find all loaded interfaces implementing a specified interface.
		/// </summary>
		/// <param name="type">Type to search for.</param>
		/// <returns>List of found items.</returns>
		public List<T> FindInterfaceType(Type type)
		{
			List<T> results = new List<T>();
			if (null != type)
			{
				foreach (T item in this._loadedInterfaces)
				{
					Type ifType = item.GetType().GetInterface(type.FullName);
					if (null != ifType)
					{
						results.Add(item);
					}
				}
			}
			return results;
		}

		/// <summary>
		/// Find all loaded interfaces implementing a specified interface by its FQN.
		/// </summary>
		/// <param name="fullname">Full qualified name of the interface to search for.</param>
		/// <returns>List of found items.</returns>
        public List<T> FindInterfaceType(string fullname)
        {
            List<T> results = new List<T>();
            foreach (T item in this._loadedInterfaces)
            {
                Type ifType = item.GetType().GetInterface(fullname);
                if (null != ifType)
                {
                    results.Add(item);
                }
            }
            return results;
        }
        #endregion
    }
}
