/// <summary>
        /// Content rules determine the mandatory and optional attributes of the class instances that are stored
        /// in the directory.
        /// </summary>
        /// <param name="obj">The object of model.</param>
        public static void CheckContent(ModelObject obj)
        {
            SetContainer <string> mustContain = new SetContainer <string>();
            SetContainer <string> mayContain  = new SetContainer <string>();

            string[] ExcludeAttributes = { "instancetype", "ntsecuritydescriptor", "objectcategory", "objectsid" };
            // Compute sets of may/must attribute
            string            className      = (string)obj[StandardNames.objectClass].UnderlyingValues.Last();
            Sequence <string> superClassList = GetSuperClassList(obj.dc, className);

            foreach (string classId in superClassList)
            {
                ModelObject classObj;
                if (!obj.dc.TryGetClass(classId, out classObj))
                {
                    // will be reported in a different checker
                    continue;
                }
                mustContain.AddRange(GetAttributeSet(classObj, StandardNames.mustContain));
                mustContain.AddRange(GetAttributeSet(classObj, StandardNames.systemMustContain));
                mayContain.AddRange(GetAttributeSet(classObj, StandardNames.mayContain));
                mayContain.AddRange(GetAttributeSet(classObj, StandardNames.systemMayContain));
            }

            //Removing default excluded attributes from this list.
            foreach (string attr in ExcludeAttributes)
            {
                if (mustContain.Contains(attr))
                {
                    mustContain.Remove(attr);
                }
            }
            // Check for all attributes
            string dn = (string)obj[StandardNames.shortName];

            //For each attribute
            foreach (string attr in obj.attributes.Keys)
            {
                if (!ExcludeAttributes.Contains(attr))
                {
                    //This attribute is in must contain list.
                    if (mustContain.Contains(attr))
                    {
                        mustContain.Remove(attr);
                    }
                    //This attribute is not in must and may contian list.
                    else if (!mayContain.Contains(attr))
                    {
                        Checks.Fail("'{0}' must not contain attribute '{1}'", dn, attr);
                    }
                }
            }

            //If must contain list is not empty, this object does not contain some must contain attributes.
            if (mustContain.Count > 0)
            {
                Checks.Fail(
                    "'{0}' does not contain required attributes '{1}'",
                    dn,
                    String.Join(",", mustContain.ToArray()));
            }
        }
        public void ValidateContentRulesRequirements(DirectoryEntries childrens, IEnumerable <IObjectOnServer> serverObjects)
        {
            bool isContent = true;

            //Setting some excluded attributes.
            SetContainer <string> ExcludedAttributes = new SetContainer <string>();

            ExcludedAttributes.Add("creationTime");
            ExcludedAttributes.Add("forceLogoff");
            ExcludedAttributes.Add("lockoutDuration");
            ExcludedAttributes.Add("lockOutObservationWindow");
            ExcludedAttributes.Add("lockoutThreshold");
            ExcludedAttributes.Add("maxPwdAge");
            ExcludedAttributes.Add("minPwdAge");
            ExcludedAttributes.Add("minPwdLength");
            ExcludedAttributes.Add("modifiedCountAtLastProm");
            ExcludedAttributes.Add("nextRid");
            ExcludedAttributes.Add("pwdProperties");
            ExcludedAttributes.Add("pwdHistoryLength");
            ExcludedAttributes.Add("objectSid");
            ExcludedAttributes.Add("serverState");
            ExcludedAttributes.Add("uASCompat");
            ExcludedAttributes.Add("modifiedCount");


            //For each domain NC object...
            foreach (DirectoryEntry entry in childrens)
            {
                SetContainer <string> mustContain = new SetContainer <string>();
                SetContainer <string> mayContain  = new SetContainer <string>();

                //Get super class chain.
                object[] superClasses = (object[])entry.Properties[StandardNames.objectClass.ToLower()].Value;

                //For each super class...
                foreach (string superClass in superClasses)
                {
                    foreach (IObjectOnServer serverObj in serverObjects)
                    {
                        //Get the object from server.
                        if (serverObj.Name.StartsWith(superClass))
                        {
                            //Collect all must and may contain attribute value.
                            if (serverObj.Properties.ContainsKey(StandardNames.mustContain.ToLower()))
                            {
                                foreach (object value in serverObj.Properties[StandardNames.mustContain.ToLower()])
                                {
                                    mustContain.Add((string)value);
                                }
                            }
                            if (serverObj.Properties.ContainsKey(StandardNames.systemMustContain.ToLower()))
                            {
                                foreach (object value in serverObj.Properties[StandardNames.systemMustContain.ToLower()])
                                {
                                    mustContain.Add((string)value);
                                }
                            }

                            if (serverObj.Properties.ContainsKey(StandardNames.mayContain.ToLower()))
                            {
                                foreach (object value in serverObj.Properties[StandardNames.mayContain.ToLower()])
                                {
                                    mayContain.Add((string)value);
                                }
                            }
                            if (serverObj.Properties.ContainsKey(StandardNames.systemMayContain.ToLower()))
                            {
                                foreach (object value in serverObj.Properties[StandardNames.systemMayContain.ToLower()])
                                {
                                    mayContain.Add((string)value);
                                }
                            }
                            break;
                        }
                    }
                }

                //For all property name of this object, it should be present in either must or may contain
                //attribute list.
                foreach (string attribute in entry.Properties.PropertyNames)
                {
                    if (!ExcludedAttributes.Contains(attribute))
                    {
                        //This attribute is in must contain list.
                        if (mustContain.Contains(attribute))
                        {
                            mustContain.Remove(attribute);
                        }
                        //This attribute is not in must and may contian list.
                        else if (!mayContain.Contains(attribute))
                        {
                            isContent = false;
                            break;
                        }
                    }
                }

                //This is for checking whether some must contain attributes are missed.
                if (mustContain.Count > 0)
                {
                    isContent = false;
                }

                if (!isContent)
                {
                    break;
                }
            }
            //MS-ADTS-Schema_R152.
            DataSchemaSite.CaptureRequirementIfIsTrue(
                isContent,
                152,
                @"In the content rules union of values in the mustContain and systemMustContain attributes specifies the 
                attributes that are required to be present on an object instance of the class in question.");

            //MS-ADTS-Schema_R153.
            DataSchemaSite.CaptureRequirementIfIsTrue(
                isContent,
                153,
                @"In the content rules  the union of values in the mustContain, systemMustContain, mayContain, and 
                systemMayContain attributes specifies the attributes that are allowed to be present on an object 
                instance of the class in question.");
        }
        /// <summary>
        ///  Check objectClass.
        /// </summary>
        /// <param name="obj">ModelObject.</param>
        public static void CheckObjectClass(ModelObject obj)
        {
            string dn          = (string)obj[StandardNames.shortName];
            Value  objectClass = obj[StandardNames.objectClass];

            if (objectClass == null)
            {
                Checks.Fail("'{0}' must have object class", dn);

                return;
            }

            // Check for resolution and last/first element compliance
            int count = 0;
            Sequence <string> classes = obj.GetAllClassIds();
            bool resolveOk            = true;

            foreach (string classId in classes)
            {
                ModelObject classObject;
                //The object must be present in Schema NC.
                if (!obj.dc.TryGetClass(classId, out classObject))
                {
                    Checks.Fail("'{0}' has undefined object class '{1}'", dn, classId);
                    resolveOk = false;
                    continue;
                }
                //Checking for the first class is Top
                if (count == 0 && classId != StandardNames.top)
                {
                    Checks.Fail("'{0}' first object class must be top", dn);
                    resolveOk = false;
                }
                //Checking for the last class is Structural class.
                if (count == objectClass.UnderlyingValues.Count - 1)
                {
                    ObjectClassCategory category = (ObjectClassCategory)(int)classObject[StandardNames.objectClassCategory];

                    if (category != ObjectClassCategory.StructuralClass)
                    {
                        Checks.Fail("'{0}' last object class must be structural");
                        resolveOk = false;
                    }
                }
                count++;
            }
            if (!resolveOk)
            {
                return;
            }

            // Check for superclass chaining
            // Checks that if the value of object class is [top,ac_1,...,ac_n,sc_1,...,sc_n],
            // then sc_n is the most specific structural class, sc_1...scn_(n-1) is the super class chain of sc_n (excluding top),
            // and ac_n is the next auxilary class before that, where ac_1...acn(n-1) is that classes chain excluding classes
            // which have been seen already before (where there can be a number of ac anchors here).
            SetContainer <string> includedClasses = new SetContainer <string>();
            int i = classes.Count - 1;

            while (i > 0)
            {
                string classId = classes[i--];
                if (includedClasses.Contains(classId))
                {
                    Checks.Fail("'{0}' object class contains repeated entries", dn);
                    break;
                }
                includedClasses.Add(classId);
                ObjectClassCategory category = (ObjectClassCategory)(int)obj.dc.GetClass(classId)[StandardNames.objectClassCategory];
                if (i == classes.Count - 2)
                {
                    // Most specific class must be structural
                    if (category != ObjectClassCategory.StructuralClass)
                    {
                        Checks.Fail("'{0}' object class most specific class must be structural", dn);
                    }
                }

                //If the server is Pre Windows 2003.
                foreach (string clId in GetSuperClassChain(obj.dc, classId).Revert())
                {
                    if (includedClasses.Contains(clId))
                    {
                        // Already included in a previous chain
                        continue;
                    }
                    includedClasses.Add(clId);
                    if (i <= 0)
                    {
                        Checks.Fail(
                            "'{0}' object class does not contain chain of super classes of '{1}' (classes missing)",
                            dn,
                            classId);
                        break;
                    }
                    if (classes[i--] != clId)
                    {
                        Checks.Fail(
                            "'{0}' object class does not contain chain of super classes '{1}' (found unexpected '{2}')",
                            dn,
                            classId,
                            classes[i + 1]);
                        break;
                    }
                }
            }
        }