using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using Raytheon.Common.PdelWriter.Utilities;

namespace Raytheon.Common.PdelWriter
{
   public class PdelWriter
   {
      #region Private Class Members
      /// <summary>
      /// Will hold the PDEL header line length that this the longest.
      /// </summary>
      private int maxLength = 0;
      #endregion

      #region Private Properties
      // Get Test Executive's PDEL report storage locations from the app.config file.
      public string TestResultsLocalFolder { get; set; }
      public string PdelDataResultsSubfolder { get; set; }
      public string TestResultsNetworkFolder { get; set; }
      public bool OutputTestResultsToSubfolder { get; set; }
      #endregion

      #region Constructors
      /// <summary>
      /// Initializes a new instance of the <see cref="PdelWriter" /> class.
      /// </summary>
      public PdelWriter()
      {
      }
      #endregion

      #region Public Members
      /// <summary>
      /// Remove extraneous punctuation that causes errors in the PDEL report generation. 
      /// </summary>
      /// <param name="dataString - data to scan for and remove extraneous punctuation"></param>
      /// <returns>Returns a string without extraneous punctuation.</returns>
      public string RemovePunctuation(string dataString)
      {
         // Remove all commas, single quotes and double quotes and semi-colons from string.
         return Regex.Replace(dataString, "[,'\";]+", "");
      }

      /// <summary>
      /// Moved outside of CreatePdelFile to set the local properties that make up the PDEL report file path.
      /// </summary>
      /// <param name="pdelInformation"></param>
      /// <param name="filename"></param>
      /// <returns></returns>
      public string CreateFilePath(PdelInformation pdelInformation, string localFolderPath, out string filename)
      {
         // Get Test Executive's PDEL report storage locations from the app.config file.
         TestResultsLocalFolder = localFolderPath;
         return CreateTestResultsFolder(pdelInformation, out filename);
      }

      /// <summary>
      /// Writes PDEL data to a file.
      /// </summary>
      /// <param name="item">The item.</param>
      public void CreatePdelFile(List<TestResult> testResults, PdelInformation pdelInformation, string localFolderPath)
      {
         if (pdelInformation != null)
         {
            var hasFailure = from s in testResults
                             where s.Result == PassFailStatus.Fail
                             select s;

            pdelInformation.UutTestStatus = hasFailure.Count() > 0 ? PassFailStatus.Fail : PassFailStatus.Pass;

            string filename = string.Empty;
            string testResultsFolder = CreateFilePath(pdelInformation, localFolderPath, out filename);

            // Find the header line that is the longest. This will help us to align the headers items together.
            foreach (KeyValuePair<string, string> kvp in pdelInformation.GetDetails())
            {
               if (maxLength < kvp.Key.Length)
               {
                  maxLength = kvp.Key.Length;
               }
            }

            var startTime = new TimeSpan();

            var stopTime = new TimeSpan();
            string pdelFilePath = Path.Combine(testResultsFolder, filename + ".pdel");

            using (System.IO.StreamWriter writer = new StreamWriter(pdelFilePath))
            {
               string comment = string.Empty;

               writer.Write(string.Format("COMMENT = **********START OF HEADER***************;{0}", Environment.NewLine));

               foreach (KeyValuePair<string, string> kvp in pdelInformation.GetDetails())
               {
                  // If there are test comments, the entry needs to be defined. 
                  if (kvp.Key == "TEST_COMMENTS")
                  {
                     writer.Write(string.Format("{0} {1} = {2}{3};{4}", "DEFINE_HEADER", kvp.Key, "User comments for test, ", pdelInformation.UutIdentification, Environment.NewLine));
                  }
                  else if (kvp.Key == "E_C_I_D_NUMBER")
                  {
                     writer.Write(string.Format("{0} {1} = {2}{3};{4}", "DEFINE_HEADER", kvp.Key, "ECID number for test, ", pdelInformation.ECIDNumber, Environment.NewLine));
                  }
                  else if
                      (kvp.Key == "SLOT_NUMBER")
                  {
                     writer.Write(string.Format("{0} {1} = {2}{3};{4}", "DEFINE_HEADER", kvp.Key, "Slot number for test, ", pdelInformation.SlotNumber, Environment.NewLine));
                  }

                  // Some UutDetails are used for housekeeping and do not get written to the PDEL file.
                  if (kvp.Value != "DoNotWriteToPDEL")
                  {
                     writer.Write(string.Format("{0} = {1};{2}", kvp.Key.PadRight(maxLength), kvp.Value == string.Empty ? "N/A" : RemovePunctuation(kvp.Value), Environment.NewLine));
                  }
               }

               writer.Write(string.Format("COMMENT = **********END OF HEADER***************;{0}{1}", Environment.NewLine, Environment.NewLine));

               writer.Write(string.Format("COMMENT = **********START OF DATA***************;{0}{1}", Environment.NewLine, Environment.NewLine));

               foreach (var result in testResults)
               {
                  writer.Write(string.Format(
                      "DEFINE_DATA {0} = {1}, {2}, {3};{4}",
                      result.PCode,
                      RemovePunctuation(result.TestName),
                      PdelDataFormatter.Format(result.MeasuredValue.ToString()),
                      PdelDataFormatter.IsNullOrEmpty(result.UnitOfMeasure),
                      Environment.NewLine));

                  writer.Write(string.Format("{0} = {1};{2}{3}", result.PCode, result.MeasuredValue.ToString(), Environment.NewLine, Environment.NewLine));
               }

               writer.Write(string.Format("COMMENT = **********END OF DATA***************;{0}{1}", Environment.NewLine, Environment.NewLine));
               writer.Flush();
            }
         }
      }
      #endregion

