using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Xml.Serialization;

namespace Raytheon.Common.PdelWriter.Utilities
{
   [XmlType("TestExecutive-PdelInformation")]
   public class PdelInformation
   {
      #region Public Properties
      /// <summary>
      /// Gets or sets the Test Data Standard Version.
      /// </summary>
      /// <value>The Test Data Standard Version.</value>
      [XmlElement("TestDataStandardVersion")]
      public string TestDataStandardVersion { get; set; }

      /// <summary>
      /// Gets or sets the UUT Identification.
      /// </summary>
      /// <value>The UUT Identification.</value>
      [XmlElement("UutIdentification")]
      public string UutIdentification { get; set; }

      /// <summary>
      /// Gets or sets the UUT Revision.
      /// Drawing Number Revision of the Unit Under Test (also know as Dash Number)
      /// </summary>
      /// <value>The UUT Revision.</value>
      [XmlElement("UutRevision")]
      public string UutRevision { get; set; }

      /// <summary>
      /// Gets or sets the UUT Serial Number.
      /// </summary>
      /// <value>The UUT Serial Number.</value>
      [XmlElement("UutSerialNumber")]
      public string UutSerialNumber { get; set; }

      /// <summary>
      /// Gets or sets the Test Procedure Revision.
      /// </summary>
      /// <value>The Test Procedure Revision.</value>
      [XmlElement("TestProcedureRevision")]
      public string TestProcedureRevision { get; set; }

      /// <summary>
      /// Gets or sets the Test Procedure Identification.
      /// </summary>
      /// <value>The Test Procedure Identification.</value>
      [XmlElement("TestProcedureIdentification")]
      public string TestProcedureIdentification { get; set; }

      /// <summary>
      /// Gets or sets the work order.
      /// Work order number for the test being run
      /// </summary>
      /// <value>The work order.</value>
      [XmlElement("WorkOrder")]
      public string WorkOrder { get; set; }

      /// <summary>
      /// Gets or sets the Work Order Operation.
      /// </summary>
      /// <value>The Work Order Operation.</value>
      [XmlElement("WorkOrderOperation")]
      public string WorkOrderOperation { get; set; }

      /// <summary>
      /// Gets or sets the Test Software Identification.
      /// </summary>
      /// <value>The Test Software Identification.</value>
      [XmlElement("TestSoftwareIdentification")]
      public string TestSoftwareIdentification { get; set; }

      /// <summary>
      /// Gets or sets the Test Software Revision.
      /// </summary>
      /// <value>The Test Software Revision.</value>
      [XmlElement("TestSoftwareRevision")]
      public string TestSoftwareRevision { get; set; }

      /// <summary>
      /// Gets or sets the Test Set Identification.
      /// </summary>
      /// <value>The Test Set Identification.</value>
      [XmlElement("TestSetIdentification")]
      public string TestSetIdentification { get; set; }

      /// <summary>
      /// Gets or sets the Test Set Revision.
      /// </summary>
      /// <value>The Test Set Revision.</value>
      [XmlElement("TestSetRevision")]
      public string TestSetRevision { get; set; }

      /// <summary>
      /// Gets or sets the Test Set Serial Number.
      /// </summary>
      /// <value>The Test Set Serial Number.</value>
      [XmlElement("TestSetSerialNumber")]
      public string TestSetSerialNumber { get; set; }

      /// <summary>
      /// Gets or sets the Test Chamber Identification.
      /// </summary>
      /// <value>The Test Chamber Identification.</value>
      [XmlElement("TestChamberIdentification")]
      public string TestChamberIdentification { get; set; }

      /// <summary>
      /// Gets or sets the Test Chamber Revision.
      /// </summary>
      /// <value>The Test Chamber Revision.</value>
      [XmlElement("TestChamberRevision")]
      public string TestChamberRevision { get; set; }

      /// <summary>
      /// Gets or sets the Test Chamber Serial Number.
      /// </summary>
      /// <value>The Test Chamber Serial Number.</value>
      [XmlElement("TestChamberSerialNumber")]
      public string TestChamberSerialNumber { get; set; }

      /// <summary>
      /// Gets or sets the Interface Adapter Identification.
      /// </summary>
      /// <value>The Interface Adapter Identification.</value>
      [XmlElement("InterfaceAdapterIdentification")]
      public string InterfaceAdapterIdentification { get; set; }

      /// <summary>
      /// Gets or sets the Interface Adapter Revision.
      /// </summary>
      /// <value>The Interface Adapter Revision.</value>
      [XmlElement("InterfaceAdapterRevision")]
      public string InterfaceAdapterRevision { get; set; }

      /// <summary>
      /// Gets or sets the Interface Adapter Serial Number.
      /// </summary>
      /// <value>The Interface Adapter Serial Number.</value>
      [XmlElement("InterfaceAdapterSerialNumber")]
      public string InterfaceAdapterSerialNumber { get; set; }

      /// <summary>
      /// Gets or sets the test category.
      /// </summary>
      /// <value>The test category.</value>
      [XmlElement("Address")]
      public TestCategory TestCategory { get; set; }

      /// <summary>
      /// Gets or sets the Test Location.
      /// </summary>
      /// <value>The Test Location.</value>
      [XmlElement("TestLocation")]
      public string TestLocation { get; set; }

