using System;
using System.Collections.Generic;
using System.Text;
using Medivators.BusinessObjects;
using Medivators.Common;
using Medivators.Common.Enums;

namespace Medivators.Parser
{
	class DSD201Parser : IDeviceParser
	{
		public void Dispose()
		{
			// nothing to dispose?
		}

		public IDeviceRecord Parse(byte[] Data)
		{
			IDeviceRecord record = null;
			bool success = true;
			try
			{				

				switch (Data[DSD201Constants.RecordTypePos])
				{
					case DSD201Constants.RawRecordTypeCycleCount:
					case DSD201Constants.RawRecordTypeDisinfectantCycleCount:
					case DSD201Constants.RawRecordTypeOperatorID:
					case DSD201Constants.RawRecordTypePatientID:
					case DSD201Constants.RawRecordTypePhysicianID:
					case DSD201Constants.RawRecordTypeScopeID:
					case DSD201Constants.RawRecordTypeSSGRatio:
						record = new DSD201HeaderRecord();
						break;
					default:
						record = new DSD201EventRecord();
						break;
				}
				record.FromByteArray(Data);
			}
			catch ( Exception ex )
			{
				ErrorHandler.GetInstance().LogException(LogEntryType.Critical, this.GetType().Name + " Parse: " + ex.ToString());
				success = false;
			}
			if (success)
				return record;
			else
				return null;
		}
		public bool Validate(byte[] Data)
		{
			// most validation occurs when values in the 
			// byte array are cast into the correct data
			// types during Parse(). But there is also a 
			// CRC check and that has to be done here.

			bool success = true;
			try
			{
				byte crc = DSD201Checksum(Data);
				byte checksumPos = 0;
				if ( IsHeaderRecord(Data) )
					checksumPos = DSD201Constants.HeaderChecksumPos;
				else
					checksumPos = DSD201Constants.EventChecksumPos;

				success = (crc == Data[checksumPos]);
			}
			catch ( Exception ex)
			{
				ErrorHandler.GetInstance().LogException(LogEntryType.Critical, this.GetType().Name + " Validate: " + ex.ToString());
				success = false;
			}
			return success;
		}
		private static byte DSD201Checksum(byte[] Data)
		{
			// the CRC only covers bytes up to -- and NOT
			// including -- the checksum itself or the end flag 

			byte rtn = 0;
			byte checksumPos = 0;
			if ( IsHeaderRecord ( Data ) )
				checksumPos = DSD201Constants.HeaderChecksumPos;
			else
				checksumPos = DSD201Constants.EventChecksumPos;

			CycleReport lockHolder = new CycleReport();
			lock (lockHolder)
			{
				for (int i = 0; i < checksumPos; i++)
				{
					rtn = Rotate(rtn);
					rtn ^= Data[i];
				}
				return rtn;
			}
		}

		private static bool IsHeaderRecord(byte[] Data)
		{
			bool rtnVal = false;

			switch (Data[DSD201Constants.RecordTypePos])
			{
				case DSD201Constants.RawRecordTypeScopeID:
				case DSD201Constants.RawRecordTypeOperatorID:
				case DSD201Constants.RawRecordTypePatientID:
				case DSD201Constants.RawRecordTypePhysicianID:
				case DSD201Constants.RawRecordTypeCycleCount:
				case DSD201Constants.RawRecordTypeDisinfectantCycleCount:
				case DSD201Constants.RawRecordTypeSSGRatio:
					rtnVal = true;
					break;
				default:
					break;
			}
			return rtnVal;
		}

		public static byte Rotate(byte value)
		{
			//	1	store bit 7
			//	2	left shift the byte
			//	3	set bit 0 = stored bit 7

			byte leftBit = (byte)(value & 128);
			byte shifted = (byte)(value << 1);
			if (leftBit > 0)
				shifted = (byte)(shifted + 1);
			return shifted;
		}
	}
}