      #region Private Methods
      public static string BuildFilename(PdelInformation pdelInformation, string separator)
      {
         return string.Format(!string.IsNullOrEmpty(pdelInformation.UutIdentification) ? (pdelInformation.UutIdentification + separator) : string.Empty)
              + string.Format(!string.IsNullOrEmpty(pdelInformation.UutSerialNumber) ? (pdelInformation.UutSerialNumber + separator) : string.Empty)
              + string.Format(!string.IsNullOrEmpty(pdelInformation.WorkOrder) ? (pdelInformation.WorkOrder + separator) : string.Empty)
              + string.Format(!string.IsNullOrEmpty(pdelInformation.TestTemperature) ? (pdelInformation.TestTemperature + separator) : string.Empty)
              + DateTime.Now.ToString("yyyyMMdd_HHmmss");
      }

      /// <summary>
      /// Create a PDEl report file based on information in the PdelInformation class and operator's values.
      /// </summary>
      /// <param name="pdelInformation"></param>
      /// <param name="filename"></param>
      /// <returns></returns>
      private string CreateTestResultsFolder(PdelInformation pdelInformation, out string filename)
      {
         var details = pdelInformation.GetDetails();

         // Check to see if user selected to save data in a subfolder.
         var subFolder = PdelDataResultsSubfolder != null ? PdelDataResultsSubfolder : string.Empty;

         // If the folder is not null or empty, get the matching UUT details value.
         if (!string.IsNullOrEmpty(subFolder) && subFolder != "None Selected")
         {
            subFolder = Regex.Replace(subFolder, @"(?<!_|^)([A-Z])", "_$1").ToUpper();

            foreach (var detail in details)
            {
               if (subFolder == detail.Key)
               {
                  subFolder = detail.Value;
               }
            }
         }
         else
         {
            // subFolder is not being used set it to empty string.
            subFolder = string.Empty;
         }

         filename = BuildFilename(pdelInformation, "_");

         string testResultsFolder = Path.Combine(TestResultsLocalFolder, subFolder);

         // Make sure the folder exists.
         if (!Directory.Exists(testResultsFolder))
         {
            Directory.CreateDirectory(testResultsFolder);
         }

         return testResultsFolder;
      }
      #endregion
   }
}