﻿using Ninject;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Einstein.Ninject
{
    internal class RegisterBehavior : IRegisterBehavior
    {
        internal RegisterBehavior(IKernel kernel)
        {
            _container = kernel;
        }

        private IKernel _container;
        private IEnumerable<Type> _types;

        IRegisterBehavior IRegisterBehavior.ThisAssembly()
        {
            _types = Assembly.GetCallingAssembly().GetTypes();
            return this;
        }

        IRegisterBehavior IRegisterBehavior.WithNamespaceContaining<T>()
        {
            _types = _types.Where(x => string.Equals(x.Namespace, typeof(T).Namespace, StringComparison.Ordinal)).ToList();
            return this;
        }

        IRegisterBehavior IRegisterBehavior.WithDefaultConventions()
        {
            _types.ConcreteTypesOnly()
                .ForEach(x =>
                {
                    x.SafeGetInterfaces(i => x.Name.EndsWith(i.Name.Substring(1)))
                        .ForEach(i => _container.Bind(i).To(x));
                });
            return this;
        }

        IRegisterBehavior IRegisterBehavior.RegisterAgainstFirstInterface()
        {
            _types.ConcreteTypesOnly()
                .ForEach(t =>
                {
                    var i = t.SafeGetInterfaces().FirstOrDefault();
                    if (i == null)
                        return;
                    _container.Bind(i).To(t);
                });
            return this;
        }

        public IRegisterBehavior ForEach(Action<Type> action)
        {
            if (action != null)
                _types.ForEach(action);
            return this;
        }
    }
}
