private void SetupTestData( out IReadOnlyCollection<Break> breaksBeingSmoothed, out SmoothBreak theSmoothBreak, out IReadOnlyCollection<Programme> scheduleProgrammes, out List<Spot> spotsForBreak, out SalesArea salesArea, out IReadOnlyDictionary<string, Clash> clashesByExternalRef, out IReadOnlyDictionary<Guid, SpotInfo> spotInfos, out ProductClashRules productClashRule, out SmoothResources smoothResources, out IClashExposureCountService clashExposureCountService, out SponsorshipRestrictionService sponsorshipRestrictionsService) { breaksBeingSmoothed = _repositoryWrapper.LoadAllTestBreaks().ToList(); theSmoothBreak = new SmoothBreak(breaksBeingSmoothed.First(), 1); scheduleProgrammes = _repositoryWrapper.LoadAllProgrammes().ToList(); spotsForBreak = new List<Spot>() { _spot }; salesArea = _repositoryWrapper.LoadAllSalesArea().First(); clashesByExternalRef = _repositoryWrapper.LoadAllClashes().ToDictionary(c => c.Externalref); spotInfos = SpotInfo.Factory( spotsForBreak, _repositoryWrapper.LoadAllProducts().ToDictionary(p => p.Externalidentifier), clashesByExternalRef ); productClashRule = ProductClashRules.LimitOnExposureCount; smoothResources = new SmoothResources(); clashExposureCountService = ClashExposureCountService.Create(); sponsorshipRestrictionsService = SponsorshipRestrictionService.Factory( spotInfos, new SponsorshipRestrictionFilterService(ImmutableList.Create<Sponsorship>()), new SmoothSponsorshipTimelineManager(new List<SmoothSponsorshipTimeline>()), scheduleProgrammes.First(), DebugLogger); }
private static void CheckProductClashExposureCount( IReadOnlyDictionary <string, Clash> clashesByExternalRef, IClashExposureCountService clashExposureCountService, SmoothFailureMessagesForSpotsCollection result, IReadOnlyDictionary <string, int> spotChildClashCodeCount, Spot spot, SpotInfo spotInfo, IReadOnlyCollection <Spot> childProductClashSpots) { if (!clashesByExternalRef.TryGetValue(spotInfo.ProductClashCode, out Clash childClash)) { return; } int exposureCount = clashExposureCountService.Calculate( childClash.Differences, (childClash.DefaultPeakExposureCount, childClash.DefaultOffPeakExposureCount), (spot.StartDateTime, spot.SalesArea) ); if (exposureCount > 0 && childProductClashSpots.Count + spotChildClashCodeCount[spotInfo.ProductClashCode] > exposureCount) { result.Add(spot.Uid, SmoothFailureMessages.T1_ProductClash); } }
public SmoothDateRange( Guid runId, Guid firstScenarioId, DateTime processorDateTime, SalesArea salesArea, ISmoothConfiguration smoothConfiguration, ISmoothDiagnostics smoothDiagnostics, ImmutableSmoothData threadSafeCollections, IClashExposureCountService clashExposureCountService, SaveSmoothChanges saveSmoothChanges, IRepositoryFactory repositoryFactory, Action <string> raiseInfo, Action <string> raiseWarning, Action <string, Exception> raiseException) { RaiseInfo = raiseInfo; RaiseWarning = raiseWarning; RaiseException = raiseException; _threadSafeCollections = threadSafeCollections; _clashExposureCountService = clashExposureCountService; _saveSmoothChanges = saveSmoothChanges; _repositoryFactory = repositoryFactory; _runId = runId; _firstScenarioId = firstScenarioId; _processorDateTime = processorDateTime; _salesArea = salesArea; _smoothConfiguration = smoothConfiguration; _smoothDiagnostics = smoothDiagnostics; _smoothFailuresFactory = new SmoothFailuresFactory(_smoothConfiguration); _smoothRecommendationsFactory = new SmoothRecommendationsFactory(_smoothConfiguration); _smoothPasses = _smoothConfiguration.SortedSmoothPasses; }
public SmoothEngine( IRepositoryFactory repositoryFactory, IClashExposureCountService clashExposureCountService, RootFolder smoothLogFileFolder) { _repositoryFactory = repositoryFactory; _smoothLogFileFolder = smoothLogFileFolder; _clashExposureCountService = clashExposureCountService; }
public BestBreakEvaluator( ISmoothDiagnostics smoothDiagnostics, SmoothResources smoothResources, IClashExposureCountService clashExposureCountService) { _smoothDiagnostics = smoothDiagnostics; _smoothResources = smoothResources; _bestBreakFactorService = new BestBreakFactorService(clashExposureCountService); _bestBreakFactorForGroupService = new BestBreakFactorForGroupService(_bestBreakFactorService); }
public FewestProductClashesBreakFactor( SmoothBreak smoothBreak, IReadOnlyCollection <Spot> spots, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, IReadOnlyDictionary <string, Product> productsByExternalRef, IReadOnlyDictionary <string, Clash> clashesByExternalRef, IProductClashChecker productClashChecker, IClashExposureCountService effectiveClashExposureCount) { _smoothBreak = smoothBreak; _spots = spots; _spotInfos = spotInfos; _productsByExternalRef = productsByExternalRef; _clashesByExternalRef = clashesByExternalRef; _productClashChecker = productClashChecker; _effectiveClashExposureCount = effectiveClashExposureCount; }
private static void CheckProductClashRulesWhenClashLimitsAreAllowed( IReadOnlyDictionary <Guid, SpotInfo> spotInfos, IReadOnlyDictionary <string, Clash> clashesByExternalRef, SmoothResources smoothResources, IClashExposureCountService clashExposureCountService, SmoothFailureMessagesForSpotsCollection result, IReadOnlyDictionary <string, int> spotChildClashCodeCount, IReadOnlyDictionary <string, int> spotParentClashCodeCount, IReadOnlyCollection <Spot> spotsAlreadyInTheBreak, Spot spot, SpotInfo spotInfo, IReadOnlyCollection <Spot> childProductClashSpots) { if (childProductClashSpots.Count > 0 && !String.IsNullOrEmpty(spotInfo.ProductClashCode)) { CheckProductClashExposureCount( clashesByExternalRef, clashExposureCountService, result, spotChildClashCodeCount, spot, spotInfo, childProductClashSpots); } // Check parent clashes var parentProductClashSpots = smoothResources.ProductClashChecker .GetProductClashesForSingleSpot( spot, spotsAlreadyInTheBreak, spotInfos, ClashCodeLevel.Parent) .ToList(); if (parentProductClashSpots.Count > 0 && !String.IsNullOrEmpty(spotInfo.ParentProductClashCode)) { CheckProductParentClashExposure( clashesByExternalRef, clashExposureCountService, result, spotParentClashCodeCount, spot, spotInfo, parentProductClashSpots); } }
/// <summary> /// Calculates the factor score for product clashes at both child and /// parent level /// </summary> private double GetFactorScoreForProductClashes( SmoothBreak smoothBreak, IReadOnlyCollection <Spot> spots, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, IReadOnlyDictionary <string, Product> productsByExternalRef, IReadOnlyDictionary <string, Clash> clashesByExternalRef, IProductClashChecker productClashChecker, IClashExposureCountService effectiveClashExposureCount) { var factorScoreCalculator = new ProductClashFactorScore(effectiveClashExposureCount); return(factorScoreCalculator.GetFactorScoreForProductClashes( smoothBreak.SmoothSpots.Select(s => s.Spot).ToList(), spots, spotInfos, productsByExternalRef, clashesByExternalRef, productClashChecker.GetProductClashesForSingleSpot )); }
public SmoothWorkerForSalesAreaDuringDateTimePeriod( IRepositoryFactory repositoryFactory, string smoothLogFileFolder, ImmutableSmoothData threadSafeCollections, IClashExposureCountService clashExposureCountService, Action <string> raiseInfo, Action <string> raiseWarning, Action <string, Exception> raiseException ) { _smoothLogFileFolder = smoothLogFileFolder; _clashExposureCountService = clashExposureCountService; _repositoryFactory = repositoryFactory; _smoothConfiguration = threadSafeCollections.SmoothConfigurationReader; _threadSafeCollections = threadSafeCollections; RaiseInfo = raiseInfo; RaiseWarning = raiseWarning; RaiseException = raiseException; }
public SmoothPassUnplacedExecuter( ISmoothDiagnostics smoothDiagnostics, SmoothResources smoothResources, SmoothProgramme smoothProgramme, SponsorshipRestrictionService sponsorshipRestrictionService, IReadOnlyCollection <Programme> allProgrammesForPeriodAndSalesArea, ISmoothConfiguration smoothConfiguration, IClashExposureCountService clashExposureCountService, IImmutableDictionary <string, Clash> clashesByExternalRef, Action <string, Exception> raiseException ) { _smoothDiagnostics = smoothDiagnostics; _smoothConfiguration = smoothConfiguration; _smoothResources = smoothResources; _smoothProgramme = smoothProgramme; _clashExposureCountService = clashExposureCountService; _sponsorshipRestrictionService = sponsorshipRestrictionService; _allProgrammesForPeriodAndSalesArea = allProgrammesForPeriodAndSalesArea; _clashesByExternalRef = clashesByExternalRef; RaiseException = raiseException; }
/// <summary> /// Evaluate whether spots can be added to break. We consider time /// remaining, break type, product clashes, campaign clashes, spot end /// time (some spots may required to be position in the first N mins of /// the programme), sponsor rules. /// </summary> public static SmoothFailureMessagesForSpotsCollection ValidateAddSpots( SmoothBreak theSmoothBreak, Programme programme, SalesArea salesArea, IReadOnlyCollection <Spot> spotsForBreak, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, IReadOnlyList <SmoothBreak> progSmoothBreaks, ProductClashRules productClashRule, bool respectCampaignClash, bool respectSpotTime, bool respectRestrictions, bool respectClashExceptions, SpotPositionRules breakPositionRules, SpotPositionRules requestedPositionInBreakRules, IReadOnlyDictionary <string, Clash> clashesByExternalRef, bool canSplitMultipartSpotsOverBreaks, SmoothResources smoothResources, IReadOnlyCollection <Break> breaksBeingSmoothed, IReadOnlyCollection <Programme> scheduleProgrammes, IClashExposureCountService clashExposureCountService, SponsorshipRestrictionService sponsorshipRestrictionsService) { var result = new SmoothFailureMessagesForSpotsCollection(theSmoothBreak); foreach (Guid spotUid in spotsForBreak.Select(s => s.Uid)) { result.InitialiseForSpot(spotUid); } if (!IsSufficientRemainingDurationToAddSpots( theSmoothBreak.RemainingAvailability, spotsForBreak)) { foreach (Guid spotUid in spotsForBreak.Select(s => s.Uid)) { result.Add( spotUid, SmoothFailureMessages.T1_InsufficentRemainingDuration); } } var(spotChildClashCodeCount, spotParentClashCodeCount) = ClashCodesForSpotsCount(spotsForBreak, spotInfos); // Check basics of whether we can add this spot to the break, // correct break type, sufficient time remaining, product clashes, // campaign clashes var spotsAlreadyInTheBreak = theSmoothBreak.SmoothSpots .ConvertAll(s => s.Spot); var canAddSpotService = CanAddSpotService.Factory(theSmoothBreak); foreach (Spot spot in spotsForBreak) { ValidateWithSponsorshipRestrictions( theSmoothBreak, sponsorshipRestrictionsService, result, spotsAlreadyInTheBreak, spot); Guid spotUid = spot.Uid; if (!canAddSpotService.CanAddSpotWithBreakType(spot.BreakType)) { result.Add(spotUid, SmoothFailureMessages.T1_InvalidBreakType); } if (respectSpotTime && !canAddSpotService.CanAddSpotWithTime(spot.StartDateTime, spot.EndDateTime)) { result.Add(spotUid, SmoothFailureMessages.T1_InvalidSpotTime); } var(spotHasClashExceptionIncludes, spotHasClashExceptionExcludes) = HasClashExceptionIncludesAndExcludes( theSmoothBreak, respectClashExceptions, smoothResources, result, spot, spotUid); bool shouldCheckProductClashRules = ( productClashRule == ProductClashRules.NoClashes || productClashRule == ProductClashRules.LimitOnExposureCount ) && !spotHasClashExceptionIncludes && !spotHasClashExceptionExcludes; if (shouldCheckProductClashRules) { var childProductClashSpots = smoothResources.ProductClashChecker .GetProductClashesForSingleSpot( spot, spotsAlreadyInTheBreak, spotInfos, ClashCodeLevel.Child); switch (productClashRule) { case ProductClashRules.NoClashes: var output = CheckProductClashRulesWhenNoClashesAreAllowed( childProductClashSpots); if (output != SmoothFailureMessages.T0_NoFailure) { result.Add(spotUid, output); } break; case ProductClashRules.LimitOnExposureCount: CheckProductClashRulesWhenClashLimitsAreAllowed( spotInfos, clashesByExternalRef, smoothResources, clashExposureCountService, result, spotChildClashCodeCount, spotParentClashCodeCount, spotsAlreadyInTheBreak, spot, spotInfos[spotUid], childProductClashSpots); break; } } if (respectCampaignClash && smoothResources.CampaignClashChecker .GetCampaignClashesForNewSpots( new List <Spot> { spot }, spotsAlreadyInTheBreak) .Count > 0) { result.Add(spotUid, SmoothFailureMessages.T1_CampaignClash); } } var multipartSpots = spotsForBreak .Where(s => s.IsMultipartSpot) .ToList(); var nonMultipartSpots = spotsForBreak .Except(multipartSpots) .ToList(); if (nonMultipartSpots.Count > 0) { ValidateNonMultipartSpots( progSmoothBreaks, breakPositionRules, requestedPositionInBreakRules, canAddSpotService, result, nonMultipartSpots); } if (multipartSpots.Count > 0) { ValidateMultipartSpots( progSmoothBreaks, breakPositionRules, requestedPositionInBreakRules, canSplitMultipartSpotsOverBreaks, canAddSpotService, result, spotsAlreadyInTheBreak, multipartSpots); } if (respectRestrictions) { ValidateWithSpotRestrictions( theSmoothBreak, programme, salesArea, spotsForBreak, smoothResources, breaksBeingSmoothed, scheduleProgrammes, result); } IndicateIfMultipartTopTailSameBreakSpotsCannotBeAdded( result, multipartSpots); return(RemoveDuplicateFailureMessages(spotsForBreak, result)); }
public BestBreakFactorService( IClashExposureCountService clashExposureCount) =>
/// <summary> /// Create a new instance of this class for each programme to smooth. /// </summary> public SmoothOneProgramme( Programme programme, IEnumerable <Break> programmeBreaks, IReadOnlyCollection <Spot> programmeSpots, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, Guid runId, SalesArea salesArea, DateTime processorDateTime, ISmoothDiagnostics smoothDiagnostics, IImmutableList <RatingsPredictionSchedule> ratingsPredictionSchedules, ImmutableSmoothData threadSafeCollections, IClashExposureCountService clashExposureCountService, SponsorshipRestrictionService sponsorshipRestrictionService, IReadOnlyCollection <Product> products, IReadOnlyCollection <Clash> clashes, IReadOnlyCollection <Programme> allProgrammesForPeriodAndSalesArea, Action <string> raiseInfo, Action <string, Exception> raiseException) { RaiseInfo = raiseInfo; RaiseException = raiseException; if (programme is null) { var guruMeditation = new ArgumentNullException(nameof(programme)); RaiseException("The programme to Smooth is null", guruMeditation); throw guruMeditation; } _smoothProgramme = new SmoothProgramme(salesArea, programme); _smoothProgramme.InitialiseSmoothBreaks(programmeBreaks); _processorDateTime = processorDateTime; _programmeSpots = programmeSpots; _spotInfos = spotInfos; _runId = runId; _threadSafeCollections = threadSafeCollections; _sponsorshipRestrictionService = sponsorshipRestrictionService; _smoothConfiguration = threadSafeCollections.SmoothConfigurationReader; _smoothDiagnostics = smoothDiagnostics; _smoothPassBookedExecuter = new SmoothPassBookedExecuter( _smoothDiagnostics, _smoothResources, _smoothProgramme, sponsorshipRestrictionService, allProgrammesForPeriodAndSalesArea, RaiseInfo, RaiseException); _smoothPassDefaultExecuter = new SmoothPassDefaultExecuter( _smoothDiagnostics, _smoothResources, _smoothProgramme, sponsorshipRestrictionService, allProgrammesForPeriodAndSalesArea, _smoothConfiguration, clashExposureCountService, _threadSafeCollections.ClashesByExternalRef, _threadSafeCollections.ProductsByExternalRef, RaiseException); _smoothPassUnplacedExecuter = new SmoothPassUnplacedExecuter( _smoothDiagnostics, _smoothResources, _smoothProgramme, sponsorshipRestrictionService, allProgrammesForPeriodAndSalesArea, _smoothConfiguration, clashExposureCountService, _threadSafeCollections.ClashesByExternalRef, RaiseException); if (_smoothConfiguration.ClashExceptionCheckEnabled) { _smoothResources.ClashExceptionChecker = new ClashExceptionChecker( threadSafeCollections.ClashExceptions, products, clashes ); } if (_smoothConfiguration.RestrictionCheckEnabled) { _smoothResources.RestrictionChecker = new RestrictionChecker( threadSafeCollections.Restrictions, products, clashes, threadSafeCollections.IndexTypes, threadSafeCollections.Universes, ratingsPredictionSchedules); } _smoothFailuresFactory = new SmoothFailuresFactory(_smoothConfiguration); _smoothRecommendationsFactory = new SmoothRecommendationsFactory(_smoothConfiguration); }
public ProductClashFactorScore(IClashExposureCountService effectiveClashExposureCount) { _effectiveClashExposureCount = effectiveClashExposureCount; }