using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http.Dependencies;

using Spring.Context;
using Spring.Context.Support;
using Spring.Core.IO;


namespace Spring.Web.Mvc
{
    /// <summary>
    /// Spring-based implementation of the <see cref="System.Web.Http.Dependencies.IDependencyResolver"/> interface for ASP.NET MVC Web API.
    /// </summary>
    public class SpringWebApiDependencyResolver : SpringMvcDependencyResolver, System.Web.Http.Dependencies.IDependencyResolver
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="SpringMvcDependencyResolver"/> class.
        /// </summary>
        /// <param name="context">The <see cref="IApplicationContext"/> to be used by the resolver</param>
        public SpringWebApiDependencyResolver(IApplicationContext context)
            : base(context)
        {
        }


        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public virtual void Dispose()
        {
            //no unmanaged resources to dispose
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns>The initialized <see cref="IDependencyScope"/> instance.</returns>
        /// <exception cref="NotImplementedException"></exception>
        public virtual IDependencyScope BeginScope()
        {
            if (HasApplicationContext && (HasChildApplicationContextConfigurationLocations || HasChildApplicationContextConfigurationResources))
            {
                string[] configurationLocations = null;
                if (HasChildApplicationContextConfigurationLocations)
                {
                    configurationLocations = ChildApplicationContextConfigurationLocations.ToArray();
                }

                IResource[] configurationResources = null;
                if (HasChildApplicationContextConfigurationResources)
                {
                    configurationResources = ChildApplicationContextConfigurationResources.ToArray();
                }

                var childContextName = string.Format("child_of_{0}", ApplicationContext.Name);
                var args = new MvcApplicationContextArgs(childContextName, ApplicationContext, configurationLocations, configurationResources, false);

                var childContext = new MvcApplicationContext(args);
                var newResolver = new SpringWebApiDependencyResolver(childContext) { ApplicationContextName = childContextName };

                RegisterContextIfNeeded(childContext);

                return newResolver;
            }
            else
            {
                return this;
            }
        }

        private void RegisterContextIfNeeded(IApplicationContext childContext)
        {
            if (!ContextRegistry.IsContextRegistered(childContext.Name))
            {
                ContextRegistry.RegisterContext(childContext);
            }
        }

        private bool HasChildApplicationContextConfigurationResources
        {
            get
            {
                return ChildApplicationContextConfigurationResources != null &&
                       ChildApplicationContextConfigurationResources.Count > 0;
            }
        }

        private bool HasChildApplicationContextConfigurationLocations
        {
            get
            {
                return ChildApplicationContextConfigurationLocations != null &&
                       ChildApplicationContextConfigurationLocations.Count > 0;
            }
        }

        private bool HasApplicationContext
        {
            get { return ApplicationContext != null; }
        }

        /// <summary>
        /// Gets or sets the child configuration locations.
        /// </summary>
        /// <value>The child configuration locations.</value>
        public virtual IList<string> ChildApplicationContextConfigurationLocations { protected get; set; }

        /// <summary>
        /// Gets or sets the child configuration resources.
        /// </summary>
        /// <value>The child configuration resources.</value>
        public virtual IList<IResource> ChildApplicationContextConfigurationResources { protected get; set; }

        /// <summary>
        /// Adds the child configuration resource.
        /// </summary>
        /// <param name="resource">The resource.</param>
        public virtual void AddChildApplicationContextConfigurationResource(IResource resource)
        {
            if (null == ChildApplicationContextConfigurationResources)
            {
                ChildApplicationContextConfigurationResources = new List<IResource>();
            }

            ChildApplicationContextConfigurationResources.Add(resource);
        }

        /// <summary>
        /// Adds the child configuration location.
        /// </summary>
        /// <param name="location">The location.</param>
        public virtual void AddChildApplicationContextConfigurationLocation(string location)
        {
            if (null == ChildApplicationContextConfigurationLocations)
            {
                ChildApplicationContextConfigurationLocations = new List<string>();
            }

            ChildApplicationContextConfigurationLocations.Add(location);
        }
    }
}