<commit_before>﻿using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using Snowflake.Game;
using Snowflake.Utility;

namespace Snowflake.Emulator.Configuration
{
    public class ConfigurationFlagStore : BaseDatabase, IConfigurationFlagStore
    {
        public string EmulatorBridgeID { get; }
        readonly string configurationFlagLocation;
        readonly IEmulatorBridge emulatorBridge;
        public ConfigurationFlagStore(IEmulatorBridge emulatorBridge)
            : base(Path.Combine(emulatorBridge.PluginDataPath, "flagscache.db"))
        {
            this.CreateDatabase();
            this.EmulatorBridgeID = emulatorBridge.PluginName;
            this.configurationFlagLocation = Path.Combine(emulatorBridge.PluginDataPath, "flagscache.db");
            this.AddDefaults(emulatorBridge.ConfigurationFlags);
            this.emulatorBridge = emulatorBridge;
        }
        private void CreateDatabase()
        {
            SQLiteConnection dbConnection = this.GetConnection();
            dbConnection.Open();
            var sqlCommand = new SQLiteCommand(@"CREATE TABLE IF NOT EXISTS flags(
                                                                flagKey TEXT PRIMARY KEY,
                                                                flagValue TEXT)", dbConnection);
            sqlCommand.ExecuteNonQuery();
            dbConnection.Close();
        }
        public void AddGame(IGameInfo gameInfo, IDictionary<string, string> flagValues)
        {


            SQLiteConnection flagDb = this.GetConnection();
            flagDb.Open();
            foreach (KeyValuePair<string, string> flagPair in flagValues)
            {
                using (var sqliteCommand = new SQLiteCommand(@"INSERT OR REPLACE INTO flags VALUES(
                                          @flagKey,
                                          @flagValue)", flagDb))
                {
                    sqliteCommand.Parameters.AddWithValue("@flagKey", $"{gameInfo.UUID}-{flagPair.Key}");
                    sqliteCommand.Parameters.AddWithValue("@flagValue", flagPair.Value);
                    sqliteCommand.ExecuteNonQuery();
                }
            }
            flagDb.Close();
        }
        public void AddGame(IGameInfo gameInfo)
        {
            IDictionary<string, string> flagValues = new Dictionary<string, string>();
            this.AddGame(gameInfo, flagValues);
        }
        public dynamic GetValue(IGameInfo gameInfo, string key, ConfigurationFlagTypes type)
        {
            return this.GetValue(key, type, gameInfo.UUID, this.GetDefaultValue(key, type));
        }
        public void SetValue(IGameInfo gameInfo, string key, object value, ConfigurationFlagTypes type)
        {
            this.SetValue(key, value, type, gameInfo.UUID);
        }
        public dynamic GetDefaultValue(string key, ConfigurationFlagTypes type)
        {
            return this.GetValue(key, type, "default", this.emulatorBridge.ConfigurationFlags[key].DefaultValue);
        }
        public void SetDefaultValue(string key, object value, ConfigurationFlagTypes type)
        {
            this.SetValue(key, value, type, "default");
        }
        private void AddDefaults(IDictionary<string, IConfigurationFlag> configurationFlags)
        {
            IDictionary<string, string> flagValues = configurationFlags.ToDictionary(flag => flag.Key, flag => flag.Value.DefaultValue);
            SQLiteConnection flagDb = this.GetConnection();
            flagDb.Open();
            foreach (KeyValuePair<string, string> flagPair in flagValues)
            {
               using(var sqliteCommand = new SQLiteCommand(@"INSERT OR REPLACE INTO flags VALUES(
                                          @flagKey,
                                          @flagValue)", flagDb)){
                   sqliteCommand.Parameters.AddWithValue("@flagKey", $"default-{flagPair.Key}");
                   sqliteCommand.Parameters.AddWithValue("@flagValue", flagPair.Value);
                   sqliteCommand.ExecuteNonQuery();
               }
            }
            flagDb.Close();
            

        }
        private void SetValue(string key, object value, ConfigurationFlagTypes type, string prefix)
        {
            SQLiteConnection flagDb = this.GetConnection();
            flagDb.Open();
            using (var sqliteCommand = new SQLiteCommand(@"INSERT OR REPLACE INTO flags VALUES(
                                          @flagKey,
                                          @flagValue)", flagDb))
            {
                sqliteCommand.Parameters.AddWithValue("@flagKey", $"{prefix}-{key}");
                sqliteCommand.Parameters.AddWithValue("@flagValue", value.ToString());
                sqliteCommand.ExecuteNonQuery();
            }
            flagDb.Close();
            
        }
        private dynamic GetValue(string key, ConfigurationFlagTypes type, string prefix, object fallback)
        {
            SQLiteConnection dbConnection = this.GetConnection();
            dbConnection.Open();
            string value = string.Empty;
            using (var sqlCommand = new SQLiteCommand(@"SELECT `flagValue` FROM `flags` WHERE `flagKey` == @searchQuery"
               , dbConnection))
            {
                sqlCommand.Parameters.AddWithValue("@searchQuery", $"{prefix}-{key}");
               
                    try
                    {
                        value = (string)sqlCommand.ExecuteScalar();
                    }
                    catch (AccessViolationException)
                    {
                        System.Threading.Thread.Sleep(500); //le concurrency hack :(
                        value = (string)sqlCommand.ExecuteScalar();
                    }
            }
            dbConnection.Close();
            value = value ?? fallback.ToString();
            switch (type)
            {
                case ConfigurationFlagTypes.SELECT_FLAG:
                    return int.Parse(value);
                case ConfigurationFlagTypes.INTEGER_FLAG:
                    return int.Parse(value);
                case ConfigurationFlagTypes.BOOLEAN_FLAG:
                    return bool.Parse(value);
                default:
                    return value;
            }
        }

        public dynamic this[IGameInfo gameInfo, string key, ConfigurationFlagTypes type]
        {
            get
            {
                return this.GetValue(gameInfo, key, type);
            }
            set
            {
                this.SetValue(gameInfo, key, value, type);
            }
        }
    }
}
<commit_msg>ConfigurationFlagStore: Port to backingStore<commit_after>﻿using System;
using System.Collections.Generic;
using System.Data.SQLite;
using System.IO;
using System.Linq;
using Snowflake.Game;
using Snowflake.Utility;

namespace Snowflake.Emulator.Configuration
{
    public class ConfigurationFlagStore : IConfigurationFlagStore
    {
        public string EmulatorBridgeID { get; }
        readonly string configurationFlagLocation;
        private readonly ISimpleKeyValueStore backingStore;
        readonly IEmulatorBridge emulatorBridge;
        public ConfigurationFlagStore(IEmulatorBridge emulatorBridge)
        {
            this.backingStore = new SqliteKeyValueStore(Path.Combine(emulatorBridge.PluginDataPath, "flagscache.db"));
            this.EmulatorBridgeID = emulatorBridge.PluginName;
            this.configurationFlagLocation = Path.Combine(emulatorBridge.PluginDataPath, "flagscache.db");
            this.AddDefaults(emulatorBridge.ConfigurationFlags);
            this.emulatorBridge = emulatorBridge;
        }

