Beispiel #1
0
        /// <summary>
        /// Initializes a new instance of the <see cref="DataStructureCellProtocols{TValue}"/> class.
        /// </summary>
        /// <param name="reportCache">The report cache in-context.</param>
        /// <param name="protocolFactory">The protocol factory to use when executing an <see cref="IOperationOutputCell{TValue}"/>'s <see cref="IOperationOutputCell{TValue}.Operation"/>.</param>
        /// <param name="timestampUtc">The timestamp (in UTC) to use when recording a <see cref="CellOpExecutionEventBase"/> with an <see cref="IOperationOutputCell{TValue}"/>.</param>
        /// <param name="getRecalcPhaseFunc">Func that gets the <see cref="RecalcPhase"/>.</param>
        public DataStructureCellProtocols(
            ReportCache reportCache,
            IProtocolFactory protocolFactory,
            DateTime timestampUtc,
            Func <RecalcPhase> getRecalcPhaseFunc)
        {
            if (reportCache == null)
            {
                throw new ArgumentNullException(nameof(reportCache));
            }

            // ReSharper disable once JoinNullCheckWithUsage
            if (protocolFactory == null)
            {
                throw new ArgumentNullException(nameof(protocolFactory));
            }

            if (timestampUtc.Kind != DateTimeKind.Utc)
            {
                throw new ArgumentException(Invariant($"{nameof(timestampUtc)} is not in UTC time."));
            }

            if (getRecalcPhaseFunc == null)
            {
                throw new ArgumentNullException(nameof(getRecalcPhaseFunc));
            }

            this.reportCache        = reportCache;
            this.protocolFactory    = protocolFactory;
            this.timestampUtc       = timestampUtc;
            this.getRecalcPhaseFunc = getRecalcPhaseFunc;
        }
Beispiel #2
0
        private static void ClearCells(
            this ReportCache reportCache,
            DateTime timestampUtc)
        {
            var details = Invariant($"Value cleared by {nameof(ReportExtensions)}.{nameof(Recalc)} or async overload.");

            foreach (var operationCell in reportCache.OperationCells)
            {
                operationCell.ClearCellValue(timestampUtc, details);
            }

            details = Invariant($"Validation cleared by {nameof(ReportExtensions)}.{nameof(Recalc)} or async overload.");

            foreach (var cell in reportCache.ValidationCells)
            {
                cell.ClearValidation(timestampUtc, details);
            }

            details = Invariant($"Availability check cleared by {nameof(ReportExtensions)}.{nameof(Recalc)} or async overload.");

            foreach (var cell in reportCache.AvailabilityCheckCells)
            {
                cell.ClearAvailabilityCheck(timestampUtc, details);
            }
        }
Beispiel #3
0
        private static ChainOfResponsibilityProtocolFactory BuildProtocolFactoryToExecuteAllOperations(
            this ReportCache reportCache,
            DateTime timestampUtc,
            IReadOnlyCollection <Func <IProtocolFactory, IProtocolFactory> > protocolFactoryFuncs,
            IReadOnlyCollection <Type> additionalTypesForCoreCellOps,
            Func <RecalcPhase> getRecalcPhaseFunc)
        {
            protocolFactoryFuncs = protocolFactoryFuncs ?? new List <Func <IProtocolFactory, IProtocolFactory> >();

            if (protocolFactoryFuncs.Any(_ => _ == null))
            {
                throw new ArgumentException(Invariant($"{nameof(protocolFactoryFuncs)} contains a null element."));
            }

            additionalTypesForCoreCellOps = additionalTypesForCoreCellOps ?? new List <Type>();

            if (additionalTypesForCoreCellOps.Any(_ => _ == null))
            {
                throw new ArgumentException(Invariant($"{nameof(additionalTypesForCoreCellOps)} contains a null element."));
            }

            var result = new ChainOfResponsibilityProtocolFactory();

            // Add caller's protocols to the chain of responsibility.
            foreach (var protocolFactoryFunc in protocolFactoryFuncs)
            {
                result.AddToEndOfChain(protocolFactoryFunc(result));
            }

            // Add DataStructureCellProtocols{TValue} and DataStructureConvenienceProtocols{TResult} to chain of responsibility.
            var typesForCoreCellOps = DefaultTypesSupportedForCoreCellOps
                                      .Concat(additionalTypesForCoreCellOps)
                                      .ToList();

            var coreProtocolsFactory = new ProtocolFactory();

            ConstructorInfo GetCellProtocolsFunc(Type type) => typeof(DataStructureCellProtocols <>).MakeGenericType(type).GetConstructors().Single();
            ConstructorInfo GetConvenienceProtocolsFunc(Type type) => typeof(DataStructureConvenienceProtocols <>).MakeGenericType(type).GetConstructors().Single();

            var cellProtocolsConstructorInfoParams        = new object[] { reportCache, result, timestampUtc, getRecalcPhaseFunc };
            var convenienceProtocolsConstructorInfoParams = new object[] { result };

            foreach (var typeForCoreCellOps in typesForCoreCellOps)
            {
                RegisterProtocols(typeForCoreCellOps, CachedTypeToCellProtocolsConstructorInfoMap, coreProtocolsFactory, GetCellProtocolsFunc, cellProtocolsConstructorInfoParams);

                RegisterProtocols(typeForCoreCellOps, CachedTypeToConvenienceProtocolsConstructorInfoMap, coreProtocolsFactory, GetConvenienceProtocolsFunc, convenienceProtocolsConstructorInfoParams);
            }

            result.AddToEndOfChain(coreProtocolsFactory);

            return(result);
        }
