
using System;

namespace Minntech.Comm
{
	public class CommDevices
	{

		#region event delegates

		public delegate void CommErrorEventHandler		(object sender, CommErrorEventArgs			e);
		public delegate void DataArrivedEventHandler	(object sender, DataArrivedEventArgs		e);
		public delegate void SettingsChangedEventHandler(object sender, SettingsChangedEventArgs	e);

		#endregion
	
		#region  interface

		//   all new comm ports will need to implement 
		//   this interface

		public interface ICommDevice : IDisposable
		{			
			bool								IsOpen		{get;}
			SupportedCommDevices				Device		{get;} 
			CommPortSettings					Settings	{get; set;} 
			void								OpenCommPort();
			void								CloseCommPort();
			void								WriteByte(Byte Value);
			void								WriteString(string Value);
			System.Windows.Forms.DialogResult	ShowControlDialog();
			event DataArrivedEventHandler		DataArrived	;
			event CommErrorEventHandler			CommError ;
			event SettingsChangedEventHandler	SettingsChanged ;
		}

		#endregion

		public CommDevices()
		{
		}


		//TODO: update with any newly support serial devices
		public enum SupportedCommDevices
		{
			CommPort,
			CommPortSoftwareSimulation
		}

		#region comm device-specific utilities
		
		/// <summary>
		/// FUNCTION reads values in a string
		/// and casts each Char into a new byte array
		/// example: "Hello" translates to {72,101,108,108,111}
		/// </summary>
		/// <param name="Value"></param>
		/// <returns></returns>
		public static Byte[] StringToByteArray( string Value )
		{
			try
			{
				if ( ( Value == null ) || ( Value.Length == 0 ) )
				{
					Byte[] rtnVal = {0};
					return rtnVal;
				}
				else
				{
					Byte[] rtnval = new Byte[Value.Length - 1];
					int idx;
					for ( idx = 0; idx < Value.Length; idx++ )
						rtnval[idx] = Convert.ToByte(Value[idx]);
					return rtnval;
				}
			}
			catch ( Exception CastEx )
			{
				throw CastEx;
			}
		}

		/// <summary>
		/// FUNCTION converts an array of Bytes to a string 
		/// that is formatted for printing. 
		/// </summary>
		/// <param name="Value"></param>
		/// <returns></returns>
		public static string ByteArrayToString(Byte[] Value )
		{
			return CommDevices.ByteArrayToString(Value, false);
		}
	
		/// <summary>
		/// FUNCTION converts an array of Bytes to a string 
		/// that is formatted for printing. When MakePrintable is TRUE, 
		/// Unprintable characters are replaced with the ASCII value inside of angle brackets
		/// example: CR would appear <013> 
		/// </summary>
		/// <param name="Value"></param>
		/// <param name="MakePrintable"></param>
		/// <returns></returns>
		public static string ByteArrayToString(Byte[] Value, bool MakePrintable )
		{
			string			rtnVal		= string.Empty;
			const string	printable	= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ~`@#$%^&*()_-+={[}]|:;'<,>.?/ " + "\\";
			try
			{
				if ( ( null != Value ) && ( Value.Length > 0 ) )
				{
					foreach ( Byte wrkByte in Value )
					{
						if ( printable.IndexOf((char)wrkByte) >= 0 )
							rtnVal += Convert.ToChar(wrkByte);
						else
							rtnVal += String.Format ("<(0)>", wrkByte );
					}
				}
				return rtnVal;
			}
			catch ( Exception CastEx )
			{
				throw CastEx;
			}
		}


		public bool[] ByteToBits (Byte Value )
		{
			bool[] rtnVal = new bool[7];
			rtnVal[0] = (Value & 128) == 128;
			rtnVal[1] = (Value & 64) == 64;
			rtnVal[2] = (Value & 32) == 32;
			rtnVal[3] = (Value & 16) == 16;
			rtnVal[4] = (Value & 8) == 8;
			rtnVal[5] = (Value & 4) == 4;
			rtnVal[6] = (Value & 2) == 2;
			rtnVal[7] = (Value & 1) == 1;
			return rtnVal;
		}
		public byte BitsToByte ( bool[] bits )
		{
			byte rtnVal = 0;
			if ( bits[0] ) rtnVal += 128;
			if ( bits[1] ) rtnVal += 64;
			if ( bits[2] ) rtnVal += 32;
			if ( bits[3] ) rtnVal += 16;
			if ( bits[4] ) rtnVal += 8;
			if ( bits[5] ) rtnVal += 4;
			if ( bits[0] ) rtnVal += 2;
			if ( bits[7] ) rtnVal += 1;
			return rtnVal;
		}

		#endregion

		#region    port settings

		public enum BaudRates
		{
			bps300,
			bps1200,
			bps2400,
			bps9600,
			bps19200,
			bps28800,
			bps38400,
			bps57600,
			bps115200
		}
		public enum HandShakes
		{
			None,
			CtsRts,
			XonXoff,
			DtrDsr
		}
		public enum StopBits
		{
			One,
			OnePointFive,
			Two,
		}
		public enum DataBits
		{
			Seven,
			Eight
		}
		public enum Parities
		{
			Even,
			Mark,
			None,
			Odd,
			Space,
		}
		public enum CommPorts
		{
			COM1,
			COM2,
			COM3,
			COM4,
			COM5,
			COM6,
			COM7,
			COM8
		}

		public struct CommPortSettings
		{
			private SupportedCommDevices _device;

			public SupportedCommDevices	Device
			{
				get { return _device;  }
				set { _device = value; }
			}
			public CommPorts			CommPort;
			public BaudRates			BaudRate;
			public DataBits				DataBit;
			public Parities				Parity;
			public StopBits				StopBit;
			public HandShakes			HandShake;
		}

		#endregion

		#region		event args

		public enum CommEvent
		{
			Break,
			Frame,
			IOE,
			Mode,
			Overrun,
			RxOver,
			RxParity,
			TxFull,
			Timeout,
			Unknown
		}
		public class CommErrorEventArgs : System.EventArgs
		{
			private CommEvent	mCommEvent;
			private string		mMessage;

			public CommErrorEventArgs (CommEvent commEvent, string Message)
			{
				mCommEvent = commEvent;
				mMessage   = Message;
			}

			public CommEvent CommEvent
			{
				get { return mCommEvent;  }
				set { mCommEvent = value; }
			}

			public string	  Message
			{
				get { return mMessage; }
				set { mMessage = value;}
			}
		}

		public class DataArrivedEventArgs : System.EventArgs
		{
			private Byte[]	mData;
			
			public DataArrivedEventArgs( Byte[] Data )
			{
				mData = Data;
			}
			public Byte[] Data
			{
				get { return mData; }
				set { mData = value;}
			}
		}
		public class SettingsChangedEventArgs : System.EventArgs
		{
			private	CommPortSettings	mSettings;
			
			public SettingsChangedEventArgs ( CommPortSettings Settings )
			{
				mSettings = Settings;
			}
			public CommPortSettings Settings
			{
				get { return mSettings; }
				set { mSettings = value;}
			}
		}
		
		#endregion

	}
}
