Zuma Lifeguard Wiki
Advertisement
using System;
using System.Collections.Generic;
using System.IO;

//Example:
//  var c = new ConfigFile("default.txt", Properties.Resources._default);
//  var x = c.Get("some keyword");
//
class ConfigFile
{
    const string DELIMITER = "=";
    const string COMMENT_CHAR_1 = ";";
    const string COMMENT_CHAR_2 = "#";

    private Dictionary<string, string> _dictionary = null;
    private List<string> _flatlist = null;

    private string _primaryFile;
    private byte[] _resource;

    // Assumes the factory-settings config file is stored as a resource in the project
    public ConfigFile(string primaryFilename, byte[] resource)
    {
        _primaryFile = primaryFilename;
        _resource = resource;
    }

    public static string MakeBase(string filename)
    {
        return filename + ".base";
    }

    private static bool StartsWithCommentChar(string s)
    {
        return (s.StartsWith(COMMENT_CHAR_1) || s.StartsWith(COMMENT_CHAR_2));
    }

    private static void ReadFileIntoDictionary(string filename, out Dictionary<string, string> dictionary, out List<string> flatList)
    {
        dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
        flatList = new List<string>();

        using (TextReader sr = new StreamReader(filename))
        {
            string input;

            while ((input = sr.ReadLine()) != null)
            {
                // If it starts with a comment character, then skip, otherwise
                // split the string into two parts, separated by an equal sign.
                if (StartsWithCommentChar(input))
                {
                    flatList.Add(input);
                }
                else if (input.Contains(DELIMITER))
                {
                    string[] parts = input.Split(new char[] { DELIMITER[0] }, 2);

                    if (parts.Length != 2)
                        throw new Exception("bad code");

                    dictionary[parts[0]] = parts[1];
                    flatList.Add(parts[0]);
                }
            }
        }
    }

    private void CreatePrimaryConfigFile(out Dictionary<string, string> d, out List<string> l)
    {
        File.WriteAllBytes(_primaryFile, _resource);
        File.WriteAllBytes(MakeBase(_primaryFile), _resource);

        ReadFileIntoDictionary(_primaryFile, out d, out l);
    }

    // Only add entries if they are new keys, or for existing keys, the base and current haven't changed.
    private static bool AddNewEntries(Dictionary<string, string> primaryDiskDictionary, Dictionary<string, string> resDictionary, Dictionary<string, string> baseDiskDictionary)
    {
        bool anEntryWasAdded = false;

        foreach (var item in resDictionary)
        {
            bool doAdd = false;

            // If the key doesn't exist in the current, then add it.
            if (!primaryDiskDictionary.ContainsKey(item.Key))
            {
                doAdd = true;
            }
            else if (baseDiskDictionary.ContainsKey(item.Key))
            {
                // If the base and the current are the same, then we can accept the new version.
                if (primaryDiskDictionary[item.Key] == baseDiskDictionary[item.Key] &&
                    primaryDiskDictionary[item.Key] == item.Value)
                {
                    doAdd = true;
                }
            }

            if (doAdd)
            {
                primaryDiskDictionary[item.Key] = item.Value;
                anEntryWasAdded = true;
            }
        }
        return anEntryWasAdded;
    }

    private static void CreateConfigurationFile(string filename, List<string> flatList, Dictionary<string, string> dictionary)
    {
        using (TextWriter stream = new StreamWriter(filename))
        {
            foreach (var item in flatList)
            {
                if (StartsWithCommentChar(item))
                    stream.WriteLine(item);
                else
                    stream.WriteLine("{0}{1}{2}", item, DELIMITER, dictionary[item]);
            }
        }
    }

    private void MergeConfigFile(out Dictionary<string, string> primaryDiskDictionary, out List<string> resList)
    {
        // Add new entries from the resource to the disk file.

        // Load the "current" version from disk
        List<string> primaryDiskList;
        ReadFileIntoDictionary(_primaryFile, out primaryDiskDictionary, out primaryDiskList);

        // Load the "base" version from disk
        // If the base file isn't there for some reason, create it by copying the primary one.
        if (!File.Exists(MakeBase(_primaryFile)))
            File.Copy(_primaryFile, MakeBase(_primaryFile), false);

        Dictionary<string, string> baseDiskDictionary;
        List<string> baseDiskList;
        ReadFileIntoDictionary(MakeBase(_primaryFile), out baseDiskDictionary, out baseDiskList);

        // Load the one from Resources.
        var tempPathResVersion = Path.GetTempFileName();
        try
        {
            File.WriteAllBytes(tempPathResVersion, _resource);

            Dictionary<string, string> resDictionary;
            ReadFileIntoDictionary(tempPathResVersion, out resDictionary, out resList);

            // Add new entries, and write dictionary to file if necessary.
            // Only add entries if they are new keys.  Or for existing keys, the base and primary haven't changed.
            if (AddNewEntries(primaryDiskDictionary, resDictionary, baseDiskDictionary))
                CreateConfigurationFile(_primaryFile, resList, primaryDiskDictionary);
        }
        finally
        {
            File.Delete(tempPathResVersion);
        }
    }

    private void LoadDictionaryFromPrimaryFile(out Dictionary<string, string> primaryDiskDictionary, out List<string> list)
    {
        // If the file is already there, add new entries from the resource to the file, otherwise start the new file as
        // clone of the resource.
        if (File.Exists(_primaryFile))
            MergeConfigFile(out primaryDiskDictionary, out list);
        else
            CreatePrimaryConfigFile(out primaryDiskDictionary, out list);
    }

    private void EnsureDictionaryLoaded()
    {
        if (_dictionary == null)
            LoadDictionaryFromPrimaryFile(out _dictionary, out _flatlist);
    }

    public string this[string key]
    {
        get
        {
            EnsureDictionaryLoaded();
            return _dictionary[key];
        }

        set
        {
            EnsureDictionaryLoaded();
            _dictionary[key] = value;

            CreateConfigurationFile(_primaryFile, _flatlist, _dictionary);
        }
    }

    public void SaveAs(string newFilename)
    {
        // Write the primary settings to the new file.
        CreateConfigurationFile(newFilename, _flatlist, _dictionary);

        // Copy the base settings of the primary file.
        File.Copy(MakeBase(_primaryFile), MakeBase(newFilename), true);
    }

    public List<string> GetList(string fieldKey)
    {
        var list = new List<string>();

        var listCount = int.Parse(this[fieldKey + " Count"]);

        for (int listIndex = 0; listIndex < listCount; listIndex++)
            list.Add(this[string.Format("{0} {1}", fieldKey, listIndex)]);

        return list;
    }
}
Advertisement