Beispiel #4
0
        private static async Task ReCalcInternalAsync(
            this Report report,
            DateTime timestampUtc,
            IReadOnlyCollection <Func <IProtocolFactory, IProtocolFactory> > protocolFactoryFuncs = null,
            IReadOnlyCollection <Type> additionalTypesForCoreCellOps = null)
        {
            // NOTE: THIS CODE IS A NEAR DUPLICATE OF THE SYNC METHOD ABOVE; NO GOOD WAY TO D.R.Y. IT OUT
            var recalcPhase = RecalcPhase.Unknown;

            // ReSharper disable once AccessToModifiedClosure
            RecalcPhase GetRecalcPhaseFunc() => recalcPhase;

            var reportCache = new ReportCache(report);

            var protocolFactory = reportCache.BuildProtocolFactoryToExecuteAllOperations(timestampUtc, protocolFactoryFuncs, additionalTypesForCoreCellOps, GetRecalcPhaseFunc);

            reportCache.ClearCells(timestampUtc);

            recalcPhase = RecalcPhase.CellOpExecution;

            foreach (var cell in reportCache.OperationCells)
            {
                var executeOperationCellIfNecessaryOp = cell.BuildExecuteOperationCellIfNecessaryOp();

                await protocolFactory.GetProtocolAndExecuteViaReflectionAsync(executeOperationCellIfNecessaryOp);
            }

            recalcPhase = RecalcPhase.Validation;

            foreach (var cell in reportCache.ValidationCells)
            {
                var validateCellIfNecessaryOp = new ValidateCellIfNecessaryOp(cell);

                await protocolFactory.GetProtocolAndExecuteViaReflectionAsync(validateCellIfNecessaryOp);
            }

            recalcPhase = RecalcPhase.AvailabilityCheck;

            foreach (var cell in reportCache.AvailabilityCheckCells)
            {
                var checkAvailabilityOfCellIfNecessaryOp = new CheckAvailabilityOfCellIfNecessaryOp(cell);

                await protocolFactory.GetProtocolAndExecuteViaReflectionAsync(checkAvailabilityOfCellIfNecessaryOp);
            }

            if (reportCache.PrepareToRerunRecalc(timestampUtc))
            {
                await report.ReCalcInternalAsync(timestampUtc, protocolFactoryFuncs, additionalTypesForCoreCellOps);
            }
        }
Beispiel #5
0
        private static bool PrepareToRerunRecalc(
            this ReportCache reportCache,
            DateTime timestampUtc)
        {
            var validityIsUnknown = reportCache.ValidationCells.Any(_ => _.GetValidity() == Validity.Unknown);

            var availabilityIsUnknown = reportCache.AvailabilityCheckCells.Any(_ => _.GetAvailability() == Availability.Unknown);

            bool result;

            if (validityIsUnknown || availabilityIsUnknown)
            {
                result = false;
            }
            else
            {
                var disabledInputCellsWithValues = reportCache
                                                   .InputCells
                                                   .Where(_ => _.GetAvailability() == Availability.Disabled)
                                                   .Where(_ => _.HasCellValue())
                                                   .ToList();

                if (disabledInputCellsWithValues.Any())
                {
                    foreach (var disabledInputCellWithValue in disabledInputCellsWithValues)
                    {
                        disabledInputCellWithValue.ClearCellValue(timestampUtc, Invariant($"{nameof(ReportExtensions)}.{nameof(Recalc)} found this disabled input cell having a value.  Clearing the value and will re-run recalc."));
                    }

                    result = true;
                }
                else
                {
                    result = false;
                }
            }

            return(result);
        }