      /// <summary>
      /// Gets or sets the Test operator.
      /// </summary>
      /// <value>The Test Operator.</value>
      [XmlElement("TestOperator")]
      public string TestOperator { get; set; }

      /// <summary>
      /// Gets or sets the Test Temperature.
      /// </summary>
      /// <value>The Test Temperature.</value>
      [XmlElement("TestTemperature")]
      public string TestTemperature { get; set; }

      /// <summary>
      /// Gets or sets the Test Start Time.
      /// </summary>
      /// <value>The Test start time.</value>
      [XmlElement("TestStartTime")]
      public DateTime TestStartTime { get; set; }

      /// <summary>
      /// Gets or sets the Test Stop Time.
      /// </summary>
      /// <value>The Test Stop Time.</value>
      [XmlElement("TestStopTime")]
      public DateTime TestStopTime { get; set; }

      /// <summary>
      /// Gets or sets the UUT Test Status.
      /// </summary>
      /// <value>The UUT Test Status.</value>
      [XmlElement("UutTestStatus")]
      public PassFailStatus UutTestStatus { get; set; }

      /// <summary>
      /// Gets or sets the test comments.
      /// </summary>
      /// <value>The test comments.</value>
      [XmlElement("TestComments")]
      public string TestComments { get; set; }

      [XmlElement("ECIDNumber")]
      public string ECIDNumber { get; set; }

      /// <summary>
      /// Physical slot number the UUT is tested in.
      /// </summary>
      [XmlElement("SlotNumber")]
      public int SlotNumber { get; set; } = 1;
      #endregion

      #region Constructors
      public PdelInformation()
      {
      }

      /// <summary>
      /// ICloneable is depreciated so we have to create a basic copy constructor.
      /// </summary>
      /// <param name="copyThis"></param>
      public PdelInformation(PdelInformation copyThis)
      {
         Clone(copyThis);
      }
      #endregion

      #region Public Members
      /// <summary>
      /// Clones the PdelInformation from copyThis to this.
      /// </summary>
      /// <param name="copyThis"></param>
      void Clone(PdelInformation cloneThis)
      {
         UutSerialNumber = cloneThis.UutSerialNumber;
         UutIdentification = cloneThis.UutIdentification;
         UutRevision = cloneThis.UutRevision;
         WorkOrder = cloneThis.WorkOrder;
         WorkOrderOperation = cloneThis.WorkOrderOperation;
         TestProcedureIdentification = cloneThis.TestProcedureIdentification;
         TestProcedureRevision = cloneThis.TestProcedureRevision;
         TestSetIdentification = cloneThis.TestSetIdentification;
         TestSoftwareRevision = cloneThis.TestSoftwareRevision;
         TestSoftwareIdentification = cloneThis.TestSoftwareIdentification;
         TestSetRevision = cloneThis.TestSetRevision;
         TestSetSerialNumber = cloneThis.TestSetSerialNumber;
         TestChamberIdentification = cloneThis.TestChamberIdentification;
         TestChamberRevision = cloneThis.TestChamberRevision;
         TestChamberSerialNumber = cloneThis.TestChamberSerialNumber;
         InterfaceAdapterIdentification = cloneThis.InterfaceAdapterIdentification;
         InterfaceAdapterRevision = cloneThis.InterfaceAdapterRevision;
         InterfaceAdapterSerialNumber = cloneThis.InterfaceAdapterSerialNumber;
         TestLocation = cloneThis.TestLocation;
         TestCategory = cloneThis.TestCategory;
         TestTemperature = cloneThis.TestTemperature;
         ECIDNumber = cloneThis.ECIDNumber;
         SlotNumber = cloneThis.SlotNumber;
      }

      /// <summary>
      /// Returns all the public properties of the current System.Type.
      /// </summary>
      /// <returns>Dictionary of key/value pairs representing PDEL Header values.</returns>
      public Dictionary<string, string> GetDetails()
      {
         Dictionary<string, string> details = new Dictionary<string, string>();

         PropertyInfo[] propertyInfos = this.GetType().GetProperties();

         foreach (PropertyInfo info in propertyInfos)
         {
            var value = string.Empty;

            foreach (var test in info.CustomAttributes)
            {
               if (test.NamedArguments != null && test.NamedArguments.Count > 0 && test.NamedArguments[0].MemberName == "EmitDefaultValue")
               {
                  value = "DoNotWriteToPDEL";
                  break;
               }
               else
               {
                  value = info.GetValue(this) == null ? "NA" : info.GetValue(this).ToString();
                  break;
               }
            }

            string name = Regex.Replace(info.Name, @"(?<!_|^)([A-Z])", "_$1").ToUpper();

            // Some of the values might be blank. They are still allowed because when a replace gets done on the HTMLWriter, 
            // the placeholders will be replaced with an empty string.
            details.Add(name, value);

            // Look to see when the test start time label got added and set the time.
            if (name == "TEST_START_TIME" || name == "TEST_STOP_TIME")
            {
               details[name] = Convert.ToDateTime(value).ToString("yyyyMMdd:HHmmss");
            }
         }

         return details;
      }

      public object Clone()
      {
         return TestProcedureRevision.Clone();
      }
      #endregion
   }
}