using System;
using System.IO;
using System.Text;

namespace Volpe.Cafe.Reporting
{
    /// <summary>
    /// Provides static methods for splitting modeling reports using specific criteria.
    /// </summary>
    [Serializable]
    public static class ReportFileSplitter
    {
        // We want to use a large (32k) and very large (256k) buffer size when
        // splitting files. Doing so significantly improves write performance,
        // since all we're doing is moving chunks of data around.
        private const int ReadBufferSize = 32 * 1024;
        private const int WriteBufferSize = 256 * 1024;

        // UTF-8 encoding (w/o the Unicode byte-order mark) for writing files
        private static Encoding UTF8NoBOM = new UTF8Encoding(false, true);

        /// <summary>
        /// Splits the report file at the specified path by scenario. If the split files from prior run exist, they
        /// will be overwritten; otherwise, multiple new files (for each scenario) will be created. The headers from
        /// the source report file will be used for each split file.
        /// </summary>
        /// <param name="sourcePath">The complete file path of the source report file to split by scenario.</param>
        public static void SplitByScenario(string sourcePath)
        {
            if (!File.Exists(sourcePath)) {
                return;
            }

            using (var sr = CreateReader(sourcePath)) {
                string header = sr.ReadLine();
                if (header == null || header.Trim().Length == 0) {
                    return;
                }

                string reportName = Path.GetFileNameWithoutExtension(sourcePath);
                string splitDir = Path.Combine(Path.GetDirectoryName(sourcePath), $"{reportName}_by_sn");
                Directory.CreateDirectory(splitDir);

                StreamWriter sw = null;
                string prevSN = null;
                string line;

                while ((line = sr.ReadLine()) != null) {
                    string sn = line.Substring(0, line.IndexOf(","));
                    if (prevSN != sn) {
                        prevSN = sn;
                        sw?.Close();

                        string splitFile = Path.Combine(splitDir, $"{reportName}_sn{sn}.csv");
                        sw = CreateWriter(splitFile);
                        sw.Write(header);
                    }

                    sw.Write(ReportFile.NewLine);
                    sw.Write(line);
                }

                sw?.Close();
            }
        }

        private static StreamReader CreateReader(string path)
        {
            return new StreamReader(path, Encoding.UTF8, true, ReadBufferSize);
        }

        private static StreamWriter CreateWriter(string path, bool append = false)
        {
            return new StreamWriter(path, append, UTF8NoBOM, WriteBufferSize);
        }

    }
}
