<commit_before>﻿//   PluginConfig.cs
//
//  Author:
//       <NAME> <<EMAIL>>
//
//  Copyright (c) 2016 <NAME>

using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;

namespace AT_Utils
{
    public abstract class CustomConfig : ConfigNodeObject
    {
        public static string GameDataRoot
        { get { return Path.Combine(KSPUtil.ApplicationRootPath, "GameData"); } }

        public static string GameDataFolder(params string[] path)
        { return Path.Combine(GameDataRoot, Utils.PathChain(path)); }

        public string AssemblyName
        { get { return Assembly.GetAssembly(GetType()).GetName().Name; } }

        public string AssemblyLocation
        { get { return Assembly.GetAssembly(GetType()).Location; } }

        public string AssemblyFolder
        { get { return Path.GetDirectoryName(AssemblyLocation); } }

        public string PluginFolder(string filename = "")
        { return Utils.PathChain(AssemblyFolder, "..", filename); }

        public string PluginData(string filename = "")
        { return Utils.PathChain(AssemblyFolder, "PluginData", AssemblyName, filename); }


        public static ConfigNode LoadNode(string filepath, bool with_message = false)
        {
            var node = ConfigNode.Load(filepath);
            if(node == null && with_message) 
                Utils.Log("Unable to read {}", filepath);
            return node;
        }

        public static bool SaveNode(ConfigNode node, string filepath)
        {
            try
            {
                Directory.CreateDirectory(Path.GetDirectoryName(filepath));
                node.Save(filepath);
                return true;
            }
            catch(Exception ex) 
            { 
                Utils.Log("Error writing {} file:\n{}", filepath, ex); 
                return false;
            }
        }

        public bool Create(string filepath)
        {
            var node = new ConfigNode();
            Save(node);
            return SaveNode(node, filepath);
        }
    }

    public abstract class PluginConfig : CustomConfig
    {
        public string DefaultFile { get { return PluginData(AssemblyName+".glob"); } }
        public string DefaultOverride { get { return PluginFolder(AssemblyName+".user"); } }
        public bool   DefaultFileExists { get { return File.Exists(DefaultFile); } }
        public virtual List<string> AllConfigFiles { get { return new List<string>{DefaultFile, DefaultOverride}; } }

        public virtual void Init() {}

        public void Load(params string[] files)
        {
            //this allows for cascading options overriding
            foreach(var f in files)
            {
                var gnode = LoadNode(f);
                if(gnode != null) Load(gnode);
            }
            Init();
        }
        public void LoadDefaultFile() { Load(DefaultFile); }
        public void CreateDefaultFile() { Create(DefaultFile); }
        public void CreateDefaultOverride() { Create(DefaultOverride); }
    }


    public abstract class PluginGlobals<T> : PluginConfig where T : PluginConfig, new()
    {
        static T instance { get; set; }
        public static T Instance 
        {
            get
            {
                if(instance == null) Load();
                return instance;
            }
        }

        public static void Load()
        {
            instance = new T();
            if(!instance.DefaultFileExists)
                instance.CreateDefaultFile();
            instance.Load(instance.AllConfigFiles.ToArray());
        }
    }
}
<commit_msg>Using CNO.Diff to save only those override values that differ from the .glob<commit_after>﻿//   PluginConfig.cs
//
//  Author:
//       <NAME> <<EMAIL>>
//
//  Copyright (c) 2016 <NAME>

using System;
using System.IO;
using System.Reflection;
using System.Collections.Generic;

namespace AT_Utils
{
    public abstract class CustomConfig : ConfigNodeObject
    {
        public static string GameDataRoot
        { get { return Path.Combine(KSPUtil.ApplicationRootPath, "GameData"); } }

        public static string GameDataFolder(params string[] path)
        { return Path.Combine(GameDataRoot, Utils.PathChain(path)); }

        public string AssemblyName
        { get { return Assembly.GetAssembly(GetType()).GetName().Name; } }

        public string AssemblyLocation
        { get { return Assembly.GetAssembly(GetType()).Location; } }

        public string AssemblyFolder
        { get { return Path.GetDirectoryName(AssemblyLocation); } }

        public string PluginFolder(string filename = "")
        { return Utils.PathChain(AssemblyFolder, "..", filename); }

        public string PluginData(string filename = "")
        { return Utils.PathChain(AssemblyFolder, "PluginData", AssemblyName, filename); }


        public static ConfigNode LoadNode(string filepath, bool with_message = false)
        {
            var node = ConfigNode.Load(filepath);
            if(node == null && with_message) 
                Utils.Log("Unable to read {}", filepath);
            return node;
        }

        public static bool SaveNode(ConfigNode node, string filepath)
        {
            try
            {
                Directory.CreateDirectory(Path.GetDirectoryName(filepath));
                node.Save(filepath);
                return true;
            }
            catch(Exception ex) 
            { 
                Utils.Log("Error writing {} file:\n{}", filepath, ex); 
                return false;
            }
        }

        public bool Create(string filepath)
        {
            var node = new ConfigNode();
            Save(node);
            return SaveNode(node, filepath);
        }
    }

    public abstract class PluginConfig : CustomConfig
    {
        public string DefaultFile { get { return PluginData(AssemblyName+".glob"); } }
        public string DefaultOverride { get { return PluginFolder(AssemblyName+".user"); } }
        public bool   DefaultFileExists { get { return File.Exists(DefaultFile); } }
        public virtual List<string> AllConfigFiles { get { return new List<string>{DefaultFile, DefaultOverride}; } }

        public virtual void Init() {}

        public void Load(params string[] files)
        {
            //this allows for cascading options overriding
            foreach(var f in files)
            {
                var gnode = LoadNode(f);
                if(gnode != null) Load(gnode);
            }
            Init();
        }
        public void LoadDefaultFile() { Load(DefaultFile); }
        public void CreateDefaultFile() { Create(DefaultFile); }
        public void CreateDefaultOverride() { Create(DefaultOverride); }
    }


    public abstract class PluginGlobals<T> : PluginConfig where T : PluginConfig, new()
    {
        static T instance { get; set; }
        public static T Instance 
        {
            get
            {
                if(instance == null) Load();
                return instance;
            }
        }

        public static void Load()
        {
            instance = new T();
            if(!instance.DefaultFileExists)
                instance.CreateDefaultFile();
            instance.Load(instance.AllConfigFiles.ToArray());
        }

        public static void SaveOverride()
        {
            var glob = new T();
            if(glob.DefaultFileExists)
            {
                glob.LoadDefaultFile();
                var diff = instance.Diff(glob);
                SaveNode(diff, glob.DefaultOverride);
            }
        }
    }
}
{'fraction_non_alphanumeric': 0.09807793575566087, 'fraction_numerical': 0.00105318588730911, 'mean_word_length': 1.8974065598779557, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, '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': '4012878', 'n_tokens_mistral': 1939, 'n_tokens_neox': 1834, 'n_words': 491}