/// <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 Sequence <ModelObject>(obj));
            }
            if (Checks.HasDiagnostics)
            {
                return(new ModelResult(ResultCode.ConstraintViolation, Checks.GetAndClearDiagnostics()));
            }
            else
            {
                return(ModelResult.Success);
            }
        }
        /// <summary>
        /// Constructs a new replica.
        /// </summary>
        /// <param name="dc">Domain controller</param>
        /// <param name="kind">Replica kind.</param>
        /// <param name="dn">Distinguished name.</param>
        /// <param name="partial">Is it partial replica</param>
        public Replica(ModelDomainController dc, ReplicaKind kind, string dn, bool partial)
        {
            this.dc      = dc;
            this.kind    = kind;
            this.dn      = dn;
            this.partial = partial;
            this.root    = new ModelObject();
            root.dc      = dc;
            AttributeContext objectClassContext =
                new AttributeContext(
                    null,
                    StandardNames.objectClass,
                    Syntax.StringObjectIdentifier,
                    false,
                    null);
            AttributeContext cnContext =
                new AttributeContext(
                    null,
                    StandardNames.cn,
                    Syntax.StringUnicode);

            switch (kind)
            {
            case ReplicaKind.Domain:
                root[StandardNames.objectClass] =
                    objectClassContext.Parse(StandardNames.top + ";" + StandardNames.domainDNS);
                break;

            case ReplicaKind.Application:
                root[StandardNames.objectClass] =
                    objectClassContext.Parse(StandardNames.top + ";" + StandardNames.domainDNS);
                break;

            case ReplicaKind.Configuration:
                root[StandardNames.cn]          = cnContext.Parse("Configuration");
                root[StandardNames.objectClass] =
                    objectClassContext.Parse(StandardNames.top + ";" + StandardNames.configuration);
                break;

            case ReplicaKind.Schema:
                root[StandardNames.cn]          = cnContext.Parse("Schema");
                root[StandardNames.objectClass] =
                    objectClassContext.Parse(StandardNames.top + ";" + StandardNames.dMD);
                break;
            }
        }
            /// <summary>
            /// Mathc method.
            /// </summary>
            /// <param name="obj">The second value.</param>
            /// <returns>On success it returns true.</returns>
            public override bool Match(ModelObject obj)
            {
                Value assignedValue = obj[attributeForEqual];

                if (assignedValue == null)
                {
                    return(false);
                }
                AttributeContext context     = obj.dc.GetAttributeContext(attributeForEqual);
                Value            parsedValue = context.Parse(valueForEqual);

                return(context.Equals(parsedValue, assignedValue));
            }
        /// <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>
        /// 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
            }
        }