public void UpdateToRelativePaths()
        {
            var toRemove = new List <string>();
            var toAdd    = new Dictionary <string, DateTime>();

            foreach (var path in Entries.Keys)
            {
                if (!Path.IsPathRooted(path))
                {
                    continue;
                }

                var relativePath = ModLoader.GetRelativePath(path, ModLoader.GetRootPath(path));
                toAdd[relativePath] = Entries[path];
                toRemove.Add(path);
            }

            foreach (var addKVP in toAdd)
            {
                if (!Entries.ContainsKey(addKVP.Key))
                {
                    Entries.Add(addKVP.Key, addKVP.Value);
                }
            }


            foreach (var path in toRemove)
            {
                Entries.Remove(path);
            }
        }
        public CacheEntry GetOrCreateCachedEntry(string absolutePath, List <MergeEntry> mergeEntries)
        {
            absolutePath = Path.GetFullPath(absolutePath);
            var relativePath = ModLoader.GetRelativePath(absolutePath, ModLoader.GetRootPath(absolutePath));


            logger.Log("");

            // TOOD - Do we need to change this?
            if (!CachedEntries.ContainsKey(relativePath) || !CachedEntries[relativePath].MatchesPaths(absolutePath, mergeEntries.Select(me => me.Path).ToList()))
            {
                var cachedAbsolutePath = Path.GetFullPath(Path.Combine(ModLoader.CacheDirectory, relativePath));
                var cachedEntry        = new CacheEntry(cachedAbsolutePath, absolutePath, mergeEntries);

                if (cachedEntry.HasErrors)
                {
                    return(null);
                }

                CachedEntries[relativePath] = cachedEntry;

                logger.Log($"Merge performed: {Path.GetFileName(absolutePath)}");
            }
            else
            {
                logger.Log($"Cached merge: {Path.GetFileName(absolutePath)} ({File.GetLastWriteTime(CachedEntries[relativePath].CacheAbsolutePath):G})");
            }

            logger.Log($"\t{relativePath}");

            foreach (MergeEntry mergeEntry in mergeEntries)
            {
                string contributingPath = mergeEntry.Path;
                logger.Log($"\t{ModLoader.GetRelativePath(contributingPath, ModLoader.GetRootPath(contributingPath))}");
            }

            logger.Log("");

            CachedEntries[relativePath].CacheHit = true;
            return(CachedEntries[relativePath]);
        }
        public void UpdateToRelativePaths()
        {
            var toRemove = new List <string>();
            var toAdd    = new Dictionary <string, CacheEntry>();

            foreach (var path in CachedEntries.Keys)
            {
                if (Path.IsPathRooted(path))
                {
                    var relativePath = ModLoader.GetRelativePath(path, ModLoader.GetRootPath(path));

                    toAdd[relativePath] = CachedEntries[path];
                    toRemove.Add(path);

                    toAdd[relativePath].CachePath = ModLoader.GetRelativePath(toAdd[relativePath].CachePath, ModLoader.GetRootPath(toAdd[relativePath].CachePath));
                    foreach (var merge in toAdd[relativePath].Merges)
                    {
                        merge.RelativePath = ModLoader.GetRelativePath(merge.RelativePath, ModLoader.GetRootPath(merge.RelativePath));
                    }
                }
            }

            foreach (var addKVP in toAdd)
            {
                if (!CachedEntries.ContainsKey(addKVP.Key))
                {
                    CachedEntries.Add(addKVP.Key, addKVP.Value);
                }
            }


            foreach (var path in toRemove)
            {
                CachedEntries.Remove(path);
            }
        }
        public bool HasCachedEntry(string originalPath, List <string> mergePaths)
        {
            var relativePath = ModLoader.GetRelativePath(originalPath, ModLoader.GetRootPath(originalPath));

            return(CachedEntries.ContainsKey(relativePath) && CachedEntries[relativePath].MatchesPaths(originalPath, mergePaths));
        }
            public CacheEntry(string absolutePath, string originalAbsolutePath, List <MergeEntry> mergeEntries)
            {
                cacheAbsolutePath   = absolutePath;
                CachePath           = ModLoader.GetRelativePath(absolutePath, ModLoader.GetRootPath(absolutePath));
                ContainingDirectory = Path.GetDirectoryName(absolutePath);
                OriginalTime        = File.GetLastWriteTimeUtc(originalAbsolutePath);

                if (string.IsNullOrEmpty(ContainingDirectory))
                {
                    HasErrors = true;
                    return;
                }

                foreach (MergeEntry mergeEntry in mergeEntries)
                {
                    string mergePath = mergeEntry.Path;
                    Merges.Add(new MergeEntryTimeTuple(ModLoader.GetRelativePath(mergePath, ModLoader.GetRootPath(mergePath)), mergeEntry, File.GetLastWriteTimeUtc(mergePath)));
                }

                Directory.CreateDirectory(ContainingDirectory);

                // do json merge if json
                if (Path.GetExtension(absolutePath)?.ToLowerInvariant() == ".json")
                {
                    // get the parent JSON
                    JObject parentJObj;
                    try
                    {
                        parentJObj = ModLoader.ParseGameJSONFile(originalAbsolutePath);
                    }
                    catch (Exception e)
                    {
                        logger.LogException($"\tParent JSON at path {originalAbsolutePath} has errors preventing any merges!", e);
                        HasErrors = true;
                        return;
                    }

                    using (var writer = File.CreateText(absolutePath))
                    {
                        // merge all of the merges
                        foreach (var mergeEntry in mergeEntries)
                        {
                            string mergePath = mergeEntry.Path;
                            try
                            {
                                // since all json files are opened and parsed before this point, they won't have errors
                                JSONMerger.MergeIntoTarget(parentJObj, ModLoader.ParseGameJSONFile(mergePath));
                            }
                            catch (Exception e)
                            {
                                logger.LogException($"\tMod JSON merge at path {ModLoader.GetRelativePath(mergePath, ModLoader.GetRootPath(mergePath))} has errors preventing merge!", e);
                            }
                        }

                        // write the merged onto file to disk
                        var jsonWriter = new JsonTextWriter(writer)
                        {
                            Formatting = Formatting.Indented
                        };
                        parentJObj.WriteTo(jsonWriter);
                        jsonWriter.Close();
                    }

                    return;
                }

                // do file append if not json
                using (var writer = File.CreateText(absolutePath))
                {
                    writer.Write(File.ReadAllText(originalAbsolutePath));

                    foreach (var mergeEntry in mergeEntries)
                    {
                        string mergePath = mergeEntry.Path;
                        writer.Write(File.ReadAllText(mergePath));
                    }
                }
            }