/// <summary>
        /// Sets the internal attribute value collection with the initial values contained in the dictionary
        /// </summary>
        /// <param name="values">The initial attributes and values to set</param>
        /// <param name="permissions">The permission hints for the attributes</param>
        private void SetInitialAttributeValues(Dictionary <string, List <string> > values, Dictionary <string, AttributePermission> permissions)
        {
            this.attributes         = new AttributeValueCollection();
            this.HasPermissionHints = false;

            foreach (KeyValuePair <string, List <string> > kvp in values)
            {
                string attributeName      = kvp.Key;
                AttributeTypeDefinition d = this.ObjectType[attributeName];
                AttributePermission     p = AttributePermission.Unknown;

                if (permissions != null)
                {
                    if (permissions.ContainsKey(attributeName))
                    {
                        p = permissions[attributeName];

                        if (p != AttributePermission.Unknown)
                        {
                            this.HasPermissionHints = true;
                        }
                    }
                }

                if (d != null)
                {
                    if (!d.IsMultivalued && kvp.Value.Count > 1)
                    {
                        throw new InvalidOperationException($"The attribute {d.SystemName} is listed in the schema as a multivalued attribute, but more than one value was returned");
                    }

                    if (kvp.Value.Count == 0)
                    {
                        this.attributes.Add(d.SystemName, new AttributeValue(d, p));
                        continue;
                    }

                    if (d.IsMultivalued)
                    {
                        this.attributes.Add(d.SystemName, new AttributeValue(d, p, kvp.Value));
                    }
                    else
                    {
                        this.attributes.Add(d.SystemName, new AttributeValue(d, p, kvp.Value.First()));
                    }

                    if (d.SystemName == AttributeNames.Locale)
                    {
                        this.Locale = new CultureInfo(kvp.Value.First());
                    }
                }
            }

            this.AddRemainingAttributesFromSchema();
        }
        private static void LoadNameValidationRegularExpressions()
        {
            ObjectTypeDefinition    objectTypeDefinition = ResourceManagementSchema.ObjectTypes[ObjectTypeNames.AttributeTypeDescription];
            AttributeTypeDefinition nameAttribute        = objectTypeDefinition.Attributes.First(t => t.SystemName == AttributeNames.Name);

            ResourceManagementSchema.AttributeNameValidationRegex = new Regex(nameAttribute.Regex);

            objectTypeDefinition = ResourceManagementSchema.ObjectTypes[ObjectTypeNames.ObjectTypeDescription];
            nameAttribute        = objectTypeDefinition.Attributes.First(t => t.SystemName == AttributeNames.Name);
            ResourceManagementSchema.ObjectTypeNameValidationRegex = new Regex(nameAttribute.Regex);
        }
        /// <summary>
        /// Gets a list of attribute changes as Put fragments for submission to the Resource Management Service
        /// </summary>
        /// <returns>A list of PutFragmentType objects containing all the value changes pending on the object</returns>
        internal List <PutFragmentType> GetPutFragements()
        {
            List <PutFragmentType> fragments = new List <PutFragmentType>();

            foreach (KeyValuePair <string, List <AttributeValueChange> > kvp in this.PendingChanges)
            {
                AttributeTypeDefinition type = this.ObjectType[kvp.Key];

                if (ResourceManagementSchema.ComputedAttributes.Contains(type.SystemName))
                {
                    continue;
                }

                foreach (AttributeValueChange change in kvp.Value)
                {
                    string value = null;

                    if (change.Value != null)
                    {
                        switch (type.Type)
                        {
                        case AttributeType.Binary:
                            value = Convert.ToBase64String((byte[])change.Value);
                            break;

                        case AttributeType.DateTime:
                            value = ((DateTime)change.Value).ToResourceManagementServiceDateFormat();
                            break;

                        case AttributeType.Integer:
                        case AttributeType.Boolean:
                        case AttributeType.String:
                        case AttributeType.Text:
                            value = change.Value.ToString();
                            break;

                        case AttributeType.Reference:
                            value = ((UniqueIdentifier)change.Value).ToString();
                            break;

                        case AttributeType.Unknown:
                        default:
                            throw new ArgumentException(string.Format("Unknown value type {0}", change.Value.GetType().Name));
                        }
                    }

                    PutFragmentType fragment = new PutFragmentType(kvp.Key, change.ChangeType, kvp.Key, null, false, value);
                    fragments.Add(fragment);
                }
            }

            return(fragments);
        }
        /// <summary>
        /// Initializes a new instance of the AttributeValue class
        /// </summary>
        /// <param name="type">The definition of the attribute to hold the values for</param>
        /// <param name="value">The initial value of the attribute</param>
        internal AttributeValue(AttributeTypeDefinition type, object value)
        {
            this.Attribute = type;

            if (this.Attribute.IsMultivalued)
            {
                this.initialValues = new List <object>();
                this.values        = new List <object>();
                this.SetMultiValue(value, true);
            }
            else
            {
                this.SetSingleValue(value, true);
            }
        }
        /// <summary>
        /// Gets a value indicating whether the specific attribute is multivalued
        /// </summary>
        /// <param name="attributeName">The attribute name</param>
        /// <returns>A value indicating whether the specific attribute is multivalued</returns>
        public static bool IsAttributeMultivalued(string attributeName)
        {
            ResourceManagementSchema.LoadSchema(ResourceManagementClient.EndpointManager);

            foreach (ObjectTypeDefinition objectType in ResourceManagementSchema.ObjectTypes.Values)
            {
                AttributeTypeDefinition attributeType = objectType.Attributes.FirstOrDefault(t => t.SystemName == attributeName);

                if (attributeType != null)
                {
                    return(attributeType.IsMultivalued);
                }
            }

            throw new NoSuchAttributeException(attributeName);
        }
        /// <summary>
        /// Initializes a new instance of the AttributeValue class
        /// </summary>
        /// <param name="type">The definition of the attribute to hold the values for</param>
        /// <param name="permission">The user's permission on this attribute, if known</param>
        /// <param name="value">The initial value of the attribute</param>
        internal AttributeValue(AttributeTypeDefinition type, AttributePermission?permission, object value)
        {
            this.Attribute         = type;
            this.hasPermissionHint = permission != null;
            this.PermissionHint    = permission ?? 0;

            if (this.Attribute.IsMultivalued)
            {
                this.initialValues = new List <object>();
                this.values        = new List <object>();
                this.SetMultiValue(value, true);
            }
            else
            {
                this.SetSingleValue(value, true);
            }
        }
        /// <summary>
        /// Gets the data type of the specific attribute
        /// </summary>
        /// <param name="attributeName">The attribute name</param>
        /// <returns>An <c>AttributeType</c> value</returns>
        public static AttributeType GetAttributeType(string attributeName)
        {
            ResourceManagementSchema.schemaLock.WaitOne();

            ResourceManagementSchema.LoadSchema(ResourceManagementClient.EndpointManager);

            foreach (ObjectTypeDefinition objectType in ResourceManagementSchema.ObjectTypes.Values)
            {
                AttributeTypeDefinition attributeType = objectType.Attributes.FirstOrDefault(t => t.SystemName == attributeName);

                if (attributeType != null)
                {
                    return(attributeType.Type);
                }
            }

            throw new NoSuchAttributeException(attributeName);
        }
        /// <summary>
        /// Sets the internal attribute value collection with the initial values contained in the dictionary
        /// </summary>
        /// <param name="values">The initial attributes and values to set</param>
        private void SetInitialAttributeValues(Dictionary<string, List<string>> values)
        {
            this.attributes = new AttributeValueCollection();

            foreach (KeyValuePair<string, List<string>> kvp in values)
            {
                if (kvp.Value.Count == 0)
                {
                    continue;
                }

                string attributeName = kvp.Key;
                AttributeTypeDefinition d = this.ObjectType[attributeName];

                if (d != null)
                {
                    if (!d.IsMultivalued && kvp.Value.Count > 1)
                    {
                        throw new InvalidOperationException("The attribute {0} is listed in the schema as a multivalued attribute, but more than one value was returned");
                    }

                    if (d.IsMultivalued)
                    {
                        this.attributes.Add(d.SystemName, new AttributeValue(d, kvp.Value));
                    }
                    else
                    {
                        this.attributes.Add(d.SystemName, new AttributeValue(d, kvp.Value.First()));
                    }

                    if (d.SystemName == AttributeNames.Locale)
                    {
                        this.Locale = new CultureInfo(kvp.Value.First());
                    }
                }
            }

            this.AddRemainingAttributesFromSchema();
        }
        /// <summary>
        /// Called by the parent ResourceManagementClient when a create operation against the Resource Management Service was successful
        /// </summary>
        /// <param name="id">The new object ID that was assigned this object</param>
        internal void CompleteCreateOperation(UniqueIdentifier id)
        {
            if (this.ModificationType != OperationType.Create)
            {
                throw new InvalidOperationException();
            }

            AttributeTypeDefinition objectID = this.ObjectType[AttributeNames.ObjectID];
            if (!this.attributes.ContainsAttribute(AttributeNames.ObjectID))
            {
                this.attributes.Add(new AttributeValue(objectID, id));
            }
            else
            {
                this.attributes[AttributeNames.ObjectID] = new AttributeValue(objectID, id);
            }

            this.CommitChanges();

            this.ModificationType = OperationType.Update;
            this.IsPlaceHolder = false;
        }
 /// <summary>
 /// Initializes a new instance of the ReadOnlyValueModificationException class
 /// </summary>
 /// <param name="attribute">The attribute that was illegally modified</param>
 public ReadOnlyValueModificationException(AttributeTypeDefinition attribute)
     : base(string.Format("An attempt was made to modify the read only attribute {0}", attribute.SystemName))
 {
 }
 /// <summary>
 /// Initializes a new instance of the AttributeValue class
 /// </summary>
 /// <param name="type">The definition of the attribute to hold the values for</param>
 internal AttributeValue(AttributeTypeDefinition type)
     : this(type, null)
 {
 }
 /// <summary>
 /// Initializes a new instance of the AttributeValue class
 /// </summary>
 /// <param name="type">The definition of the attribute to hold the values for</param>
 /// <param name="permission">The user's permission on this attribute, if known</param>
 internal AttributeValue(AttributeTypeDefinition type, AttributePermission permission)
     : this(type, permission, null)
 {
 }
 /// <summary>
 /// Initializes a new instance of the AttributeValue class
 /// </summary>
 /// <param name="type">The definition of the attribute to hold the values for</param>
 /// <param name="value">The initial value of the attribute</param>
 internal AttributeValue(AttributeTypeDefinition type, object value)
     : this(type, null, value)
 {
 }