/// <summary>
        /// Adds a schema class.
        /// </summary>
        /// <param name="obj">The object of model.</param>
        void AddClass(ModelObject obj)
        {
            string governsId = (string)obj[StandardNames.governsId];
            string displayName = ((string)obj[StandardNames.ldapDisplayName]).ToLower();
            Checks.IsTrue(!classMap.ContainsKey(displayName), "class '{0}' must not be declared twice", displayName);
            classMap[displayName] = obj;
            Checks.IsTrue(
                !classGovernsIdToDisplayNameMap.ContainsKey(governsId), 
                "class '{0}' has ambigious id '{1}'", 
                displayName, 
                governsId);
            classGovernsIdToDisplayNameMap[governsId] = displayName;

            // Add object class if not defined by schema
            if (obj[StandardNames.objectClass] == null)
            {
                obj[StandardNames.objectClass] =new AttributeContext(
                    this,
                    StandardNames.objectClass, 
                    Syntax.StringObjectIdentifier, 
                    false, 
                    null).Parse(StandardNames.top + ";" + StandardNames.classSchema);
            }
        }
        /// <summary>
        /// Adds a set of object definitions to the schema. The format of the schema
        /// is a sequence of lines where objects are separated by empty lines.
        /// Each line of an object definition is a pair of an attribute display name and an
        /// attribute value, separated by ':'. Takes care of "bootstrapping" the contents of
        /// the schema, resolving cyclic dependencies between attribute definitions and objects. 
        /// </summary>
        /// <param name="schema">The schema, represented as explained above.</param>
        /// <param name="valueSubstitution">A substitution of strings which should be applied to each value in the 
        /// schema. For example, may map '&lt;rootdomaindn&gt;' as used in schemas to represent the root name of the 
        /// current DC to an actual value</param>
        /// <param name="serverVersion">Specify the OS version of the server</param>
        /// <returns>Result of the Load Schema method.</returns>
        public ModelResult LoadSchema(IEnumerable<string> schema, Map<string, string> valueSubstitution, OSVersion serverVersion)
        {
            SequenceContainer<ModelObject> newObjects = new SequenceContainer<ModelObject>();
            UnresolvedSyntax unresolvedSyntax = new UnresolvedSyntax();

            #region Pass 1: read in objects resolving only builtin attributes
            // We need this phase for bootstrapping, as we don't have the
            // attributes available which are used in the objects. Thus
            // in this phase, we just parse attribute values of a certain set
            // of builting attributes which are required to get attribute syntax
            // definitions.
            InitializeBuiltinAttributes();
            ModelObject tempobj = null;
            ModelObject obj = null;
            
            foreach (string rawLine in schema)
            {
                string line = (rawLine == null)?null:rawLine.Trim();

                if (String.IsNullOrEmpty(line))
                {
                    // Object ends here
                    if (obj != null)
                    {
                        if (obj[StandardNames.attributeID] == null && obj[StandardNames.governsId] == null)
                        {
                            if (obj.attributes.Count == 1)
                            {
                                // If the server is Windows 2000
                                if (serverVersion == OSVersion.WinSvr2000)
                                {
                                    string attr = obj.attributes.Keys.ElementAt(0);

                                    if (tempobj.attributes.Keys.Contains(attr))
                                    {
                                        tempobj.attributes.Keys.Remove(attr);
                                        tempobj.attributes.Add(obj.attributes.ElementAt(0));
                                    }
                                    else
                                    {
                                        tempobj.attributes.Add(obj.attributes.ElementAt(0));
                                    }
                                    newObjects.RemoveAt(newObjects.Count - 1);
                                    newObjects.Add(tempobj);
                                }
                            }
                            else
                            {
                                Checks.Fail("attributeId/governsId is mandatory for each object {0}.", obj[StandardNames.cn]);
                            }
                        }
                        else if (obj[StandardNames.attributeID] != null)
                        {
                            AddAttribute(obj);
                            newObjects.Add(obj);
                        }
                        else if (obj[StandardNames.governsId] != null)
                        {
                            // This is a class definition. Fill in class map.
                            AddClass(obj);
                            newObjects.Add(obj);
                        }
                        tempobj = obj;
                        obj = null;
                    }
                }
                else
                {
                    if (obj == null)
                    {
                        obj = new ModelObject();
                    }
                    obj.dc = this;

                    string attr, valueString;
                    string[] splits = line.Split(new char[] { ':' }, 2);

                    if (splits == null || splits.Length != 2)
                    {
                        Checks.Fail("invalid schema line '{0}'", line);
                        continue;
                    }
                    attr = splits[0].Trim().ToLower();
                    valueString = Substitute(valueSubstitution, splits[1].Trim());
                    AttributeContext parsingContext;

                    if (!builtinAttributeSyntax.TryGetValue(attr, out parsingContext))
                    {
                        parsingContext = new AttributeContext(this, attr, unresolvedSyntax);
                    }
                    obj[attr] = parsingContext.Parse(valueString);
                }
            }
            #endregion

            #region Pass 2: resolve syntax of all new objects
            // As we have now attribute definitions which map to the syntax, we can parse
            // All values in the new objects.
            foreach (ModelObject newObj in newObjects)
            {
                foreach (string attr in newObj.attributes.Keys)
                {
                    AttributeContext parsingContext = GetAttributeContext(attr);
                    Value value = newObj[attr];

                    if (value.Syntax is UnresolvedSyntax)
                    {
                        newObj[attr] = parsingContext.Parse((string)value);
                    }
                    else
                    {
                        Checks.IsTrue(
                            parsingContext.syntax == value.Syntax,
                            "bultin syntax assignment of '{0}' must match syntax declared in schema", 
                            attr);
                    }
                }
            }
            #endregion

            #region Pass 3: add objects
            // Now all definitions are complete. Add them to schema replica root.
            foreach (ModelObject newObj in newObjects)
            {
                AddChild(schemaReplica.root, newObj);
            }
            #endregion

            #region Pass 4: check consistency
            // The tree is finally setup. Now check for consistency
            Consistency.Check(newObjects.ToSequence());
            #endregion

            if (Checks.HasDiagnostics)
            {
                return new ModelResult(ResultCode.ConstraintViolation, Checks.GetAndClearLog(), Checks.GetAndClearDiagnostics());
            }
            else
            {
                //return Result.Success;
                ModelResult tempRes = new ModelResult(ResultCode.Success);
                tempRes.logMessage = Checks.GetAndClearLog();
                return tempRes;
            }

        }
        /// <summary>
        /// Reads a schema from a set of XML files. Returns an enumeration of lines, where each line
        /// represents an attribute definition with ':' a separator between attribute name and attribute value,
        /// and where the empty line indicates the end of an object definition.
        /// </summary>

        /// <param name="includeFilePatterns">Included file folders</param>
        /// <param name="excludeFiles">Excluded file folder</param>
        /// <param name="isProtocolXMLApplied">Set this to true if new protocol XML applied</param>
        /// <param name="serverVersion">Specify the OS version of the server</param>
        /// <returns>Returns string array.</returns>
        public static string[] ReadSchema(string[] includeFilePatterns, string[] excludeFiles, bool isProtocolXMLApplied, OSVersion serverVersion)
        {
            bool          criticalOnly = false;
            List <string> result       = new List <string>();

            Checks.MakeLog("Start loading of XML data...");
            if (isProtocolXMLApplied == true)
            {
                foreach (string file in Expand(includeFilePatterns, excludeFiles))
                {
                    if (serverVersion >= OSVersion.Win2016)
                    {
                        #region raw XMLs used after Windows Server 2016 are changed to openXML type

                        using (WordprocessingDocument wdDoc = WordprocessingDocument.Open(file, false))
                        {
                            XNamespace w   = @"http://schemas.openxmlformats.org/wordprocessingml/2006/main";
                            XNamespace xml = @"http://www.w3.org/XML/1998/namespace";

                            var        items         = wdDoc.MainDocumentPart.Document.Body;
                            XAttribute currentStyle  = null;
                            XAttribute previousStyle = null;
                            string     previousLine  = "";
                            foreach (var item in items)
                            {
                                if (item is Paragraph)
                                {
                                    XElement xe = XElement.Parse(item.OuterXml);
                                    currentStyle = xe.Descendants(w + "pPr").Descendants(w + "pStyle").Attributes(w + "val").FirstOrDefault();
                                    if (currentStyle != null && currentStyle.Value.Equals("Code"))
                                    {
                                        var    texts       = xe.Descendants(w + "t");
                                        string currentLine = "";
                                        foreach (var text in texts)
                                        {
                                            currentLine += text.Value;
                                        }
                                        if (currentLine.Contains("<SchemaNCDN>"))
                                        {
                                            currentLine = currentLine.Replace("<SchemaNCDN>", "CN=Schema,CN=Configuration,<RootDomainDN>");
                                        }
                                        var testsAttr = texts.Attributes(xml + "space").FirstOrDefault();
                                        if (testsAttr != null && testsAttr.Value.Equals("preserve"))
                                        {
                                            if (currentLine.StartsWith(" "))
                                            {
                                                previousLine += currentLine.TrimStart();
                                            }
                                            else
                                            {
                                                if (!string.IsNullOrEmpty(previousLine))
                                                {
                                                    result.Add(previousLine);
                                                }
                                                previousLine = currentLine;
                                            }
                                        }
                                        else
                                        {
                                            if (!string.IsNullOrEmpty(previousLine))
                                            {
                                                result.Add(previousLine);
                                            }
                                            previousLine = currentLine;
                                        }
                                    }
                                    else if (previousStyle != null && previousStyle.Value.Equals("Code"))
                                    {
                                        if (!string.IsNullOrEmpty(previousLine))
                                        {
                                            // If the code does not end with an empty string, add one to seperate it with other schema objects in the result list.
                                            result.Add(previousLine);
                                            result.Add(string.Empty);
                                        }
                                        else
                                        {
                                            // There exists in TD when code already ends up with an empty string.
                                            result.Add(previousLine);
                                        }
                                        previousLine = "";
                                    }
                                    previousStyle = currentStyle;
                                }
                            }
                        }

                        #endregion
                    }
                    else
                    {
                        #region raw XMLs used before Windows Server 2012 R2

                        System.IO.StreamReader sr = new StreamReader(file);
                        string tmp = sr.ReadToEnd();
                        sr.Close();

                        //Get data from <snippet> element
                        int index = tmp.IndexOf("</snippet>");

                        if (serverVersion == OSVersion.WinSvr2008R2)
                        {
                            if (tmp.IndexOf("windows_unreleased") > -1)
                            {
                                if (tmp.IndexOf("</snippet>", tmp.IndexOf("windows_unreleased")) > -1)
                                {
                                    string temper = tmp.Substring(tmp.IndexOf("windows_unreleased"));
                                    if (temper.ToLower().Contains("cn:") && temper.ToLower().Contains("ldapdisplayname:"))
                                    {
                                        tmp   = temper;
                                        index = tmp.IndexOf("</snippet>");
                                    }
                                }
                            }
                        }

                        if (index > -1)
                        {
                            index = tmp.LastIndexOf(">", index) + 1;
                            string sp = tmp.Substring(index, tmp.IndexOf("</snippet>") - index);
                            index = tmp.IndexOf("<snippet");
                            string        spTag    = tmp.Substring(index, tmp.IndexOf(">", index) - index + 1);
                            List <string> autoText = new List <string>();
                            index = 0;

                            //Get platform information
                            while (index < tmp.Length)
                            {
                                int begin = tmp.IndexOf("<auto_text>", index);

                                if (begin > -1)
                                {
                                    int end = tmp.IndexOf("</auto_text>", index);

                                    if (begin > -1 && end > -1 && end > begin)
                                    {
                                        string newAdd = tmp.Substring(begin + "<auto_text>".Length, end - begin - "<auto_text>".Length);
                                        bool   toAdd  = true;

                                        foreach (string cont in autoText)
                                        {
                                            if (cont == newAdd)
                                            {
                                                toAdd = false;
                                                break;
                                            }
                                        }
                                        if (toAdd == true)
                                        {
                                            autoText.Add(newAdd);
                                        }
                                        index = end + "</auto_text>".Length;
                                    }
                                }
                                else
                                {
                                    break;
                                }
                            }

                            List <string> implementationSpecific = new List <string>();

                            foreach (string tagTla in autoText)
                            {
                                if (!tagTla.Equals("windows") && !tagTla.Equals("exchange_server"))
                                {
                                    implementationSpecific.Add(tagTla);
                                }
                            }
                            List <string> lines      = new List <string>();
                            bool          isCritical = false;
                            string        value      = sp;
                            value = value.Replace(" ", String.Empty);
                            //Modified. For new XML files, lines are separated by \n, not \n\r
                            string[] splitTag    = { "\n" };
                            string[] tmpValue    = value.Split(splitTag, StringSplitOptions.RemoveEmptyEntries);
                            string   parsedValue = String.Empty;

                            for (int k = 0; k < tmpValue.Length; k++)
                            {
                                if (!tmpValue[k].Contains(":") || tmpValue[k].IndexOf(":") == 1)
                                {
                                    parsedValue = parsedValue + tmpValue[k];
                                }
                                else
                                {
                                    parsedValue = parsedValue + "\r\n" + tmpValue[k];
                                }
                            }
                            if (parsedValue.Contains("&lt;RootDomainDN&gt;"))
                            {
                                parsedValue = parsedValue.Replace("&lt;RootDomainDN&gt;", "<RootDomainDN>");
                            }
                            else if (parsedValue.Contains("&lt;SchemaNCDN&gt;"))
                            {
                                parsedValue = parsedValue.Replace("&lt;SchemaNCDN&gt;", "CN=Schema,CN=Configuration,<RootDomainDN>");
                            }
                            string[] splitTag2 = { "\r\n" };
                            tmpValue = parsedValue.Split(splitTag2, StringSplitOptions.RemoveEmptyEntries);
                            string savedString = String.Empty;

                            foreach (string line in tmpValue)
                            {
                                if (line.Length > 0)
                                {
                                    if (line[line.Length - 1] != ':')
                                    {
                                        lines.Add(savedString + line);
                                        if (criticalOnly && !isCritical)
                                        {
                                            isCritical = CheckCritical(line);
                                        }
                                        savedString = String.Empty;
                                    }
                                    else
                                    {
                                        savedString = line;
                                    }
                                }
                            }
                            if (!criticalOnly || isCritical)
                            {
                                result.AddRange(lines);
                                result.Add(String.Empty); //separate records by an empty element
                            }
                        }

                        #endregion
                    }
                }
            }
            else
            {
                foreach (string file in Expand(includeFilePatterns, excludeFiles))
                {
                    XmlTextReader reader = new XmlTextReader(file);
                    reader.XmlResolver   = null;
                    reader.DtdProcessing = DtdProcessing.Prohibit;
                    XPathDocument  doc  = new XPathDocument(reader);
                    XPathNavigator node = doc.CreateNavigator();

                    // The TD XML has no formal tag for representing the object definitions in ADA* and ADSC.
                    // However, it seems that all those definitions are included in an <example> tag which
                    // in turn contains a <snippet> tag with CDATA, and the snippet tag has a type attribute "syntax".
                    // We use this for identifying the object definitions. However, this code may require
                    // changes if the TD XML representation changes, or if it discovered that we include
                    // too many or not enough objects.
                    foreach (XPathNavigator snippet in node.Select("//example/snippet"))
                    {
                        List <string> implementationSpecific = new List <string>();
                        foreach (XPathNavigator tagTla in node.Select("//p/tla"))
                        {
                            if (
                                !tagTla.GetAttribute("rid", String.Empty).Equals("windows") &&
                                !tagTla.GetAttribute("rid", String.Empty).Equals("exchange_server"))
                            {
                                implementationSpecific.Add(tagTla.GetAttribute("rid", String.Empty));
                            }
                        }

                        if (
                            serverVersion != OSVersion.WinSvr2008R2 &&
                            (implementationSpecific.Count == 1 &&
                             (implementationSpecific.Contains("windows_server_7"))))
                        {
                            continue;
                        }
                        List <string> lines      = new List <string>();
                        bool          isCritical = false;
                        string        value      = snippet.Value;
                        int           i          = 0;

                        while (i >= 0)
                        {
                            string line = ExtractLine(value, ref i).Trim();

                            while (i >= 0 && Char.IsWhiteSpace(value[i]))
                            {
                                line += ExtractLine(value, ref i).Trim();
                            }
                            if (line != String.Empty)
                            {
                                lines.Add(line);
                                if (criticalOnly && !isCritical)
                                {
                                    isCritical = CheckCritical(line);
                                }
                            }
                        }
                        if (!criticalOnly || isCritical)
                        {
                            result.AddRange(lines);
                            result.Add(String.Empty);
                        }
                    }
                }
            }
            Checks.MakeLog("Successfully loaded XML data files...");
            return(result.ToArray());
        }
        /// <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)
        {
            List <string> mustContain = new List <string>();
            List <string> mayContain  = new List <string>();

            string[] ExcludeAttributes = { "instancetype", "ntsecuritydescriptor", "objectcategory", "objectsid" };
            // Compute sets of may/must attribute
            string        className      = (string)obj[StandardNames.objectClass].UnderlyingValues.Last();
            List <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()));
            }
        }
        /// <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;
            List <string> classes   = obj.GetAllClassIds().ToList();
            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).
            List <string> includedClasses = new List <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))
                {
                    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;
                    }
                }
            }
        }
        /// <summary>
        /// Inheritance is the ability to build new classes from existing classes.
        /// </summary>
        /// <param name="obj">The object of model.</param>
        public static void CheckInheritance(ModelObject obj)
        {
            string dn = (string)obj[StandardNames.shortName];
            //Get super class id.
            string superClassId = (string)obj[StandardNames.subClassOf];

            if (superClassId == null)
            {
                Checks.Fail("'{0}' must have a super class", dn);
            }
            else
            {
                ModelObject superClass;
                if (!obj.dc.TryGetClass(superClassId, out superClass))
                {
                    Checks.Fail("'{0}' has undefined super class '{1}'", dn, superClassId);
                }
                else
                {
                    string thisClassId = (string)obj[StandardNames.governsId];

                    if (thisClassId != StandardNames.topGovernsId && thisClassId == superClassId)
                    {
                        Checks.Fail("{0} cannot inherit from itself", dn);
                    }

                    //Get super class and current class category.
                    ObjectClassCategory thisCategory  = (ObjectClassCategory)(int)obj[StandardNames.objectClassCategory];
                    ObjectClassCategory superCategory = (ObjectClassCategory)(int)superClass[StandardNames.objectClassCategory];
                    bool categoryOk;

                    switch (thisCategory)
                    {
                    //Abstract Class must be inherited from Abstract Class.
                    case ObjectClassCategory.AbstractClass:
                        categoryOk = superCategory == ObjectClassCategory.AbstractClass;
                        break;

                    //Auxiliary Class must not be inherited from Structural Class
                    case ObjectClassCategory.AuxiliaryClass:
                        categoryOk = superCategory != ObjectClassCategory.StructuralClass;
                        break;

                    //Structural Class must not be inherited from Auxiliary Class
                    case ObjectClassCategory.StructuralClass:
                        categoryOk = superCategory != ObjectClassCategory.AuxiliaryClass;
                        break;

                    //Default.
                    default:
                        categoryOk = true;
                        break;
                    }

                    if (!categoryOk)
                    {
                        Checks.Fail("{0} must have object class category which is compatible with its super class", dn);
                    }
                }
            }
        }
        /// <summary>
        /// If it is a structural object class, then the objectClass attribute of objects of the class does not contain
        /// the name of the auxiliary class aux.
        /// </summary>
        /// <param name="obj">The object of model.</param>
        public static void CheckStructure(ModelObject obj)
        {
            //Collect possSuperiors.
            List <object> possSuperiors = new List <object>();
            //Get current class name.
            string className = obj[StandardNames.ldapDisplayName].UnderlyingValues.ElementAt(0).ToString();
            //Get super class list.
            List <string> superClassList = GetSuperClassList(obj.dc, className);

            //For each super class
            foreach (string superClass in superClassList)
            {
                //Get class object of this class name.
                ModelObject classObject = obj.dc.GetClass(superClass);

                //Get possSuperiors.
                if (classObject[StandardNames.possSuperiors] != null)
                {
                    possSuperiors.AddRange(classObject[StandardNames.possSuperiors].UnderlyingValues);
                }

                //Get systemPossSuperiors.
                if (classObject[StandardNames.systemPossSuperiors] != null)
                {
                    possSuperiors.AddRange(classObject[StandardNames.systemPossSuperiors].UnderlyingValues);
                }
            }

            //For each poss superior class name...
            foreach (string possSuperior in possSuperiors)
            {
                #region two

                //Get the poss superior object and possibleInferiors attribute.
                ModelObject superiorObj = obj.dc.GetClass(possSuperior);
                ModelObject attrObject  = superiorObj.dc.GetAttribute(StandardNames.possibleInferiors);

                if (superiorObj != null)
                {
                    AttributeContext parsingContext = obj.dc.GetAttributeContext(StandardNames.possibleInferiors);

                    //If this class alrady contains the possibleInferiors...
                    if (superiorObj[StandardNames.possibleInferiors] != null)
                    {
                        string valueString = String.Empty;
                        foreach (object val in superiorObj[StandardNames.possibleInferiors].UnderlyingValues)
                        {
                            valueString = valueString + val.ToString() + ";";
                        }

                        //Append the current class name with already existing possibleInferiors attribute.
                        valueString = valueString + className;
                        superiorObj[StandardNames.possibleInferiors] = parsingContext.Parse(valueString);
                    }
                    else
                    {
                        //Create a new possibleInferiors attribute with the cureent class name.
                        superiorObj[StandardNames.possibleInferiors] = parsingContext.Parse(className);
                    }
                }
                else
                {
                    Checks.Fail(
                        "{0} class's possSuperior {1} is not in Schema NC.",
                        className,
                        superiorObj.attributes[StandardNames.cn].UnderlyingValues.ElementAt(0).ToString());
                }

                #endregion
            }
        }
        /// <summary>
        /// Adds an object to DC at parent location.
        /// The objects content is specified by a sequence of strings where each string
        /// consists of a pair of attribute name and value.
        /// </summary>
        /// <param name="parentDN">The DN of parent.</param>
        /// <param name="attributes">All attributes of model object.</param>
        public ModelResult Add(string parentDN, params string[] attributes)
        {
            ModelObject parent = TryFindObject(parentDN);

            if (parent == null)
            {
                return(new ModelResult(ResultCode.NoSuchObject, "cannot find '{0}'", parentDN));
            }

            ModelObject obj = new ModelObject();

            obj.dc = this;

            foreach (string line in attributes)
            {
                string   attr, valueString;
                string[] splits = line.Split(new char[] { ':' }, 2);
                if (splits == null || splits.Length != 2)
                {
                    return(new ModelResult(ResultCode.InvalidAttributeSyntax));
                }
                attr        = splits[0].Trim();
                valueString = splits[1].Trim();
                ModelObject attrObj;

                if (!TryGetAttribute(splits[0], out attrObj))
                {
                    return(new ModelResult(ResultCode.NoSuchAttribute, attr));
                }

                AttributeContext parsingContext = GetAttributeContext(attr);
                obj[attr] = parsingContext.Parse(valueString);

                if (Checks.HasDiagnostics)
                {
                    return(new ModelResult(ResultCode.InvalidAttributeSyntax, Checks.GetAndClearDiagnostics()));
                }
            }
            string rdnName = GetRDNAttributeName(obj);

            if (rdnName != null)
            {
                string rdn = (string)obj[rdnName];
                if (parent.childs.ContainsKey(rdn))
                {
                    return(new ModelResult(ResultCode.EntryAlreadyExists));
                }
                AddChild(parent, obj);
                Consistency.Check(new List <ModelObject> {
                    obj
                });
            }
            if (Checks.HasDiagnostics)
            {
                return(new ModelResult(ResultCode.ConstraintViolation, Checks.GetAndClearDiagnostics()));
            }
            else
            {
                return(ModelResult.Success);
            }
        }