// **********************************************************************************************************
//    BITCommand.cs
//    8/31/2023
//    NGI - Next Generation Interceptor
//    
//    Contract No. HQ0856-21-C-0003/1022000209
//    
//    DISTRIBUTION STATEMENT F: FURTHER DISSEMINATION ONLY AS DIRECTED BY
//    MISSILE DEFENSE AGENCY, MDA/GMY NEXT GENERATION INTERCEPTOR PROJECT
//    OFFICE (DATE OF DETERMINATION 14 JUNE 2021) OR HIGHER DOD AUTHORITY.
//    OTHER REQUESTS FOR THIS DOCUMENT SHALL BE REFERRED TO: MISSILE DEFENSE
//    AGENCY, CONTRACTS DIRECTORATE, ATTN: GMY‐K, BLDG. 5222 MARTIN ROAD,
//    REDSTONE ARSENAL, AL 35898. 
//    
//    WARNING: THIS DOCUMENT CONTAINS TECHNICAL DATA WHOSE EXPORT IS
//    RESTRICTED BY THE ARMS EXPORT CONTROL ACT (TITLE 22, U.S.C., 
//    SECTION 2751, ET SEQ.) OR THE EXPORT ADMINISTRATION ACT OF 1979 
//    (TITLE 50 U.S.C. APP. 2401 ET SEQ.), AS AMENDED. VIOLATIONS OF 
//    THESE EXPORT LAWS ARE SUBJECT TO SEVERE CRIMINAL PENALTIES. 
//    DISSEMINATE IN ACCORDANCE WITH PROVISIONS OF DOD DIRECTIVE 5230.25. 
//    
//    RAYTHEON PROPRIETARY: THIS DOCUMENT CONTAINS DATA OR INFORMATION
//    PROPRIETARY TO RAYTHEON COMPANY AND IS RESTRICTED TO USE ONLY BY
//    PERSONS AUTHORIZED BY RAYTHEON COMPANY IN WRITING TO USE IT. 
//    DISCLOSURE TO UNAUTHORIZED PERSONS WOULD LIKELY CAUSE SUBSTANTIAL 
//    COMPETITIVE HARM TO RAYTHEON COMPANY'S BUSINESS POSITION. NEITHER
//    SAID DOCUMENT NOR ITS CONTENTS SHALL BE FURNISHED OR DISCLOSED TO
//    OR COPIED OR USED BY PERSONS OUTSIDE RAYTHEON COMPANY WITHOUT THE
//    EXPRESS WRITTEN APPROVAL OF RAYTHEON COMPANY.
//    
//    UNPUBLISHED WORK - COPYRIGHT RAYTHEON COMPANY. 
//    
//    DESTRUCTION NOTICE - FOR CLASSIFIED DOCUMENTS FOLLOW THE PROCEDURES IN
//    DOD 5220.22-M, NATIONAL INDUSTRIAL SECURITY PROGRAM OPERATING MANUAL,
//    FEBRUARY 2006, INCORPORATING CHANGE 1, MARCH 28, 2013, CHAPTER 5,
//    SECTION 7, OR DODM 5200.01-VOLUME 3, DOD INFORMATION SECURITY PROGRAM:
//    PROTECTION OF CLASSIFIED INFORMATION, ENCLOSURE 3, SECTION 17. FOR
//    CONTROLLED UNCLASSIFIED INFORMATION FOLLOW THE PROCEDURES IN DODM 
//    5200.01-VOLUME 4, INFORMATION SECURITY PROGRAM: CONTROLLED UNCLASSIFIED
//    INFORMATION.
//    
//    CONTROLLED BY: MISSILE DEFENSE AGENCY
//    CONTROLLED BY: GROUND-BASED MIDCOURSE DEFENSE PROGRAM OFFICE
//    CUI CATEGORY: CTI
//    DISTRIBUTION/DISSEMINATION CONTROL: F
//    POC: Alex Kravchenko (1118268)
// **********************************************************************************************************
// Ignore Spelling: Deserialized

using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Serialization;

namespace BitGenSoftMeasurementManagerLib
{

	[XmlType(TypeName = "ResponseMessageType")]
	public enum ResponseMessageType
	{
		U, // Unknown or Undefined
		R, // Required
		E, // Error
		P  // Parametric
	}

	[XmlType(TypeName = "ParamType")]
	public enum ParameterType
	{
		U, // Unknown or Undefined will default to string
		N, // Numeric
		S, // String
		A, // Array
		P  // p-data array
	}


