Пример #1
0
 public SmoothScenarioExecutor(
     ISmoothDiagnostics smoothDiagnostics,
     IReadOnlyDictionary <Guid, SpotInfo> spotInfos,
     SponsorshipRestrictionService sponsorshipRestrictionService)
 {
     _smoothDiagnostics             = smoothDiagnostics;
     _spotInfos                     = spotInfos;
     _sponsorshipRestrictionService = sponsorshipRestrictionService;
 }
Пример #2
0
        /// <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);
        }
Пример #3
0
        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;
        }
Пример #4
0
        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
                );
        }
Пример #5
0
 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);
            }
        }
Пример #7
0
        /// <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));
        }