﻿using System;

using Microsoft.Practices.Unity;

using NuClear.ValidationRules.Replication.Host.Factories.Replication;
using NuClear.Replication.Core;
using NuClear.Replication.Core.DataObjects;
using NuClear.ValidationRules.OperationsProcessing;
using NuClear.ValidationRules.Storage.Model.Facts;
using NuClear.ValidationRules.Replication.Accessors;
using NuClear.ValidationRules.Replication.Accessors.Rulesets;
using NuClear.ValidationRules.Replication.Messages;

namespace NuClear.ValidationRules.Replication.Host.DI
{
    public static partial class Bootstrapper
    {
        private static IUnityContainer ConfigureReplication(this IUnityContainer container, Func<LifetimeManager> entryPointSpecificLifetimeManagerFactory)
        {
            return container
                   // ErmFactsFlow
                   .RegisterAccessor<Account, AccountAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<AccountDetail, AccountDetailAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<Bargain, BargainAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<BargainScanFile, BargainScanFileAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<Bill, BillAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<BranchOffice, BranchOfficeAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<BranchOfficeOrganizationUnit, BranchOfficeOrganizationUnitAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<Category, CategoryAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<CategoryOrganizationUnit, CategoryOrganizationUnitAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<CostPerClickCategoryRestriction, CostPerClickCategoryRestrictionAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<Deal, DealAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<LegalPerson, LegalPersonAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<LegalPersonProfile, LegalPersonProfileAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<NomenclatureCategory, NomenclatureCategoryAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<Order, OrderAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<OrderConsistency, OrderConsistencyAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<OrderWorkflow, OrderWorkflowAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<OrderItem, OrderItemAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<OrderPosition, OrderPositionAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<OrderPositionAdvertisement, OrderPositionAdvertisementAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<OrderPositionCostPerClick, OrderPositionCostPerClickAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<OrderProcessingRequest, OrderProcessingRequestAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<OrderScanFile, OrderScanFileAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<Position, PositionAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<PositionChild, PositionChildAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<Price, PriceAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<PricePosition, PricePositionAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<Project, ProjectAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<ReleaseInfo, ReleaseInfoAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<ReleaseWithdrawal, ReleaseWithdrawalAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<SalesModelCategoryRestriction, SalesModelCategoryRestrictionAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterAccessor<UnlimitedOrder, UnlimitedOrderAccessor>(entryPointSpecificLifetimeManagerFactory)

                   // AmsFactsFlow
                   .RegisterMemoryAccessor<Advertisement, AdvertisementAccessor>(entryPointSpecificLifetimeManagerFactory)

                   // RulesetFactsFlow
                   .RegisterMemoryAccessor<Ruleset, RulesetAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterMemoryAccessor<Ruleset.AssociatedRule, RulesetAssociatedRuleAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterMemoryAccessor<Ruleset.DeniedRule, RulesetDeniedRuleAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterMemoryAccessor<Ruleset.QuantitativeRule, RulesetQuantitativeRuleAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterMemoryAccessor<Ruleset.RulesetProject, RulesetProjectAccessor>(entryPointSpecificLifetimeManagerFactory)

                   // InfoRussiaFactsFlow
                   .RegisterMemoryAccessor<Firm, FirmAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterMemoryAccessor<FirmInactive, FirmInactiveAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterMemoryAccessor<FirmAddress, FirmAddressAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterMemoryAccessor<FirmAddressInactive, FirmAddressInactiveAccessor>(entryPointSpecificLifetimeManagerFactory)
                   .RegisterMemoryAccessor<FirmAddressCategory, FirmAddressCategoryAccessor>(entryPointSpecificLifetimeManagerFactory)

                   // FijiFactsFlow
                   .RegisterMemoryAccessor<Building, BuildingAccessor>(entryPointSpecificLifetimeManagerFactory)

                   .RegisterType<IDataObjectsActorFactory, UnityDataObjectsActorFactory>(entryPointSpecificLifetimeManagerFactory())
                   .RegisterType<IAggregateActorFactory, UnityAggregateActorFactory>(entryPointSpecificLifetimeManagerFactory())
                   .RegisterType<IValidationResultCache, ValidationResultCache>(entryPointSpecificLifetimeManagerFactory())
                   .RegisterType<IValidationRuleRegistry, MassValidationRuleRegistry>(entryPointSpecificLifetimeManagerFactory());
        }

        private static IUnityContainer RegisterAccessor<TFact, TAccessor>(this IUnityContainer container, Func<LifetimeManager> entryPointSpecificLifetimeManagerFactory)
            where TAccessor : IStorageBasedDataObjectAccessor<TFact>, IDataChangesHandler<TFact>
            => container
                .RegisterType<IStorageBasedDataObjectAccessor<TFact>, TAccessor>(entryPointSpecificLifetimeManagerFactory())
                .RegisterType<IDataChangesHandler<TFact>, TAccessor>(entryPointSpecificLifetimeManagerFactory());

        private static IUnityContainer RegisterMemoryAccessor<TFact, TAccessor>(this IUnityContainer container, Func<LifetimeManager> entryPointSpecificLifetimeManagerFactory)
            where TAccessor : IMemoryBasedDataObjectAccessor<TFact>, IDataChangesHandler<TFact>
            => container
                .RegisterType<IMemoryBasedDataObjectAccessor<TFact>, TAccessor>(entryPointSpecificLifetimeManagerFactory())
                .RegisterType<IDataChangesHandler<TFact>, TAccessor>(entryPointSpecificLifetimeManagerFactory());
    }
}
