/// <summary>
        /// Converts <paramref name="results"/> to a list of anonymous objects.
        /// </summary>
        /// <param name="results">The validation results to convert.</param>
        /// <param name="controlList">The control metadata list.</param>
        /// <param name="firstError">When the method returns, will contain the earliest control that has an error.</param>
        /// <returns>A new list of anonymous objects.</returns>
        public static Dictionary<string, List<string>> ConvertValidationResultsToErrorMessages(ValidationResults results, ControlList controlList, out Control firstError)
        {
            int minPos = int.MaxValue;
            firstError = null;

            Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
            foreach (ValidationResult result in results)
            {
                string errorKey = Regex.Replace(result.Key, "[" + Regex.Escape(".[") + "\\]]+", "-");
                if (!errors.ContainsKey(errorKey))
                {
                    errors.Add(errorKey, new List<string>());
                }

                errors[errorKey].Add(result.Message);
                string controlName = Regex.Match(errorKey, "[a-z0-9_]+$", RegexOptions.IgnoreCase).Value;
                Control control = controlList.FindRecursive(controlName);
                if (control == null)
                {
                    controlName = Regex.Match(errorKey, "[a-z0-9_]+(?=-" + controlName + "$)", RegexOptions.IgnoreCase).Value;
                    control = controlList.FindRecursive(controlName);
                }

                if (control.Position < minPos)
                {
                    minPos = control.Position;
                    firstError = control;
                }
            }

            return errors;
        }
        /// <summary>
        /// Renders <paramref name="control"/> to the <paramref name="document"/>.
        /// </summary>
        /// <param name="document">The PDF document.</param>
        /// <param name="control">The control to be rendered.</param>
        /// <param name="level">The depth down the control tree being rendered (affects indenting).</param>
        /// <param name="controlList">The complete control list.</param>
        protected override void DoRender(Document document, Control control, int level, ControlList controlList)
        {
            IControlWithOptions controlWithOptions = control as IControlWithOptions;
            string suffix = string.Format(" {0}", controlWithOptions.AllowMultipleSelect ? PdfResources.IndicateAll : PdfResources.IndicateOne);
            FormattedText formattedSuffix = new FormattedText
                                            {
                                                Style = StyleNames.Normal,
                                                Italic = true
                                            };
            formattedSuffix.AddText(suffix);
            this.Label.Add(formattedSuffix);

            RepeaterOptionSource optionSource = controlWithOptions.OptionSource as RepeaterOptionSource;
            RepeaterControl repeater = controlList.FindRecursive<RepeaterControl>(optionSource.RepeaterName);
            ControlList valueList = new ControlList();
            valueList.AddRange(optionSource.ValueFields.Select(valueField => repeater.Controls.FindRecursive<Control>(valueField)));

            for (int i = 1; i <= (repeater.MaximumCount ?? PdfConstants.DefaultRepeaterLength); i++)
            {
                this.ListRenderer.Render(valueList, this.Factory, level, controlList);
            }
        }
        /// <summary>
        /// Gets the replacement string for a token.
        /// </summary>
        /// <param name="token">The token being replaced.</param>
        /// <param name="format">A format string.</param>
        /// <param name="application">The application to source data from.</param>
        /// <param name="controls">The controls.</param>
        /// <param name="path">Specifies the path to the token.</param>
        /// <param name="defaultReplaceValue">The default replace value.</param>
        /// <returns>
        /// The replacement string.
        /// </returns>
        /// <remarks>
        /// Order of precedence: (1) Timestamp; (2) <paramref name="application" /> object; (3) application data.
        /// </remarks>
        private string GetReplacementString(string token, string format, Application application, ControlList controls, ApplicationDataPath path, string defaultReplaceValue)
        {
            Control control = controls.FindRecursive(c => c.Name == token);
            object value = this.GetTokenValue(token, application, control, path);
            if (value == null)
            {
                return defaultReplaceValue;
            }

            if (value is Array)
            {
                object[] valueArray = value as object[];
                StringBuilder builder = new StringBuilder();
                if (valueArray.Length == 0)
                {
                    return defaultReplaceValue;
                }

                string appendFormat = valueArray[0] is string ? "'{0}'" : "{0}";
                builder.AppendFormat(appendFormat, valueArray[0]);
                for (var i = 1; i < valueArray.Length; i++)
                {
                    builder.Append(",");
                    builder.AppendFormat(appendFormat, valueArray[i]);
                }

                return builder.ToString();
            }

            string formatString = string.IsNullOrEmpty(format) ? "{0}" : string.Format("{{0:{0}}}", format.Substring(1, format.Length - 2));
            return string.Format(CultureInfo.CurrentCulture, formatString, value);
        }
        /// <summary>
        /// Validates an application.
        /// </summary>
        /// <param name="application">The application to validate.</param>
        /// <param name="pagesToValidate">The pagesToValidate to validate.</param>
        /// <param name="controls">A list of all controls.</param>
        /// <param name="controlsAccess">The control access list for the current user.</param>
        /// <param name="subpageControlId">The id of the control acting as the current subpage. If <see langword="null" />, then all controls are validated.</param>
        /// <param name="product">The product object.</param>
        /// <returns>
        /// The <see cref="ValidationResults" />.
        /// </returns>
        private ValidationResults ValidateApplication(Application application, PageList pagesToValidate, ControlList controls, List<ControlAccess> controlsAccess, int? subpageControlId = null, ProductDefinition product = null)
        {
            List<ControlWithOptions> controlsWithOptions = controls.FindAllRecursive<ControlWithOptions>();

            if (controlsWithOptions.Any())
            {
                this.RegisterOptionControls(application.FormOrganisationId, true, controlsWithOptions, application.ApplicationData);
            }

            var controlList = pagesToValidate.AllControls;
            var ruleList = pagesToValidate.AllRules;

            if (subpageControlId != null)
            {
                var subpageControl = controlList.FindRecursive<GroupControl>(x => x.Id == subpageControlId);
                if (subpageControl != null)
                {
                    controlList = new ControlList { subpageControl };

                    TruthConditionList validRules = new TruthConditionList();
                    validRules.AddRange(ruleList.Where(rule => controlList.FindRecursive(x => x.Id.ToString().Equals(((ValidateTruthCondition)rule).Error.Position)) != null));

                    ruleList = validRules;
                }
            }

            ServiceEndpointList endpointList = pagesToValidate.AllExternalRuleHandlers.Count > 0 ?
                     this.DataAccess.GetServiceEndpointList() :
                     new ServiceEndpointList();

            RegexValidatorList regexValidators = this.DataAccess.GetValidatorList();

            if (product != null)
            {
                this.FillControlReferences(pagesToValidate, product.FormDefinition.Pages.AllControls);
                foreach (var referencedControls in pagesToValidate.Select(p => p.ReferencedControls))
                {
                    foreach (var control in referencedControls)
                    {
                        var exists = controls.FindRecursive(control.Name) != null;
                        if (exists)
                        {
                            continue;
                        }

                        controls.AddRange(referencedControls);
                    }
                }
            }

            ApplicationValidator validator = new ApplicationValidator(controls, controlList, controlsAccess, ruleList, pagesToValidate.AllExternalRuleHandlers, endpointList, this.endpointCommunicator, regexValidators);
            return validator.Validate(application);
        }