public SmoothScenarioExecutor( ISmoothDiagnostics smoothDiagnostics, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, SponsorshipRestrictionService sponsorshipRestrictionService) { _smoothDiagnostics = smoothDiagnostics; _spotInfos = spotInfos; _sponsorshipRestrictionService = sponsorshipRestrictionService; }
/// <summary> /// <para> Adds spots to break. If multiple spots are being /// added then they're typically related. E.g. TOP & TAIL. /// </para> /// <para> The break sequence will be updated later when the break has /// been filled, will be updated to start from 1. For specific positions /// (FIB, SIB etc) then the break sequence is assigned as a large positive /// or negative number and everything else is inserted between. /// </para> /// </summary> public static List <SmoothSpot> AddSpotsToBreak( SmoothBreak smoothBreak, int smoothPassSequence, int smoothPassIterationSequence, IReadOnlyCollection <Spot> spots, SpotPositionRules passRequestedPositionInBreakRules, bool canMoveSpotToOtherBreak, ICollection <Guid> spotIdsUsed, string bestBreakFactorGroupName, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, SponsorshipRestrictionService sponsorshipRestrictionService ) { var smoothSpots = new List <SmoothSpot>(); foreach (Spot spot in spots) { IReadOnlyDictionary <string, bool> hasSpotPositions = smoothBreak.GetSpotPositions(); int breakSeq = SpotPositioning.GetBreakSequenceNumber( smoothBreak, passRequestedPositionInBreakRules, spot, hasSpotPositions ); // Default break sequence to middle of break if (breakSeq == 0) { breakSeq = SpotPositioning.GetBreakSeqForMiddleOfBreak(smoothBreak); } smoothSpots.Add( smoothBreak.AddSpot( spot, smoothPassSequence, smoothPassIterationSequence, breakSeq, currentSpot: true, canMoveSpotToOtherBreak, bestBreakFactorGroupName, spotInfos[spot.Uid].ExternalBreakRefAtRunStart ) ); sponsorshipRestrictionService.TriggerRecalculationOfAllowedRestrictionLimits( SpotAction.AddSpot, spot, smoothBreak.TheBreak ); FlagSpotAsUsed(spot, spotIdsUsed); } return(smoothSpots); }
public SmoothPassBookedExecuter( ISmoothDiagnostics smoothDiagnostics, SmoothResources smoothResources, SmoothProgramme smoothProgramme, SponsorshipRestrictionService sponsorshipRestrictionService, IReadOnlyCollection <Programme> allProgrammesForPeriodAndSalesArea, Action <string> raiseInfo, Action <string, Exception> raiseException ) { _smoothDiagnostics = smoothDiagnostics; _smoothResources = smoothResources; _sponsorshipRestrictionService = sponsorshipRestrictionService; _allProgrammesForPeriodAndSalesArea = allProgrammesForPeriodAndSalesArea; _smoothProgramme = smoothProgramme; RaiseInfo = raiseInfo; RaiseException = raiseException; }
public static void RemoveSpotFromBreak( SmoothBreak smoothBreak, Spot spot, ICollection <Guid> spotIdsUsed, SponsorshipRestrictionService sponsorshipRestrictionService ) { smoothBreak.RemoveSpot(spot); if (spotIdsUsed.Contains(spot.Uid)) { _ = spotIdsUsed.Remove(spot.Uid); } sponsorshipRestrictionService.TriggerRecalculationOfAllowedRestrictionLimits( SpotAction.RemoveSpot, spot, smoothBreak.TheBreak ); }
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; }
private static void ValidateWithSponsorshipRestrictions( SmoothBreak theSmoothBreak, SponsorshipRestrictionService sponsorshipRestrictionsService, SmoothFailureMessagesForSpotsCollection result, IReadOnlyCollection <Spot> spotsAlreadyInTheBreak, Spot spot) { Break theBreak = theSmoothBreak.TheBreak; IReadOnlyCollection <(Guid spotUid, SmoothFailureMessages failureMessage)> serviceResult = sponsorshipRestrictionsService.CheckSponsorshipRestrictions( spot, theBreak.ExternalBreakRef, theBreak.ScheduledDate, theBreak.Duration, spotsAlreadyInTheBreak ); foreach ((Guid spotUid, SmoothFailureMessages failureMessage) in serviceResult) { result.Add(spotUid, failureMessage); } }
/// <summary> /// Add booked spots to break to stop overbooking /// </summary> public static List <SmoothSpot> AddBookedSpotsToBreak( SmoothBreak smoothBreak, IReadOnlyCollection <Spot> spots, IReadOnlyDictionary <Guid, SpotInfo> spotInfos, ISet <Guid> spotIdsUsed, SponsorshipRestrictionService sponsorshipRestrictionService ) { if (smoothBreak is null) { throw new ArgumentNullException(nameof(smoothBreak)); } if (spots is null) { throw new ArgumentNullException(nameof(spots)); } if (spotInfos is null) { throw new ArgumentNullException(nameof(spotInfos)); } if (spotIdsUsed is null) { throw new ArgumentNullException(nameof(spotIdsUsed)); } var smoothSpots = new List <SmoothSpot>(); foreach (var spot in spots) { int breakSeq; if (spot.IsMultipartSpot) { breakSeq = SpotPositioning.GetBreakSeqFromMultipartSpotPosition( spot.MultipartSpot, spot.MultipartSpotPosition); } else { breakSeq = SpotPositioning.GetBreakSeqFromRequestedPositionInBreakOrActualPositionInBreak( spot.RequestedPositioninBreak, spot.ActualPositioninBreak); } smoothSpots.Add( smoothBreak.AddSpot( spot, smoothPassSequence: 0, smoothPassIterationSequence: 0, breakSeq, currentSpot: false, canMoveSpotToOtherBreak: false, bestBreakFactorGroupName: null, spotInfos[spot.Uid].ExternalBreakRefAtRunStart) ); sponsorshipRestrictionService.TriggerRecalculationOfAllowedRestrictionLimits( SpotAction.AddSpot, spot, smoothBreak.TheBreak ); FlagSpotAsUsed(spot, spotIdsUsed); } return(smoothSpots); }
/// <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)); }