	[XmlType(TypeName = "BITResponseMsg")]
	public class BITResponseMsg
	{
		[XmlAttribute("type")]
		public ResponseMessageType ResponseType { get; set; }

		[XmlText]
		public string Name { get; set; }
	}

	[XmlType("Value")]
	public class BITParameter
	{
		[XmlAttribute(AttributeName = "name")]
		public string Key { get; set; }

		[XmlAttribute(AttributeName = "type")]
		public ParameterType ParameterType { get; set; }

		[XmlAttribute(AttributeName = "delim")]
		public string Delim { get; set; }

		[XmlText]
		public string Value { get; set; }
	}

	[Serializable]
	public class BITCommand
	{
        [XmlElement(ElementName = "Command")]
		public string Command { get; set; }

		[XmlElement(ElementName = "CommandTimeout")]
		public uint CommandTimeout { get; set; }

		[XmlArray("CommandParameters")]
		[XmlArrayItem("Value", Type = typeof(BITParameter))]
		public List<BITParameter> CommandParameters { get; set; } = new List<BITParameter>();

		[XmlArray("CommandResponses")]
		[XmlArrayItem("BITResponseMsg", Type = typeof(BITResponseMsg))]
		public List<BITResponseMsg> CommandResponses { get; set; } = new List<BITResponseMsg>();

		[XmlElement(ElementName = "ParametricResponse")]
		public string ParametricResponse { get; set; }

		[XmlElement(ElementName = "ParametricTimeout")]
		public uint ParametricTimeout { get; set; }

		[XmlArray("ResponseParameters")]
		[XmlArrayItem("Value", Type = typeof(BITParameter))]
		public List<BITParameter> ResponseParameters { get; set; } = new List<BITParameter>();

		/// <summary>
		/// converts one hex parameter string into parameter array
		/// </summary>
		public void UnfoldHexParameters()
		{
			if (!CommandParameters.Any(p => p.ParameterType == ParameterType.P))
				return;

			var paramList = CommandParameters.Where(p => p.ParameterType == ParameterType.P).ToList();
			List<BITParameter> removeList = new List<BITParameter>();
			foreach (BITParameter param in paramList) 
			{
				AddPDataArrayValues(param.Key, param.Value, param.Delim);
				removeList.Add(param);
			}
			CommandParameters.RemoveAll(c => removeList.Contains(c));
		}

		/// <summary>
		/// takes a hex string and breaks it up into individual characters
		/// then inserts them as parameters
		/// </summary>
		/// <param name="key"></param>
		/// <param name="value"></param>
		/// <param name="delim"></param>
		private void AddPDataArrayValues(string key, string value, string delim)
		{
			var parms = BreakByPages(value, delim);

			int index = 0;
			foreach (var item in parms)
			{
				string itemKey = $"{key}[{index++}]";
				string itemValue = item;
				CommandParameters.Add(new BITParameter { Key = itemKey, Value = itemValue } );
			}
		}

		/// <summary>
		/// takes a large hex string and breaks it in multiple pages based on the known header
		/// adjusts the size of the page to be divisible by 4 bytes
		/// and also adds a 12 byte footer of zero values to the end of the page
		/// </summary>
		/// <param name="hexStr"></param>
		/// <param name="header"></param>
		/// <returns></returns>
		private static IEnumerable<string> BreakByPages(string hexStr, string header)
		{
			const int footerSize = 12;
			string[] pages = hexStr.Split(new[] { header }, StringSplitOptions.RemoveEmptyEntries);

			foreach (string page in pages)
			{
				string completePage = header + page;
				int pageSize = (completePage.Length + 7) & ~7;
				string paddedPage = completePage.PadRight(pageSize + (footerSize * 2), '0');
				IEnumerable<string> hexChars = BreakIntoHexCharacters(paddedPage);
				foreach (string hexChar in hexChars)
				{
					yield return hexChar;
				}
			}
		}

		/// <summary>
		/// takes a large string of hex characters and breaks it into individual hex values
		/// then yields these values to the calling code
		/// </summary>
		/// <param name="hexString"></param>
		/// <returns></returns>
		public static IEnumerable<string> BreakIntoHexCharacters(string hexString)
		{
			int characterSize = 2;
			int length = hexString.Length;
			for (int i = 0; i < length; i += characterSize)
			{
				if (i + characterSize > length)
				{
					hexString = hexString.PadRight(i + characterSize, '0');
				}
				yield return "0x" + hexString.Substring(i, characterSize);
			}
		}
	}
}
