/// <summary>
        /// Adds a collection of Types to the collection
        /// </summary>
        /// <param name="types">The collection of types to add</param>
        public void AddRange(TypeCollection types)
        {
            if (types == null)
            {
                throw new ArgumentNullException("types");
            }

            foreach (Type type in types)
            {
                this.Add(type);
            }
        }
		/// <summary>
		/// Uses the PluginProviders specified to load Plugin Types that will be used to create Plugins.
		/// </summary>
		/// <param name="progressViewer">The callback object implementing IProgressViewer that will be used to monitor progress.</param>
		/// <param name="pluginProviders">The collection of PluginProviders that will be used to load the Plugin Types from their various sources.</param>
		/// <returns></returns>
		public static TypeCollection LoadPluginTypes(IProgressViewer progressViewer, PluginProviderCollection pluginProviders)
		{
			TypeCollection pluginTypes = new TypeCollection();
			foreach (PluginProvider provider in pluginProviders)
			{
				try
				{
					Log.WriteLine("Loading Plugin Types. PluginProvider: '{0}'.", provider.Name);

					TypeCollection types = provider.LoadPluginTypes(progressViewer);
					if (types != null)
					{
						pluginTypes.AddRange(types);
					}
				}
				catch(Exception ex)
				{
					Log.WriteLine(ex);
				}
			}
			return pluginTypes;
		}
		/// <summary>
		/// Adds a collection of Types to the collection
		/// </summary>
		/// <param name="types">The collection of types to add</param>
		public void AddRange(TypeCollection types)
		{
			if (types == null)
				throw new ArgumentNullException("types");

			foreach (Type type in types)
			{				
				this.Add(type);
			}
		}
		/// <summary>
		/// Initializes a new instance of the TypeCollection class
		/// </summary>
		/// <param name="types">A TypeCollection filled with types to add to the collection</param>
		public TypeCollection(TypeCollection types)
		{
			this.AddRange(types);
		}
		/// <summary>
		/// Creates PluginDescriptors from each Plugin Type specified.
		/// </summary>
		/// <param name="progressViewer">The callback object implementing IProgressViewer that will be used to monitor progress.</param>
		/// <param name="types">The collection of Plugin Types to create descriptors for.</param>
		/// <returns></returns>
		public static PluginDescriptorCollection CreatePluginDescriptors(IProgressViewer progressViewer, TypeCollection types)
		{
			PluginDescriptorCollection descriptors = new PluginDescriptorCollection();
			foreach (Type type in types)
			{
				try
				{
					string message = string.Format("Creating PluginDescriptor, Type: '{0}'.", type.FullName);
                    ProgressViewer.SetExtendedDescription(progressViewer, message);
					Log.WriteLine(message);

                    PluginDescriptor descriptor = new PluginDescriptor(type);

                    descriptors.Add(descriptor);
				}
				catch(Exception ex)
				{
					Log.WriteLine(ex);
				}
			}
			return descriptors;
		}
			/// <summary>
			/// Searches for plugins in the application's startup path
			/// </summary>
			/// <param name="viewer"></param>
			/// <returns>null if no plugins were found</returns>
			private TypeCollection InternalSearchForPluginTypes(IProgressViewer progressViewer)
			{				
				TypeCollection types = null;
				
				// starting in the startup path
				DirectoryInfo directoryInfo = new DirectoryInfo(Application.StartupPath);
				
				// look for all the dlls
				FileInfo[] files = directoryInfo.GetFiles("*.dll");

				// see if we can find any plugins defined in each assembly
				foreach (FileInfo file in files)
				{
					// try and load the assembly
					Assembly assembly = this.LoadAssembly(file.FullName);					
					if (assembly != null)
					{
                        ProgressViewer.SetExtendedDescription(progressViewer, string.Format("Searching for plugins. Searching '{0}'...", assembly.GetName().Name));

						// see if the assembly has any plugins defined in it
						TypeCollection typesInAssembly = this.LoadPluginTypesFromAssembly(assembly);						
						if (typesInAssembly != null)
						{
							if (types == null)
								types = new TypeCollection();

							// add the types defined as plugins to the master list
							types.AddRange(typesInAssembly);
						}
					}
				}

				return types;
			}
			/// <summary>
			/// Loads a TypeCollection with the plugins defined in the assembly
			/// </summary>
			/// <param name="assembly">The assembly to check for plugin definitions</param>
			/// <returns></returns>
			private TypeCollection LoadPluginTypesFromAssembly(Assembly assembly)
			{                
				TypeCollection types = null;
                
                try
                {
                    object[] value = assembly.GetCustomAttributes(typeof(PluginDefinitionAttribute), false);
    				
                    if (value != null)
                    {
                        PluginDefinitionAttribute[] attributes = (PluginDefinitionAttribute[])value;
    					
                        foreach (PluginDefinitionAttribute attribute in attributes)
                        {
                            if (types == null)
                                types = new TypeCollection();

                            types.Add(attribute.Type);
                        }
                    }
                }
                catch(Exception ex)
                {
                    Log.WriteLine(ex);
                }

				return types;
			}
 /// <summary>
 /// Initializes a new instance of the TypeCollection class
 /// </summary>
 /// <param name="types">A TypeCollection filled with types to add to the collection</param>
 public TypeCollection(TypeCollection types)
 {
     this.AddRange(types);
 }