namespace Caliburn.Micro.Core {
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reflection;
    /// 
    /// Extension methods for the .
    /// 
    public static class ContainerExtensions {
        /// 
        /// Registers a singleton.
        /// 
        /// The type of the implementation.
        /// The container.
        /// The key.
        /// The container.
        public static SimpleContainer Singleton(this SimpleContainer container, string key = null) {
            return Singleton(container, key);
        }
        /// 
        /// Registers a singleton.
        /// 
        /// The type of the service.
        /// The type of the implementation.
        /// The container.
        /// The key.
        /// The container.
        public static SimpleContainer Singleton(this SimpleContainer container, string key = null)
            where TImplementation : TService {
            container.RegisterSingleton(typeof (TService), key, typeof (TImplementation));
            return container;
        }
        /// 
        /// Registers an service to be created on each request.
        /// 
        /// The type of the implementation.
        /// The container.
        /// The key.
        /// The container.
        public static SimpleContainer PerRequest(this SimpleContainer container, string key = null) {
            return PerRequest(container, key);
        }
        /// 
        /// Registers an service to be created on each request.
        /// 
        /// The type of the service.
        /// The type of the implementation.
        /// The container.
        /// The key.
        /// The container.
        public static SimpleContainer PerRequest(this SimpleContainer container, string key = null)
            where TImplementation : TService {
            container.RegisterPerRequest(typeof (TService), key, typeof (TImplementation));
            return container;
        }
        /// 
        /// Registers an instance with the container.
        /// 
        /// The type of the service.
        /// The container.
        /// The instance.
        /// The container.
        public static SimpleContainer Instance(this SimpleContainer container, TService instance) {
            container.RegisterInstance(typeof (TService), null, instance);
            return container;
        }
        /// 
        /// Registers a custom service handler with the container.
        /// 
        /// The type of the service.
        /// The container.
        /// The handler.
        /// The container.
        public static SimpleContainer Handler(this SimpleContainer container,
                                                        Func handler) {
            container.RegisterHandler(typeof (TService), null, handler);
            return container;
        }
        /// 
        /// Registers all specified types in an assembly as singleton in the container.
        /// 
        /// The type of the service.
        /// The container.
        /// The assembly.
        /// The type filter.
        /// The container.
        public static SimpleContainer AllTypesOf(this SimpleContainer container, Assembly assembly,
                                                           Func filter = null) {
            if (filter == null)
                filter = type => true;
            var serviceType = typeof (TService);
            var types = from type in assembly.GetTypes()
                        where serviceType.IsAssignableFrom(type)
                              && !type.IsAbstract()
                              && !type.IsInterface()
                              && filter(type)
                        select type;
            foreach (var type in types) {
                container.RegisterSingleton(typeof (TService), null, type);
            }
            return container;
        }
        /// 
        /// Requests an instance.
        /// 
        /// The type of the service.
        /// The container.
        /// The key.
        /// The instance.
        public static TService GetInstance(this SimpleContainer container, string key = null) {
            return (TService) container.GetInstance(typeof (TService), key);
        }
        /// 
        /// Gets all instances of a particular type.
        /// 
        /// The type to resolve.
        /// The container.
        /// The resolved instances.
        public static IEnumerable GetAllInstances(this SimpleContainer container) {
            return container.GetAllInstances(typeof (TService)).Cast();
        }
        /// 
        /// Determines if a handler for the service/key has previously been registered.
        /// 
        /// The service type.
        /// The container.
        /// The key.
        /// True if a handler is registere; false otherwise.
        public static bool HasHandler(this SimpleContainer container, string key = null) {
            return container.HasHandler(typeof (TService), key);
        }
        /// 
        ///   Unregisters any handlers for the service/key that have previously been registered.
        /// 
        /// The service type.
        /// The container.
        /// The key.
        public static void UnregisterHandler(this SimpleContainer container, string key = null) {
            container.UnregisterHandler(typeof(TService), key);
        }
    }
}