using System;
using System.Windows.Forms;
using System.Threading;
using System.Collections;
using System.Collections.Specialized;
using System.Timers;

using nsAlienRFID2;


namespace Ex4
{
	public class Form1 : System.Windows.Forms.Form
	{
		#region "Private members"...
		private clsReaderMonitor mMonitor;
		private System.Timers.Timer mTimer;
		private volatile  bool mbInsideElapsed = false;
		private ListDictionary mReaderList;
		private bool mbClosing = false;
		private Queue mMessageQ;
		#endregion

		#region "Auto-generated code"

		private System.Windows.Forms.RichTextBox rtxMessages;
		private System.Windows.Forms.Button btnCheckPorts;
		private System.Windows.Forms.Button btnGetReaderList;
		private System.Windows.Forms.CheckBox chkComPortMonitoring;
		private System.Windows.Forms.ListBox lbReaders;
		private System.Windows.Forms.GroupBox groupBox1;
		private System.Windows.Forms.GroupBox groupBox2;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.NumericUpDown udUpdeateInterval;
		private System.Windows.Forms.Button btnClearReaderList;
		private System.Windows.Forms.Button btnClearLogs;
		private System.ComponentModel.IContainer components;

		public Form1()
		{
			//
			// Required for Windows Form Designer support
			//
			InitializeComponent();
		}

