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

namespace Wayne.Lib.IO
{
    /// <summary>
    /// Class that manages an Ini-file.
    /// </summary>
    public class IniFile
    {
        private readonly IFileSupport fileSupport;

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="serviceLocator">The service locator.</param>
        public IniFile(IServiceLocator serviceLocator)
        {
            fileSupport = serviceLocator.GetService<IFileSupport>();
            Sections = new Dictionary<string, IniFileSection>();
        }

        /// <summary>
        /// The sections of the ini-file.
        /// </summary>
        public Dictionary<string, IniFileSection> Sections { get; private set; }

        /// <summary>
        /// Returns existing or creates a new section.
        /// </summary>
        /// <param name="sectionName">The name of the section.</param>
        /// <returns></returns>
        public IniFileSection GetSection(string sectionName)
        {
            IniFileSection section;
            if (!Sections.TryGetValue(sectionName, out section))
            {
                section = new IniFileSection();
                Sections.Add(sectionName, section);
            }
            return section;
        }

        /// <summary>
        /// Save ini file.
        /// </summary>
        /// <param name="fileName">The name of the file.</param>
        public void SaveToFile(string fileName)
        {
            using (Stream stream = fileSupport.Open(fileName, FileMode.Create, FileAccess.Write, FileShare.None))
            {
                using (StreamWriter streamWriter = new StreamWriter(stream))
                {
                    foreach (KeyValuePair<string, IniFileSection> sectionValuePair in Sections)
                    {
                        streamWriter.WriteLine(string.Concat("[", sectionValuePair.Key, "]"));
                        foreach (KeyValuePair<string, string> valuePair in sectionValuePair.Value.Values)
                        {
                            if (valuePair.Value != null)
                                streamWriter.WriteLine(string.Concat(valuePair.Key.Trim(), "=", valuePair.Value.Trim()));
                            else
                                streamWriter.WriteLine(valuePair.Key.Trim());
                        }
                        streamWriter.WriteLine();
                    }
                }
            }
        }

        /// <summary>
        /// Read an ini-file.
        /// </summary>
        /// <param name="fileName">The name of the file.</param>
        public void LoadFromFile(string fileName)
        {
            Sections.Clear();
            using (Stream stream = fileSupport.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                using (StreamReader streamReader = new StreamReader(stream))
                {
                    IniFileSection currentSection = null;
                    while (!streamReader.EndOfStream)
                    {
                        string line = streamReader.ReadLine().Trim();
                        if (!string.IsNullOrEmpty(line))
                        {
                            if (line.StartsWith("["))
                            {
                                if (line.EndsWith("]"))
                                {
                                    string sectionName = line.Substring(1, line.Length - 2);
                                    currentSection = new IniFileSection();
                                    Sections[sectionName] = currentSection;
                                }
                                else
                                {
                                    // Bad section name. Ignore this line.
                                }
                            }
                            else if (currentSection != null)
                            {
                                int equalSignIndex = line.IndexOf('=');
                                if (equalSignIndex > -1)
                                {
                                    string key = line.Substring(0, equalSignIndex);
                                    string value = line.Substring(equalSignIndex + 1);
                                    currentSection.Values[key] = value;
                                }
                                else
                                    currentSection.Values[line] = null;
                            }
                            else
                            {
                                // No section has started. Ignore this line.
                            }
                        }
                    }
                }
            }
        }
    }

    /// <summary>
    /// A section of an Ini file.
    /// </summary>
    public class IniFileSection
    {
        /// <summary>
        /// Constructor.
        /// </summary>
        public IniFileSection()
        {
            Values = new Dictionary<string, string>();
        }

        /// <summary>
        /// The values of the section.
        /// </summary>
        public Dictionary<string, string> Values { get; private set; }
    }
}