/**
         * Generates bodies of all sections that contain a list of source files plus a dictionary of project navigator groups.
         */
        public void GenerateSectionsContents(ref string PBXBuildFileSection, ref string PBXFileReferenceSection,
                                             ref string PBXSourcesBuildPhaseSection, ref Dictionary <string, XcodeFileGroup> Groups)
        {
            StringBuilder FileSection       = new StringBuilder();
            StringBuilder ReferenceSection  = new StringBuilder();
            StringBuilder BuildPhaseSection = new StringBuilder();

            foreach (var CurSourceFile in SourceFiles)
            {
                XcodeSourceFile SourceFile    = CurSourceFile as XcodeSourceFile;
                string          FileName      = Path.GetFileName(SourceFile.FilePath);
                string          FileExtension = Path.GetExtension(FileName);
                string          FilePath      = Utils.MakePathRelativeTo(SourceFile.FilePath, XcodeProjectFileGenerator.MasterProjectRelativePath);
                string          FilePathMac   = Utils.CleanDirectorySeparators(FilePath, '/');

                // Xcode doesn't parse the project file correctly if the build files don't use the same file reference ID,
                // so you can't just manually add an entry for UE4CmdLineRun.m, because the ID will conflict with the
                // ID that gets generated above implicitly by "XcodeSourceFile SourceFile = CurSourceFile as XcodeSourceFile;"
                // At the same time, it is necessary to manually add an entry for it, because we're compiling the unit test with
                // exactly one source file.
                // This is ugly, but the project file generator wasn't designed to handle special cases like this,
                // so we're left with little choice.
                if (FileName == "UE4CmdLineRun.m")
                {
                    SourceFile.ReplaceGUIDS(UE4CmdLineRunFileGuid, UE4CmdLineRunFileRefGuid);
                }

                if (IsGeneratedProject)
                {
                    FileSection.Append(string.Format("\t\t{0} /* {1} in {2} */ = {{isa = PBXBuildFile; fileRef = {3} /* {1} */; }};" + ProjectFileGenerator.NewLine,
                                                     SourceFile.FileGUID,
                                                     FileName,
                                                     GetFileCategory(FileExtension),
                                                     SourceFile.FileRefGUID));
                }

                ReferenceSection.Append(string.Format("\t\t{0} /* {1} */ = {{isa = PBXFileReference; lastKnownFileType = {2}; name = \"{1}\"; path = \"{3}\"; sourceTree = SOURCE_ROOT; }};" + ProjectFileGenerator.NewLine,
                                                      SourceFile.FileRefGUID,
                                                      FileName,
                                                      GetFileType(FileExtension),
                                                      FilePathMac));

                if (IsPartOfUE4XcodeHelperTarget(SourceFile))
                {
                    BuildPhaseSection.Append("\t\t\t\t" + SourceFile.FileGUID + " /* " + FileName + " in Sources */," + ProjectFileGenerator.NewLine);
                }

                string         GroupPath = Path.GetFullPath(Path.GetDirectoryName(SourceFile.FilePath));
                XcodeFileGroup Group     = FindGroupByFullPath(ref Groups, GroupPath);
                if (Group != null)
                {
                    Group.Files.Add(SourceFile);
                }
            }

            PBXBuildFileSection         += FileSection.ToString();
            PBXFileReferenceSection     += ReferenceSection.ToString();
            PBXSourcesBuildPhaseSection += BuildPhaseSection.ToString();
        }
        /**
         * Returns a project navigator group to which the file should belong based on its path.
         * Creates a group tree if it doesn't exist yet.
         */
        public XcodeFileGroup FindGroupByFullPath(ref Dictionary <string, XcodeFileGroup> Groups, string FullPath)
        {
            string RelativePath = (FullPath == XcodeProjectFileGenerator.MasterProjectRelativePath) ? "" : Utils.MakePathRelativeTo(FullPath, XcodeProjectFileGenerator.MasterProjectRelativePath);

            if (RelativePath.StartsWith(".."))
            {
                string UE4Dir = Path.GetFullPath(Directory.GetCurrentDirectory() + "../../..");
                RelativePath = Utils.MakePathRelativeTo(FullPath, UE4Dir);
            }

            string[] Parts       = RelativePath.Split(Path.DirectorySeparatorChar);
            string   CurrentPath = "";
            Dictionary <string, XcodeFileGroup> CurrentParent = Groups;

            foreach (string Part in Parts)
            {
                XcodeFileGroup CurrentGroup;

                if (CurrentPath != "")
                {
                    CurrentPath += Path.DirectorySeparatorChar;
                }

                CurrentPath += Part;

                if (!CurrentParent.ContainsKey(CurrentPath))
                {
                    CurrentGroup = new XcodeFileGroup(Path.GetFileName(CurrentPath), CurrentPath);
                    CurrentParent.Add(CurrentPath, CurrentGroup);
                }
                else
                {
                    CurrentGroup = CurrentParent[CurrentPath];
                }

                if (CurrentPath == RelativePath)
                {
                    return(CurrentGroup);
                }

                CurrentParent = CurrentGroup.Children;
            }

            return(null);
        }
        /**
         * Returns a project navigator group to which the file should belong based on its path.
         * Creates a group tree if it doesn't exist yet.
         */
        public XcodeFileGroup FindGroupByFullPath(ref Dictionary<string, XcodeFileGroup> Groups, string FullPath)
        {
            string RelativePath = (FullPath == XcodeProjectFileGenerator.MasterProjectRelativePath) ? "" : Utils.MakePathRelativeTo(FullPath, XcodeProjectFileGenerator.MasterProjectRelativePath);
            if (RelativePath.StartsWith(".."))
            {
                string UE4Dir = Path.GetFullPath(Directory.GetCurrentDirectory() + "../../..");
                RelativePath = Utils.MakePathRelativeTo(FullPath, UE4Dir);
            }

            string[] Parts = RelativePath.Split(Path.DirectorySeparatorChar);
            string CurrentPath = "";
            Dictionary<string, XcodeFileGroup> CurrentParent = Groups;

            foreach (string Part in Parts)
            {
                XcodeFileGroup CurrentGroup;

                if (CurrentPath != "")
                {
                    CurrentPath += Path.DirectorySeparatorChar;
                }

                CurrentPath += Part;

                if (!CurrentParent.ContainsKey(CurrentPath))
                {
                    CurrentGroup = new XcodeFileGroup(Path.GetFileName(CurrentPath), CurrentPath);
                    CurrentParent.Add(CurrentPath, CurrentGroup);
                }
                else
                {
                    CurrentGroup = CurrentParent[CurrentPath];
                }

                if (CurrentPath == RelativePath)
                {
                    return CurrentGroup;
                }

                CurrentParent = CurrentGroup.Children;
            }

            return null;
        }
		private void AppendGroup(XcodeFileGroup Group, StringBuilder Content, bool bFilesOnly)
		{
			if (!Group.bIsReference)
			{
				if (!bFilesOnly)
				{
					Content.Append(string.Format("\t\t{0} = {{{1}", Group.GroupGuid, ProjectFileGenerator.NewLine));
					Content.Append("\t\t\tisa = PBXGroup;" + ProjectFileGenerator.NewLine);
					Content.Append("\t\t\tchildren = (" + ProjectFileGenerator.NewLine);

					foreach (XcodeFileGroup ChildGroup in Group.Children.Values)
					{
						Content.Append(string.Format("\t\t\t\t{0} /* {1} */,{2}", ChildGroup.GroupGuid, ChildGroup.GroupName, ProjectFileGenerator.NewLine));
					}
				}

				foreach (XcodeSourceFile File in Group.Files)
				{
					Content.Append(string.Format("\t\t\t\t{0} /* {1} */,{2}", File.FileRefGuid, File.Reference.GetFileName(), ProjectFileGenerator.NewLine));
				}

				if (!bFilesOnly)
				{
					Content.Append("\t\t\t);" + ProjectFileGenerator.NewLine);
					Content.Append("\t\t\tname = \"" + Group.GroupName + "\";" + ProjectFileGenerator.NewLine);
					Content.Append("\t\t\tpath = \"" + Group.GroupPath + "\";" + ProjectFileGenerator.NewLine);
					Content.Append("\t\t\tsourceTree = \"<group>\";" + ProjectFileGenerator.NewLine);
					Content.Append("\t\t};" + ProjectFileGenerator.NewLine);

					foreach (XcodeFileGroup ChildGroup in Group.Children.Values)
					{
						AppendGroup(ChildGroup, Content, bFilesOnly: false);
					}
				}
			}
		}
		/// <summary>
		/// Returns a project navigator group to which the file should belong based on its path.
		/// Creates a group tree if it doesn't exist yet.
		/// </summary>
		public XcodeFileGroup FindGroupByRelativePath(ref Dictionary<string, XcodeFileGroup> Groups, string RelativePath)
		{
			string[] Parts = RelativePath.Split(Path.DirectorySeparatorChar);
			string CurrentPath = "";
			Dictionary<string, XcodeFileGroup> CurrentParent = Groups;

			foreach (string Part in Parts)
			{
				XcodeFileGroup CurrentGroup;

				if (CurrentPath != "")
				{
					CurrentPath += Path.DirectorySeparatorChar;
				}

				CurrentPath += Part;

				if (!CurrentParent.ContainsKey(CurrentPath))
				{
					CurrentGroup = new XcodeFileGroup(Path.GetFileName(CurrentPath), CurrentPath);
					CurrentParent.Add(CurrentPath, CurrentGroup);
				}
				else
				{
					CurrentGroup = CurrentParent[CurrentPath];
				}

				if (CurrentPath == RelativePath)
				{
					return CurrentGroup;
				}

				CurrentParent = CurrentGroup.Children;
			}

			return null;
		}