		/// <summary>
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if (components != null) 
				{
					components.Dispose();
				}
			}
			base.Dispose( disposing );
		}

		#region Windows Form Designer generated code
		/// <summary>
		/// Required method for Designer support - do not modify
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
            this.rtxMessages = new System.Windows.Forms.RichTextBox();
            this.btnCheckPorts = new System.Windows.Forms.Button();
            this.btnGetReaderList = new System.Windows.Forms.Button();
            this.chkComPortMonitoring = new System.Windows.Forms.CheckBox();
            this.lbReaders = new System.Windows.Forms.ListBox();
            this.groupBox1 = new System.Windows.Forms.GroupBox();
            this.btnClearReaderList = new System.Windows.Forms.Button();
            this.groupBox2 = new System.Windows.Forms.GroupBox();
            this.udUpdeateInterval = new System.Windows.Forms.NumericUpDown();
            this.label1 = new System.Windows.Forms.Label();
            this.btnClearLogs = new System.Windows.Forms.Button();
            this.groupBox1.SuspendLayout();
            this.groupBox2.SuspendLayout();
            ((System.ComponentModel.ISupportInitialize)(this.udUpdeateInterval)).BeginInit();
            this.SuspendLayout();
            // 
            // rtxMessages
            // 
            this.rtxMessages.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.rtxMessages.BackColor = System.Drawing.SystemColors.WindowFrame;
            this.rtxMessages.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.rtxMessages.Location = new System.Drawing.Point(16, 16);
            this.rtxMessages.Name = "rtxMessages";
            this.rtxMessages.Size = new System.Drawing.Size(416, 184);
            this.rtxMessages.TabIndex = 4;
            this.rtxMessages.Text = "";
            // 
            // btnCheckPorts
            // 
            this.btnCheckPorts.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.btnCheckPorts.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.btnCheckPorts.Location = new System.Drawing.Point(480, 224);
            this.btnCheckPorts.Name = "btnCheckPorts";
            this.btnCheckPorts.Size = new System.Drawing.Size(112, 32);
            this.btnCheckPorts.TabIndex = 9;
            this.btnCheckPorts.Text = "&Check Ports";
            this.btnCheckPorts.UseVisualStyleBackColor = false;
            this.btnCheckPorts.Click += new System.EventHandler(this.btnCheckPorts_Click);
            // 
            // btnGetReaderList
            // 
            this.btnGetReaderList.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
            this.btnGetReaderList.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.btnGetReaderList.ForeColor = System.Drawing.SystemColors.WindowText;
            this.btnGetReaderList.Location = new System.Drawing.Point(24, 112);
            this.btnGetReaderList.Name = "btnGetReaderList";
            this.btnGetReaderList.Size = new System.Drawing.Size(112, 32);
            this.btnGetReaderList.TabIndex = 10;
            this.btnGetReaderList.Text = "Get &Reader List";
            this.btnGetReaderList.UseVisualStyleBackColor = false;
            this.btnGetReaderList.Click += new System.EventHandler(this.btnGetReaderList_Click);
            // 
            // chkComPortMonitoring
            // 
            this.chkComPortMonitoring.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.chkComPortMonitoring.Location = new System.Drawing.Point(136, -2);
            this.chkComPortMonitoring.Name = "chkComPortMonitoring";
            this.chkComPortMonitoring.Size = new System.Drawing.Size(16, 24);
            this.chkComPortMonitoring.TabIndex = 11;
            this.chkComPortMonitoring.CheckedChanged += new System.EventHandler(this.chkComPortMonitoring_CheckedChanged);
            // 
            // lbReaders
            // 
            this.lbReaders.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)));
            this.lbReaders.BackColor = System.Drawing.SystemColors.WindowText;
            this.lbReaders.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.lbReaders.Location = new System.Drawing.Point(8, 16);
            this.lbReaders.Name = "lbReaders";
            this.lbReaders.Size = new System.Drawing.Size(144, 82);
            this.lbReaders.TabIndex = 12;
            // 
            // groupBox1
            // 
            this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.groupBox1.Controls.Add(this.lbReaders);
            this.groupBox1.Controls.Add(this.btnClearReaderList);
            this.groupBox1.Controls.Add(this.btnGetReaderList);
            this.groupBox1.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.groupBox1.Location = new System.Drawing.Point(456, 8);
            this.groupBox1.Name = "groupBox1";
            this.groupBox1.Size = new System.Drawing.Size(160, 192);
            this.groupBox1.TabIndex = 13;
            this.groupBox1.TabStop = false;
            this.groupBox1.Text = "Reader List";
            // 
            // btnClearReaderList
            // 
            this.btnClearReaderList.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
            this.btnClearReaderList.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.btnClearReaderList.ForeColor = System.Drawing.SystemColors.WindowText;
            this.btnClearReaderList.Location = new System.Drawing.Point(24, 152);
            this.btnClearReaderList.Name = "btnClearReaderList";
            this.btnClearReaderList.Size = new System.Drawing.Size(112, 32);
            this.btnClearReaderList.TabIndex = 15;
            this.btnClearReaderList.Text = "C&lear Reader List";
            this.btnClearReaderList.UseVisualStyleBackColor = false;
            this.btnClearReaderList.Click += new System.EventHandler(this.btnClearReaderList_Click);
            // 
            // groupBox2
            // 
            this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.groupBox2.Controls.Add(this.chkComPortMonitoring);
            this.groupBox2.Controls.Add(this.udUpdeateInterval);
            this.groupBox2.Controls.Add(this.label1);
            this.groupBox2.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.groupBox2.Location = new System.Drawing.Point(192, 208);
            this.groupBox2.Name = "groupBox2";
            this.groupBox2.Size = new System.Drawing.Size(240, 56);
            this.groupBox2.TabIndex = 14;
            this.groupBox2.TabStop = false;
            this.groupBox2.Text = "Com Ports Monitoring";
            // 
            // udUpdeateInterval
            // 
            this.udUpdeateInterval.Increment = new decimal(new int[] {
            1000,
            0,
            0,
            0});
            this.udUpdeateInterval.Location = new System.Drawing.Point(144, 27);
            this.udUpdeateInterval.Maximum = new decimal(new int[] {
            2147483647,
            0,
            0,
            0});
            this.udUpdeateInterval.Minimum = new decimal(new int[] {
            10000,
            0,
            0,
            0});
            this.udUpdeateInterval.Name = "udUpdeateInterval";
            this.udUpdeateInterval.Size = new System.Drawing.Size(80, 20);
            this.udUpdeateInterval.TabIndex = 13;
            this.udUpdeateInterval.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
            this.udUpdeateInterval.Value = new decimal(new int[] {
            10000,
            0,
            0,
            0});
            this.udUpdeateInterval.ValueChanged += new System.EventHandler(this.udUpdeateInterval_ValueChanged);
            // 
            // label1
            // 
            this.label1.Location = new System.Drawing.Point(24, 32);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(128, 16);
            this.label1.TabIndex = 12;
            this.label1.Text = "Update Interval (msec):";
            // 
            // btnClearLogs
            // 
            this.btnClearLogs.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.btnClearLogs.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(192)))));
            this.btnClearLogs.Location = new System.Drawing.Point(40, 224);
            this.btnClearLogs.Name = "btnClearLogs";
            this.btnClearLogs.Size = new System.Drawing.Size(112, 32);
            this.btnClearLogs.TabIndex = 15;
            this.btnClearLogs.Text = "Cl&ear Logs";
            this.btnClearLogs.UseVisualStyleBackColor = false;
            this.btnClearLogs.Click += new System.EventHandler(this.btnClearLogs_Click);
            // 
            // Form1
            // 
            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
            this.BackColor = System.Drawing.SystemColors.ControlText;
            this.ClientSize = new System.Drawing.Size(632, 274);
            this.Controls.Add(this.btnClearLogs);
            this.Controls.Add(this.groupBox2);
            this.Controls.Add(this.btnCheckPorts);
            this.Controls.Add(this.rtxMessages);
            this.Controls.Add(this.groupBox1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.Closing += new System.ComponentModel.CancelEventHandler(this.Form1_Closing);
            this.groupBox1.ResumeLayout(false);
            this.groupBox2.ResumeLayout(false);
            ((System.ComponentModel.ISupportInitialize)(this.udUpdeateInterval)).EndInit();
            this.ResumeLayout(false);

		}
		#endregion

		/// <summary>
		/// The main entry point for the application.
		/// </summary>
		[STAThread]
		static void Main() 
		{
				Application.Run(new Form1());
		}

		#endregion

		private void Form1_Load(object sender, System.EventArgs e)
		{
			#region "Application title"
			Thread.CurrentThread.Name = "Alien-Ex4: Test Serial Discovery";
			this.Text = "Alien Library .NET - Testing Serial Discovery Example";
			#endregion

			mMonitor = new clsReaderMonitor();
			mMonitor.UpdateInterval = (int)udUpdeateInterval.Value;

			#region "Objects for passing results from another threads to GUI"...
			//		The following line if un-commented will partially freeze the GUI.
			//	mMonitor.SynchronizingObject = this;	
			//		Using System.Timers.Timer with setting Synchronization object is an alternative.
			mTimer = new System.Timers.Timer();
			mTimer.Elapsed += new ElapsedEventHandler(mTimer_Elapsed);
			mTimer.SynchronizingObject = this;
			mTimer.Start();

			mReaderList = new ListDictionary();
			mMessageQ = new Queue();
			#endregion

			#region	"Subscribe to clsReaderMonitor events"...
			mMonitor.ReaderAddedOnSerial += 
				new clsReaderMonitor.ReaderAddedOnSerialEventHandler(mMonitor_ReaderAdded);
			mMonitor.ReaderRenewedOnSerial += 
				new clsReaderMonitor.ReaderRenewedOnSerialEventHandler(mMonitor_ReaderRenewed);
			mMonitor.ReaderRemovedOnSerial += 
				new clsReaderMonitor.ReaderRemovedOnSerialEventHandler(mMonitor_ReaderRemoved);
			#endregion
			
			mMonitor.ComPortsMonitoring = chkComPortMonitoring.Checked;
		}
		
		private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			mbClosing = true;
			Thread.Sleep(1);
			mMonitor.Dispose();
			mTimer.Stop();
			mTimer.Dispose();
		}


        string getTime()
        {
            return DateTime.Now.ToString("hh:mm:ss") + "\t";
        }

		
		private void mMonitor_ReaderAdded(IReaderInfo data)
		{
			lock (mReaderList.SyncRoot)
			{
				if (!mReaderList.Contains(data.Name))
					mReaderList.Add(data.Name, data);
			}
			#region "Queue incomming messages for display"
			lock (mMessageQ.SyncRoot)
			{
				mMessageQ.Enqueue(getTime() + data.Name + " - has been added to the list on COM" + data.ComPort);
			}
			#endregion
		}

		private void mMonitor_ReaderRenewed(IReaderInfo data)
		{
			lock (mMessageQ.SyncRoot)
			{
				mMessageQ.Enqueue(data.Name + " - has been renewed on the list on COM" + data.ComPort);
			}
		}

		private void mMonitor_ReaderRemoved(IReaderInfo data)
		{
			lock (mReaderList.SyncRoot)
			{
				if (mReaderList.Contains(data.Name))
					mReaderList.Remove(data.Name);
			}
			lock (mMessageQ.SyncRoot)
			{
				mMessageQ.Enqueue(data.Name + " - has been marked as 'Lost' on COM" + data.ComPort);
			}
		}


		private void btnCheckPorts_Click(object sender, System.EventArgs e)
		{
			this.Cursor = Cursors.WaitCursor;
			String result = mMonitor.CheckComPorts();
			if (result == "")
			{
				result = getTime() + " Reader found!\r\n";
				btnGetReaderList_Click(null, null);
			}
			rtxMessages.AppendText(result + "\r\n");
			this.Cursor = Cursors.Default;
		}

		private void btnGetReaderList_Click(object sender, System.EventArgs e)
		{
			IReaderInfo [] rs;
			this.Cursor = Cursors.WaitCursor;
			int cnt = mMonitor.GetReaderListOnSerial(out rs);

			mReaderList.Clear();
			lbReaders.Items.Clear();

			if (cnt == 0)
			{
				rtxMessages.AppendText("Reader List empty\r\n");
			}
			else
			{
				for (int i = 0; i < cnt; i++)
				{
					mReaderList.Add(rs[i].Name, rs[i]);
					lbReaders.Items.Add(rs[i].Name + " on " + rs[i].IPAddress);
				}
			}
			this.Cursor = Cursors.Default;
		}

		private void chkComPortMonitoring_CheckedChanged(object sender, System.EventArgs e)
		{
			bool status = chkComPortMonitoring.Checked;
			mMonitor.ComPortsMonitoring = status;
			if (status)
			{
				mMonitor.StartListening();
				mReaderList.Clear();
				mTimer.Enabled = true;
			}
			else
			{
				mMonitor.StopListening();
				mReaderList.Clear();
				mTimer.Enabled = false;
			}

		}

		private void udUpdeateInterval_ValueChanged(object sender, System.EventArgs e)
		{
			mMonitor.UpdateInterval = (int) udUpdeateInterval.Value;
			mTimer.Interval = (double) udUpdeateInterval.Value;
		}

		private void btnClearReaderList_Click(object sender, System.EventArgs e)
		{
			mMonitor.ClearSerialReaders();
			lbReaders.Items.Clear();
			mReaderList.Clear();
		}

		private void mTimer_Elapsed(object sender, ElapsedEventArgs e)
		{
			if (mbInsideElapsed) 
				return;
			mbInsideElapsed = true;

			if (mTimer != null)
			{
				mTimer.Stop();
				lock (mReaderList.SyncRoot)
				{
					lbReaders.Items.Clear();
					foreach (DictionaryEntry de in mReaderList)
					{
						ReaderInfo ri = (ReaderInfo)de.Value;
						string name = ri.Name + " on " + ri.IPAddress;
						if (lbReaders.FindStringExact(name) == ListBox.NoMatches)
							lbReaders.Items.Add(name);
					}
				}
				#region "Display messages"...
				lock (mMessageQ.SyncRoot)
				{
					if (mMessageQ.Count > 0)
					{
						rtxMessages.AppendText ((string)mMessageQ.Dequeue() + "\r\n");
					}
				}
				#endregion
				if (!mbClosing)
					mTimer.Start();

				mbInsideElapsed = false;
			}
		}

		private void btnClearLogs_Click(object sender, System.EventArgs e)
		{
			rtxMessages.Clear();
		}
	}
}
