SuperSocketHostBuilder<TReceivePackage>


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using SuperSocket;
using SuperSocket.ProtoBase;
using SuperSocket.Server;

namespace SuperSocket
{
    public class SuperSocketHostBuilder : HostBuilderAdapter>, ISuperSocketHostBuilder, IHostBuilder
    {
        private Func _serverOptionsReader;

        protected List> ConfigureServicesActions { get; private set; } = new List>();

        protected List> ConfigureSupplementServicesActions = new List>();

        public SuperSocketHostBuilder(IHostBuilder hostBuilder)
            : base(hostBuilder)
        {

        }

        public SuperSocketHostBuilder()
            : this(args: null)
        {

        }

        public SuperSocketHostBuilder(string[] args)
            : base(args)
        {

        }

        public override IHost Build()
        {
            return HostBuilder.ConfigureServices((ctx, services) =>
            {
                RegisterBasicServices(ctx, services, services);
            }).ConfigureServices((ctx, services) =>
            {
                foreach (var action in ConfigureServicesActions)
                {
                    action(ctx, services);
                }

                foreach (var action in ConfigureSupplementServicesActions)
                {
                    action(ctx, services);
                }
            }).ConfigureServices((ctx, services) =>
            {
                RegisterDefaultServices(ctx, services, services);
            }).Build();
        }

        public ISuperSocketHostBuilder ConfigureSupplementServices(Action configureDelegate)
        {
            ConfigureSupplementServicesActions.Add(configureDelegate);
            return this;
        }

        ISuperSocketHostBuilder ISuperSocketHostBuilder.ConfigureSupplementServices(Action configureDelegate)
        {
            return ConfigureSupplementServices(configureDelegate);
        }

        protected virtual void RegisterBasicServices(HostBuilderContext builderContext, IServiceCollection servicesInHost, IServiceCollection services)
        {
            var serverOptionReader = _serverOptionsReader;

            if (serverOptionReader == null)
            {
                serverOptionReader = (ctx, config) =>
                {
                    return config;
                };
            }

            services.AddOptions();

            var config = builderContext.Configuration.GetSection("serverOptions");
            var serverConfig = serverOptionReader(builderContext, config);

            services.Configure(serverConfig);
        }

        protected virtual void RegisterDefaultServices(HostBuilderContext builderContext, IServiceCollection servicesInHost, IServiceCollection services)
        {
            // if the package type is StringPackageInfo
            if (typeof(TReceivePackage) == typeof(StringPackageInfo))
            {
                services.TryAdd(ServiceDescriptor.Singleton, DefaultStringPackageDecoder>());
            }

            services.TryAdd(ServiceDescriptor.Singleton, DefaultStringEncoderForDI>());

            // if no host service was defined, just use the default one
            if (!CheckIfExistHostedService(services))
            {
                RegisterDefaultHostedService(servicesInHost);
            }
        }

        protected virtual bool CheckIfExistHostedService(IServiceCollection services)
        {
            return services.Any(s => s.ServiceType == typeof(IHostedService)
                && typeof(SuperSocketService).IsAssignableFrom(GetImplementationType(s)));
        }

        private Type GetImplementationType(ServiceDescriptor serviceDescriptor)
        {
            if (serviceDescriptor.ImplementationType != null)
                return serviceDescriptor.ImplementationType;

            if (serviceDescriptor.ImplementationInstance != null)
                return serviceDescriptor.ImplementationInstance.GetType();

            if (serviceDescriptor.ImplementationFactory != null)
            {
                var typeArguments = serviceDescriptor.ImplementationFactory.GetType().GenericTypeArguments;

                if (typeArguments.Length == 2)
                    return typeArguments[1];
            }

            return null;
        }

        protected virtual void RegisterDefaultHostedService(IServiceCollection servicesInHost)
        {
            RegisterHostedService>(servicesInHost);
        }

