public static FluentValidation.Results.ValidationResult Validate(RawTakeRateData data)
        {
            FluentValidation.Results.ValidationResult featureLevelResults = null;
            FluentValidation.Results.ValidationResult modelLevelResults   = null;
            FluentValidation.Results.ValidationResult featureMixResults   = null;

            // Bit of a hack here, we need to bind a reference to all of the available feature packs
            // to each individual feature pack. This is needed as for pack item take rates, the take is the sum of any feature packs
            // containing that item. We could validate at a higher level, but then we won't be able to identify which pack is in error

            foreach (var pack in data.FeaturePacks)
            {
                pack.AllPacks = data.FeaturePacks;
            }

            Parallel.Invoke(
                () => featureLevelResults = TakeRateDataValidator.ValidateData(data),
                () => modelLevelResults   = TakeRateSummaryValidator.ValidateData(data),
                () => featureMixResults   = TakeRateFeatureMixValidator.ValidateData(data)
                );

            var allErrors = featureLevelResults.Errors
                            .Concat(modelLevelResults.Errors)
                            .Concat(featureMixResults.Errors);

            var validationFailures = allErrors as IList <ValidationFailure> ?? allErrors.ToList();

            return(new FluentValidation.Results.ValidationResult(validationFailures));
        }
        public static FluentValidation.Results.ValidationResult ValidateData(RawTakeRateData data)
        {
            var validator = new TakeRateFeatureMixValidator();

            return(validator.Validate(data));
        }