/// <summary>
        /// Creates inert DiffFiles and adds them to the folderNode, so that further operations
        /// can be performed on them later.
        /// </summary>
        /// <param name="folderNode"></param>
        /// <param name="fileNames"></param>
        /// <param name="ownerType"></param>
        private void AddFileNodesToFolderNode(ref DiffFolder folderNode, string[] fileNames, DiffFolder.TypeOfOwner ownerType)
        {
            foreach (string fileName in fileNames)
            {
                if (Path.GetExtension(fileName).ToLower() != ".aaz")
                {
                    DiffFile fileNode = new DiffFile(Path.GetFileName(fileName));

                    switch (ownerType)
                    {
                    case DiffFolder.TypeOfOwner.Parent:
                        fileNode.FilePathPrevGen = fileName;
                        break;

                    case DiffFolder.TypeOfOwner.Generated:
                        fileNode.FilePathTemplate = fileName;
                        break;

                    case DiffFolder.TypeOfOwner.User:
                        fileNode.FilePathUser = fileName;
                        break;
                    }
                    folderNode.AddFile(fileNode, ownerType);
                }
            }
        }
        /// <summary>
        /// Gets the type of diff for the current object. Also sets the lowest common denominator diff type for the diffFile.
        /// </summary>
        /// <param name="diffFile"></param>
        /// <param name="userFileExists"></param>
        /// <param name="parentFileExists"></param>
        /// <param name="userEntityFound"></param>
        /// <param name="parentEntityFound"></param>
        /// <returns>The type of diff of the current object.</returns>
        private TypeOfDiff SetDiffType(DiffFile diffFile, bool userFileExists, bool parentFileExists, bool userEntityFound, bool parentEntityFound)
        {
            TypeOfDiff newDiffType = TypeOfDiff.ExactCopy;

            if (userFileExists && parentFileExists)
            {
                if (userEntityFound && parentEntityFound)
                {
                    newDiffType = TypeOfDiff.ExactCopy;
                }
                else if (userEntityFound && !parentEntityFound)
                {
                    newDiffType = TypeOfDiff.TemplateChangeOnly;
                }
                else if (!userEntityFound && parentEntityFound)
                {
                    newDiffType = TypeOfDiff.UserChangeOnly;
                }
                else if (!userEntityFound && !parentEntityFound)
                {
                    newDiffType = TypeOfDiff.UserAndTemplateChange;
                }
            }
            else if (userFileExists && !parentFileExists)
            {
                if (userEntityFound)
                {
                    newDiffType = TypeOfDiff.ExactCopy;
                }
                else
                {
                    newDiffType = TypeOfDiff.UserChangeOnly;
                }
            }
            else if (!userFileExists && parentFileExists)
            {
                if (parentEntityFound)
                {
                    newDiffType = TypeOfDiff.ExactCopy;
                }
                else
                {
                    newDiffType = TypeOfDiff.UserChangeOnly;
                }
            }
            TypeOfDiff currentDiffType = diffFile.DiffType;

            diffFile.DiffType = ArchAngel.Providers.CodeProvider.CSharp.Utility.ModifyTypeOfDiff(currentDiffType, newDiffType);
            return(newDiffType);
        }
        public TypeOfDiff DisplayNodeFiles(TreeListNode node, DiffFile currentDiffFile, ArchAngel.Providers.CodeProvider.CSharp.MapInfoType mapInfo, AutoMergeTypes autoMergeType, OriginTypes originType)
        {
            CurrentDiffFile = currentDiffFile;
            CurrentMapInfo = mapInfo;
            OriginType = originType;
            Type type = null;

            if (mapInfo.UserObject != null)
            {
                type = mapInfo.UserObject.GetType();
            }
            else if (mapInfo.TemplateObject != null)
            {
                type = mapInfo.TemplateObject.GetType();
            }
            else if (mapInfo.PrevGenObject != null)
            {
                type = mapInfo.PrevGenObject.GetType();
            }
            string userText = null;
            string templateText = null;
            string prevGenText = null;
            string mergedText = null;

            if (type == typeof(ArchAngel.Providers.CodeProvider.CSharp.Class) ||
                type == typeof(ArchAngel.Providers.CodeProvider.CSharp.Interface) ||
                type == typeof(ArchAngel.Providers.CodeProvider.CSharp.Namespace) ||
                type == typeof(ArchAngel.Providers.CodeProvider.CSharp.Struct))
            {
                userText = mapInfo.UserObject == null ? null : ((ArchAngel.Providers.CodeProvider.CSharp.Class)mapInfo.UserObject).ToString(false);
                templateText = mapInfo.TemplateObject == null ? null : ((ArchAngel.Providers.CodeProvider.CSharp.Class)mapInfo.TemplateObject).ToString(false);
                prevGenText = mapInfo.PrevGenObject == null ? null : ((ArchAngel.Providers.CodeProvider.CSharp.Class)mapInfo.PrevGenObject).ToString(false);
            }
            else
            {
                userText = mapInfo.UserObject == null ? null : mapInfo.UserObject.ToString();
                templateText = mapInfo.TemplateObject == null ? null : mapInfo.TemplateObject.ToString();
                prevGenText = mapInfo.PrevGenObject == null ? null : mapInfo.PrevGenObject.ToString();
            }
            if (mapInfo.Parent != null)
            {
                mergedText = mapInfo.Parent.ToString();
            }
            else if (mapInfo.MergedObject != null)
            {
                mergedText = mapInfo.MergedObject.ToString();
            }
            return DisplayNodeFiles(node, CurrentDiffFile, autoMergeType, userText, templateText, prevGenText, mergedText, mapInfo.DiffType, OriginType);
        }
        /// <summary>
        /// Gets the type of diff for the current object. Also sets the lowest common denominator diff type for the diffFile.
        /// </summary>
        /// <param name="diffFile"></param>
        /// <param name="userFileExists"></param>
        /// <param name="parentFileExists"></param>
        /// <param name="userEntityFound"></param>
        /// <param name="parentEntityFound"></param>
        /// <returns>The type of diff of the current object.</returns>
        private TypeOfDiff SetDiffType(DiffFile diffFile, bool userFileExists, bool parentFileExists, bool userEntityFound, bool parentEntityFound)
        {
            TypeOfDiff newDiffType = TypeOfDiff.ExactCopy;

            if (userFileExists && parentFileExists)
            {
                if (userEntityFound && parentEntityFound)
                {
                    newDiffType = TypeOfDiff.ExactCopy;
                }
                else if (userEntityFound && !parentEntityFound)
                {
                    newDiffType = TypeOfDiff.TemplateChangeOnly;
                }
                else if (!userEntityFound && parentEntityFound)
                {
                    newDiffType = TypeOfDiff.UserChangeOnly;
                }
                else if (!userEntityFound && !parentEntityFound)
                {
                    newDiffType = TypeOfDiff.UserAndTemplateChange;
                }
            }
            else if (userFileExists && !parentFileExists)
            {
                if (userEntityFound)
                {
                    newDiffType = TypeOfDiff.ExactCopy;
                }
                else
                {
                    newDiffType = TypeOfDiff.UserChangeOnly;
                }
            }
            else if (!userFileExists && parentFileExists)
            {
                if (parentEntityFound)
                {
                    newDiffType = TypeOfDiff.ExactCopy;
                }
                else
                {
                    newDiffType = TypeOfDiff.UserChangeOnly;
                }
            }
            TypeOfDiff currentDiffType = diffFile.DiffType;
            diffFile.DiffType = ArchAngel.Providers.CodeProvider.CSharp.Utility.ModifyTypeOfDiff(currentDiffType, newDiffType);
            return newDiffType;
        }
        /// <summary>
        /// Performs an in depth diff by breaking code files into their constituent parts (functions, properties
        /// etc, so that these elements can be diffed without regard to their ordering.
        /// </summary>
        /// <param name="diffFile"></param>
        private void PerformSuperDiff(ref DiffFile diffFile)
        {
            try
            {
                switch (Path.GetExtension(diffFile.Path).ToLower())
                {
                    case ".cs":
                        Providers.CSharpFormatter formatter = new Providers.CSharpFormatter(diffFile.Path);
                        formatter.CreateObjectModel = true;
                        formatter.RaiseError += formatter_RaiseError;

                        try
                        {
                            // TODO: get the code for each file type (user, generated, prevGen), then
                            // break into classes, functions etc, and  perform a diff3 on each entity.
                            // We REALLY need to store these results in the objects, so that this process
                            // happens once, when the initial population occurs, and doesn't need to happen
                            // again when the user clicks a childTreeListNode to display the text and conflicts.

                            // Reset the DiffType
                            diffFile.DiffType = TypeOfDiff.ExactCopy;

                            if (File.Exists(diffFile.FilePathPrevGen))
                            {
                                formatter.Reset();
                                formatter.CodeFilePath = diffFile.FilePathPrevGen;
                                formatter.GetFormattedCode(Slyce.Common.Utility.ReadTextFile(diffFile.FilePathPrevGen));
                                diffFile.CodeRootParent = formatter.Controller.Root;
                                diffFile.CodeRootParent.SortAllMembers();
                            }
                            if (File.Exists(diffFile.FilePathTemplate))
                            {
                                formatter.Reset();
                                formatter.CodeFilePath = diffFile.FilePathTemplate;
                                formatter.GetFormattedCode(Slyce.Common.Utility.ReadTextFile(diffFile.FilePathTemplate));
                                diffFile.CodeRootTemplate = formatter.Controller.Root;
                                diffFile.CodeRootTemplate.SortAllMembers();
                            }
                            if (File.Exists(diffFile.FilePathUser))
                            {
                                formatter.Reset();
                                formatter.CodeFilePath = diffFile.FilePathUser;
                                formatter.GetFormattedCode(Slyce.Common.Utility.ReadTextFile(diffFile.FilePathUser));
                                diffFile.CodeRootUser = formatter.Controller.Root;
                                diffFile.CodeRootUser.SortAllMembers();

                                // TODO: this check of whether the code object model has been correctly created must get removed from the final build
                                //string code = diffFile.CodeRootUser.ToString();
                                //formatter.Reset();
                                //formatter.ParseCode(code);

                                //if (!diffFile.CodeRootUser.IsTheSame(ArchAngel.Providers.CodeProvider.Controller.Root))
                                //{
                                //    throw new InvalidProgramException("The code object model has not been written correctly: " + ArchAngel.Providers.CodeProvider.CSharp.BaseConstruct.ComparisonDifference);
                                //}
                            }
                        }
                        catch (Exception ex)
                        {
                            diffFile.ParseErrorDescription = ex.Message;
                        }
                        bool ignoreAllOmits = false;

                        if (File.Exists(diffFile.FilePathTemplate) &&
                            !File.Exists(diffFile.FilePathUser))
                        {
                            // If the user file is missing, then all code objects are also going to be missing and
                            // will therefore get marked at 'Omit = true', but infact we need to generate them.
                            ignoreAllOmits = true;
                        }
                        TypeOfDiff resultingDiffType;
                        Providers.CodeProvider.CSharp.Utility utility = new Providers.CodeProvider.CSharp.Utility();
                        diffFile.CodeRootAll = utility.CreateCombinedCodeRoot(diffFile.CodeRootTemplate, diffFile.CodeRootUser, diffFile.CodeRootParent, out resultingDiffType, ignoreAllOmits);
                        diffFile.CodeRootAll.SortAllMembers();
                        diffFile.DiffType = resultingDiffType;

                        break;
                    default:
                        // No SuperDiff available for this type of file (no parser created yet).
                        break;
                }
            }
            catch (Exception ex)
            {
                Controller.ReportError(ex);
            }
        }
        /// <summary>
        /// Creates inert DiffFiles and adds them to the folderNode, so that further operations
        /// can be performed on them later.
        /// </summary>
        /// <param name="folderNode"></param>
        /// <param name="fileNames"></param>
        /// <param name="ownerType"></param>
        private void AddFileNodesToFolderNode(ref DiffFolder folderNode, string[] fileNames, DiffFolder.TypeOfOwner ownerType)
        {
            foreach (string fileName in fileNames)
            {
                if (Path.GetExtension(fileName).ToLower() != ".aaz")
                {
                    DiffFile fileNode = new DiffFile(Path.GetFileName(fileName));

                    switch (ownerType)
                    {
                        case DiffFolder.TypeOfOwner.Parent:
                            fileNode.FilePathPrevGen = fileName;
                            break;
                        case DiffFolder.TypeOfOwner.Generated:
                            fileNode.FilePathTemplate = fileName;
                            break;
                        case DiffFolder.TypeOfOwner.User:
                            fileNode.FilePathUser = fileName;
                            break;
                    }
                    folderNode.AddFile(fileNode, ownerType);
                }
            }
        }
        internal void PerformDiffOfFile(DiffFile diffFile, ref bool fileNeedsToBeCounted)
        {
            // Don't process files that had errors during generation
            for (int errFileCounter = 0; errFileCounter < GenerationErrors.Count; errFileCounter++)
            {
                if (Slyce.Common.Utility.StringsAreEqual(diffFile.RelativePath, GenerationErrors[errFileCounter].FileName, false))
                {
                    //continue;
                    return;
                }
            }
            if (UniqueFilesForCount[diffFile.RelativePath] != null &&
                (bool)UniqueFilesForCount[diffFile.RelativePath] == false)
            {
                fileNeedsToBeCounted = true;
                UniqueFilesForCount[diffFile.RelativePath] = true;
            }
            else
            {
                fileNeedsToBeCounted = false;
            }
            if (diffFile.Path.IndexOf(".aaz") > 0 ||
                diffFile.HasParseError)
            {
                //continue;
                return;
            }
            if (FileBeingProcessed != null)
            {
                FileBeingProcessed(diffFile.Path);
            }
            // Perform a 3-way diff on the file
            string parentFile = Path.Combine(PreviousGenerationFolder, diffFile.RelativePath);
            string userFile = Path.Combine(Controller.Instance.ProjectSettings.ProjectPath, diffFile.RelativePath);
            string templateFile = Path.Combine(Controller.Instance.GetTempFilePathForComponent(ComponentKey.WorkbenchFileGenerator), diffFile.RelativePath);
            string mergedFile = Path.Combine(StagingFolder, diffFile.RelativePath + ".merged");

            if(CheckFilesForModifications(diffFile.RelativePath) == false)
            {
                RaiseDiffFinishedEvent(diffFile.Name, TypeOfDiff.ExactCopy);
                return;
            }

            diffFile.FilePathTemplate = templateFile;
            diffFile.FilePathUser = userFile;
            diffFile.FilePathPrevGen = parentFile;

            if (File.Exists(mergedFile))
            {
                bool mergeComplete = true;

                // Binary files are never in an unknown state, they are all or nothing.
                // Text files need to be checked.
                if (diffFile.IsText)
                {
                    using (TextReader tr = new StreamReader(mergedFile))
                    {
                        string line;
                        //int lineCounter = 0;

                        while ((line = tr.ReadLine()) != null &&
                            mergeComplete)
                        {
                            int pipeIndex = line.IndexOf("|");
                            int backColor = int.Parse(line.Substring(0, pipeIndex));

                            if (backColor != -1 &&
                                backColor != 0)
                            {
                                mergeComplete = false;
                            }
                            //lineCounter++;
                        }
                    }
                }
                if (mergeComplete)
                {
                    diffFile.DiffType = TypeOfDiff.Warning;
                }
                else
                {
                    diffFile.DiffType = TypeOfDiff.Conflict;
                }
            }
            else
            {
                if (diffFile.IsText)
                {
                    if (File.Exists(parentFile) &&
                              File.Exists(userFile) &&
                              File.Exists(templateFile))
                    {
                        // Perform 3-way diff
                        string fileBodyParent = IOUtility.GetTextFileBody(parentFile);
                        string fileBodyUser = IOUtility.GetTextFileBody(userFile);
                        string fileBodyGenerated = IOUtility.GetTextFileBody(templateFile);

                        string mergedText;
                        slyceMerge = SlyceMerge.Perform3wayDiff(fileBodyUser, fileBodyParent, fileBodyGenerated, out mergedText);
                        diffFile.DiffType = slyceMerge.DiffType;
                        string newFile = "";

                        if (slyceMerge.DiffType != TypeOfDiff.Conflict)
                        {
                            switch (slyceMerge.DiffType)
                            {
                                case TypeOfDiff.ExactCopy:
                                    newFile = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                                    Slyce.Common.Utility.FileCopy(userFile, newFile);
                                    break;
                                case TypeOfDiff.TemplateChangeOnly:
                                    newFile = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                                    Slyce.Common.Utility.FileCopy(templateFile, newFile);
                                    break;
                                case TypeOfDiff.UserAndTemplateChange:
                                    newFile = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";

                                    if (!Directory.Exists(Path.GetDirectoryName(newFile)))
                                    {
                                        Directory.CreateDirectory(Path.GetDirectoryName(newFile));
                                    }
                                    Slyce.Common.Utility.WriteToFile(newFile, mergedText);
                                    break;
                                case TypeOfDiff.UserChangeOnly:
                                    newFile = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                                    Slyce.Common.Utility.FileCopy(userFile, newFile);
                                    break;
                                case TypeOfDiff.Warning:
                                    throw new Exception("Oops");
                            }
                        }
                    }
                    else if (File.Exists(parentFile) &&
                              File.Exists(userFile) &&
                              !File.Exists(templateFile))
                    {
                        // No template file, just use the user file
                        diffFile.DiffType = TypeOfDiff.UserChangeOnly;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(userFile, newPath);
                    }
                    else if (File.Exists(parentFile) &&
                                  !File.Exists(userFile) &&
                                  File.Exists(templateFile))
                    {
                        // No user file, just use the template file
                        diffFile.DiffType = TypeOfDiff.TemplateChangeOnly;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(templateFile, newPath);
                    }
                    else if (!File.Exists(parentFile) &&
                                  File.Exists(userFile) &&
                                  File.Exists(templateFile))
                    {
                        // No parent file, make sure the user merges the template and user files
                        SlyceMerge.LineSpan[] userLines;
                        SlyceMerge.LineSpan[] templateLines;
                        string combinedText;
                        diffFile.DiffType = SlyceMerge.PerformTwoWayDiff(false, IOUtility.GetTextFileBody(userFile), IOUtility.GetTextFileBody(templateFile), out userLines, out templateLines, out combinedText);

                        if (diffFile.DiffType == TypeOfDiff.ExactCopy)
                        {
                            string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                            Slyce.Common.Utility.FileCopy(templateFile, newPath);
                        }
                        else
                        {
                            throw new NotImplementedException("This scenario has not been handled yet. Please contact [email protected] with: PerformDiffOfFolder(PrevGen file doesn't exist, and TypeOfDiff = " + diffFile.DiffType + ")");
                        }
                        //diffFile.DiffType = SlyceMerge.TypeOfDiff.Conflict; // TODO: Work out what should be done in this instance
                        //throw new Exception("TODO: determine course of action, what should be copied to staging folder.");
                        //string newPath = templateFile.Replace(ProjectFolder, StagingFolder) + ".copy";
                        //Utility.FileCopy(templateFile, newPath);
                    }
                    else if (File.Exists(parentFile) &&
                        !File.Exists(userFile) &&
                        !File.Exists(templateFile))
                    {
                        // TODO: It looks like the file was deleted by the user, AND it was removed from the template, so therefore the
                        // user doesn't want this file anymore. Get user to confirm?
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(parentFile, newPath);
                    }
                    else if (!File.Exists(parentFile) &&
                                 !File.Exists(userFile) &&
                                 File.Exists(templateFile))
                    {
                        string newPath = templateFile.Replace(Controller.Instance.GetTempFilePathForComponent(ComponentKey.WorkbenchFileGenerator), StagingFolder) + ".copy";
                        Slyce.Common.Utility.FileCopy(templateFile, newPath);
                    }
                    else if (!File.Exists(parentFile) &&
                                  File.Exists(userFile) &&
                                  !File.Exists(templateFile))
                    {
                        // TODO: Do we really need to go to the effort of copying etc, because it only exists in the user folder,
                        // so if we take no action it will still exist there - that should be fine ;-)
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(userFile, newPath);
                    }
                    else
                    {
                        // TODO: Shouldn't really be a warning...
                        diffFile.DiffType = TypeOfDiff.Warning;
                        throw new Exception(string.Format("TODO: determine course of action, what should be copied to staging folder, because no file exists: \n{0}\n{1}\n{2}", parentFile, userFile, templateFile));
                    }
                }
                else // Binary file
                {
                    string crcParent = File.Exists(parentFile) ? Slyce.Common.Utility.GetCheckSumOfFile(parentFile) : "";
                    string crcTemplate = File.Exists(templateFile) ? Slyce.Common.Utility.GetCheckSumOfFile(templateFile) : "";
                    string crcUser = File.Exists(userFile) ? Slyce.Common.Utility.GetCheckSumOfFile(userFile) : "";

                    diffFile.MD5Parent = crcParent;
                    diffFile.MD5Template = crcTemplate;
                    diffFile.MD5User = crcUser;

                    // TODO: perform CheckSum of binary file
                    if (!string.IsNullOrEmpty(crcParent) &&
                        !string.IsNullOrEmpty(crcTemplate) &&
                        !string.IsNullOrEmpty(crcUser))
                    {
                        if (crcParent == crcUser &&
                                crcUser == crcTemplate)
                        {
                            diffFile.DiffType = TypeOfDiff.ExactCopy;
                            string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                            Slyce.Common.Utility.FileCopy(userFile, newPath);
                        }
                        else if (crcParent == crcUser &&
                                    crcParent != crcTemplate)
                        {
                            diffFile.DiffType = TypeOfDiff.TemplateChangeOnly;
                            string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                            Slyce.Common.Utility.FileCopy(userFile, newPath);
                        }
                        else if (crcParent != crcUser &&
                                    crcParent == crcTemplate)
                        {
                            diffFile.DiffType = TypeOfDiff.UserChangeOnly;
                            string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                            Slyce.Common.Utility.FileCopy(userFile, newPath);
                        }
                        else if (crcParent != crcUser &&
                             crcUser == crcTemplate)
                        {
                            diffFile.DiffType = TypeOfDiff.UserAndTemplateChange;
                        }
                    }
                    else if (string.IsNullOrEmpty(crcParent) &&
                        !string.IsNullOrEmpty(crcTemplate) &&
                        !string.IsNullOrEmpty(crcUser))
                    {
                        diffFile.DiffType = TypeOfDiff.Conflict;
                    }
                    else if (!string.IsNullOrEmpty(crcParent) &&
                                !string.IsNullOrEmpty(crcTemplate) &&
                                string.IsNullOrEmpty(crcUser))
                    {
                        diffFile.DiffType = TypeOfDiff.TemplateChangeOnly;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(templateFile, newPath);
                    }
                    else if (!string.IsNullOrEmpty(crcParent) &&
                            string.IsNullOrEmpty(crcTemplate) &&
                            !string.IsNullOrEmpty(crcUser))
                    {
                        diffFile.DiffType = TypeOfDiff.UserChangeOnly;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(userFile, newPath);
                    }
                    else if (string.IsNullOrEmpty(crcParent) &&
                            !string.IsNullOrEmpty(crcTemplate) &&
                            string.IsNullOrEmpty(crcUser))
                    {
                        // This is a new file that has been generated
                        diffFile.DiffType = TypeOfDiff.ExactCopy;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(templateFile, newPath);
                    }
                    else
                    {
                        throw new NotImplementedException("Not coded yet. Seems like only one version of binary file exists. Probably just need to copy as-is.");
                    }
                }
            }
            if (diffFile.DiffType != TypeOfDiff.ExactCopy)
            {
                // Only perform the costly SuperDiff if it is not an exact copy
                //ArchAngel.IntelliMerge.DiffItems.DiffFile diffFile = diffFile;
                PerformSuperDiff(ref diffFile);
            }
            if (fileNeedsToBeCounted)
            {
                switch (diffFile.DiffType)
                {
                    case TypeOfDiff.Conflict:
                        m_numConflicts++;
                        break;
                    case TypeOfDiff.ExactCopy:
                        m_numExactCopy++;
                        break;
                    case TypeOfDiff.TemplateChangeOnly:
                    case TypeOfDiff.UserAndTemplateChange:
                    case TypeOfDiff.UserChangeOnly:
                    case TypeOfDiff.Warning:
                        m_numResolvable++;
                        break;
                    default:
                        throw new NotImplementedException("Not coded yet");
                }
                RaiseDiffFinishedEvent(diffFile.Name, diffFile.DiffType);
            }

            Slyce.Common.Utility.DeleteFileBrute(templateFile + ".prevgen.md5");
            Slyce.Common.Utility.DeleteFileBrute(templateFile + ".user.md5");

            if (diffFile.DiffType == TypeOfDiff.ExactCopy)
            {
                // Store the MD5 hashes of the files we just diff'd, so we don't do them again.
                if(File.Exists(parentFile))
                    Slyce.Common.Utility.CreateMD5HashFileForTextFile(parentFile, templateFile + ".prevgen.md5");
                if(File.Exists(userFile))
                    Slyce.Common.Utility.CreateMD5HashFileForTextFile(userFile, templateFile + ".user.md5");
            }
        }
 public TypeOfDiff DisplayNodeFiles(TreeListNode node, DiffFile currentDiffFile)
 {
     OriginType = OriginTypes.DiffFile;
     return DisplayNodeFiles(node, currentDiffFile, AutoMergeTypes.None, "", "", "", "", currentDiffFile.DiffType, OriginType);
 }
        public TypeOfDiff DisplayNodeFiles(TreeListNode node, DiffFile currentDiffFile, AutoMergeTypes autoMergeType, string userText, string templateText, string parentText, string mergedText, TypeOfDiff currentDiffType, OriginTypes originType)
        {
            OriginType = originType;
            CurrentDiffFile = currentDiffFile;
            CurrentDiffType = currentDiffType;
            BusyPopulatingEditor = true;

            if (node.Tag.GetType() == typeof(DiffFile) &&
                !((DiffFile)node.Tag).IsText)
            {
                ucBinaryFileViewer1.RootParent = SlyceMergeWorker.PreviousGenerationFolder;
                ucBinaryFileViewer1.RootTemplate = Controller.Instance.GetTempFilePathForComponent(ComponentKey.WorkbenchFileGenerator);
                ucBinaryFileViewer1.RootUser = Controller.Instance.ProjectSettings.ProjectPath;
                ucBinaryFileViewer1.DiffFile = (DiffFile)node.Tag;
                // Binary file
                ucBinaryFileViewer1.Visible = true;
                ucBinaryFileViewer1.Left = this.Left;
                ucBinaryFileViewer1.Width = this.ClientSize.Width;
                ucBinaryFileViewer1.Top = this.Top;
                ucBinaryFileViewer1.Height = this.ClientSize.Height;
                SetNavigationButtons();
                ShowBinaryFiles(node);
                return GetCurrentDiffStatus();
            }
            else
            {
                ucBinaryFileViewer1.Visible = false;
            }
            OrigianlLineSpan = null;
            bool filesTheSame = true;
            syntaxEditor1.ResetText();

            // Perform a 3-way diff on the file
            string parentFile = "";
            string userFile = "";
            string templateFile = "";
            string mergedFile = "";
            string fileBodyParent = null;
            string fileBodyUser = null;
            string fileBodyGenerated = null;

            if (OriginType == OriginTypes.DiffFile)
            {
                parentFile = Path.Combine(SlyceMergeWorker.PreviousGenerationFolder, ((DiffFile)node.Tag).RelativePath);
                userFile = Path.Combine(Controller.Instance.ProjectSettings.ProjectPath, ((DiffFile)node.Tag).RelativePath);
                templateFile = Path.Combine(Controller.Instance.GetTempFilePathForComponent(ComponentKey.WorkbenchFileGenerator), ((DiffFile)node.Tag).RelativePath);
                mergedFile = Path.Combine(SlyceMergeWorker.StagingFolder, ((DiffFile)node.Tag).RelativePath + ".merged");

                fileBodyParent = File.Exists(parentFile) ? IOUtility.GetTextFileBody(parentFile) : "";
                fileBodyUser = File.Exists(userFile) ? IOUtility.GetTextFileBody(userFile) : "";
                fileBodyGenerated = File.Exists(templateFile) ? IOUtility.GetTextFileBody(templateFile) : "";
            }
            else
            {
                fileBodyParent = parentText;
                fileBodyUser = userText;
                fileBodyGenerated = templateText;
            }
            fileBodyParent = Slyce.Common.Utility.StandardizeLineBreaks(fileBodyParent, Slyce.Common.Utility.LineBreaks.Unix);
            fileBodyUser = Slyce.Common.Utility.StandardizeLineBreaks(fileBodyUser, Slyce.Common.Utility.LineBreaks.Unix);
            fileBodyGenerated = Slyce.Common.Utility.StandardizeLineBreaks(fileBodyGenerated, Slyce.Common.Utility.LineBreaks.Unix);
            DetermineFileType(node);

            if (CurrentDiffType == TypeOfDiff.UserChangeOnly)
            {
                MarginTextUser = "******";
                Slyce.IntelliMerge.UI.Utility.Perform2WayDiffInSingleEditor(syntaxEditor1, ref fileBodyUser, ref fileBodyParent, true);
                syntaxEditor1.Document.ReadOnly = true;
                toolStripButtonAcceptTemplateChanges.Enabled = false;
                toolStripButtonAcceptUserChanges.Enabled = false;
                this.Text = "View only - No conflicts";
                buttonClose.Text = "&Close";
                buttonSave.Visible = false;
                SetNavigationButtons();
                this.ShowDialog(Controller.Instance.MainForm);
                return CurrentDiffType;
            }
            else if (CurrentDiffType == TypeOfDiff.TemplateChangeOnly)
            {
                MarginTextUser = "******";

                if (fileBodyGenerated == null)
                {
                    // This is marked as a TemplateChange because the template DELETED the corresponding entity
                    DisplayingTextMessage = true;
                    toolStripComboBoxFileType.Text = Slyce.Common.SyntaxEditorHelper.LanguageNameFromEnum(Slyce.Common.SyntaxEditorHelper.Languages.PlainText);
                    syntaxEditor1.WordWrap = ActiproSoftware.SyntaxEditor.WordWrapType.Word;
                    syntaxEditor1.Text = "This is a TemplateChange because it looks like the Template has not created the corresponding entity. In effect, the template has DELETED the corresponding entity. Alternatively, the corresponding entity has been RENAMED, or it's namespace has been renamed. If this is the case, click 'Select Match' on the popup menu to locate a renamed version of this entity if the template has renamed it (or its namespace).";
                }
                else
                {
                    Slyce.IntelliMerge.UI.Utility.Perform2WayDiffInSingleEditor(syntaxEditor1, ref fileBodyGenerated, ref fileBodyParent, true);
                }
                syntaxEditor1.Document.ReadOnly = true;
                toolStripButtonAcceptTemplateChanges.Enabled = false;
                toolStripButtonAcceptUserChanges.Enabled = false;
                this.Text = "View only - No conflicts";
                buttonClose.Text = "&Close";
                buttonSave.Visible = false;
                SetNavigationButtons();
                this.ShowDialog(Controller.Instance.MainForm);
                return CurrentDiffType;
            }
            else if (CurrentDiffType == TypeOfDiff.UserAndTemplateChange)
            {
                if (OriginType == OriginTypes.DiffFile)
                {
                    string mergedFileName = mergedFile.Replace(".merged", ".copy");

                    if (!File.Exists(mergedFileName))
                    {
                        throw new Exception("Merged file with user and template changes not found.");
                    }
                    mergedText = IOUtility.GetTextFileBody(mergedFileName);
                    mergedText = Slyce.Common.Utility.StandardizeLineBreaks(mergedText, Slyce.Common.Utility.LineBreaks.Unix);
                }
                SlyceMerge.LineSpan[] userLines;
                SlyceMerge.LineSpan[] templateLines;
                SlyceMerge.LineSpan[] rightLinesUser;
                SlyceMerge.LineSpan[] rightLinesTemplate;
                string combinedText;
                SlyceMerge.PerformTwoWayDiff(false, mergedText, fileBodyUser, out userLines, out rightLinesUser, out combinedText);
                SlyceMerge.PerformTwoWayDiff(false, mergedText, fileBodyGenerated, out templateLines, out rightLinesTemplate, out combinedText);
                syntaxEditor1.Text = mergedText;

                for (int i = 0; i < userLines.Length; i++)
                {
                    #region Get offset
                    int offsetUser = 0;

                    for (int counterRightLineUser = 0; counterRightLineUser < rightLinesUser.Length; counterRightLineUser++)
                    {
                        if (rightLinesUser[counterRightLineUser].StartLine < userLines[i].StartLine)
                        {
                            offsetUser += (rightLinesUser[counterRightLineUser].EndLine - rightLinesUser[counterRightLineUser].StartLine + 1);
                        }
                        else
                        {
                            break;
                        }

                    }
                    #endregion

                    for (int lineCounter = userLines[i].StartLine; lineCounter <= userLines[i].EndLine; lineCounter++)
                    {
                        syntaxEditor1.Document.Lines[lineCounter - offsetUser].BackColor = Slyce.IntelliMerge.UI.Utility.ColourNewGen;
                    }
                }
                for (int i = 0; i < templateLines.Length; i++)
                {
                    #region Get offset
                    int offsetTemplate = 0;

                    for (int counterRightLineTemplate = 0; counterRightLineTemplate < rightLinesTemplate.Length; counterRightLineTemplate++)
                    {
                        if (rightLinesTemplate[counterRightLineTemplate].StartLine < templateLines[i].StartLine)
                        {
                            offsetTemplate += (rightLinesTemplate[counterRightLineTemplate].EndLine - rightLinesTemplate[counterRightLineTemplate].StartLine + 1);
                        }
                        else
                        {
                            break;
                        }
                    }
                    #endregion

                    for (int lineCounter = templateLines[i].StartLine; lineCounter <= templateLines[i].EndLine; lineCounter++)
                    {
                        syntaxEditor1.Document.Lines[lineCounter - offsetTemplate].BackColor = Slyce.IntelliMerge.UI.Utility.ColourUser;
                    }
                }
                syntaxEditor1.Document.ReadOnly = true;
                toolStripButtonAcceptTemplateChanges.Enabled = false;
                toolStripButtonAcceptUserChanges.Enabled = false;
                this.Text = "View only - No conflicts";
                buttonClose.Text = "&Close";
                buttonSave.Visible = false;
                SetNavigationButtons();
                this.ShowDialog(Controller.Instance.MainForm);
                return currentDiffFile.DiffType;
            }
            syntaxEditor1.SuspendPainting();

            if (File.Exists(mergedFile))
            {
                using (TextReader tr = new StreamReader(mergedFile))
                {
                    string line = "";
                    int lineCounter = 0;
                    int pipeIndex = 0;
                    int backColor = 0;

                    while ((line = tr.ReadLine()) != null)
                    {
                        pipeIndex = line.IndexOf("|");
                        backColor = int.Parse(line.Substring(0, pipeIndex));
                        syntaxEditor1.Document.AppendText(line.Substring(pipeIndex + 1) + Environment.NewLine);
                        syntaxEditor1.Document.Lines[lineCounter].BackColor = Color.FromArgb(backColor);
                        lineCounter++;
                    }
                }
            }
            else // A merged file hasn't been created yet, so conflicts still exist
            {
                if (fileBodyParent != null &&
                          fileBodyUser != null &&
                          fileBodyGenerated != null)
                {
                    // Perform 3-way diff
                    string output;
                    SlyceMerge slyceMerge = SlyceMerge.Perform3wayDiff(fileBodyUser, fileBodyParent, fileBodyGenerated, out output);
                    int lineCounter = 0;
                    StringBuilder sb = new StringBuilder(Math.Max(fileBodyUser.Length, Math.Max(fileBodyParent.Length, fileBodyGenerated.Length)) + 1000);
                    System.Collections.ArrayList colouredLines = new System.Collections.ArrayList();

                    foreach (SlyceMerge.LineText line in slyceMerge.Lines)
                    {
                        int charPos = 0;
                        int numLineBreaks = 0;
                        charPos = line.Text.IndexOf("\r", 0);

                        if (charPos < 0) { numLineBreaks++; }

                        while (charPos >= 0)
                        {
                            numLineBreaks++;
                            charPos = line.Text.IndexOf("\r", charPos + 1);
                        }
                        sb.AppendLine(line.Text.Replace("\r", ""));
                        colouredLines.Add(new SlyceMerge.LineSpan(lineCounter, lineCounter + numLineBreaks, line.Colour));
                        lineCounter += numLineBreaks;
                    }
                    int linesToRemove = 0;
                    string text = sb.ToString();
                    string lastChar = text.Substring(text.Length - linesToRemove - 1);

                    while (lastChar.Length == 0 ||
                        lastChar == "\n" ||
                        lastChar == "\r" &&
                        text.Length >= linesToRemove + 1)
                    {
                        linesToRemove++;
                        lastChar = text.Substring(text.Length - linesToRemove - 1, 1);
                    }
                    syntaxEditor1.Document.Text = text.Substring(0, text.Length - linesToRemove);

                    for (int i = 0; i < colouredLines.Count; i++)
                    {
                        SlyceMerge.LineSpan ls = (SlyceMerge.LineSpan)colouredLines[i];

                        if (ls.OriginalColor != Color.White) { filesTheSame = false; }

                        for (int x = ls.StartLine; x <= ls.EndLine; x++)
                        {
                            if (x >= syntaxEditor1.Document.Lines.Count)
                            {
                                break;
                            }
                            syntaxEditor1.Document.Lines[x].BackColor = ls.OriginalColor;
                        }
                    }
                    if (filesTheSame)
                    {
                        this.Text = "No Changes";
                    }
                }
                else if (fileBodyParent != null &&
                          fileBodyUser != null &&
                          fileBodyGenerated == null)
                {
                    // No template file, just use the user file
                    syntaxEditor1.Text = fileBodyUser;
                    this.Text = "No Conflicts";
                }
                else if (fileBodyParent != null &&
             fileBodyUser == null &&
            fileBodyGenerated != null)
                {
                    // No user file, just use the template file
                    Slyce.IntelliMerge.UI.Utility.Perform2WayDiffInSingleEditor(syntaxEditor1, ref fileBodyGenerated, ref fileBodyParent, true);
                }
                else if (fileBodyParent == null &&
                       fileBodyUser != null &&
                  fileBodyGenerated != null)
                {
                    // No parent file, make sure the user merges the template and user files
                    string combinedText;
                    Slyce.IntelliMerge.SlyceMerge.LineSpan[] userLines;
                    Slyce.IntelliMerge.SlyceMerge.LineSpan[] templateLines;
                    SlyceMerge.PerformTwoWayDiff(false, fileBodyUser, fileBodyGenerated, out userLines, out templateLines, out combinedText);
                    Slyce.IntelliMerge.UI.Utility.PopulateSyntaxEditor(syntaxEditor1, combinedText, userLines, templateLines);
                    this.Text = "User changes vs generated";
                }
                else
                {
                    if (fileBodyParent != null)
                    {
                        if (File.Exists(userFile) || File.Exists(templateFile))
                        {
                            throw new Exception("More than one file exists. Shouldn't be here.");
                        }
                        syntaxEditor1.Text = fileBodyParent;
                        this.Text = "Unchanged file";
                    }
                    else if (fileBodyUser != null)
                    {
                        if (File.Exists(parentFile) || File.Exists(templateFile))
                        {
                            throw new Exception("More than one file exists. Shouldn't be here.");
                        }
                        syntaxEditor1.Text = fileBodyUser;
                        this.Text = "User-only file";
                    }
                    else if (fileBodyGenerated != null)
                    {
                        if (File.Exists(parentFile) || File.Exists(userFile))
                        {
                            throw new Exception("More than one file exists. Shouldn't be here.");
                        }
                        syntaxEditor1.Text = fileBodyGenerated;
                        this.Text = "Newly Generated file";
                    }
                }
            }
            syntaxEditor1.Refresh();

            if (syntaxEditor1.Document.Text.Length > 0)
            {
                syntaxEditor1.SelectedView.Selection.StartOffset = 0;
                syntaxEditor1.SelectedView.Selection.EndOffset = 0;
            }
            syntaxEditor1.Document.Modified = false;
            syntaxEditor1.ResumePainting();
            BusyPopulatingEditor = false;

            switch (autoMergeType)
            {
                case AutoMergeTypes.None:
                    GotoNextConflictLine(0);
                    this.ShowDialog(Controller.Instance.MainForm);
                    break;
                case AutoMergeTypes.KeepUserChanges:
                    AcceptAllUserChanges();

                    if (!SaveCurrentFile(false))
                    {
                        MessageBox.Show("There was a problem processing this file automatically. Please resolve these changes manually.", "Auto Processing Problem", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        GotoNextConflictLine(0);
                        this.ShowDialog(Controller.Instance.MainForm);
                    }
                    break;
                case AutoMergeTypes.KeepTemplateChanges:
                    AcceptAllTemplateChanges();

                    if (!SaveCurrentFile(false))
                    {
                        MessageBox.Show("There was a problem processing this file automatically. Please resolve these changes manually.", "Auto Processing Problem", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                        GotoNextConflictLine(0);
                        this.ShowDialog(Controller.Instance.MainForm);
                    }
                    break;
            }
            SetNavigationButtons();
            if (CancelClicked) { return TypeOfDiff.Conflict; }
            else { return GetCurrentDiffStatus(); }
        }
        /// <summary>
        /// Performs an in depth diff by breaking code files into their constituent parts (functions, properties
        /// etc, so that these elements can be diffed without regard to their ordering.
        /// </summary>
        /// <param name="diffFile"></param>
        private void PerformSuperDiff(ref DiffFile diffFile)
        {
            try
            {
                switch (Path.GetExtension(diffFile.Path).ToLower())
                {
                case ".cs":
                    Providers.CSharpFormatter formatter = new Providers.CSharpFormatter(diffFile.Path);
                    formatter.CreateObjectModel = true;
                    formatter.RaiseError       += formatter_RaiseError;

                    try
                    {
                        // TODO: get the code for each file type (user, generated, prevGen), then
                        // break into classes, functions etc, and  perform a diff3 on each entity.
                        // We REALLY need to store these results in the objects, so that this process
                        // happens once, when the initial population occurs, and doesn't need to happen
                        // again when the user clicks a childTreeListNode to display the text and conflicts.

                        // Reset the DiffType
                        diffFile.DiffType = TypeOfDiff.ExactCopy;

                        if (File.Exists(diffFile.FilePathPrevGen))
                        {
                            formatter.Reset();
                            formatter.CodeFilePath = diffFile.FilePathPrevGen;
                            formatter.GetFormattedCode(Slyce.Common.Utility.ReadTextFile(diffFile.FilePathPrevGen));
                            diffFile.CodeRootParent = formatter.Controller.Root;
                            diffFile.CodeRootParent.SortAllMembers();
                        }
                        if (File.Exists(diffFile.FilePathTemplate))
                        {
                            formatter.Reset();
                            formatter.CodeFilePath = diffFile.FilePathTemplate;
                            formatter.GetFormattedCode(Slyce.Common.Utility.ReadTextFile(diffFile.FilePathTemplate));
                            diffFile.CodeRootTemplate = formatter.Controller.Root;
                            diffFile.CodeRootTemplate.SortAllMembers();
                        }
                        if (File.Exists(diffFile.FilePathUser))
                        {
                            formatter.Reset();
                            formatter.CodeFilePath = diffFile.FilePathUser;
                            formatter.GetFormattedCode(Slyce.Common.Utility.ReadTextFile(diffFile.FilePathUser));
                            diffFile.CodeRootUser = formatter.Controller.Root;
                            diffFile.CodeRootUser.SortAllMembers();

                            // TODO: this check of whether the code object model has been correctly created must get removed from the final build
                            //string code = diffFile.CodeRootUser.ToString();
                            //formatter.Reset();
                            //formatter.ParseCode(code);

                            //if (!diffFile.CodeRootUser.IsTheSame(ArchAngel.Providers.CodeProvider.Controller.Root))
                            //{
                            //    throw new InvalidProgramException("The code object model has not been written correctly: " + ArchAngel.Providers.CodeProvider.CSharp.BaseConstruct.ComparisonDifference);
                            //}
                        }
                    }
                    catch (Exception ex)
                    {
                        diffFile.ParseErrorDescription = ex.Message;
                    }
                    bool ignoreAllOmits = false;

                    if (File.Exists(diffFile.FilePathTemplate) &&
                        !File.Exists(diffFile.FilePathUser))
                    {
                        // If the user file is missing, then all code objects are also going to be missing and
                        // will therefore get marked at 'Omit = true', but infact we need to generate them.
                        ignoreAllOmits = true;
                    }
                    TypeOfDiff resultingDiffType;
                    Providers.CodeProvider.CSharp.Utility utility = new Providers.CodeProvider.CSharp.Utility();
                    diffFile.CodeRootAll = utility.CreateCombinedCodeRoot(diffFile.CodeRootTemplate, diffFile.CodeRootUser, diffFile.CodeRootParent, out resultingDiffType, ignoreAllOmits);
                    diffFile.CodeRootAll.SortAllMembers();
                    diffFile.DiffType = resultingDiffType;

                    break;

                default:
                    // No SuperDiff available for this type of file (no parser created yet).
                    break;
                }
            }
            catch (Exception ex)
            {
                Controller.ReportError(ex);
            }
        }
        internal void PerformDiffOfFile(DiffFile diffFile, ref bool fileNeedsToBeCounted)
        {
            // Don't process files that had errors during generation
            for (int errFileCounter = 0; errFileCounter < GenerationErrors.Count; errFileCounter++)
            {
                if (Slyce.Common.Utility.StringsAreEqual(diffFile.RelativePath, GenerationErrors[errFileCounter].FileName, false))
                {
                    //continue;
                    return;
                }
            }
            if (UniqueFilesForCount[diffFile.RelativePath] != null &&
                (bool)UniqueFilesForCount[diffFile.RelativePath] == false)
            {
                fileNeedsToBeCounted = true;
                UniqueFilesForCount[diffFile.RelativePath] = true;
            }
            else
            {
                fileNeedsToBeCounted = false;
            }
            if (diffFile.Path.IndexOf(".aaz") > 0 ||
                diffFile.HasParseError)
            {
                //continue;
                return;
            }
            if (FileBeingProcessed != null)
            {
                FileBeingProcessed(diffFile.Path);
            }
            // Perform a 3-way diff on the file
            string parentFile   = Path.Combine(PreviousGenerationFolder, diffFile.RelativePath);
            string userFile     = Path.Combine(Controller.Instance.ProjectSettings.ProjectPath, diffFile.RelativePath);
            string templateFile = Path.Combine(Controller.Instance.GetTempFilePathForComponent(ComponentKey.WorkbenchFileGenerator), diffFile.RelativePath);
            string mergedFile   = Path.Combine(StagingFolder, diffFile.RelativePath + ".merged");

            if (CheckFilesForModifications(diffFile.RelativePath) == false)
            {
                RaiseDiffFinishedEvent(diffFile.Name, TypeOfDiff.ExactCopy);
                return;
            }

            diffFile.FilePathTemplate = templateFile;
            diffFile.FilePathUser     = userFile;
            diffFile.FilePathPrevGen  = parentFile;

            if (File.Exists(mergedFile))
            {
                bool mergeComplete = true;

                // Binary files are never in an unknown state, they are all or nothing.
                // Text files need to be checked.
                if (diffFile.IsText)
                {
                    using (TextReader tr = new StreamReader(mergedFile))
                    {
                        string line;
                        //int lineCounter = 0;

                        while ((line = tr.ReadLine()) != null &&
                               mergeComplete)
                        {
                            int pipeIndex = line.IndexOf("|");
                            int backColor = int.Parse(line.Substring(0, pipeIndex));

                            if (backColor != -1 &&
                                backColor != 0)
                            {
                                mergeComplete = false;
                            }
                            //lineCounter++;
                        }
                    }
                }
                if (mergeComplete)
                {
                    diffFile.DiffType = TypeOfDiff.Warning;
                }
                else
                {
                    diffFile.DiffType = TypeOfDiff.Conflict;
                }
            }
            else
            {
                if (diffFile.IsText)
                {
                    if (File.Exists(parentFile) &&
                        File.Exists(userFile) &&
                        File.Exists(templateFile))
                    {
                        // Perform 3-way diff
                        string fileBodyParent    = IOUtility.GetTextFileBody(parentFile);
                        string fileBodyUser      = IOUtility.GetTextFileBody(userFile);
                        string fileBodyGenerated = IOUtility.GetTextFileBody(templateFile);

                        string mergedText;
                        slyceMerge        = SlyceMerge.Perform3wayDiff(fileBodyUser, fileBodyParent, fileBodyGenerated, out mergedText);
                        diffFile.DiffType = slyceMerge.DiffType;
                        string newFile = "";

                        if (slyceMerge.DiffType != TypeOfDiff.Conflict)
                        {
                            switch (slyceMerge.DiffType)
                            {
                            case TypeOfDiff.ExactCopy:
                                newFile = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                                Slyce.Common.Utility.FileCopy(userFile, newFile);
                                break;

                            case TypeOfDiff.TemplateChangeOnly:
                                newFile = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                                Slyce.Common.Utility.FileCopy(templateFile, newFile);
                                break;

                            case TypeOfDiff.UserAndTemplateChange:
                                newFile = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";

                                if (!Directory.Exists(Path.GetDirectoryName(newFile)))
                                {
                                    Directory.CreateDirectory(Path.GetDirectoryName(newFile));
                                }
                                Slyce.Common.Utility.WriteToFile(newFile, mergedText);
                                break;

                            case TypeOfDiff.UserChangeOnly:
                                newFile = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                                Slyce.Common.Utility.FileCopy(userFile, newFile);
                                break;

                            case TypeOfDiff.Warning:
                                throw new Exception("Oops");
                            }
                        }
                    }
                    else if (File.Exists(parentFile) &&
                             File.Exists(userFile) &&
                             !File.Exists(templateFile))
                    {
                        // No template file, just use the user file
                        diffFile.DiffType = TypeOfDiff.UserChangeOnly;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(userFile, newPath);
                    }
                    else if (File.Exists(parentFile) &&
                             !File.Exists(userFile) &&
                             File.Exists(templateFile))
                    {
                        // No user file, just use the template file
                        diffFile.DiffType = TypeOfDiff.TemplateChangeOnly;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(templateFile, newPath);
                    }
                    else if (!File.Exists(parentFile) &&
                             File.Exists(userFile) &&
                             File.Exists(templateFile))
                    {
                        // No parent file, make sure the user merges the template and user files
                        SlyceMerge.LineSpan[] userLines;
                        SlyceMerge.LineSpan[] templateLines;
                        string combinedText;
                        diffFile.DiffType = SlyceMerge.PerformTwoWayDiff(false, IOUtility.GetTextFileBody(userFile), IOUtility.GetTextFileBody(templateFile), out userLines, out templateLines, out combinedText);

                        if (diffFile.DiffType == TypeOfDiff.ExactCopy)
                        {
                            string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                            Slyce.Common.Utility.FileCopy(templateFile, newPath);
                        }
                        else
                        {
                            throw new NotImplementedException("This scenario has not been handled yet. Please contact [email protected] with: PerformDiffOfFolder(PrevGen file doesn't exist, and TypeOfDiff = " + diffFile.DiffType + ")");
                        }
                        //diffFile.DiffType = SlyceMerge.TypeOfDiff.Conflict; // TODO: Work out what should be done in this instance
                        //throw new Exception("TODO: determine course of action, what should be copied to staging folder.");
                        //string newPath = templateFile.Replace(ProjectFolder, StagingFolder) + ".copy";
                        //Utility.FileCopy(templateFile, newPath);
                    }
                    else if (File.Exists(parentFile) &&
                             !File.Exists(userFile) &&
                             !File.Exists(templateFile))
                    {
                        // TODO: It looks like the file was deleted by the user, AND it was removed from the template, so therefore the
                        // user doesn't want this file anymore. Get user to confirm?
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(parentFile, newPath);
                    }
                    else if (!File.Exists(parentFile) &&
                             !File.Exists(userFile) &&
                             File.Exists(templateFile))
                    {
                        string newPath = templateFile.Replace(Controller.Instance.GetTempFilePathForComponent(ComponentKey.WorkbenchFileGenerator), StagingFolder) + ".copy";
                        Slyce.Common.Utility.FileCopy(templateFile, newPath);
                    }
                    else if (!File.Exists(parentFile) &&
                             File.Exists(userFile) &&
                             !File.Exists(templateFile))
                    {
                        // TODO: Do we really need to go to the effort of copying etc, because it only exists in the user folder,
                        // so if we take no action it will still exist there - that should be fine ;-)
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(userFile, newPath);
                    }
                    else
                    {
                        // TODO: Shouldn't really be a warning...
                        diffFile.DiffType = TypeOfDiff.Warning;
                        throw new Exception(string.Format("TODO: determine course of action, what should be copied to staging folder, because no file exists: \n{0}\n{1}\n{2}", parentFile, userFile, templateFile));
                    }
                }
                else                 // Binary file
                {
                    string crcParent   = File.Exists(parentFile) ? Slyce.Common.Utility.GetCheckSumOfFile(parentFile) : "";
                    string crcTemplate = File.Exists(templateFile) ? Slyce.Common.Utility.GetCheckSumOfFile(templateFile) : "";
                    string crcUser     = File.Exists(userFile) ? Slyce.Common.Utility.GetCheckSumOfFile(userFile) : "";

                    diffFile.MD5Parent   = crcParent;
                    diffFile.MD5Template = crcTemplate;
                    diffFile.MD5User     = crcUser;

                    // TODO: perform CheckSum of binary file
                    if (!string.IsNullOrEmpty(crcParent) &&
                        !string.IsNullOrEmpty(crcTemplate) &&
                        !string.IsNullOrEmpty(crcUser))
                    {
                        if (crcParent == crcUser &&
                            crcUser == crcTemplate)
                        {
                            diffFile.DiffType = TypeOfDiff.ExactCopy;
                            string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                            Slyce.Common.Utility.FileCopy(userFile, newPath);
                        }
                        else if (crcParent == crcUser &&
                                 crcParent != crcTemplate)
                        {
                            diffFile.DiffType = TypeOfDiff.TemplateChangeOnly;
                            string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                            Slyce.Common.Utility.FileCopy(userFile, newPath);
                        }
                        else if (crcParent != crcUser &&
                                 crcParent == crcTemplate)
                        {
                            diffFile.DiffType = TypeOfDiff.UserChangeOnly;
                            string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                            Slyce.Common.Utility.FileCopy(userFile, newPath);
                        }
                        else if (crcParent != crcUser &&
                                 crcUser == crcTemplate)
                        {
                            diffFile.DiffType = TypeOfDiff.UserAndTemplateChange;
                        }
                    }
                    else if (string.IsNullOrEmpty(crcParent) &&
                             !string.IsNullOrEmpty(crcTemplate) &&
                             !string.IsNullOrEmpty(crcUser))
                    {
                        diffFile.DiffType = TypeOfDiff.Conflict;
                    }
                    else if (!string.IsNullOrEmpty(crcParent) &&
                             !string.IsNullOrEmpty(crcTemplate) &&
                             string.IsNullOrEmpty(crcUser))
                    {
                        diffFile.DiffType = TypeOfDiff.TemplateChangeOnly;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(templateFile, newPath);
                    }
                    else if (!string.IsNullOrEmpty(crcParent) &&
                             string.IsNullOrEmpty(crcTemplate) &&
                             !string.IsNullOrEmpty(crcUser))
                    {
                        diffFile.DiffType = TypeOfDiff.UserChangeOnly;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(userFile, newPath);
                    }
                    else if (string.IsNullOrEmpty(crcParent) &&
                             !string.IsNullOrEmpty(crcTemplate) &&
                             string.IsNullOrEmpty(crcUser))
                    {
                        // This is a new file that has been generated
                        diffFile.DiffType = TypeOfDiff.ExactCopy;
                        string newPath = Path.Combine(StagingFolder, diffFile.RelativePath) + ".copy";
                        Slyce.Common.Utility.FileCopy(templateFile, newPath);
                    }
                    else
                    {
                        throw new NotImplementedException("Not coded yet. Seems like only one version of binary file exists. Probably just need to copy as-is.");
                    }
                }
            }
            if (diffFile.DiffType != TypeOfDiff.ExactCopy)
            {
                // Only perform the costly SuperDiff if it is not an exact copy
                //ArchAngel.IntelliMerge.DiffItems.DiffFile diffFile = diffFile;
                PerformSuperDiff(ref diffFile);
            }
            if (fileNeedsToBeCounted)
            {
                switch (diffFile.DiffType)
                {
                case TypeOfDiff.Conflict:
                    m_numConflicts++;
                    break;

                case TypeOfDiff.ExactCopy:
                    m_numExactCopy++;
                    break;

                case TypeOfDiff.TemplateChangeOnly:
                case TypeOfDiff.UserAndTemplateChange:
                case TypeOfDiff.UserChangeOnly:
                case TypeOfDiff.Warning:
                    m_numResolvable++;
                    break;

                default:
                    throw new NotImplementedException("Not coded yet");
                }
                RaiseDiffFinishedEvent(diffFile.Name, diffFile.DiffType);
            }

            Slyce.Common.Utility.DeleteFileBrute(templateFile + ".prevgen.md5");
            Slyce.Common.Utility.DeleteFileBrute(templateFile + ".user.md5");

            if (diffFile.DiffType == TypeOfDiff.ExactCopy)
            {
                // Store the MD5 hashes of the files we just diff'd, so we don't do them again.
                if (File.Exists(parentFile))
                {
                    Slyce.Common.Utility.CreateMD5HashFileForTextFile(parentFile, templateFile + ".prevgen.md5");
                }
                if (File.Exists(userFile))
                {
                    Slyce.Common.Utility.CreateMD5HashFileForTextFile(userFile, templateFile + ".user.md5");
                }
            }
        }