using iq2dev.com.iqCommLib;
using iq2dev.com.IQCommLib;
using iq2dev.com.IQCommLib.Example;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace iqCommLib.Example
{
    static internal class FastProcessingExample
    {
		public static void FastProcessingIsdu_Example(ProtocolCommunicator protocolCommunicator)
		{
#if true
			const UInt16 index = 600;
			const byte subIndex = 0;
			byte value = (byte)new Random().Next(0, Byte.MaxValue);
			//Fast processing ISDU Transmission
			protocolCommunicator.SwitchCachedMode(MST_IsduCacheModeE.MST_FAST_ISDU_PROCESSING_ENABLED);
			try
			{
				Program.LoggingEvent($"Write value: {value}");
				FastProcessingExtention.WriteODSync(protocolCommunicator, index, subIndex, new List<byte>() { value });
				List<byte> valueList = FastProcessingExtention.ReadODSync(protocolCommunicator, index, subIndex);
				Program.LoggingEvent($"Read valie: {valueList[0]}");
			}
			finally
			{
				protocolCommunicator.SwitchCachedMode(MST_IsduCacheModeE.MST_ISDU_CACHE_DISABLED);
			}
#else //compare speeds
			const UInt16 testIndex = 600;
			const byte testSubIndex = 0;
			const int TEST_REPETITIONS = 50; //quantity of paar operation
			var leagsyResult = IsduTestSequenceUInteger(protocolCommunicator, testIndex, testSubIndex, false, TEST_REPETITIONS);
			var fastProcessingResult = IsduTestSequenceUInteger(protocolCommunicator, testIndex, testSubIndex, true, TEST_REPETITIONS);

			//test application tag
			IsduTestSequenceString(protocolCommunicator, 24, 0, 32, TEST_REPETITIONS);

			Program.LoggingEvent($"Test integer result:");
			Program.LoggingEvent($"Read Write. Legacy {leagsyResult.Item1:00.00} seconds. Fast Processing: {fastProcessingResult.Item1:00.00}. " +
				$"  Improvement {100 - (fastProcessingResult.Item1 / leagsyResult.Item1 * 100):00.00} %");
			Program.LoggingEvent($"Write Write. Legacy {leagsyResult.Item2:00.00} seconds. Fast Processing: {fastProcessingResult.Item2:00.00}" +
				$"  Improvement {100 - (fastProcessingResult.Item2 / leagsyResult.Item2 * 100):00.00} %");
			Program.LoggingEvent($"Read Read. Legacy {leagsyResult.Item3:00.00} seconds. Fast Processing: {fastProcessingResult.Item3:00.00}" +
				$"  Improvement {100 - (fastProcessingResult.Item3 / leagsyResult.Item3 * 100):00.00} %");
#endif
		}

		static void IsduTestSequenceString(
			ProtocolCommunicator protocolCommunicator,
			UInt16 index,
			byte subindex,
			int length,
			int repeat)
		{
			Stopwatch timer = new Stopwatch();
			timer.Start();

#if true
			protocolCommunicator.SwitchCachedMode(MST_IsduCacheModeE.MST_ISDU_CACHE_DISABLED);
			//Legacy ISDU Transmission
			for (var counter = 0; counter < repeat; counter++)
			{
				var guidString = Guid.NewGuid().ToString().Substring(0, length);
				var guidList = Encoding.UTF8.GetBytes(guidString);
				Program.LoggingEvent($"Write string parameter: {guidString}");
				protocolCommunicator.WriteOD(index, 0, guidList.ToList());
				List<byte> stringParamByteList = protocolCommunicator.ReadOD(index, 0);
				string stringParam = Encoding.UTF8.GetString(stringParamByteList.ToArray(), 0, stringParamByteList.Count);
				Program.LoggingEvent($"Read string parameter: {stringParam}");
			}
			var legacyTime = timer.Elapsed.TotalSeconds;
#endif
			timer.Restart();
			//Fast processing ISDU Transmission
			protocolCommunicator.SwitchCachedMode(MST_IsduCacheModeE.MST_FAST_ISDU_PROCESSING_ENABLED);
			try
			{
				for (var counter = 0; counter < repeat; counter++)
				{
					var guidString = Guid.NewGuid().ToString().Substring(0, length);
					var guidList = Encoding.UTF8.GetBytes(guidString);
					Program.LoggingEvent($"Write string parameter: {guidString}");
					FastProcessingExtention.WriteODSync(protocolCommunicator, index, 0, guidList.ToList());
					List<byte> stringParamByteList = FastProcessingExtention.ReadODSync(protocolCommunicator, index, 0);
					string stringParam = Encoding.UTF8.GetString(stringParamByteList.ToArray(), 0, stringParamByteList.Count);
					Program.LoggingEvent($"Read string parameter: {stringParam}");
					if (guidString != stringParam)
					{
						throw new Exception($"Written gag {guidString} is not equal after read: {stringParam}");
					}
				}
			}
			finally
			{
				protocolCommunicator.SwitchCachedMode(MST_IsduCacheModeE.MST_ISDU_CACHE_DISABLED);
			}
			var fastProcessingTime = timer.Elapsed.TotalSeconds;
			Program.LoggingEvent($"Legacy ISDU Transmission Time: {legacyTime} seconds");
			Program.LoggingEvent($"Fast processing ISDU Transmission Time: {fastProcessingTime} seconds");
		}

		static Tuple<double, double, double> IsduTestSequenceUInteger(
			ProtocolCommunicator protocolCommunicator,
			UInt16 index,
			byte subindex,
			bool isFastProcessing,
			int repeat)
		{
			Tuple<double, double, double> result;

			Stopwatch timer = new Stopwatch();
			timer.Start();

			if (isFastProcessing)
			{
				protocolCommunicator.SwitchCachedMode(MST_IsduCacheModeE.MST_FAST_ISDU_PROCESSING_ENABLED);
			}
			else
			{
				protocolCommunicator.SwitchCachedMode(MST_IsduCacheModeE.MST_ISDU_CACHE_DISABLED);
			}
			try
			{
				List<byte> initialValue = ReadOd(protocolCommunicator, index, subindex, isFastProcessing);
				timer.Restart();
				for (var counter = 0; counter < repeat; counter++)
				{
					Program.LoggingEvent($"Read/Write sequence: {counter}/{repeat}. Fast processing: [{isFastProcessing}]");

					//generate new value
					var writeValue = initialValue.ToArray();
					new Random().NextBytes(writeValue);

					WriteOd(protocolCommunicator, index, subindex, writeValue.ToList(), isFastProcessing);
					List<byte> valueList = ReadOd(protocolCommunicator, index, subindex, isFastProcessing);
					if (Enumerable.SequenceEqual(writeValue.ToList(), valueList) == false)
					{
						throw new Exception($"Read value are not equal to written value. \n" +
							$"Written: {BitConverter.ToString(writeValue.ToArray())} \n" +
							$"Read: {BitConverter.ToString(valueList.ToArray())}");
					}
				}
				double readWriteTime = timer.Elapsed.TotalSeconds;

				timer.Restart();
				for (var counter = 0; counter < repeat * 2; counter++)
				{
					Program.LoggingEvent($"Write/Write sequence: {counter}/{repeat}. Fast processing: [{isFastProcessing}]");
					WriteOd(protocolCommunicator, index, subindex, initialValue.ToList(), isFastProcessing);
				}
				double writeWriteTime = timer.Elapsed.TotalSeconds;

				initialValue = ReadOd(protocolCommunicator, index, subindex, isFastProcessing);
				timer.Restart();
				for (var counter = 0; counter < repeat * 2; counter++)
				{
					Program.LoggingEvent($"Read/Read sequence: {counter}/{repeat}. Fast processing: [{isFastProcessing}]");
					List<byte> valueList = ReadOd(protocolCommunicator, index, subindex, isFastProcessing);
					Program.LoggingEvent($"\t Value: {BitConverter.ToString(valueList.ToArray())}");
				}
				double readReadTime = timer.Elapsed.TotalSeconds;
				result = new Tuple<double, double, double>(readWriteTime, writeWriteTime, readReadTime);
			}
			finally
			{
				if (isFastProcessing)
				{
					protocolCommunicator.SwitchCachedMode(MST_IsduCacheModeE.MST_ISDU_CACHE_DISABLED);
				}
			}

			timer.Stop();

			return result;
		}

		static List<byte> ReadOd(ProtocolCommunicator protocolCommunicator, UInt16 index, byte subIndex, bool isFastProcessing)
		{
			if (isFastProcessing)
			{
				return FastProcessingExtention.ReadODSync(protocolCommunicator, index, subIndex);
			}
			else
			{
				return protocolCommunicator.ReadOD(index, subIndex);
			}
		}

		static void WriteOd(ProtocolCommunicator protocolCommunicator, UInt16 index, byte subIndex, List<byte> data, bool isFastProcessing)
		{
			if (isFastProcessing)
			{
				FastProcessingExtention.WriteODSync(protocolCommunicator, index, 0, data.ToList());
			}
			else
			{
				protocolCommunicator.WriteOD(index, 0, data.ToList());
			}
		}
	}
}
