private void GeneratePartialClassHeader(StringBuilder sb, bool isUserFile)
        {
            sb.AppendLine("// Generated class v" + this.htmlUnitVersion
                          + (isUserFile ? ", can be modified" : ", don't modify"));
            sb.AppendLine();
            if (!isUserFile)
            {
                sb.AppendLine("using System;");
                sb.AppendLine("using System.Collections.Generic;");
                sb.AppendLine("using System.Collections.Specialized;");
                sb.AppendLine("using System.Linq;");
                sb.AppendLine("using System.Text;");
                sb.AppendLine();
            }
            sb.Append("namespace ");
            sb.AppendLine(TargetNamespace);
            sb.AppendLine("{");

            var interfaceList = new StringBuilder();

            if (isUserFile)
            {
                sb.AppendLine("   public partial class " + TargetNameWithoutNamespace);
            }
            else
            {
                IEnumerable <Type> wrappedInterfaces = WrappedType
                                                       .GetInterfaces()
                                                       .Where(i => Repository.TypeIsWrapped(i));

                foreach (var wrappedInterface in wrappedInterfaces)
                {
                    interfaceList.AppendFormat(", {0}", Repository.GetTargetFullName(wrappedInterface));
                    Repository.MarkUsageOfType(wrappedInterface);
                }

                if (WrappedBase != null && Repository.TypeIsWrapped(WrappedBase))
                {
                    Repository.MarkUsageOfType(WrappedBase);
                }

                sb.AppendFormat(
                    "   public partial class {0} : {1}{2}\r\n",
                    TargetNameWithoutNamespace,
                    TargetBaseName,
                    interfaceList
                    );
            }

            sb.AppendLine("   {");
        }
        private void ScanMembers(Type type)
        {
            // The special meal of today: find interfaces that is new on this class, and clashes with existing fields!

            var newInterfacesForThisSubclass =
                WrappedType
                .GetInterfaces()
                .Except(WrappedBase != null ? WrappedBase.GetInterfaces() : new Type[] { })
                .Where(i => Repository.TypeIsWrapped(i));

            var existingNames = new HashSet <string>(
                Methods.Values.Select(m => m.TargetMethodInfo.Name));

            var methodsOfNewInterfaces =
                newInterfacesForThisSubclass
                .SelectMany(il => il.GetMethods())
                .Where(m => existingNames.Contains(m.Name))
                .ToArray();

            foreach (var wmiRo in Methods.Values)
            {
                var wmi = wmiRo; // To get correct lambda closure!

                var conflictingMethods = methodsOfNewInterfaces
                                         .Where(m => wmi.TargetMethodInfo.Name == m.Name)
                                         .Where(m => IsMethodSignatureCastable(m, wmi.TargetMethodInfo))
                                         .ToArray();

                foreach (var cm in conflictingMethods)
                {
                    Console.WriteLine("Conflicting method: " + cm);
                }

                if (conflictingMethods.Any())
                {
                    throw new InvalidOperationException();
                }
            }

            // First extract all properties and methods

            IEnumerable <MethodInfo> nonObsoleteMethods = type
                                                          .GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly)
                                                          .Where(mi => (!mi.GetCustomAttributes(typeof(ObsoleteAttribute), true).Any()))
                                                          .Where(mi => (!mi.Name.Contains("<")))
                                                          // TODO: Support methods with weird names that starts with "<bridge>"
                                                          .Where(mi =>
                                                                 (type.BaseType == null ||
                                                                  type.BaseType.GetMethod(mi.Name,
                                                                                          mi.GetParameters().Select(pi => pi.ParameterType).ToArray())
                                                                  == null));

            foreach (MethodInfo method in nonObsoleteMethods)
            {
                bool wrappedAsProperty = false;

                if (method.Name.Length > 3 && method.IsPublic)
                {
                    if (method.Name.StartsWith("get") &&
                        method.ReturnType != typeof(void) &&
                        method.GetParameters().Length == 0
                        // We can't convert methods to properties that will cause the property to have the same name as the type.
                        && method.Name.Substring(3) != type.Name)
                    {
                        GetWrapperPropInfoFor(Properties, method.Name.Substring(3)).GetterMethod = method;
                        wrappedAsProperty = true;
                    }
                    else if (method.Name.StartsWith("set") &&
                             method.GetParameters().Length == 1 &&
                             method.ReturnType == typeof(void))
                    {
                        GetWrapperPropInfoFor(Properties, method.Name.Substring(3)).SetterMethod = method;
                        wrappedAsProperty = true;
                    }
                }

                if (!wrappedAsProperty)
                {
                    Methods.Add(method.ToString(), new WrapperMethodInfo(this, method));
                }
            }

            if (!type.IsAbstract)
            {
                // Extract constructors
                var nonObsoletePublicConstructors = type
                                                    .GetConstructors()
                                                    .Where(mi => (!mi.GetCustomAttributes(typeof(ObsoleteAttribute), true).Any()))
                                                    .Where(mi => mi.DeclaringType == type)
                                                    .Where(mi => !mi.IsAbstract);

                foreach (var constructor in nonObsoletePublicConstructors)
                {
                    Constructors.Add(new WrapperConstructorInfo(this, constructor));
                }
            }

            // Extract public static

            var publicStaticFields = type
                                     .GetFields(BindingFlags.Public | BindingFlags.Static)
                                     .Where(mi => (!mi.GetCustomAttributes(typeof(ObsoleteAttribute), true).Any()))
                                     .Where(f => !f.FieldType.IsInterface);

            foreach (var field in publicStaticFields)
            {
                StaticPublicFields.Add(new WrapperStaticPublicField(this, field));
            }
        }
        public void GenerateInterfaceCode(StringBuilder sb)
        {
            // {0} is namespace declarations
            // {1} is namespace of interface
            // {2} is name of interface
            // {3} is to be filled with methods and properties etc..

            var baseInterfaceString = new StringBuilder();

            foreach (var baseInterface in WrappedType.GetInterfaces().Where(i => Repository.TypeIsWrapped(i)))
            {
                Repository.MarkUsageOfType(baseInterface);
                baseInterfaceString.Append(", ");
                baseInterfaceString.Append(Repository.GetTargetFullName(baseInterface));
            }

            const string fileFmt           = @"// Wrapper for {5}
{0}

namespace {1}
{{
   public interface {2} : NHtmlUnit.IObjectWrapper{3}
   {{
{4}
   }}
}}
";
            var          namespaceIncludes =
                @"// Generated class v" + this.htmlUnitVersion + @", don't modify

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;

";

            var body = new StringBuilder();

#warning HACK HACK HACK ON
            if (!WrappedType.FullName.StartsWith("org.w3c.dom."))
            {
                foreach (var wpi in Properties.Where(x => x.Value.GetterMethod != null))
                {
                    wpi.Value.GeneratePropertyCode(body);
                }

                foreach (var wm in Methods)
                {
                    wm.Value.GenerateMethodCode(body);
                }
            }

            sb.AppendFormat(fileFmt,
                            namespaceIncludes,
                            TargetNamespace,
                            TargetNameWithoutNamespace,
                            baseInterfaceString,
                            body,
                            WrappedType.FullName);
        }