/// <summary>
        /// Updates the cli types.
        /// </summary>
        /// <returns>
        /// Returns whether or not any files were added to the project.
        /// </returns>
        /// <param name='monitor'>
        /// A progress monitor.
        /// </param>
        /// <param name='context'>
        /// A sync-back context.
        /// </param>
        /// <param name='typesAdded'>
        /// An output variable specifying whether or not any types were added to the project.
        /// </param>
        bool UpdateCliTypes(IProgressMonitor monitor, XcodeSyncBackContext context, out bool typesAdded)
        {
            var provider = dnp.LanguageBinding.GetCodeDomProvider();
            var options  = new System.CodeDom.Compiler.CodeGeneratorOptions();
            var writer   = MonoDevelop.DesignerSupport.CodeBehindWriter.CreateForProject(
                new MonoDevelop.Core.ProgressMonitoring.NullProgressMonitor(), dnp);

            monitor.BeginTask(GettextCatalog.GetString("Detecting changes made in Xcode"), 0);
            Dictionary <string, NSObjectTypeInfo> newTypes;
            Dictionary <string, ProjectFile>      newFiles;
            var updates = context.GetTypeUpdates(monitor, provider, out newTypes, out newFiles);

            if ((updates == null || updates.Count == 0) && newTypes == null && newFiles == null)
            {
                monitor.Log.WriteLine("No changes found");
                monitor.EndTask();
                typesAdded = false;
                return(false);
            }

            monitor.Log.WriteLine("Found {0} changed types", updates.Count);
            monitor.EndTask();

            int count = updates.Count + (newTypes != null ? newTypes.Count : 0);

            monitor.BeginTask(GettextCatalog.GetString("Updating types in MonoDevelop"), count);

            // First, add new types...
            if (newTypes != null && newTypes.Count > 0)
            {
                foreach (var nt in newTypes)
                {
                    if (provider is Microsoft.CSharp.CSharpCodeProvider)
                    {
                        var cs = new CSharpCodeTypeDefinition()
                        {
                            WrapperNamespace = infoService.WrapperRoot,
                            Provider         = provider,
                            Type             = nt.Value,
                        };

                        string baseDir = Path.GetDirectoryName(nt.Key);
                        if (!Directory.Exists(baseDir))
                        {
                            Directory.CreateDirectory(baseDir);
                        }

                        writer.WriteFile(nt.Key, cs.TransformText());
                    }
                    else
                    {
                        // FIXME: implement support for non-C# languages
                    }

                    monitor.Step(1);
                }

                typesAdded = true;
            }
            else
            {
                typesAdded = false;
            }

            // Next, generate the designer files for any added/changed types
            foreach (var df in updates)
            {
                monitor.Log.WriteLine("Syncing {0} types from Xcode to file '{1}'", df.Value.Count, df.Key);
                if (provider is Microsoft.CSharp.CSharpCodeProvider)
                {
                    var cs = new CSharpCodeCodebehind()
                    {
                        Types            = df.Value,
                        WrapperNamespace = infoService.WrapperRoot,
                        Provider         = provider,
                    };
                    writer.WriteFile(df.Key, cs.TransformText());
                }
                else
                {
                    var ccu = GenerateCompileUnit(provider, options, df.Key, df.Value);
                    writer.WriteFile(df.Key, ccu);
                }

                monitor.Step(1);
            }

            writer.WriteOpenFiles();

            // Update sync timestamps
            foreach (var df in updates)
            {
                foreach (var type in df.Value)
                {
                    context.SetSyncTimeToNow(type.ObjCName + ".h");
                    context.SetSyncTimeToNow(type.ObjCName + ".m");
                }
            }

            // Add new files to the DotNetProject
            if (newFiles != null)
            {
                foreach (var f in newFiles)
                {
                    monitor.Log.WriteLine("Added new designer file {0}", f.Key);
                    dnp.AddFile(f.Value);
                }
            }

            monitor.EndTask();

            return(newFiles != null && newFiles.Count > 0);
        }
        /// <summary>
        /// Adds the custom classes from user interface definition files.
        /// </summary>
        /// <returns>
        /// <c>true</c> if new types were added to the project, or <c>false</c> otherwise.
        /// </returns>
        /// <param name='monitor'>
        /// A progress monitor.
        /// </param>
        /// <param name='context'>
        /// A sync-back context.
        /// </param>
        bool AddCustomClassesFromUIDefinitionFiles(IProgressMonitor monitor, XcodeSyncBackContext context)
        {
            var provider = dnp.LanguageBinding.GetCodeDomProvider();
            var options  = new System.CodeDom.Compiler.CodeGeneratorOptions();
            var writer   = MonoDevelop.DesignerSupport.CodeBehindWriter.CreateForProject(
                new MonoDevelop.Core.ProgressMonitoring.NullProgressMonitor(), dnp);
            bool addedTypes = false;

            monitor.BeginTask(GettextCatalog.GetString("Generating custom classes defined in UI definition files"), 0);

            // Collect our list of custom classes from UI definition files
            foreach (var job in context.FileSyncJobs)
            {
                if (!HasInterfaceDefinitionExtension(job.Original))
                {
                    continue;
                }

                string relative = job.SyncedRelative.ParentDirectory;
                string dir      = dnp.BaseDirectory;

                if (!string.IsNullOrEmpty(relative))
                {
                    dir = Path.Combine(dir, relative);
                }

                foreach (var type in GetCustomTypesFromUIDefinition(job.Original))
                {
                    if (context.ProjectInfo.ContainsType(type.ObjCName))
                    {
                        continue;
                    }

                    string designerPath = Path.Combine(dir, type.ObjCName + ".designer." + provider.FileExtension);
                    string path         = Path.Combine(dir, type.ObjCName + "." + provider.FileExtension);
                    string ns           = dnp.GetDefaultNamespace(path);

                    type.CliName = ns + "." + provider.CreateValidIdentifier(type.ObjCName);

                    if (provider is Microsoft.CSharp.CSharpCodeProvider)
                    {
                        CodebehindTemplateBase cs = new CSharpCodeTypeDefinition()
                        {
                            WrapperNamespace = infoService.WrapperRoot,
                            Provider         = provider,
                            Type             = type,
                        };

                        writer.WriteFile(path, cs.TransformText());

                        List <NSObjectTypeInfo> types = new List <NSObjectTypeInfo> ();
                        types.Add(type);

                        cs = new CSharpCodeCodebehind()
                        {
                            WrapperNamespace = infoService.WrapperRoot,
                            Provider         = provider,
                            Types            = types,
                        };

                        writer.WriteFile(designerPath, cs.TransformText());

                        context.ProjectInfo.InsertUpdatedType(type);
                    }
                    else
                    {
                        // FIXME: implement support for non-C# languages
                    }

                    dnp.AddFile(new ProjectFile(path));
                    dnp.AddFile(new ProjectFile(designerPath)
                    {
                        DependsOn = path
                    });
                    addedTypes = true;
                }
            }

            writer.WriteOpenFiles();

            monitor.EndTask();

            return(addedTypes);
        }