        public void AddGame(IGameInfo gameInfo, IDictionary<string, string> flagValues)
        {
            this.backingStore.InsertObjects(flagValues
                .ToDictionary(flagPair => $"{gameInfo.UUID}-{flagPair.Key}",
                flagPair => flagPair.Value));
        }
        public void AddGame(IGameInfo gameInfo)
        {
            IDictionary<string, string> flagValues = new Dictionary<string, string>();
            this.AddGame(gameInfo, flagValues);
        }
        public dynamic GetValue(IGameInfo gameInfo, string key, ConfigurationFlagTypes type)
        {
            return this.GetValue(key, type, gameInfo.UUID, this.GetDefaultValue(key, type));
        }
        public void SetValue(IGameInfo gameInfo, string key, object value, ConfigurationFlagTypes type)
        {
            this.SetValue(key, value, type, gameInfo.UUID);
        }
        public dynamic GetDefaultValue(string key, ConfigurationFlagTypes type)
        {
            return this.GetValue(key, type, "default", this.emulatorBridge.ConfigurationFlags[key].DefaultValue);
        }
        public void SetDefaultValue(string key, object value, ConfigurationFlagTypes type)
        {
            this.SetValue(key, value, type, "default");
        }
        private void AddDefaults(IDictionary<string, IConfigurationFlag> configurationFlags)
        {
            IDictionary<string, string> flagValues = configurationFlags
                .ToDictionary(flag => flag.Key, flag => flag.Value.DefaultValue);

            this.backingStore.InsertObjects(flagValues.ToDictionary(flagPair => $"default-{flagPair.Key}", 
                flagPair => flagPair.Value));
        }
        private void SetValue(string key, object value, ConfigurationFlagTypes type, string prefix)
        {
            switch (type)
            {
                case ConfigurationFlagTypes.BOOLEAN_FLAG:
                    this.backingStore.InsertObject($"{prefix}-{key}", (bool)value);
                    break;
                case ConfigurationFlagTypes.INTEGER_FLAG:
                    this.backingStore.InsertObject($"{prefix}-{key}", (int)value);
                    break;
                case ConfigurationFlagTypes.SELECT_FLAG:
                    this.backingStore.InsertObject($"{prefix}-{key}", (int)value);
                    break;
            }
        }

        private dynamic GetValue(string key, ConfigurationFlagTypes type, string prefix, object fallback)
        {
            switch (type)
            {
                case ConfigurationFlagTypes.BOOLEAN_FLAG:
                    return this.backingStore.GetObject<bool>($"{prefix}-{key}");
                case ConfigurationFlagTypes.INTEGER_FLAG:
                    return this.backingStore.GetObject<int>($"{prefix}-{key}");
                case ConfigurationFlagTypes.SELECT_FLAG:
                    return this.backingStore.GetObject<int>($"{prefix}-{key}");
                default:
                    return fallback;
            }
        }

        public dynamic this[IGameInfo gameInfo, string key, ConfigurationFlagTypes type]
        {
            get
            {
                return this.GetValue(gameInfo, key, type);
            }
            set
            {
                this.SetValue(gameInfo, key, value, type);
            }
        }
    }
}

{'fraction_non_alphanumeric': 0.08683473389355742, 'fraction_numerical': 0.0002710761724044456, 'mean_word_length': 1.8343149807938541, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 26, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1084802', 'n_tokens_mistral': 2681, 'n_tokens_neox': 2577, 'n_words': 539}