/// <summary>
        /// loads the saved connection properties into the form
        /// </summary>
        private void LoadFrom(ConnectionProperties props)
        {
            this.txtConnectionString.Text = props.ConnectionString;
            this.LoadedAssemblies         = props.AssemblyLocations.ToDictionary(loc => loc, loc =>
            {
                if (!File.Exists(loc))
                {
                    return(null);
                }
                else
                {
                    return(this.loadSafely(loc));
                }
            });
            this.LoadedTypes.Clear();
            this.LoadedTypes.AddRange(MongoDynamicDataContextDriver.CommonTypes.Values);
            var badAssemblies = new HashSet <Assembly>();

            this.LoadedTypes.AddRange(this.LoadedAssemblies.Values.Where(x => x != null)
                                      .SelectMany(ass =>
            {
                try
                {
                    return(ass.GetExportedTypes());
                }
                catch (Exception)
                {
                    badAssemblies.Add(ass);
                    return(Enumerable.Empty <Type>());
                }
            }));
            foreach (var badAssembly in badAssemblies)
            {
                var key = this.LoadedAssemblies.First(x => x.Value == badAssembly).Key;
                this.LoadedAssemblies[key] = null;
            }
            this.mDatabases = new Dictionary <string, HashSet <CollectionTypeMapping> >();
            foreach (var pair in props.CollectionTypeMappings)
            {
                this.mDatabases[pair.Key] = new HashSet <CollectionTypeMapping>(pair.Value);
            }

            this.cbDatabases.Items.Clear();
            this.cbDatabases.Items.AddRange(this.mDatabases.Keys.Cast <object>().ToArray());
            string db = this.mDatabases.Keys.FirstOrDefault();

            this.cbDatabases.SelectedItem = db;
            if (db != null)
            {
                this.dgCollectionTypes.DataSource = this.mDatabases[db].Select(m => new TypeMappingWrapper(m)).ToList();
            }
            else
            {
                this.dgCollectionTypes.DataSource = null;
            }
            if (props.SelectedDatabase != null)
            {
                this.cbDatabases.SelectedIndex = this.cbDatabases.Items.IndexOf(props.SelectedDatabase);
            }

            this.lbCustomSerializers.Items.Clear();
            this.SerializerMappings.Clear();
            if (props.CustomSerializers != null)
            {
                foreach (var pair in props.CustomSerializers)
                {
                    var keyType = this.LoadedTypes.FirstOrDefault(x => string.Equals(pair.Key, x.FullName));
                    var valType = this.LoadedTypes.FirstOrDefault(x => string.Equals(pair.Value, x.FullName));
                    if (keyType != null && valType != null)
                    {
                        this.SerializerMappings[keyType] = valType;
                    }
                }
            }
            this.lbCustomSerializers.Items.AddRange(this.SerializerMappings.Select(pair => new SerializerMappingWrapper {
                Type = pair.Key, Serializer = pair.Value
            }).Cast <object>().ToArray());

            this.mAdditionalOptions = props.AdditionalOptions;

            this.mInitializationQuery = props.InitializationQuery;
            if (this.mInitializationQuery != null)
            {
                this.SetLoadedQueryName(Path.GetFileName(this.mInitializationQuery.Location));
            }

            UpdateLoadedAssemblies();
        }
        private List <string> ValidateLinqQuery(LinqPadQuery query, ConnectionProperties props)
        {
            List <string> errors = new List <string>();

            StringBuilder sb = new StringBuilder();

            foreach (var ns in query.Namespaces)
            {
                sb.Append("using ").Append(ns).AppendLine(";");
            }
            sb.AppendFormat(@"
public class TestQuery
{{
    public TestQuery()
    {{

    }}

    {0}
}}", query.Query);

            var             driver = new MongoDynamicDataContextDriver();
            CompilerResults results;

            using (var codeProvider = new CSharpCodeProvider(new Dictionary <string, string>()
            {
                { "CompilerVersion", "v4.0" }
            }))
            {
                var assemblyNames = new HashSet <string>(query.References, new AssemblyPathEqualityComparer());

                //add additional assemblies which may or may not have been overridden
                assemblyNames.AddRange("System.dll System.Core.dll".Split());
                assemblyNames.Add(Path.Combine(driver.GetDriverFolder(), "MongoDB.Driver.dll"));
                assemblyNames.Add(Path.Combine(driver.GetDriverFolder(), "MongoDB.Bson.dll"));
                assemblyNames.Add(Path.Combine(driver.GetDriverFolder(), "LinqPadMongoDriver.dll"));

                var options = new CompilerParameters(assemblyNames.ToArray());
                options.GenerateInMemory = true;

                results = codeProvider.CompileAssemblyFromSource(options, sb.ToString());
            }
            if (results.Errors.Count > 0)
            {
                errors.AddRange(results.Errors.Cast <CompilerError>().Select(x => x.ToString()));

                return(errors);
            }

            Type       compiledType = results.CompiledAssembly.GetType("TestQuery");
            object     instance     = Activator.CreateInstance(compiledType);
            MethodInfo initMethod   = compiledType.GetMethod("Initialize", new[] { typeof(ConnectionProperties) });

            if (initMethod == null)
            {
                errors.Add(string.Format("The query must contain a method called Initialize that takes one parameter of type {0}", typeof(ConnectionProperties)));
                return(errors);
            }


            return(errors);
        }
 private void clearToolStripMenuItem_Click(object sender, EventArgs e)
 {
     this.mConnection = new ConnectionProperties();
     this.LoadFrom(this.mConnection);
 }
        /// <summary>
        /// Gets the additional namespaces that should be imported for queries using this driver
        /// </summary>
        /// <param name="cxInfo">the serialized connection properties.</param>
        /// <returns>The namespaces that should be imported as strings</returns>
        public override IEnumerable <string> GetNamespacesToAdd(IConnectionInfo cxInfo)
        {
            ConnectionProperties props = propsSerializer.Deserialize(cxInfo.DriverData);

            return(GetNamespacesToAdd(props));
        }
        /// <summary>
        /// Generates the Dynamic Driver class as a string of code to be compiled.
        /// </summary>
        /// <param name="props">The deserialized Connection Properties</param>
        /// <param name="assemblies">The already-loaded assemblies.</param>
        /// <param name="nameSpace">The namespace of the driver class</param>
        /// <param name="typeName">The name of the driver class</param>
        /// <returns>The Driver class as a string of C# code</returns>
        public string GenerateDynamicCode(ConnectionProperties props, List <Assembly> assemblies, string nameSpace, string typeName)
        {
            var writer = new StringWriter();

            // write namespace and opening brace
            if (!string.IsNullOrEmpty(nameSpace))
            {
                writer.Write("namespace ");
                writer.WriteLine(nameSpace);
                writer.WriteLine("{");
            }

            // write using directives
            writer.WriteLine(
                @"using System.Linq;
using MongoDB.Driver;
using MongoDB.Driver.Linq;
using System.IO;
using System;
using GDSX.Externals.LinqPad.Driver;
");

            // write type declaration
            writer.WriteLine(string.Format("public class {0}\n{{", typeName));
            writer.WriteLine(string.Format("\tpublic {0}(MongoServer mongo)\n\t{{", typeName));
            writer.WriteLine(
                @"     this.mongo = mongo;
    }

    private readonly MongoServer mongo;

    public TextWriter SqlTabWriter { get; set; }
");

            if (props.InitializationQuery != null)
            {
                writer.WriteLine(
                    @"
    private CustomInitQuery mCustomInitializer;
    public CustomInitQuery CustomInitializer 
    { 
        get
        {
            return this.mCustomInitializer;
        }
    }

    public void DoCustomInit(ConnectionProperties props)
    {
        if(mCustomInitializer == null)
        {
            mCustomInitializer = new CustomInitQuery();
            mCustomInitializer.Initialize(props);
        }
    }
");
            }

            writer.WriteLine(string.Format(
                                 "\tpublic String ConnectionString {{ get {{ return \"{0}\"; }} }}\n", props.ConnectionString));

            string db = props.SelectedDatabase;

            writer.WriteLine(string.Format(
                                 "\tpublic String DatabaseName {{ get {{ return \"{0}\"; }} }}\n", db));
            writer.WriteLine(string.Format(
                                 "\tpublic MongoDatabase db {{ get {{ return this.mongo.GetDatabase(\"{0}\"); }} }}\n", db));

            HashSet <string> names           = new HashSet <string>();
            List <string>    initializations = new List <string>();

            foreach (var collection in props.CollectionTypeMappings[db])
            {
                var  name = collection.CollectionName;
                Type type = null;
                if (!string.IsNullOrEmpty(collection.CollectionType) && !string.IsNullOrEmpty(name))
                {
                    type = this.TryLoadType(assemblies, collection.CollectionType);
                }

                var pluralizedName = DoPluralize(name);

                if (type == null)
                {
                    //writer.WriteLine(string.Format(
                    //    "\tpublic MongoCollection {1}Collection {{ get {{ return this.db.GetCollection(\"{0}\"); }} }}\r\n" +
                    //    "\tpublic IQueryable<{2}> {1} {{ get {{ return this.{1}Collection.AsQueryable<{2}>().Select(x => x); }} }}", name, pluralizedName, typeof(BsonDocument).FullName));
                }
                else
                {
                    names.Add(pluralizedName);
                    //Select(x => x) to get around bug in mongo query provider
                    writer.WriteLine(string.Format(
                                         "\tprivate Interceptor<{0}> m{2};\r\n" +
                                         "\tpublic IQueryable<{0}> {2} {{ get {{ return this.m{2}.AsQueryable<{0}>().Select(x => x); }} }}\n", type.FullName, name, pluralizedName));

                    //generate initialization strings
                    initializations.Add(string.Format("\t\tthis.m{2} = new Interceptor<{0}>(this.db.GetCollection<{0}>(\"{1}\"), this.SqlTabWriter);", type.FullName, name, pluralizedName));
                    if (props.AdditionalOptions.AllowSaveForAllTypes ||
                        props.AdditionalOptions.ExplicitSaveAllowedTypes.Contains(type.ToString()))
                    {
                        initializations.Add(string.Format("\t\tthis.m{0}.AllowSave = true;", pluralizedName));
                    }

                    writer.WriteLine(string.Format(
                                         "\tpublic Interceptor<{0}> {2}Collection {{ get {{ return this.m{2}; }} }}\n", type.FullName, name, pluralizedName));
                }
            }

            writer.WriteLine(
                @"    /// <summary>
    /// Submits all changes to queried objects by calling Save on the objects given by
    /// <see cref=""ToUpdate""/>
    /// </summary>
    public void SubmitChanges()
    {
        int modified = 0;");

            foreach (string name in names)
            {
                writer.WriteLine(string.Format("\t\tmodified += this.m{0}.SubmitChanges();", name));
            }

            writer.WriteLine(
                @"    
        if (modified == 0 && !TrackChanges){
            Console.WriteLine(""No changes were submitted.  Did you mean to turn on TrackChanges?"");
        }
    }");

            writer.WriteLine(
                @"    private bool mTrackChanges = false;
    /// <summary>
    /// If true, changes made to collection objects will be tracked and can be updated
    /// using SubmitChanges.  Defaults to off to avoid unnecessary serialization.
    /// </summary>
    public bool TrackChanges
    {
        get
        {
            return mTrackChanges;
        }
        set
        {
            mTrackChanges = value;
");

            foreach (string name in names)
            {
                writer.WriteLine(string.Format("\t\t\tthis.m{0}.TrackChanges = value;", name));
            }

            writer.WriteLine(
                @"        }
    }");

            writer.WriteLine(
                @"    public void InitCollections()
    {");
            foreach (string init in initializations)
            {
                writer.WriteLine(init);
            }

            writer.WriteLine("\t}");

            // write type closing brace
            writer.WriteLine("}");

            // write namespace closing brace
            if (!string.IsNullOrEmpty(nameSpace))
            {
                writer.WriteLine("}");
            }

            return(writer.ToString());
        }
        /// <summary>
        /// Builds the Schema tree for display to the user
        /// </summary>
        /// <param name="props">The deserialized Connection Properties</param>
        /// <param name="assemblies">The already-loaded assemblies.</param>
        /// <returns>A tree of ExplorerItem objects which is shown to the user in LinqPad's UI</returns>
        public List <ExplorerItem> BuildSchema(ConnectionProperties props, List <Assembly> assemblies)
        {
            List <ExplorerItem> ret = new List <ExplorerItem>();

            List <ExplorerItem> UntypedCollections = new List <ExplorerItem>();
            List <ExplorerItem> TypedCollections   = new List <ExplorerItem>();

            ret.Add(new ExplorerItem("db", ExplorerItemKind.QueryableObject, ExplorerIcon.LinkedDatabase));

            foreach (var ctm in props.CollectionTypeMappings[props.SelectedDatabase])
            {
                ExplorerItem coll = null;
                Type         type = null;
                if (!string.IsNullOrEmpty(ctm.CollectionType))
                {
                    type = this.TryLoadType(assemblies, ctm.CollectionType);
                }

                if (type != null)
                {
                    var name = DoPluralize(ctm.CollectionName);

                    coll = new ExplorerItem(name, ExplorerItemKind.QueryableObject, ExplorerIcon.Table)
                    {
                        IsEnumerable = true,
                        DragText     = name,
                        ToolTipText  = String.Format("Queryable of {0}", type.Name)
                    };

                    foreach (PropertyInfo info in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                    {
                        //ignore BSON ignored properties
                        if (info.GetCustomAttributes(typeof(BsonIgnoreAttribute), true).Any())
                        {
                            continue;
                        }

                        if (coll.Children == null)
                        {
                            coll.Children = new List <ExplorerItem>();
                        }

                        coll.Children.Add(new ExplorerItem(info.Name, ExplorerItemKind.Property, ExplorerIcon.Column));
                    }

                    ret.Add(coll);

                    var tColl = new ExplorerItem(name + "Collection", ExplorerItemKind.CollectionLink, ExplorerIcon.View)
                    {
                        IsEnumerable = true,
                        DragText     = name + "Collection",
                        ToolTipText  = String.Format("MongoCollection of {0}", type.Name)
                    };
                    tColl.Children = coll.Children;
                    TypedCollections.Add(tColl);
                }
                else
                {
                    UntypedCollections.Add(new ExplorerItem(ctm.CollectionName, ExplorerItemKind.Category, ExplorerIcon.Blank));
                }
            }

            if (TypedCollections.Count > 0)
            {
                var item = new ExplorerItem("Collections", ExplorerItemKind.Category, ExplorerIcon.Box);
                item.Children = TypedCollections;
                ret.Add(item);
            }


            if (UntypedCollections.Count > 0)
            {
                var item = new ExplorerItem("Untyped Collections", ExplorerItemKind.Category, ExplorerIcon.Box);
                item.Children = UntypedCollections;
                ret.Add(item);
            }


            if (ret.Count == 0)
            {
                throw new Exception("No databases mapped to types");
            }
            return(ret);
        }