/// <summary>
        /// Recursively initialises a control list.
        /// </summary>
        /// <param name="container">The container to initialise.</param>
        /// <param name="controlList">The control list.</param>
        private void InitControlList(Dictionary<string, object> container, ControlList controlList)
        {
            var controls = controlList.Flatten().OfType<IControlWithDefaultValue>().Cast<ValueControl>();
            foreach (var valueControl in controls)
            {
                if (valueControl != null)
                {
                    var initialValue = this.GetInitialControlValue(valueControl);
                    var stringValue = initialValue as string;
                    if (stringValue != null && stringValue == string.Empty)
                    {
                        continue;
                    }

                    var enumerable = initialValue as IEnumerable<object>;
                    if (enumerable != null && !enumerable.Any())
                    {
                        continue;
                    }

                    container.Add(valueControl.Name, initialValue);
                }
            }
        }
        /// <summary>
        /// Gets the control access level for each control in <paramref name="controlList"/>.
        /// </summary>
        /// <param name="session">The session.</param>
        /// <param name="application">The application the user is trying to access.</param>
        /// <param name="controlList">The control list.</param>
        /// <param name="roleList">The list of roles.</param>
        /// <param name="versionNumber">The version number.</param>
        /// <param name="defaultAccessLevel">The default access level to use when there is no entitlement for a control. If not set it will default to the application base access level.</param>
        /// <returns>
        /// The control entitlements that the user has.
        /// </returns>
        public List<ControlAccess> GetControlsAccess(SecureSession session, Application application, ControlList controlList, RoleList roleList, int versionNumber, AccessLevel? defaultAccessLevel = null)
        {
            IEnumerable<Control> allControls = controlList.Flatten();
            Dictionary<string, string> userRoles = this.DetermineRolesForUser(session, roleList, application);
            ControlEntitlementList controlEntitlements = this.securityService.GetControlEntitlements(application.FormId, versionNumber, application.WorkflowState, userRoles.Keys);
            controlEntitlements.Merge();

            if (!defaultAccessLevel.HasValue)
            {
                defaultAccessLevel = this.GetApplicationAccess(session, application, roleList, versionNumber);
            }

            if (session.AuthenticatedUser.IsAdministrator())
            {
                return allControls.Select(control => new ControlAccess(control.Id, control.Type == ControlType.Calculation ? AccessLevel.Read : AccessLevel.Write)).ToList();
            }

            return allControls.Select(
                control =>
                {
                    var entitlement = controlEntitlements.FirstOrDefault(e => e.ControlId == control.Id);

                    if (control.Type == ControlType.Calculation)
                    {
                        AccessLevel calcAccessLevel;
                        if (entitlement == null)
                        {
                            calcAccessLevel = AccessLevel.Read;
                        }
                        else
                        {
                            calcAccessLevel = entitlement.AccessLevel == AccessLevel.NoAccess ? AccessLevel.NoAccess : AccessLevel.Read;
                        }

                        return new ControlAccess(control.Id, calcAccessLevel);
                    }

                    if (entitlement == null)
                    {
                        return new ControlAccess(control.Id, defaultAccessLevel.Value);
                    }

                    return new ControlAccess(control.Id, entitlement.AccessLevel);
                }).ToList();
        }
        /// <summary>
        /// Determines the list of controls that are being referenced by other controls.
        /// </summary>
        /// <param name="pages">The page list.</param>
        /// <param name="allControls">The control list.</param>
        private void FillControlReferences(PageList pages, ControlList allControls)
        {
            IEnumerable<Control> flattenedControls = null;

            // currently we need to find only the references of repeater controls (#1683). We can add other references when we need them.
            foreach (var page in pages)
            {
                page.ReferencedControls = new ControlList();
                IEnumerable<Control> controls = page.Controls.Flatten();
                foreach (var control in controls)
                {
                    if (control.Type != ControlType.Repeater)
                    {
                        continue;
                    }

                    RepeaterControl repeater = control as RepeaterControl;
                    bool hasMasterRepeater = !string.IsNullOrWhiteSpace(repeater.MasterControlName);
                    if (!hasMasterRepeater)
                    {
                        continue;
                    }

                    // flattening the control list can be expensive, so do it only if needed.
                    if (flattenedControls == null)
                    {
                        flattenedControls = allControls.Flatten().Where(c => c.Type == ControlType.Repeater);
                    }

                    Control masterRepeater = flattenedControls.FirstOrDefault(c => c.Name == repeater.MasterControlName);
                    page.ReferencedControls.Add(masterRepeater);
                }
            }
        }