<commit_before>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text.RegularExpressions;
using OpenSage.Content;
using OpenSage.Data.Ini;
using OpenSage.Logic.Object;
using OpenSage.Scripting;

namespace OpenSage.Data.Map
{
    internal class UserMapCache
    {
        private const string MapCacheIniPath = @"Maps\MapCache.ini";

        private readonly ContentManager _contentManager;

        public UserMapCache(ContentManager contentManager)
        {
            _contentManager = contentManager;
        }
        
        internal void Initialize(AssetStore assetStore)
        {
            // We need to check if there is an existing MapCache.ini file and if yes,
            // load it so that we can figure out which entries are outdated.
            // Then we need to update these entries, update the file, and parse it
            // again. In order to do that we first load it in a temporary scope.
            assetStore.PushScope();

            var mapCacheIniEntry = _contentManager.UserDataFileSystem.GetFile(MapCacheIniPath);
            if (mapCacheIniEntry != null)
            {
                _contentManager.LoadIniFile(mapCacheIniEntry);
            }

            // for each map, check if it was modified and the MapCache needs to be updated.
            var mapCacheEntries = new Dictionary<string, MapCache>();

            foreach (var mapEntry in EnumerateMaps())
            {
                var buildMapCache = false;
                var mapCache = assetStore.MapCaches.GetByName(mapEntry.FullFilePath);
                var fileInfo = new FileInfo(mapEntry.FullFilePath);

                if (mapCache == null)
                {
                    // new map
                    buildMapCache = true;
                }
                else
                {
                    var timestamp = DateTime.FromFileTime((((long)mapCache.TimestampHi) << 32) | (uint)mapCache.TimestampLo);

                    // TODO: Should we check the CRC here as well?
                    // If yes, which implementation should we use?
                    if (fileInfo.LastWriteTime != timestamp &&
                        fileInfo.Length != mapCache.FileSize)
                    {
                        // existing map modified
                        buildMapCache = true;
                    }
                }

                if (buildMapCache)
                {
                    mapCache = BuildMapCache(mapEntry, fileInfo, assetStore);
                }

                mapCacheEntries.Add(mapEntry.FullFilePath, mapCache);
            }

            // Get rid of the old MapCaches, generate the file based on
            // the updated ones and load it again, this time for real.
            assetStore.PopScope();

            var fullMapCacheIniPath = Path.Combine(_contentManager.UserDataFileSystem.RootDirectory, MapCacheIniPath);

            GenerateMapCacheIniFile(fullMapCacheIniPath, mapCacheEntries);

            mapCacheIniEntry = new FileSystemEntry(
                _contentManager.UserDataFileSystem,
                MapCacheIniPath,
                (uint)new FileInfo(fullMapCacheIniPath).Length,
                () => File.OpenRead(fullMapCacheIniPath));

            _contentManager.UserDataFileSystem.Update(mapCacheIniEntry);
            _contentManager.LoadIniFile(mapCacheIniEntry);
        }

        private IEnumerable<FileSystemEntry> EnumerateMaps()
        {
            var maps = from file in _contentManager.UserDataFileSystem.Files
                       where Path.GetExtension(file.FilePath) == ".map"
                       let parts = file.FilePath.Split(Path.DirectorySeparatorChar)
                       where parts.Length == 3
                           && parts[0] == "maps"
                           && parts[1] == Path.GetFileNameWithoutExtension(parts[2])
                       select file;
            return maps;
        }
<commit_msg>Fix maps directory not being created for map cache<commit_after>﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Numerics;
using System.Text.RegularExpressions;
using OpenSage.Content;
using OpenSage.Data.Ini;
using OpenSage.Logic.Object;
using OpenSage.Scripting;

namespace OpenSage.Data.Map
{
    internal class UserMapCache
    {
        private const string MapCacheIniPath = @"Maps\MapCache.ini";

        private readonly ContentManager _contentManager;

        public UserMapCache(ContentManager contentManager)
        {
            _contentManager = contentManager;
        }
        
        internal void Initialize(AssetStore assetStore)
        {
            // We need to check if there is an existing MapCache.ini file and if yes,
            // load it so that we can figure out which entries are outdated.
            // Then we need to update these entries, update the file, and parse it
            // again. In order to do that we first load it in a temporary scope.
            assetStore.PushScope();

            var mapCacheIniEntry = _contentManager.UserDataFileSystem.GetFile(MapCacheIniPath);
            if (mapCacheIniEntry != null)
            {
                _contentManager.LoadIniFile(mapCacheIniEntry);
            }

            // for each map, check if it was modified and the MapCache needs to be updated.
            var mapCacheEntries = new Dictionary<string, MapCache>();

            foreach (var mapEntry in EnumerateMaps())
            {
                var buildMapCache = false;
                var mapCache = assetStore.MapCaches.GetByName(mapEntry.FullFilePath);
                var fileInfo = new FileInfo(mapEntry.FullFilePath);

                if (mapCache == null)
                {
                    // new map
                    buildMapCache = true;
                }
                else
                {
                    var timestamp = DateTime.FromFileTime((((long)mapCache.TimestampHi) << 32) | (uint)mapCache.TimestampLo);

                    // TODO: Should we check the CRC here as well?
                    // If yes, which implementation should we use?
                    if (fileInfo.LastWriteTime != timestamp &&
                        fileInfo.Length != mapCache.FileSize)
                    {
                        // existing map modified
                        buildMapCache = true;
                    }
                }

                if (buildMapCache)
                {
                    mapCache = BuildMapCache(mapEntry, fileInfo, assetStore);
                }

                mapCacheEntries.Add(mapEntry.FullFilePath, mapCache);
            }

            // Get rid of the old MapCaches, generate the file based on
            // the updated ones and load it again, this time for real.
            assetStore.PopScope();

            var fullMapCacheIniPath = Path.Combine(_contentManager.UserDataFileSystem.RootDirectory, MapCacheIniPath);

            // Create the full path, user directory should already exist but the maps folder may not
            Directory.CreateDirectory(Path.GetDirectoryName(fullMapCacheIniPath));

            GenerateMapCacheIniFile(fullMapCacheIniPath, mapCacheEntries);

            mapCacheIniEntry = new FileSystemEntry(
                _contentManager.UserDataFileSystem,
                MapCacheIniPath,
                (uint)new FileInfo(fullMapCacheIniPath).Length,
                () => File.OpenRead(fullMapCacheIniPath));

            _contentManager.UserDataFileSystem.Update(mapCacheIniEntry);
            _contentManager.LoadIniFile(mapCacheIniEntry);
        }

        private IEnumerable<FileSystemEntry> EnumerateMaps()
        {
            var maps = from file in _contentManager.UserDataFileSystem.Files
                       where Path.GetExtension(file.FilePath) == ".map"
                       let parts = file.FilePath.Split(Path.DirectorySeparatorChar)
                       where parts.Length == 3
                           && parts[0] == "maps"
                           && parts[1] == Path.GetFileNameWithoutExtension(parts[2])
                       select file;
            return maps;
        }

{'fraction_non_alphanumeric': 0.07083739045764362, 'fraction_numerical': 0.0014605647517039922, 'mean_word_length': 1.6896890343698854, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2355602', 'n_tokens_mistral': 2044, 'n_tokens_neox': 1935, 'n_words': 526}