/// <summary>
        /// Compares database objects (except tables and columns) from two distinct XML schema files. These files are generated 
        /// by the SerializeDB method.  This method is called from the CompareSchema method.
        /// </summary>
        /// <param name="_serverDB">Used to identify which server the compare objects came from</param>
        /// <param name="xmlSourceDoc">The XmlDataDocument, the source XML to compare with the destination XML.</param>
        /// <param name="xmlDestinationDoc">The XmlDataDocument, the destination/target XML to compare with the source XML.</param>
        /// <param name="xmlDiffDoc">The XML Diffgram document to update.</param>
        /// <param name="type">The type of database object collection to compare, i.e. defaults, UDDTs, rules, views, functions, 
        /// stored procedures, and triggers.</param>
        /// <param name="xmlDiff">The XmlDiff Object used from the GotDotNet XmlDiff class. Performs the XML node compare.</param>
        /// <param name="CompareTextFlag">Flag that performs full text compare between objects</param>
        /// <param name="sqlObjectName">specifies a specific SQL object to compare</param>
        public static void CompareObjects(string _serverDB, XmlDocument xmlSourceDoc, XmlDocument xmlDestinationDoc,
            XmlDocument xmlDiffDoc, _NodeType type, XmlDiff xmlDiff, bool CompareTextFlag, string sqlObjectName)
        {
            SortedList sl = new SortedList();
            SortedList slDep = new SortedList();

            bool addFlag = false;
            bool alterFlag = false;
            bool sortFlag = false;

            string selectNodes = string.Empty;
            string selectText = string.Empty;
            string typeName = string.Empty;
            string depText = string.Empty;

            // iterate thru the source tables 
            // we are going to ignore destination tables which are not in the source DB
            // as they could be custom tables added by some outside tool or person
            switch (type)
            {
                case _NodeType.SPROC:
                    {
                        selectNodes = SPROCPATH;
                        selectText = SPROCTEXT;
                        depText = SPROCDEP;
                        typeName = type.ToString();
                        sortFlag = true;
                        break;
                    }
                case _NodeType.FUNCTION:
                    {
                        selectNodes = FUNCPATH;
                        selectText = FUNCTEXT;
                        depText = FUNCDEP;
                        typeName = type.ToString().Substring(0, 4);
                        sortFlag = true;
                        break;
                    }
                case _NodeType.VIEW:
                    {
                        selectNodes = VIEWPATH;
                        selectText = VIEWTEXT;
                        depText = VIEWDEP;
                        typeName = type.ToString();
                        sortFlag = true;
                        break;
                    }
                case _NodeType.TRIGGER:
                    {
                        selectNodes = TRIGGERPATH;
                        selectText = TRIGGERTEXT;
                        typeName = type.ToString();
                        break;
                    }
                case _NodeType.DEFAULT:
                    {
                        selectNodes = DEFAULTPATH;
                        selectText = DEFAULTTEXT;
                        typeName = type.ToString();
                        break;
                    }
                case _NodeType.RULE:
                    {
                        selectNodes = RULEPATH;
                        selectText = RULETEXT;
                        typeName = type.ToString();
                        break;
                    }
                case _NodeType.UDDT:
                    {
                        selectNodes = UDDTPATH;
                        selectText = UDDTTEXT;
                        typeName = type.ToString();
                        break;
                    }
            }

            SortedList slMatch = new SortedList();
            XmlNodeList xNodeList = xmlSourceDoc.SelectNodes(selectNodes, nsmgr_Source);
            XmlNode xnDestParent = xmlDestinationDoc.SelectSingleNode(selectNodes, nsmgr_Dest);

            // use stringbuilder class as it should be faster
            StringBuilder sourceTxt = new StringBuilder();
            StringBuilder destTxt = new StringBuilder();
            StringBuilder sortedname = new StringBuilder();

            foreach (XmlNode xnChild_Source in xNodeList)
            {
                XmlNode xnDest = null;
                XmlNodeList XmlDestTextList = null;
                sourceTxt.Length = 0;
                destTxt.Length = 0;
                int destNodeCount = 0;
                int sourceNodeCount = 0;

                string SqlObjectName = xnChild_Source.ChildNodes[0].InnerXml;
                if (sqlObjectName != null && !SqlObjectName.ToLower().Equals(sqlObjectName.ToLower()))
                {
                    continue; // loop until passed in object name is found
                }
                string xpath = selectText + SqlObjectName + "']";
                XmlNode xnChk = xnChild_Source.SelectSingleNode("Check_Sum");
                string src_checksum = string.Empty;
                string dst_checksum = string.Empty;
                if (xnChk != null)
                {
                    src_checksum = xnChk.InnerXml;
                }

                logger.Debug("\n{2}: Comparing {1}: {0}.", SqlObjectName, type.ToString().ToLower(), _serverDB);

                // walk thru destination xml doc nodes to find matching sproc node
                if (xnDestParent != null)
                {
                    xnDest = xnDestParent.SelectSingleNode(selectNodes + "[" + xpath.Split('[')[1]);
                }
                // get xmlnodes for text rows in destination doc
                if (xnDest != null)
                {
                    xnChk = xnDest.SelectSingleNode("Check_Sum");
                    if (xnChk != null)
                    {
                        dst_checksum = xnChk.InnerXml;
                    }
                    // if objects don't compare then walk each line of text
                    if (!xmlDiff.Compare(xnChild_Source, xnDest))
                    {
                        XmlDestTextList = xnDest.SelectNodes(selectText.Split('[')[0]);
                        // only comapre the text length (not a checksum) if there is not a match on the nodes
                        if (xnChk != null && dst_checksum == src_checksum)
                        {
                            continue;
                        }
                    }
                    else
                    {
                        continue;
                    }
                }
                if (xnDest != null && XmlDestTextList != null && XmlDestTextList.Count > 0)
                {
                    // don't care about existing UDDTs and Defaults, only new ones
                    // so resume at next node
                    if (type == _NodeType.UDDT || type == _NodeType.DEFAULT || type == _NodeType.RULE)
                    {
                        continue;
                    }

                    if (CompareTextFlag)
                    {
                        // get xmlnodes for text rows in source
                        XmlNodeList xnlSource = xnChild_Source.SelectNodes(xpath, nsmgr_Source);
                        // build text for source
                        foreach (XmlNode xnSource in xnlSource)
                        {
                            // ignore blank text nodes, tabs, newline and carriage returns
                            if (xnSource.SelectSingleNode("Text") == null || xnSource.SelectSingleNode("Text").InnerText.Length == 0)
                            {
                                continue;
                            }
                            sourceNodeCount += 1;
                            sourceTxt.Append(xnSource.SelectSingleNode("Text").InnerText.ToLower().Trim());
                            sourceTxt.Replace(" ", "");
                            sourceTxt.Replace("\n", "");
                            sourceTxt.Replace("\r", "");
                            sourceTxt.Replace("\t", "");
                        }
                        if (sourceTxt.ToString().Length > 0)
                        {
                            // build text for destination
                            foreach (XmlNode xnChild in XmlDestTextList)
                            {
                                // ignore blank text nodes, tabs, newline and carriage returns
                                if (xnChild.SelectSingleNode("Text") == null || xnChild.SelectSingleNode("Text").InnerText.Length == 0)
                                {
                                    continue;
                                }
                                destNodeCount += 1;
                                destTxt.Append(xnChild.SelectSingleNode("Text").InnerText.ToLower().Trim());
                                destTxt.Replace(" ", "");
                                destTxt.Replace("\n", "");
                                destTxt.Replace("\r", "");
                                destTxt.Replace("\t", "");
                                // look for this text string in the source text string
                                // if theres no match then we do not need to look thru
                                // all the dest text nodes, so exit out of loop, instead of continuing on
                                // Contains = true if the value parameter occurs within this string, or if value is the empty string (""); otherwise, false. 
                                if (!sourceTxt.ToString().Contains(destTxt.ToString()) && destTxt.ToString().Length > 0)
                                {
                                    break;
                                }
                            }
                        }
                        //CompareInfo compare = CultureInfo.InvariantCulture.CompareInfo;
                        //int compareResult = compare.Compare(sourceTxt.ToString(), destTxt.ToString(), CompareOptions.IgnoreCase | CompareOptions.IgnoreSymbols | CompareOptions.IgnoreNonSpace);
                    }
                    else
                    {
                        alterFlag = true;
                    }
                    // compare source and dest text
                    if (sourceTxt.ToString().ToLower() != destTxt.ToString().ToLower())
                    {
                        alterFlag = true;
                    }
                    // if no differences then resume at next source node
                    if (!alterFlag)
                    {
                        continue;
                    }
                }
                else  // we have a source node, but no matching destination node so set the add flag to true
                {
                    addFlag = true;
                }
                // if no destination text, we need to add it from the source
                if (sourceNodeCount > 0 && (destNodeCount == 0 || xnDest == null))
                {
                    // the object_text node was not found in the destination so add parent node for object to DiffDoc as an add
                    addFlag = true;
                }
                XmlNode xNode = null;
                if (addFlag)
                {
                    xNode = xmlDiffDoc.CreateNode(XmlNodeType.Element, typeName, xmlDiffDoc.NamespaceURI);
                    XmlAttribute xNodeAttrib = xmlDiffDoc.CreateAttribute("Action");
                    xNodeAttrib.Value = "Add";
                    xNode.InnerXml = xnChild_Source.InnerXml;
                    xNode.Attributes.Append(xNodeAttrib);
                    if (!sortFlag) xmlDiffDoc.SelectSingleNode("/DataBase_Schema").AppendChild(xNode);
                    addFlag = false;
                }
                if (alterFlag)
                {
                    xNode = xmlDiffDoc.CreateNode(XmlNodeType.Element, typeName, xmlDiffDoc.NamespaceURI);
                    XmlAttribute xNodeAttrib = xmlDiffDoc.CreateAttribute("Action");
                    xNodeAttrib.Value = "Alter";
                    xNode.InnerXml = xnChild_Source.InnerXml;
                    xNode.Attributes.Append(xNodeAttrib);
                    if (!sortFlag) xmlDiffDoc.SelectSingleNode("/DataBase_Schema").AppendChild(xNode);
                    alterFlag = false;
                }
                if (sortFlag)
                {
                    if (xNode != null)
                    {
                        XmlNodeList xnlSource = xnChild_Source.SelectNodes(depText + SqlObjectName + "']", nsmgr_Source);
                        // get dependencies names and add to sorted list
                        int ii = 0;
                        foreach (XmlNode xnSource in xnlSource)
                        {
                            if (xnSource.ChildNodes[1] != null)
                            {
                                slDep.Add(string.Format("{1:0000}!{0}", SqlObjectName.ToLower(), ii), xnSource.ChildNodes[1].InnerXml.ToLower());
                                ii += 1;
                            }
                        }
                        if (ii > 0)
                        {
                            sl.Add(string.Format("{1:0000}!{0}", SqlObjectName.ToLower(), ii), xNode);
                        }
                        else
                        {
                            sl.Add(string.Format("0000!{0}", SqlObjectName.ToLower()), xNode);
                        }
                    }
                }
            } // end of main for loop
            if (sortFlag)
            {
                // if sldep has count > 0 then we need to do some additional sorting
                SortedList sl2 = new SortedList();
                int zz = 0;
                for (int ii = 0; ii < sl.Count; ii++)
                {
                    sl2.Add(string.Format("{1:00000},{0}", sl.GetKey(ii).ToString(), zz), sl.GetByIndex(ii));
                    zz += 10;
                }
                if (slDep.Count > 0)
                {
                    int start = 0;
                    RecurseDependencies(_serverDB, ref sl2, ref slDep, 0, ref start);
                }
                for (int ii = 0; ii < sl2.Count; ii++)
                {
                    XmlNode xn = (XmlNode)sl2.GetByIndex(ii);
                    xmlDiffDoc.SelectSingleNode("/DataBase_Schema").AppendChild(xn);
                }
            }
        }
 /// <summary>
 /// Compares database objects (except tables and columns) from two distinct XML schema files. These files are generated 
 /// by the SerializeDB method.  This method is called from the CompareSchema method.
 /// </summary>
 /// <param name="_serverDB">Used to identify which server the compare objects came from</param>
 /// <param name="xmlSourceDoc">The XmlDataDocument, the source XML to compare with the destination XML.</param>
 /// <param name="xmlDestinationDoc">The XmlDataDocument, the destination/target XML to compare with the source XML.</param>
 /// <param name="xmlDiffDoc">The XML Diffgram document to update.</param>
 /// <param name="type">The type of database object collection to compare, i.e. defaults, UDDTs, rules, views, functions, 
 /// stored procedures, and triggers.</param>
 /// <param name="xmlDiff">The XmlDiff Object used from the GotDotNet XmlDiff class. Performs the XML node compare.</param>
 /// <param name="CompareTextFlag">Flag that performs full text compare between objects</param>
 public static void CompareObjects(string _serverDB, XmlDocument xmlSourceDoc, XmlDocument xmlDestinationDoc,
     XmlDocument xmlDiffDoc, _NodeType type, XmlDiff xmlDiff, bool CompareTextFlag)
 {
     CompareObjects(_serverDB, xmlSourceDoc, xmlDestinationDoc, xmlDiffDoc, type, xmlDiff, CompareTextFlag, null);
 }