/// <summary>
 /// Determines if an option set is one of the customer address 1 or 2 option sets.
 /// </summary>
 /// <param name="entity">The CRM <c>Entity</c> currently being integrated.</param>
 /// <param name="field">The <see cref="FieldDefinition"/> for the CRM attribute currently being integrated.</param>
 /// <returns>True if the field is one of the customer address 1 or 2 fields, false otherwise.</returns>
 internal static bool IsSpecialAddressPicklist(Entity entity, FieldDefinition field)
 {
     return entity.LogicalName == "customeraddress" && GetSpecialAddressPicklistFields().Contains(field.Name) && entity.Contains("addressnumber") && IsAddressOneOrTwo(entity);
 }
        /// <summary>
        /// Validates that a product is not new when retrieving from the product catalog
        /// </summary>
        /// <param name="product">The <c>Entity</c> that contains the <c>product</c> that was retrieved</param>
        /// <param name="productKey">The value of the product's dynamics_integrationkey</param>
        public static void ValidateInventoriedProduct(Entity product, string productKey)
        {
            if (product == null)
            {
                throw new AdapterException(string.Format(CultureInfo.CurrentCulture, Resources.ArgumentNullExceptionMessage), new ArgumentNullException("product")) { ExceptionId = AdapterException.SystemExceptionGuid };
            }

            if (product.Contains(CRM2011AdapterUtilities.IsNew) && (bool)product[CRM2011AdapterUtilities.IsNew] == true)
            {
                throw new AdapterException(string.Format(CultureInfo.CurrentCulture, Resources.NonIntegratedProductSuppliedExceptionMessage, productKey)) { ExceptionId = ErrorCodes.ProductNotFound };
            }
        }
        /// <summary>
        /// Determines if the supplied CRM <c>Entity</c> is address 1 or 2.
        /// </summary>
        /// <param name="childEntity">The CRM <c>customeraddress</c> to be checked.</param>
        /// <returns>True if the <c>customeraddress</c> that was supplied is address 1 or 2.</returns>
        internal static bool IsAddressOneOrTwo(Entity childEntity)
        {
            if (childEntity.Contains("addressnumber"))
            {
                int addressNumber = (int)childEntity["addressnumber"];
                return addressNumber == 1 || addressNumber == 2;
            }

            return false;
        }
        /// <summary>
        /// Assigns an object to be the value for a property on a <c>Entity</c>.
        /// </summary>
        /// <param name="reference">The <c>object</c> be assigned as the value</param>
        /// <param name="entity">The <c>Entity</c> to be assigned to</param>
        /// <param name="propertyToBeAssignedValue">The name of the property on the <c>Entity</c> to assign the supplied object to</param>
        /// <remarks>If the <c>object</c> is null, nothing is assigned to the property</remarks>
        protected static void AssignReferencePropertyValue(EntityReference reference, Entity entity, string propertyToBeAssignedValue)
        {
            if (entity == null)
            {
                throw new AdapterException(string.Format(CultureInfo.CurrentCulture, Resources.ArgumentNullExceptionMessage), new ArgumentNullException("entity")) { ExceptionId = AdapterException.SystemExceptionGuid };
            }

            // These checks are only for updates
            if (entity.Contains(CRM2011AdapterUtilities.IsNew) && !(bool)entity[CRM2011AdapterUtilities.IsNew])
            {
                if (entity.Contains(propertyToBeAssignedValue))
                {
                    if (reference == null)
                    {
                        // Since the reference entity supplied is null, remove the property from the retrieved entity to avoid a potential update storm
                        entity.Attributes.Remove(propertyToBeAssignedValue);
                    }
                    else if (((EntityReference)entity[propertyToBeAssignedValue]).Id == reference.Id)
                    {
                        // Since this property has the same value we are trying to assign it, remove it to avoid a potential update storm
                        entity.Attributes.Remove(propertyToBeAssignedValue);
                    }
                    else
                    {
                        entity[propertyToBeAssignedValue] = reference;
                    }

                    return;
                }
            }

            // This is a new instance or the existing instance did not contain this property when it was retrieved
            if (reference != null)
            {
                entity[propertyToBeAssignedValue] = reference;
            }
        }
        /// <summary>
        /// Used to actually create instances of the child entities in an inherited class.
        /// </summary>
        /// <param name="parentKey">The <c>Key</c> of the parent entity.</param>
        /// <param name="childEntity">The child entity to be created in the form of a <c>Entity</c>.</param>
        /// <param name="collectionFieldName">The name of the field in the <c>ObjectProvider</c>'s configuration file that is being mapped currently.</param>
        protected virtual void CreateUpdateChildInstanceForField(Guid parentKey, Entity childEntity, string collectionFieldName)
        {
            if (parentKey == null || childEntity == null)
            {
                throw new AdapterException(string.Format(CultureInfo.CurrentCulture, Resources.ArgumentNullExceptionMessage)) { ExceptionId = AdapterException.SystemExceptionGuid };
            }

            if (!childEntity.Contains(childEntity.LogicalName + "id"))
            {
                // Set a default value of parnet entity name + id
                string parentAttribName = this.ProvidedEntityName + "id";

                // Select the child entity's type def
                TypeDefinition childType = this.ObjectDefinition.Types.SingleOrDefault(td => td.Name == childEntity.LogicalName);
                if (childType != null)
                {
                    // Query to limit the number of fields on the child type we iterate over when looking for the parent field
                    var childFields = from childField in childType.Children
                                      where childField.AdditionalAttributes != null
                                      select childField;
                    foreach (FieldDefinition fieldDef in childFields)
                    {
                        XmlAttribute attrib = fieldDef.AdditionalAttributes.FirstOrDefault(at => at.Name == CRM2011AdapterUtilities.IsParentField);
                        if (attrib != null && attrib.Value.ToUpperInvariant() == true.ToString().ToUpperInvariant())
                        {
                            // Set the parent field's name and break out of the foreach loop
                            parentAttribName = fieldDef.Name;
                            break;
                        }
                    }
                }

                childEntity[parentAttribName] = new EntityReference(this.ProvidedEntityName, parentKey);
                this.CreateNewEntity(childEntity);
            }
            else
            {
                this.UpdateEntity(childEntity);
            }
        }
        /// <summary>
        /// Removes properties and sets state for an entity
        /// </summary>
        /// <param name="entity">A <c>Entity</c> to prep for an update operation.</param>
        private void PrepEntityForUpdate(Entity entity)
        {
            entity.Attributes.Remove(CRM2011AdapterUtilities.IsNew);
            this.SetState(entity);
            if (entity.Contains("owninguser") && entity["owninguser"].GetType().Equals(typeof(EntityReference)))
            {
                this.SetOwner(entity);
            }

            RemoveStateCode(entity);
            RemoveStatusCode(entity);
        }
        /// <summary>
        /// Removes the status code from a <c>Entity</c>
        /// </summary>
        /// <param name="entity">The <c>Entity</c> to remove the status code from</param>
        /// <returns>The value of the status code that was removed</returns>
        private static OptionSetValue RemoveStatusCode(Entity entity)
        {
            OptionSetValue status = null;
            if (entity.Contains("statuscode") && entity["statuscode"] != null)
            {
                status = (OptionSetValue)entity["statuscode"];
                entity.Attributes.Remove("statuscode");
            }

            return status;
        }
 /// <summary>
 /// Removes properties from the <c>Entity</c> that are not needed.
 /// </summary>
 /// <param name="entity">The <c>Entity</c> that is being created / updated.</param>
 /// <param name="dictionary">The <c>Dictionary</c> that contains the data to placed into the supplied <c>DynmicEntity</c></param>
 private static void RemoveProperties(Entity entity, Dictionary<string, object> dictionary)
 {
     // Only loop if this is an update
     if (entity.Contains(CRM2011AdapterUtilities.IsNew) && !(bool)entity[CRM2011AdapterUtilities.IsNew])
     {
         var updateProperties = from property in entity.Attributes where dictionary.Keys.Contains(property.Key) || property.Key == CRM2011AdapterUtilities.IsNew || property.Key == entity.LogicalName + "id" || property.Key == "addressnumber" || CRM2011AdapterUtilities.GetSpecialAddressPicklistFields().Contains(property.Key) select property;
         entity.Attributes = new AttributeCollection();
         updateProperties.ToList().ForEach(prop => entity.Attributes.Add(prop));
     }
 }
 /// <summary>
 /// Checks if the state of an entity is already properly set and removes it if it is, otherwise it is set.
 /// </summary>
 /// <param name="dictionary">The <c>Dictionary</c> that contains the state to be set on the entity.</param>
 /// <param name="entity">The CRM <c>Entity</c> to set the state on.</param>
 /// <param name="propertyName">The state code property name.</param>
 /// <param name="adapter">The <see cref="DynamicCrmAdapter"/> to be used for state name to value conversions.</param>
 private static void CheckStateAndStatus(Dictionary<string, object> dictionary, Entity entity, string propertyName, DynamicCrmAdapter adapter)
 {
     int stateToSet = (int)dictionary[propertyName];
     if (!entity.Contains(propertyName) || CRM2011AdapterUtilities.ConvertStateNameToValue(entity[propertyName].ToString(), entity.LogicalName, adapter) != stateToSet)
     {
         entity[propertyName] = new OptionSetValue(stateToSet);
     }
     else
     {
         entity.Attributes.Remove(propertyName);
         if (entity.Contains("statuscode"))
         {
             entity.Attributes.Remove("statuscode");
         }
     }
 }
        /// <summary>
        /// Sets the state code for this instance.
        /// </summary>
        /// <param name="entity">The <c>Entity</c> to set the state code for.</param>
        protected void SetState(Entity entity)
        {
            if (entity != null && entity.Contains("statecode"))
            {
                if (!entity.Contains("statuscode"))
                {
                    entity["statuscode"] = new OptionSetValue(-1);
                }

                OrganizationRequest request = this.GetSetStateRequest(((OptionSetValue)entity["statecode"]).Value, ((OptionSetValue)entity["statuscode"]).Value, entity.Id);
                if (request != null)
                {
                    try
                    {
                        this.CallCrmExecuteWebMethod(request);
                    }
                    catch (AdapterException ae)
                    {
                        if (ae.ExceptionId == ErrorCodes.CrmPlatformException)
                        {
                            ae.ExceptionId = ErrorCodes.StateSettingError;
                        }

                        throw;
                    }
                }
            }
        }