private void MapSubclasses(System.Collections.ArrayList subclasses, System.Collections.Specialized.StringCollection extendedClassesNames, System.Collections.ArrayList mappedClassesNames, System.Xml.XmlTextWriter writer)
        {
            System.Collections.ArrayList mappedSubclassesNames = new System.Collections.ArrayList();
            // Map each subclass after the class it extends
            while (subclasses.Count > 0)
            {
                for (int i = subclasses.Count - 1; i >= 0; i--)
                {
                    System.Type type = subclasses[i] as System.Type;
                    string      extendedClassName = extendedClassesNames[i];
                    if (extendedClassName == null)
                    {
                        throw new MappingException("You must specify the Extends attribute of the Subclass: " + type.FullName);
                    }

                    if (!mappedClassesNames.Contains(extendedClassName) &&
                        !mappedSubclassesNames.Contains(extendedClassName))
                    {
                        bool extendedClassFoundButNotMappedYet = false;
                        // Make sure that the extended class is mapped (in this assembly)
                        foreach (System.Type subclass in subclasses)
                        {
                            if (HbmWriterHelper.GetNameWithAssembly(subclass)
                                == extendedClassName)
                            {
                                if (subclass == type)
                                {
                                    throw new MappingException("The Subclass " + type.FullName + " extends itself.");
                                }
                                else
                                {
                                    extendedClassFoundButNotMappedYet = true;
                                    break;
                                }
                            }
                        }
                        if (extendedClassFoundButNotMappedYet)
                        {
                            continue;                             // Map this one later
                        }
                        // Else unknown extended class:
                        //   Assume it is mapped somewhere else and map this subclass
                    }

                    if (IsSubclass(type, typeof(SubclassAttribute)))
                    {
                        HbmWriter.WriteSubclass(writer, type);
                    }
                    else if (IsSubclass(type, typeof(JoinedSubclassAttribute)))
                    {
                        HbmWriter.WriteJoinedSubclass(writer, type);
                    }
                    else if (IsSubclass(type, typeof(UnionSubclassAttribute)))
                    {
                        HbmWriter.WriteUnionSubclass(writer, type);
                    }

                    // Note: Do not add to mappedClassesNames because it is for x-subclasses (and a x-subclasses shouldn't extend another x-subclasses)
                    mappedSubclassesNames.Add(HbmWriterHelper.GetNameWithAssembly(type));
                    subclasses.RemoveAt(i);
                    extendedClassesNames.RemoveAt(i);
                }
            }
        }
        /// <summary> Writes the mapping of all mapped classes of the specified assembly in the specified stream. </summary>
        /// <param name="stream">Where the xml is written.</param>
        /// <param name="assembly">Assembly used to extract user-defined types containing a valid attribute (can be [Class] or [xSubclass]).</param>
        public virtual void Serialize(System.IO.Stream stream, System.Reflection.Assembly assembly)
        {
            if (stream == null)
            {
                throw new System.ArgumentNullException("stream");
            }
            if (assembly == null)
            {
                throw new System.ArgumentNullException("assembly");
            }

            System.Xml.XmlTextWriter writer = new System.Xml.XmlTextWriter(stream, System.Text.Encoding.UTF8);
            writer.Formatting = System.Xml.Formatting.Indented;
            writer.WriteStartDocument();
            if (WriteDateComment)
            {
                writer.WriteComment(string.Format("Generated from NHibernate.Mapping.Attributes on {0}.", System.DateTime.Now.ToString("u")));
            }
            WriteHibernateMapping(writer, null);

            // Write imports (classes decorated with the [ImportAttribute])
            foreach (System.Type type in assembly.GetTypes())
            {
                object[] imports = type.GetCustomAttributes(typeof(ImportAttribute), false);
                foreach (ImportAttribute import in imports)
                {
                    writer.WriteStartElement("import");
                    if (import.Class != null && import.Class != string.Empty)
                    {
                        writer.WriteAttributeString("class", import.Class);
                    }
                    else                     // Assume that it is the current type that must be imported
                    {
                        writer.WriteAttributeString("class", HbmWriterHelper.GetNameWithAssembly(type));
                    }
                    if (import.Rename != null && import.Rename != string.Empty)
                    {
                        writer.WriteAttributeString("rename", import.Rename);
                    }
                    writer.WriteEndElement();
                }
            }

            // Write classes and x-subclasses (classes must come first if inherited by "external" subclasses)
            int classCount = 0;

            System.Collections.ArrayList mappedClassesNames = new System.Collections.ArrayList();
            foreach (System.Type type in assembly.GetTypes())
            {
                if (!IsClass(type))
                {
                    continue;
                }
                HbmWriter.WriteClass(writer, type);
                mappedClassesNames.Add(HbmWriterHelper.GetNameWithAssembly(type));
                classCount++;
            }

            System.Collections.ArrayList subclasses = new System.Collections.ArrayList();
            System.Collections.Specialized.StringCollection extendedClassesNames = new System.Collections.Specialized.StringCollection();
            foreach (System.Type type in assembly.GetTypes())
            {
                if (!IsSubclass(type))
                {
                    continue;
                }
                bool        map = true;
                System.Type t   = type;
                while ((t = t.DeclaringType) != null)
                {
                    if (IsClass(t) || AreSameSubclass(type, t)) // If a base class is also mapped... (Note: A x-subclass can only contain x-subclasses of the same family)
                    {
                        map = false;                            // This class's mapping is already included in the mapping of the base class
                        break;
                    }
                }
                if (map)
                {
                    subclasses.Add(type);
                    if (IsSubclass(type, typeof(SubclassAttribute)))
                    {
                        extendedClassesNames.Add((type.GetCustomAttributes(typeof(SubclassAttribute), false)[0] as SubclassAttribute).Extends);
                    }
                    else if (IsSubclass(type, typeof(JoinedSubclassAttribute)))
                    {
                        extendedClassesNames.Add((type.GetCustomAttributes(typeof(JoinedSubclassAttribute), false)[0] as JoinedSubclassAttribute).Extends);
                    }
                    else if (IsSubclass(type, typeof(UnionSubclassAttribute)))
                    {
                        extendedClassesNames.Add((type.GetCustomAttributes(typeof(UnionSubclassAttribute), false)[0] as UnionSubclassAttribute).Extends);
                    }
                }
            }
            classCount += subclasses.Count;
            MapSubclasses(subclasses, extendedClassesNames, mappedClassesNames, writer);

            writer.WriteEndElement();             // </hibernate-mapping>
            writer.WriteEndDocument();
            writer.Flush();

            if (classCount == 0)
            {
                throw new MappingException("The following assembly contains no mapped classes: " + assembly.FullName);
            }
            if (!Validate)
            {
                return;
            }

            // Validate the generated XML stream
            try
            {
                writer.BaseStream.Position = 0;
                System.Xml.XmlTextReader tr = new System.Xml.XmlTextReader(writer.BaseStream);

                var reader = CreateReader(tr);

                _stop = false;
                while (reader.Read() && !_stop)                // Read to validate (stop at the first error)
                {
                    ;
                }
            }
            catch (System.Exception ex)
            {
                Error.Append(ex.ToString()).Append(System.Environment.NewLine + System.Environment.NewLine);
            }
        }