using System;

namespace Wayne.Lib
{
    /// <summary>
    /// This interface represents the locator part of the service container. Clients are often only interested in retrieving
    /// services from the container and thus only interested in this contract instead of the entire service container.
    /// </summary>
    public interface IServiceLocator
    {
        /// <summary>
        /// Retrieves the service of type serviceType from the container.
        /// </summary>
        /// <typeparam name="TServiceContract">Type of service.</typeparam>
        /// <returns>Service from the service container.</returns>
        TServiceContract GetService<TServiceContract>();

        /// <summary>
        /// Retrieves the service of type serviceType from the container.
        /// </summary>
        /// <typeparam name="TServiceContract">Type of service.</typeparam>
        /// <param name="serviceId">Id of the service , supplied upon registration.</param>
        /// <returns>Service from the service container.</returns>
        TServiceContract GetService<TServiceContract>(string serviceId);





        /// <summary>
        /// Retrieves the service of type serviceType from the container.
        /// </summary>
        /// <param name="serviceType">Type of service.</param>
        /// <returns>Service from the service container.</returns>
        object GetService(Type serviceType);

        /// <summary>
        /// Retrieves the service of type serviceType from the container.
        /// </summary>
        /// <param name="serviceType">Type of service.</param>
        /// <param name="serviceId">Id of the service , supplied upon registration.</param>
        /// <returns>Service from the service container.</returns>
        object GetService(Type serviceType, string serviceId);


        /// <summary>
        /// Gets a registered service. If the service is not registered, it invokes the supplied
        /// callback to get a default instance of the service. NOTE that this instance is not automatically registered.
        /// </summary>
        /// <typeparam name="TServiceContract"></typeparam>
        /// <param name="func"></param>
        /// <returns></returns>
        TServiceContract GetServiceOrDefault<TServiceContract>(CreateDefaultService<TServiceContract> func);

        /// <summary>
        /// Gets a registered service. If the service is not registered, it invokes the supplied
        /// callback to get a default instance of the service. NOTE that this instance is not automatically registered.
        /// </summary>
        /// <typeparam name="TServiceContract"></typeparam>
        /// <param name="func"></param>
        /// <param name="serviceId">Id of the service , supplied upon registration.</param>
        /// <returns></returns>
        TServiceContract GetServiceOrDefault<TServiceContract>(CreateDefaultService<TServiceContract> func, string serviceId);

        /// <summary>
        /// Creates an instance of T. Service locator uses the first constructor it finds that it can use based on what is
        /// registered in the service container and the additional parameters.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="additionalParameter">List of parameters that</param>
        /// <returns>An instance of the created object</returns>
        [Obsolete("Use ServiceActivator.Create<T> instead")]
        T CreateInstance<T>(params object[] additionalParameter) where T : class;

        /// <summary>
        /// Creates an instance of T. Service locator uses the first constructor it finds that it can use based on what is
        /// registered in the service container and the additional parameters.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="serviceId">Id of the service , supplied upon registration.</param>
        /// <param name="additionalParameter">List of parameters that</param>
        /// <returns>An instance of the created object</returns>
        [Obsolete("Use ServiceActivator.Create<T> instead")]
        T CreateInstance<T>(string serviceId, params object[] additionalParameter) where T : class;

        /// <summary>
        /// Creates an instance of the specified type. Service locator uses the first constructor it finds that it can use
        /// based on what is regeistered in the service container and the additional parameters.
        /// </summary>
        /// <param name="typeToInstantiate"></param>
        /// <param name="additionalParameter"></param>
        /// <returns></returns>
        object CreateInstance(Type typeToInstantiate, params object[] additionalParameter);

        /// <summary>
        /// Creates an instance of the specified type. Service locator uses the first constructor it finds that it can use
        /// based on what is regeistered in the service container and the additional parameters.
        /// </summary>
        /// <param name="typeToInstantiate"></param>
        /// <param name="serviceId">Id of the service , supplied upon registration.</param>
        /// <param name="additionalParameter"></param>
        /// <returns></returns>
        object CreateInstance(Type typeToInstantiate, string serviceId, params object[] additionalParameter);



        /// <summary>
        /// Tries to locate the service T. If it does not succeed, it returns null.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T TryGetService<T>();

        /// <summary>
        /// Tries to locate the service T. If it does not succeed, it returns null.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="serviceId">Id of the service , supplied upon registration.</param>
        /// <returns></returns>
        T TryGetService<T>(string serviceId);



        /// <summary>
        /// Tries to locate the specified service. If it does not succeed it returns null.
        /// </summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        object TryGetService(Type serviceType);

        /// <summary>
        /// Tries to locate the specified service. If it does not succeed it returns null.
        /// </summary>
        /// <param name="serviceType"></param>
        /// <param name="serviceId">Id of the service , supplied upon registration.</param>
        /// <returns></returns>
        object TryGetService(Type serviceType, string serviceId);
 
    }

    /// <summary>
    /// Delegate for creating a default service with the IServiceLocator.GetServiceOrDefault method.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <returns></returns>
    public delegate T CreateDefaultService<T>();
}