using System;
using System.Diagnostics;
using Medivators.Comm;
using Medivators.Common;
using Medivators.Common.Enums;
using Medivators.Common.Logging;
using Medivators.Common.Settings;

namespace Medivators.SerialDevices
{
	/// <summary>
	/// Summary description for DSD201.
	/// </summary>
	public class DSD201: ISerialDevice	
	{

		#region DSD-201 Constants

		public static string TxStartDelimiter = Convert.ToString((char)20) + Convert.ToString((char)17);
		public static string TxEndDelimiter = Convert.ToString((char)13) + Convert.ToString((char)10);

		#endregion

		private ICommDevice	_port			= null;
		private string		_buffer			= string.Empty;
		private Log			_log			= null;

		public event RecordReceivedEventHandler	RecordReceived;

		#region construct/init/dispose
		public DSD201() 
		{
		}
		public void Dispose()
		{			
			if ( this._port != null )
				this._port.Dispose();
		}
		#endregion

		public ICommDevice CommPort
		{
			get { return _port; }
			set 
			{ 
				if ( this._port != null )
					this._port.Dispose();
					
				this._port = value; 
				this._port.DataArrived += new DataArrivedEventHandler(this.CommDataArrived);
				this._port.CommError += new CommErrorEventHandler(this.CommDataError);
			}			
		}
		public Log Log
		{
			get { return this._log; }
			set { this._log = value; }
		}
		public SupportedSerialDevices Device
		{
			get { return SupportedSerialDevices.DSD201; }
		}

		#region events
		protected void CommDataArrived ( object sender, DataArrivedEventArgs e )
		{
			try
			 {
				bool malformed = false;
				this._log.WriteLog(LogEntryType.DebugTrace, "DSD201 data received [" + 
						Utilities.ByteArrayToString(e.Data, true) + 
						"]");

				// only write full records to the transmission queue

				// step1: add new data to any leftover from previous calls
				foreach ( byte chr in e.Data )
					this._buffer += (char)chr;

				// step2: walk data looking for startofline and endofline indicators
				//		  NOTE: must begin walking at first startofline. Any characters
				//		  in the buffer but before the startofline are discarded
				
				bool done = false;
				
				while ( ( this._buffer.Length > 0 ) && ( ! done ) )
				{
					int start = this._buffer.IndexOf(TxStartDelimiter);
					if (start > 0)
					{
						//	discard anything before the start 
						this._buffer = _buffer.Substring(start);
						start = 0;
					}
					if (start < 0)
					{
						//	if no start in string, we're done. Leave the buffer in case 
						//	this is a record fragment
						done = true;
					}
					else
					{
						//	find next end of line
						int end = this._buffer.IndexOf(TxEndDelimiter);
						//	if no ends in string, we're done. But retain the record
						//	in case an end is on the way
						if (end < 0)
						{
							done = true;
						}
						else
						{
							//	we have a start and an end. Notify record consumer.
							string record = this._buffer.Substring(start, end + TxEndDelimiter.Length);
							if (record != string.Empty)
							{
								this._log.WriteLog(LogEntryType.DebugTrace, "DSD201 record identified and received event raised. Record:" + _buffer);
								this.RecordReceived(this, new RecordReceivedEventArgs(Utilities.StringToByteArray(record)));
								this._buffer = this._buffer.Substring(record.Length);
							}
							else
							{
								done = true;
								malformed = true;
							}
						}
					}
				}
				if ( malformed )
					this._log.WriteLog(LogEntryType.DebugTrace, "DSD201 reports malformed record received: " + Utilities.ByteArrayToString(e.Data), EventLogEntryType.Warning);
			}
			catch ( Exception ex )
			{
				this._log.WriteLog(LogEntryType.Critical, "CommDataArrived - likely malformed record [" + Utilities.ByteArrayToString(e.Data) + "]:" + ex.ToString(), EventLogEntryType.Error, Utilities.StringToByteArray(e.ToString()));
			}
		}
		private void CommDataError   ( object sender, CommErrorEventArgs e )
		{
			// write error state message to log
			this._log.WriteLog(LogEntryType.Critical, "CommDataError: " + e.Message, EventLogEntryType.Error, Utilities.StringToByteArray(e.ToString()));
		}
		#endregion
	}
}
