private IList<FilePath> GenerateCodeBehindForHeader(ProjectTypeCache cache, CodeBehindWriter writer, FilePath file)
        {
            IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- Parsing {0}", file);

            // Parse and collect information from the document
            AntlrFileStream stream = new AntlrFileStream (file);
            ObjCLexer lexer = new ObjCLexer (stream);
            CommonTokenStream tokenStream = new CommonTokenStream (lexer);
            ObjCParser parser = new ObjCParser (tokenStream);

            ObjCParser.Translation_unitContext context = parser.translation_unit ();
            NativeClassDescriptionCollector<int> visitor = new NativeClassDescriptionCollector<int> ();
            context.Accept (visitor);

            /*
            IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- Dump classes");
            foreach (NativeClassDescriptor classDescriptor in visitor.Descriptors) {
                IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- ClassName={0}", classDescriptor.ClassName);
                IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- SuperClassName={0}", classDescriptor.SuperClassName);
                foreach (NativeMethodDescriptor descriptor in classDescriptor.Methods) {
                    IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- {0}", descriptor);
                }
                foreach (NativeInstanceVariableDescriptor descriptor in classDescriptor.InstanceVariables) {
                    IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- {0}", descriptor);
                }
            }
            */

            List<FilePath> designerFiles = new List<FilePath> ();
            foreach (NativeClassDescriptor classDescriptor in visitor.Descriptors) {
                // Check if the class should be generated
                if (!ShouldGenerateForHeader (classDescriptor)) {
                    IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForHeader -- Skipping {0} (no outlets or no actions)", classDescriptor.ClassName);
                    continue;
                }

                // Generate the designer part
                FilePath designerFile = this.CodeGenerator.GenerateCodeBehindCode (cache, writer, classDescriptor.ClassName, new []{ classDescriptor });
                if (designerFile != FilePath.Null) {
                    designerFiles.Add (designerFile);
                }
            }

            return designerFiles;
        }
 protected ObjectiveCWriter(MonobjcProject project)
 {
     this.project = project;
     this.cache = ProjectTypeCache.Get(this.project);
 }
        private IList<FilePath> GenerateCodeBehindForXib(ProjectTypeCache cache, CodeBehindWriter writer, FilePath file)
        {
            IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForXib -- Parsing {0}", file);

            // Parse and collect information from the document
            IBDocument document = IBDocument.LoadFromFile (file);
            ClassDescriptionCollector visitor = new ClassDescriptionCollector ();
            document.Root.Accept (visitor);

            List<FilePath> designerFiles = new List<FilePath> ();
            foreach (string className in visitor.ClassNames) {
                // Check if the class should be generated
                if (!ShouldGenerateForXib (visitor, className)) {
                    IDELogger.Log ("CodeBehindHandler::GenerateCodeBehindForXib -- Skipping {0} (no outlets, no actions or reserved name)", className);
                    continue;
                }

                // Generate the designer part
                FilePath designerFile = this.CodeGenerator.GenerateCodeBehindCode (cache, writer, className, visitor [className]);
                if (designerFile != FilePath.Null) {
                    designerFiles.Add (designerFile);
                }
            }

            return designerFiles;
        }
 /// <summary>
 /// Get the type cache for the given project.
 /// </summary>
 public static ProjectTypeCache Get(MonobjcProject project)
 {
     ProjectTypeCache cache;
     if (!caches.TryGetValue (project, out cache)) {
         IDELogger.Log ("ProjectTypeCache::Get -- create cache for {0}", project.Name);
         cache = new ProjectTypeCache (project);
         caches.Add (project, cache);
     }
     return cache;
 }
        /// <summary>
        ///   Generates the design code for an Interface Builder file.
        /// </summary>
        /// <param name = "resolver">The type resolver.</param>
        /// <param name = "writer">The writer.</param>
        /// <param name = "className">Name of the class.</param>
        /// <param name = "enumerable">The class descriptions.</param>
        /// <returns>The path to the designer file.</returns>
        public FilePath GenerateCodeBehindCode(ProjectTypeCache cache, CodeBehindWriter writer, String className, IEnumerable<IIBClassDescriptor> descriptors)
        {
            FilePath designerFile = null;
            String defaultNamespace;
            MonobjcProject project = cache.Project;

            IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Generate designer code for '{0}'", className);

            IType type = cache.ResolvePartialType (className);
            FilePath mainFile = cache.GetMainFile (type);
            if (mainFile != FilePath.Null) {
                if (mainFile.Extension == ".dll") {
                    IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Skipping '{0}' as it comes from a DLL", className);
                    return FilePath.Null;
                }

                if (!cache.IsInProject (type)) {
                    IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Skipping '{0}' as it comes from another project", className);
                    return FilePath.Null;
                }

                // The filname is based on the compilation unit parent folder and the type name
                FilePath parentDirectory = mainFile.ParentDirectory;
                FilePath filename = project.LanguageBinding.GetFileName (type.Name + Constants.DOT_DESIGNER);
                designerFile = parentDirectory.Combine (filename);
                defaultNamespace = type.Namespace;
            } else {
                // Combine the filename in the default directory
                FilePath parentDirectory = project.BaseDirectory;
                FilePath filename = project.LanguageBinding.GetFileName (className + Constants.DOT_DESIGNER);
                designerFile = parentDirectory.Combine (filename);
                defaultNamespace = project.GetDefaultNamespace (designerFile);
            }

            IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Put designer code in '{0}'", designerFile);

            // Create the compilation unit
            CodeCompileUnit ccu = new CodeCompileUnit ();
            CodeNamespace ns = new CodeNamespace (defaultNamespace);
            ccu.Namespaces.Add (ns);

            // Create the partial class
            CodeTypeDeclaration typeDeclaration = new CodeTypeDeclaration (className);
            typeDeclaration.IsClass = true;
            typeDeclaration.IsPartial = true;

            // List for import collection
            Set<String> imports = new Set<string> ();
            imports.Add ("Monobjc");

            // Create fields for outlets);
            foreach (IBOutletDescriptor outlet in descriptors.SelectMany(d => d.Outlets)) {
                IType outletType = cache.ResolvePartialType (outlet.ClassName);
                outletType = outletType ?? cache.ResolvePartialType ("id");
                outletType = outletType ?? cache.ResolveType (typeof(IntPtr));

                IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Resolving outlet '{0}' of type '{1}' => '{2}'", outlet.Name, outlet.ClassName, outletType.FullName);

                imports.Add (outletType.Namespace);

                CodeTypeMember property = this.GenerateOutletProperty (outletType, outlet.Name);
                typeDeclaration.Members.Add (property);
            }

            // Create methods for exposed actions
            foreach (IBActionDescriptor action in descriptors.SelectMany(d => d.Actions)) {
                IType argumentType = cache.ResolvePartialType (action.Argument);
                argumentType = argumentType ?? cache.ResolvePartialType ("id");
                argumentType = argumentType ?? cache.ResolveType (typeof(IntPtr));

                IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Resolving action '{0}' of type '{1}' => '{2}'", action.Message, action.Argument, argumentType.FullName);

                imports.Add (argumentType.Namespace);

                CodeTypeMember exposedMethod = this.GenerateActionExposedMethod (action.Message, argumentType);
                typeDeclaration.Members.Add (exposedMethod);

                CodeTypeMember partialMethod = this.GenerateActionPartialMethod (action.Message, argumentType);
                typeDeclaration.Members.Add (partialMethod);
            }

            // Add namespaces
            CodeNamespaceImport[] namespaceImports = imports.Select (import => new CodeNamespaceImport (import)).ToArray ();
            ns.Imports.AddRange (namespaceImports);

            // Add the type
            ns.Types.Add (typeDeclaration);

            // Write the result
            writer.WriteFile (designerFile, ccu);

            return designerFile;
        }
        protected virtual CodeCompileUnit GenerateCodeCompileUnit(ProjectTypeCache cache, String defaultNamespace, String className, IEnumerable<IBPartialClassDescription> enumerable)
        {
            // Create the compilation unit
            CodeCompileUnit ccu = new CodeCompileUnit ();
            CodeNamespace ns = new CodeNamespace (defaultNamespace);
            ccu.Namespaces.Add (ns);

            // Create the partial class
            CodeTypeDeclaration typeDeclaration = new CodeTypeDeclaration (className);
            typeDeclaration.IsClass = true;
            typeDeclaration.IsPartial = true;

            // List for import collection
            Set<String> imports = new Set<string> ();
            imports.Add ("Monobjc");

            // Create fields for outlets);
            foreach (IBOutletDescriptor outlet in enumerable.SelectMany(d => d.Outlets)) {
                IType outletType = cache.ResolvePartialType (outlet.ClassName);
                outletType = outletType ?? cache.ResolvePartialType ("id");
                outletType = outletType ?? cache.ResolveType (typeof(IntPtr));

                IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Resolving outlet '{0}' of type '{1}' => '{2}'", outlet.Name, outlet.ClassName, outletType.FullName);

                imports.Add (outletType.Namespace);

                CodeTypeMember property = this.GenerateOutletProperty (outletType, outlet.Name);
                typeDeclaration.Members.Add (property);
            }

            // Create methods for exposed actions
            foreach (IBActionDescriptor action in enumerable.SelectMany(d => d.Actions)) {
                IType argumentType = cache.ResolvePartialType (action.Argument);
                argumentType = argumentType ?? cache.ResolvePartialType ("id");
                argumentType = argumentType ?? cache.ResolveType (typeof(IntPtr));

                IDELogger.Log ("BaseCodeBehindGenerator::GenerateCodeBehindCode -- Resolving action '{0}' of type '{1}' => '{2}'", action.Message, action.Argument, argumentType.FullName);

                imports.Add (argumentType.Namespace);

                CodeTypeMember exposedMethod = this.GenerateActionExposedMethod (action.Message, argumentType);
                typeDeclaration.Members.Add (exposedMethod);

                CodeTypeMember partialMethod = this.GenerateActionPartialMethod (action.Message, argumentType);
                typeDeclaration.Members.Add (partialMethod);
            }

            // Add namespaces
            CodeNamespaceImport[] namespaceImports = imports.Select (import => new CodeNamespaceImport (import)).ToArray ();
            ns.Imports.AddRange (namespaceImports);

            // Add the type
            ns.Types.Add (typeDeclaration);

            return ccu;
        }
        /// <summary>
        ///   Generates the design code for framework loading.
        /// </summary>
        /// <param name = "resolver">The type resolver.</param>
        /// <param name = "frameworks">The frameworks.</param>
        /// <returns>The path to the designer file.</returns>
        public FilePath GenerateFrameworkLoadingCode(ProjectTypeCache cache, String[] frameworks)
        {
            IEnumerable<IType> entryPoints = cache.GetEntryPoints ();
            IType entryPoint = entryPoints.SingleOrDefault ();
            if (entryPoint != null) {
                IMethod method = cache.GetMainMethod (entryPoint);
                if (method != null) {
                    // Get the start line of the method
                    DomRegion region = method.BodyRegion;
                    int startLine = region.BeginLine;

                    // Load the entry point file
                    String fileName = region.FileName;
                    List<String> lines = File.ReadAllLines (fileName).ToList ();

                    // Search for desginer region indices
                    int startIndex = lines.FindIndex (startLine - 1, l => this.IsDesignerRegionDelimiter (l, true));
                    int endIndex = -1;
                    if (startIndex != -1) {
                        endIndex = lines.FindIndex (startIndex, l => this.IsDesignerRegionDelimiter (l, false));
                    }
                    if (startIndex != -1 && endIndex != -1) {
                        // Build a new list of lines with the new code
                        List<String> newLines = new List<String> ();
                        newLines.AddRange (lines.Take (startIndex));
                        newLines.AddRange (this.GenerateFrameworkLoadingcode (frameworks));
                        newLines.AddRange (lines.Skip (endIndex + 1));

                        // Write it to the file
                        File.WriteAllLines (fileName, newLines.ToArray ());

                        return fileName;
                    }
                }
            }
            return null;
        }