        protected virtual void RegisterHostedService(IServiceCollection servicesInHost)
            where THostedService : class, IHostedService
        {
            servicesInHost.AddSingleton();
            servicesInHost.AddSingleton(s => s.GetService() as IServerInfo);
            servicesInHost.AddHostedService(s => s.GetService());
        }

        public ISuperSocketHostBuilder ConfigureServerOptions(Func serverOptionsReader)
        {
            _serverOptionsReader = serverOptionsReader;
            return this;
        }

        ISuperSocketHostBuilder ISuperSocketHostBuilder.ConfigureServices(Action configureDelegate)
        {
            return ConfigureServices(configureDelegate);
        }

        public override SuperSocketHostBuilder ConfigureServices(Action configureDelegate)
        {
            ConfigureServicesActions.Add(configureDelegate);
            return this;
        }

        public virtual ISuperSocketHostBuilder UsePipelineFilter()
            where TPipelineFilter : IPipelineFilter, new()
        {
            return this.ConfigureServices((ctx, services) =>
            {
                services.AddSingleton, DefaultPipelineFilterFactory>();
            });
        }

        public virtual ISuperSocketHostBuilder UsePipelineFilterFactory()
            where TPipelineFilterFactory : class, IPipelineFilterFactory
        {
            return this.ConfigureServices((ctx, services) =>
            {
                services.AddSingleton, TPipelineFilterFactory>();
            });
        }

        public virtual ISuperSocketHostBuilder UseSession()
            where TSession : IAppSession
        {
            return this.UseSessionFactory>();
        }

        public virtual ISuperSocketHostBuilder UseSessionFactory()
            where TSessionFactory : class, ISessionFactory
        {
            return this.ConfigureServices(
                (hostCtx, services) =>
                {
                    services.AddSingleton();
                }
            );
        }

        public virtual ISuperSocketHostBuilder UseHostedService()
            where THostedService : class, IHostedService
        {
            if (!typeof(SuperSocketService).IsAssignableFrom(typeof(THostedService)))
            {
                throw new ArgumentException($"The type parameter should be subclass of {nameof(SuperSocketService)}", nameof(THostedService));
            }

            return this.ConfigureServices((ctx, services) =>
            {
                RegisterHostedService(services);
            });
        }


        public virtual ISuperSocketHostBuilder UsePackageDecoder()
            where TPackageDecoder : class, IPackageDecoder
        {
            return this.ConfigureServices(
                (hostCtx, services) =>
                {
                    services.AddSingleton, TPackageDecoder>();
                }
            );
        }

        public virtual ISuperSocketHostBuilder UseMiddleware()
            where TMiddleware : class, IMiddleware
        {
            return this.ConfigureServices((ctx, services) =>
            {
                services.TryAddEnumerable(ServiceDescriptor.Singleton());
            });
        }

        public ISuperSocketHostBuilder UsePackageHandlingScheduler()
            where TPackageHandlingScheduler : class, IPackageHandlingScheduler
        {
            return this.ConfigureServices(
                (hostCtx, services) =>
                {
                    services.AddSingleton, TPackageHandlingScheduler>();
                }
            );
        }

        public ISuperSocketHostBuilder UsePackageHandlingContextAccessor()
        {
            return this.ConfigureServices(
                 (hostCtx, services) =>
                 {
                     services.AddSingleton, PackageHandlingContextAccessor>();
                 }
             );
        }
    }

    public static class SuperSocketHostBuilder
    {
        public static ISuperSocketHostBuilder Create()
            where TReceivePackage : class
        {
            return Create(args: null);
        }

        public static ISuperSocketHostBuilder Create(string[] args)
        {
            return new SuperSocketHostBuilder(args);
        }

        public static ISuperSocketHostBuilder Create()
            where TPipelineFilter : IPipelineFilter, new()
        {
            return Create(args: null);
        }

        public static ISuperSocketHostBuilder Create(string[] args)
            where TPipelineFilter : IPipelineFilter, new()
        {
            return new SuperSocketHostBuilder(args)
                .UsePipelineFilter();
        }
    }
}