/*******************************************************************************
 * 
 * Ex9 - Notifications and Streaming.cs
 *
 * Copyright (c) 2007 Alien Technology Corporation.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1)	Redistributions of source code must retain the above copyright 
 *		notice, this list of conditions and the following disclaimer. 
 *
 * 2)	Redistributions in binary form must reproduce the above copyright 
 *		notice, this list of conditions and the following disclaimer 
 *		in the documentation and/or other materials provided with the distribution. 
 *
 * 3)	Neither the name of Alien Technology Corporation nor the names of any 
 *		contributors may be used to endorse or promote products derived from this 
 *		software without specific prior written permission. 
 *
 *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *	ARE DISCLAIMED. IN NO EVENT SHALL ALIEN TECHNOLOGY CORPORATION OR ITS 
 *	CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 *	EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
 *	PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
 *	OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 *	WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 *	OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
 *	OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *
 *  Abstract:
 *		This file contains a Windows example application code utilizing Alien .NET API.
 *		To run this program with one or more Alien readers in your network you have to 
 *      connect them to some IO devices ("switchy-box", "light-stack" etc.)  To get 
 *      digital output events, you can also issue ExternalOutput commands in HyperTerminal
 *      sessions on serial connections.
 *
 ***********************************************************************************/

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Diagnostics;
using System.IO;


using nsAlienRFID2;

namespace nsNotificationsAndStreamingEx9
{
	/// <summary>
	/// Sample application for getting different types of automatic messages from Alien readers.
	/// </summary>
	public class FormNetworkNotificationsEx9 : System.Windows.Forms.Form
	{
		private class MyStoredReaderState
		{
			internal string userName = null;
			internal string password = null;
			internal int commandPort = 23;
			internal string readerAddress = null;
			internal string readerName = null;
			internal string notifyAddress = null;
			internal string notifyMode = null;
			internal string notifyTime = null;
			internal string tagStreamMode = null;
			internal string ioStreamMode = null;
			internal string tagStreamAddress = null;
			internal string ioStreamAddress = null;
			internal string autoMode = null;
			internal string notifyFormat = null;
			internal string tagStreamFormat = null;
			internal string ioStreamFormat = null;
			internal string tagListMillis = null;
			internal string autoWaitOutput = null;
			internal string autoWorkOutput = null;
			internal string autoTrueOutput = null;
			internal string autoFalseOutput = null;
			internal string ioStreamKeepAliveTime = null;
			internal string tagStreamKeepAliveTime = null;

			internal MyStoredReaderState(){}
		}

		private int miReadersCount = 0;
		
		CAlienServer[] mServers = new CAlienServer[3];
		clsReaderMonitor mDiscoverer = null;

		const int NOTIFY_PORT = 7797;
		const int TAGSTREAM_PORT = 7798;
		const int IOSTREAM_PORT = 7799;

		Hashtable mClients = new Hashtable();		// readers' IP Addresses as keys; clsReader objects as items
		Hashtable mStoredStates = new Hashtable();	// readers' IP Addresses as keys; MyStoredReaderState objects as items

		static readonly object moCurrentReadersLock = new object();

		private delegate void displayMessageDlgt(string msg);
		private delegate void addNewReaderDlgt(MyStoredReaderState rs);

		private int miOldNodeIndex = -1;	// for showing different tooltips for different nodes

		private System.Windows.Forms.GroupBox groupBox5;
		private System.Windows.Forms.GroupBox groupBox9;
		private System.Windows.Forms.TextBox txtNotifications;
		private System.Windows.Forms.Label label1;
		private System.Windows.Forms.Button btnClear;
		private System.Windows.Forms.CheckBox chkAddDiscovered;
		private System.Windows.Forms.GroupBox groupBox1;
		private System.Windows.Forms.ToolTip toolTip1;
		private System.Windows.Forms.Label lblReaderName;
		private System.Windows.Forms.Label lblReadersCount;
		private System.Windows.Forms.Button btnAddReader;
		private System.Windows.Forms.Label label5;
		private System.Windows.Forms.Label lblConnections;
		private System.Windows.Forms.CheckedListBox chlServers;
		private System.Windows.Forms.TreeView treeView1;
		private System.ComponentModel.IContainer components;

		public FormNetworkNotificationsEx9()
		{
			//
			// 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.components = new System.ComponentModel.Container();
			this.groupBox5 = new System.Windows.Forms.GroupBox();
			this.chlServers = new System.Windows.Forms.CheckedListBox();
			this.lblConnections = new System.Windows.Forms.Label();
			this.label5 = new System.Windows.Forms.Label();
			this.groupBox9 = new System.Windows.Forms.GroupBox();
			this.lblReaderName = new System.Windows.Forms.Label();
			this.btnClear = new System.Windows.Forms.Button();
			this.txtNotifications = new System.Windows.Forms.TextBox();
			this.btnAddReader = new System.Windows.Forms.Button();
			this.lblReadersCount = new System.Windows.Forms.Label();
			this.label1 = new System.Windows.Forms.Label();
			this.chkAddDiscovered = new System.Windows.Forms.CheckBox();
			this.groupBox1 = new System.Windows.Forms.GroupBox();
			this.treeView1 = new System.Windows.Forms.TreeView();
			this.toolTip1 = new System.Windows.Forms.ToolTip(this.components);
			this.groupBox5.SuspendLayout();
			this.groupBox9.SuspendLayout();
			this.groupBox1.SuspendLayout();
			this.SuspendLayout();
			// 
			// groupBox5
			// 
			this.groupBox5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.groupBox5.Controls.Add(this.chlServers);
			this.groupBox5.Controls.Add(this.lblConnections);
			this.groupBox5.Controls.Add(this.label5);
			this.groupBox5.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.groupBox5.Location = new System.Drawing.Point(640, 24);
			this.groupBox5.Name = "groupBox5";
			this.groupBox5.Size = new System.Drawing.Size(216, 128);
			this.groupBox5.TabIndex = 48;
			this.groupBox5.TabStop = false;
			this.groupBox5.Text = " Servers: ";
			// 
			// chlServers
			// 
			this.chlServers.CheckOnClick = true;
			this.chlServers.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.chlServers.Location = new System.Drawing.Point(16, 24);
			this.chlServers.Name = "chlServers";
			this.chlServers.Size = new System.Drawing.Size(184, 52);
			this.chlServers.TabIndex = 67;
			this.toolTip1.SetToolTip(this.chlServers, "Check / Uncheck to Start / Stop Listening");
			this.chlServers.ItemCheck += new System.Windows.Forms.ItemCheckEventHandler(this.chlServers_ItemCheck);
			// 
			// lblConnections
			// 
			this.lblConnections.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.lblConnections.BackColor = System.Drawing.SystemColors.Control;
			this.lblConnections.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblConnections.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.lblConnections.ForeColor = System.Drawing.Color.Black;
			this.lblConnections.Location = new System.Drawing.Point(152, 96);
			this.lblConnections.Name = "lblConnections";
			this.lblConnections.Size = new System.Drawing.Size(48, 16);
			this.lblConnections.TabIndex = 65;
			this.lblConnections.Text = "0";
			this.lblConnections.TextAlign = System.Drawing.ContentAlignment.TopCenter;
			// 
			// label5
			// 
			this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.label5.BackColor = System.Drawing.SystemColors.ControlText;
			this.label5.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.label5.ForeColor = System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(255)), ((System.Byte)(192)));
			this.label5.Location = new System.Drawing.Point(24, 96);
			this.label5.Name = "label5";
			this.label5.Size = new System.Drawing.Size(104, 24);
			this.label5.TabIndex = 66;
			this.label5.Text = "Current Connections Count: ";
			this.label5.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
			// 
			// groupBox9
			// 
			this.groupBox9.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.groupBox9.Controls.Add(this.lblReaderName);
			this.groupBox9.Controls.Add(this.btnClear);
			this.groupBox9.Controls.Add(this.txtNotifications);
			this.groupBox9.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.groupBox9.Location = new System.Drawing.Point(16, 24);
			this.groupBox9.Name = "groupBox9";
			this.groupBox9.Size = new System.Drawing.Size(608, 568);
			this.groupBox9.TabIndex = 59;
			this.groupBox9.TabStop = false;
			this.groupBox9.Text = "Last Notification from:  ";
			// 
			// lblReaderName
			// 
			this.lblReaderName.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.lblReaderName.ForeColor = System.Drawing.Color.Lime;
			this.lblReaderName.Location = new System.Drawing.Point(152, 2);
			this.lblReaderName.Name = "lblReaderName";
			this.lblReaderName.Size = new System.Drawing.Size(160, 16);
			this.lblReaderName.TabIndex = 62;
			this.lblReaderName.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
			// 
			// btnClear
			// 
			this.btnClear.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.btnClear.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(255)), ((System.Byte)(192)));
			this.btnClear.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.btnClear.ForeColor = System.Drawing.SystemColors.WindowText;
			this.btnClear.Location = new System.Drawing.Point(344, 8);
			this.btnClear.Name = "btnClear";
			this.btnClear.Size = new System.Drawing.Size(56, 24);
			this.btnClear.TabIndex = 61;
			this.btnClear.Text = "&Clear";
			this.btnClear.Click += new System.EventHandler(this.btnClear_Click);
			// 
			// txtNotifications
			// 
			this.txtNotifications.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.txtNotifications.BackColor = System.Drawing.SystemColors.WindowFrame;
			this.txtNotifications.Font = new System.Drawing.Font("Microsoft Sans Serif", 7.8F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.txtNotifications.ForeColor = System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(255)), ((System.Byte)(192)));
			this.txtNotifications.Location = new System.Drawing.Point(16, 24);
			this.txtNotifications.Multiline = true;
			this.txtNotifications.Name = "txtNotifications";
			this.txtNotifications.ReadOnly = true;
			this.txtNotifications.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
			this.txtNotifications.Size = new System.Drawing.Size(584, 536);
			this.txtNotifications.TabIndex = 36;
			this.txtNotifications.Text = "";
			// 
			// btnAddReader
			// 
			this.btnAddReader.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.btnAddReader.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(255)), ((System.Byte)(192)));
			this.btnAddReader.Font = new System.Drawing.Font("Microsoft Sans Serif", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.btnAddReader.ForeColor = System.Drawing.SystemColors.WindowText;
			this.btnAddReader.Location = new System.Drawing.Point(56, 64);
			this.btnAddReader.Name = "btnAddReader";
			this.btnAddReader.Size = new System.Drawing.Size(104, 24);
			this.btnAddReader.TabIndex = 60;
			this.btnAddReader.Text = "&Add Reader ...";
			this.btnAddReader.Click += new System.EventHandler(this.btnAddReader_Click);
			// 
			// lblReadersCount
			// 
			this.lblReadersCount.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.lblReadersCount.BackColor = System.Drawing.SystemColors.Control;
			this.lblReadersCount.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;
			this.lblReadersCount.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.lblReadersCount.ForeColor = System.Drawing.Color.Black;
			this.lblReadersCount.Location = new System.Drawing.Point(152, 96);
			this.lblReadersCount.Name = "lblReadersCount";
			this.lblReadersCount.Size = new System.Drawing.Size(48, 16);
			this.lblReadersCount.TabIndex = 61;
			this.lblReadersCount.Text = "0";
			this.lblReadersCount.TextAlign = System.Drawing.ContentAlignment.TopCenter;
			// 
			// label1
			// 
			this.label1.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.label1.Location = new System.Drawing.Point(16, 96);
			this.label1.Name = "label1";
			this.label1.Size = new System.Drawing.Size(128, 16);
			this.label1.TabIndex = 62;
			this.label1.Text = "Current Active Readers:";
			this.label1.TextAlign = System.Drawing.ContentAlignment.BottomCenter;
			// 
			// chkAddDiscovered
			// 
			this.chkAddDiscovered.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
			this.chkAddDiscovered.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.chkAddDiscovered.Location = new System.Drawing.Point(24, 24);
			this.chkAddDiscovered.Name = "chkAddDiscovered";
			this.chkAddDiscovered.Size = new System.Drawing.Size(176, 32);
			this.chkAddDiscovered.TabIndex = 64;
			this.chkAddDiscovered.Text = "Add all &Discovered Readers";
			this.toolTip1.SetToolTip(this.chkAddDiscovered, "Use default discovery settings \\r\\nand attempt to connect to reader with default " +
				"settings");
			this.chkAddDiscovered.CheckedChanged += new System.EventHandler(this.chkAddDiscovered_CheckedChanged);
			// 
			// 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.treeView1);
			this.groupBox1.Controls.Add(this.btnAddReader);
			this.groupBox1.Controls.Add(this.chkAddDiscovered);
			this.groupBox1.Controls.Add(this.lblReadersCount);
			this.groupBox1.Controls.Add(this.label1);
			this.groupBox1.Font = new System.Drawing.Font("Microsoft Sans Serif", 9.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.groupBox1.Location = new System.Drawing.Point(640, 160);
			this.groupBox1.Name = "groupBox1";
			this.groupBox1.Size = new System.Drawing.Size(216, 432);
			this.groupBox1.TabIndex = 65;
			this.groupBox1.TabStop = false;
			this.groupBox1.Text = "Clients: ";
			// 
			// treeView1
			// 
			this.treeView1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) 
				| System.Windows.Forms.AnchorStyles.Right)));
			this.treeView1.CheckBoxes = true;
			this.treeView1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(0)));
			this.treeView1.ImageIndex = -1;
			this.treeView1.Location = new System.Drawing.Point(16, 128);
			this.treeView1.Name = "treeView1";
			this.treeView1.SelectedImageIndex = -1;
			this.treeView1.Size = new System.Drawing.Size(184, 288);
			this.treeView1.TabIndex = 66;
			this.toolTip1.SetToolTip(this.treeView1, "Check reader to configure.");
			this.treeView1.AfterCheck += new System.Windows.Forms.TreeViewEventHandler(this.treeView1_AfterCheck);
			this.treeView1.MouseMove += new System.Windows.Forms.MouseEventHandler(this.treeView1_MouseMove);
			// 
			// toolTip1
			// 
			this.toolTip1.AutoPopDelay = 5000;
			this.toolTip1.InitialDelay = 500;
			this.toolTip1.ReshowDelay = 0;
			// 
			// FormNetworkNotificationsEx9
			// 
			this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
			this.BackColor = System.Drawing.SystemColors.ControlText;
			this.ClientSize = new System.Drawing.Size(872, 602);
			this.Controls.Add(this.groupBox1);
			this.Controls.Add(this.groupBox9);
			this.Controls.Add(this.groupBox5);
			this.ForeColor = System.Drawing.Color.FromArgb(((System.Byte)(255)), ((System.Byte)(255)), ((System.Byte)(192)));
			this.Name = "FormNetworkNotificationsEx9";
			this.Text = "Ex9 - Network only Notifications";
			this.Closing += new System.ComponentModel.CancelEventHandler(this.Form_Closing);
			this.Load += new System.EventHandler(this.Form_Load);
			this.groupBox5.ResumeLayout(false);
			this.groupBox9.ResumeLayout(false);
			this.groupBox1.ResumeLayout(false);
			this.ResumeLayout(false);

		}
		#endregion

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

		
		
		private void Form_Load(object sender, System.EventArgs e)
		{
			// If you have more than 1 IP Address on your PC use the two parameters' constructor instead.
			mServers[0] = new CAlienServer(7797);	// Notifications
			mServers[1] = new CAlienServer(7798);	// TagStream
			mServers[2] = new CAlienServer(7799);	// IOStream

			chlServers.Items.Add("Notify Server", false);
			chlServers.Items.Add("TagStream Server", false);
			chlServers.Items.Add("IOStream Server", false);


			mDiscoverer = new clsReaderMonitor();

			mClients = new Hashtable();
			for (int i = 0; i < 3; i++)
			{
				addServerEvents(i);
			}
			mDiscoverer.ReaderAdded += new nsAlienRFID2.clsReaderMonitor.ReaderAddedEventHandler(mDiscoverer_ReaderAdded);

		}

		private void Form_Closing(object sender, System.ComponentModel.CancelEventArgs e)
		{
			lock (moCurrentReadersLock)
			{
				foreach (object o in mStoredStates.Keys)
				{
                    string address = o as string;
					if (mClients.ContainsKey(address))
					{
						try 
						{ 
							MyStoredReaderState rs = mStoredStates[address] as MyStoredReaderState;

							clsReader reader = mClients[address] as clsReader;

							if (!reader.IsConnected)
								reader.ConnectAndLogin(address, rs.commandPort, rs.userName, rs.password);

							restoreReaderState(rs, ref reader);
							reader.Dispose();
						}
						catch {}
					}
				}
			}
		}


		private void addServerEvents(int idx)
		{
			mServers[idx].ServerMessageReceived += new CAlienServer.ServerMessageReceivedEventHandler(mServer_ServerMessageReceived);
			mServers[idx].ServerConnectionEstablished += new CAlienServer.ServerConnectionEstablishedEventHandler(mServer_ServerConnectionEstablished);
			mServers[idx].ServerConnectionEnded += new CAlienServer.ServerConnectionEndedEventHandler(mServer_ServerConnectionEnded);
			mServers[idx].ServerSocketError += new CAlienServer.ServerSocketErrorEventHandler(mServer_ServerSocketError);
		}

		private void displayText(String data)
		{
			try
			{
				if (this.InvokeRequired)
				{
					object[] temp = {data};
					this.Invoke(new displayMessageDlgt(displayText),temp);
					return;
				}
				else
				{
					txtNotifications.Text += data.Replace("\0","") + "\r\n";

					NotifyInfo ni = null;
					AlienUtils.ParseNotification(data, out ni);
					if (ni != null)
					{
						lblReaderName.Text = ni.ReaderName;
					}
				}
			}
			catch(Exception ex)
			{
				Debug.WriteLine("Exception in the DiscplayText(): " + ex.Message);
			}
		}

		private void decreaseConnectionsCount(string msg)
		{
			try 
			{
				if (this.InvokeRequired)
				{
					object[] temp = {msg};
					this.Invoke(new displayMessageDlgt(decreaseConnectionsCount), temp);
					return;
				}
				else
				{
					int count = int.Parse(lblConnections.Text);
					if (count > 0)
						count--;
					lblConnections.Text = count.ToString();
					txtNotifications.Text += "Connection ended: " + msg.Replace("\0", "") + "\r\n";
				}
			}
			catch (Exception ex)
			{
				Debug.WriteLine("Exception in the decreaseConnectionsCount(): " + ex.Message);
			}
		}
		private void increaseConnectionsCount(string msg)
		{
			try 
			{
				if (this.InvokeRequired)
				{
					object[] temp = {msg};
					this.Invoke(new displayMessageDlgt(increaseConnectionsCount), temp);
					return;
				}
				else
				{
					int count = int.Parse(lblConnections.Text);
					count++;
					lblConnections.Text = count.ToString();
					txtNotifications.Text += "Connection added: " + msg.Replace("\0", "") + "\r\n";
				}
			}
			catch (Exception ex)
			{
				Debug.WriteLine("Exception in the increaseConnectionsCount(): " + ex.Message);
			}
		}


		private void btnAddReader_Click(object sender, System.EventArgs e)
		{
			FormAddReader dlg = new FormAddReader();
			if (dlg.ShowDialog() != DialogResult.OK)
				return;

			string sIPaddress = dlg.txtAddress.Text.Trim();
			string sPort = dlg.txtPort.Text;
			string sUsername = dlg.txtUsername.Text;
			string sPassword = dlg.txtPassword.Text;

			MyStoredReaderState rs = new MyStoredReaderState();
			rs.readerAddress = sIPaddress;
			try 
			{
				rs.commandPort = int.Parse(sPort);
				rs.userName = sUsername;
				rs.password = sPassword;

				lock (moCurrentReadersLock)
				{
					if (!mStoredStates.ContainsKey(sIPaddress))
						mStoredStates.Add(sIPaddress, rs);
					else
						mStoredStates[sIPaddress] = rs;
					
					addNewReader(rs);
				}
			}
			catch(Exception ex)
			{
				MessageBox.Show(ex.Message);
			}
		}

		private void btnClear_Click(object sender, System.EventArgs e)
		{
			txtNotifications.Clear();
		}


		private void mServer_ServerMessageReceived(string msg)
		{
            if (msg != null)
			    displayText(msg.Insert(msg.IndexOf(" ") + 1, "\r\n"));
		}
		private void mServer_ServerConnectionEstablished(string id)
		{
			increaseConnectionsCount(id);
		}		
		private void mServer_ServerConnectionEnded(string id)
		{
			decreaseConnectionsCount(id);
		}

		private void mServer_ServerSocketError(string msg)
		{
			displayText(msg);
		}

		
		private void chkAddDiscovered_CheckedChanged(object sender, System.EventArgs e)
		{
			if (chkAddDiscovered.Checked)
				mDiscoverer.StartListening();
			else
				mDiscoverer.StopListening();
		}

		private void mDiscoverer_ReaderAdded(IReaderInfo data)
		{
			if (mStoredStates.ContainsKey(data.IPAddress))
				return;

			MyStoredReaderState rs = new MyStoredReaderState();
			rs.readerAddress = data.IPAddress;
			rs.commandPort = data.TelnetPort;
			rs.readerName = data.Name;
			lock (moCurrentReadersLock)
			{
				if (!mStoredStates.ContainsKey(data.IPAddress))
					mStoredStates.Add(data.IPAddress, rs);

				addNewReader(rs);
			}
		}

		
		private void addNewReader(MyStoredReaderState rs)
		{
			if (this.InvokeRequired)
			{
				object[] temp = {rs};
				try 
				{
					this.Invoke(new addNewReaderDlgt(addNewReader), temp);
				}
				catch (Exception ex)
				{
					Debug.WriteLine(ex.Message);
				}
				return;
			}
			else
			{
				bool found = false;
				foreach(TreeNode n in treeView1.Nodes)
				{
					if (n.Text == rs.readerAddress)
					{
						found = true;
						break;
					}
				}

				if (!found) 
				{
					TreeNode[] nodeChildren = new TreeNode[3];
					nodeChildren[0] = new TreeNode("Notify");
					nodeChildren[1] = new TreeNode("TagStream");
					nodeChildren[2] = new TreeNode("IOStream");
					TreeNode node = new TreeNode(rs.readerAddress, nodeChildren);
					node.Tag = rs.readerAddress;

					miReadersCount++;

					treeView1.Nodes.Add(node);
				}
				lblReadersCount.Text = miReadersCount.ToString();
			}
		}

		private void connect(MyStoredReaderState myReaderState, ref clsReader reader)
		{
			if (myReaderState.userName == null)
				myReaderState.userName = "alien";
			if (myReaderState.password == null)
				myReaderState.password = "password";

			lock (moCurrentReadersLock)
			{
				reader.ConnectAndLogin(
					myReaderState.readerAddress,
					myReaderState.commandPort, 
					myReaderState.userName, 
					myReaderState.password);
			}
		}
		
		
		private void saveReaderState(MyStoredReaderState myReaderState)
		{
			string sIPaddress = myReaderState.readerAddress;

			clsReader reader = null;
			lock (moCurrentReadersLock)
			{
				try 
				{
					if (!mClients.ContainsKey(sIPaddress))
					{
						reader = new clsReader();
						connect(myReaderState, ref reader);
						if (!reader.IsConnected)
						{
							throw new Exception("Can't connect to the reader.");
						}

						string r = null;
				
						try { r = reader.TagStreamAddress; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.tagStreamAddress = r; r = null; }

						try { r = reader.TagStreamMode; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.tagStreamMode = r; r = null; }

						try { r = reader.IOStreamAddress; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.ioStreamAddress = r; r = null; }

						try { r = reader.IOStreamMode; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.ioStreamMode = r; r = null; }

						try { r = reader.NotifyAddress; }  catch{ }
						if ((r != null) && r.IndexOf("Error") == -1)
						{	myReaderState.notifyAddress = r; r = null; }

						try { r = reader.NotifyMode; }   catch{ }
						if ((r != null) && r.IndexOf("Error") == -1)
						{	myReaderState.notifyMode = r; r = null; }

						try { r = reader.NotifyTime; }	catch{ }
						if ((r != null) && r.IndexOf("Error") == -1)
						{	myReaderState.notifyTime = r; r = null; }

						try { r = reader.NotifyFormat; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.notifyFormat = r; r = null; }

						try { r = reader.TagStreamFormat; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.tagStreamFormat = r; r = null; }

						try { r = reader.IOStreamFormat; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.ioStreamFormat = r; r = null; }

						try { r = reader.TagListMillis; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.tagListMillis = r; r = null; }

						try { r = reader.AutoWaitOutput; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.autoWaitOutput = r; r = null; }

						try { r = reader.AutoWorkOutput; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.autoWorkOutput = r; r = null; }

						try { r = reader.AutoTrueOutput; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.autoTrueOutput = r; r = null; }

						try { r = reader.AutoFalseOutput; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.autoFalseOutput = r; r = null; }

						try { r = reader.IOStreamKeepAliveTime; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.ioStreamKeepAliveTime = r; r = null; }

						try { r = reader.TagStreamKeepAliveTime; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.tagStreamKeepAliveTime = r; r = null; }

						try { r = reader.AutoMode; } catch{ }
						if ((r != null) && (r.IndexOf("Error") == -1))
						{	myReaderState.autoMode = r; r = null; }

						mClients.Add(sIPaddress, reader);
					}
				}
				catch (Exception ex)
				{
					if (mClients.ContainsKey(sIPaddress))
						mClients.Remove(sIPaddress);

					if ((reader != null) && (reader.IsConnected))
						reader.Dispose();
				}
			}// releasing lock
		}

		private void restoreReaderState(MyStoredReaderState rs, ref clsReader reader)
		{
			try { reader.AutoMode = "Off"; } catch{ }
			if (rs.notifyMode != null)
				try { reader.NotifyMode = rs.notifyMode; } catch{ }
			if (rs.tagStreamMode != null)
				try { reader.TagStreamMode = rs.tagStreamMode; } catch{ }
			if (rs.ioStreamMode != null)
				try { reader.IOStreamMode = rs.ioStreamMode; } catch{ }
			if (rs.notifyTime != null)
				try { reader.NotifyTime = rs.notifyTime; } catch{ }
			if (rs.notifyAddress != null)
				try { reader.NotifyAddress = rs.notifyAddress; } catch{ }
			if (rs.tagStreamAddress != null)
				try { reader.TagStreamAddress = rs.tagStreamAddress; } catch{ }
			if (rs.ioStreamAddress != null)
				try { reader.IOStreamAddress = rs.ioStreamAddress; } catch{ }
			if (rs.notifyFormat != null)
				try { reader.NotifyFormat = rs.notifyFormat; } catch{ }
			if (rs.tagStreamFormat != null)
				try { reader.TagStreamFormat = rs.tagStreamFormat; } catch{ }
			if (rs.ioStreamFormat != null)
				try { reader.IOStreamFormat = rs.ioStreamFormat; } catch{ }
			if (rs.tagListMillis != null)
				try { reader.TagListMillis = rs.tagListMillis; } catch{ }
			if (rs.autoWaitOutput != null)
				try { reader.AutoWaitOutput = rs.autoWaitOutput; } catch{ }
			if (rs.autoWorkOutput != null)
				try { reader.AutoWorkOutput = rs.autoWorkOutput; } catch{ }
			if (rs.autoTrueOutput != null)
				try { reader.AutoTrueOutput = rs.autoTrueOutput; } catch{ }
			if (rs.autoFalseOutput != null)
				try { reader.AutoFalseOutput = rs.autoFalseOutput; } catch{ }
			if (rs.ioStreamKeepAliveTime != null)
				try { reader.IOStreamKeepAliveTime = rs.ioStreamKeepAliveTime; } catch{ }
			if (rs.tagStreamKeepAliveTime != null)
				try { reader.TagStreamKeepAliveTime= rs.tagStreamKeepAliveTime; } catch{ }
			if (rs.autoMode != null)
				try { reader.AutoMode = rs.autoMode; } catch{ }
		}


		private void chlServers_ItemCheck(object sender, System.Windows.Forms.ItemCheckEventArgs e)
		{
			this.Cursor = Cursors.WaitCursor;

			if (e.NewValue == CheckState.Checked)
				mServers[e.Index].StartListening();
			else
				mServers[e.Index].StopListening();

			this.Cursor = Cursors.Default;
		}

		
		private void treeView1_AfterCheck(object sender, System.Windows.Forms.TreeViewEventArgs e)
		{
			string tag = e.Node.Tag as string;
			if ((tag != null) && (tag != ""))
			{
				if (e.Node.Checked)
				{
					lock (moCurrentReadersLock)		
					{
						if (!mClients.ContainsKey(tag))	// configuring reader for the first time
						{
							saveReaderState(mStoredStates[tag] as MyStoredReaderState);
							clsReader reader = null;
							reader = mClients[tag] as clsReader;
							if ((reader == null) || (!reader.IsConnected))
							{
								MessageBox.Show("Can't connect to the reader.");
								treeView1.Nodes.Remove(e.Node);
								lblReadersCount.Text = (--miReadersCount).ToString();
							}
							else
							{
								this.Cursor = Cursors.WaitCursor;

								// any of these can throw, especially for older readers
								try { reader.NotifyAddress = mServers[0].NotificationHost; } catch{ }
								try { reader.TagStreamAddress = mServers[1].NotificationHost; } catch{ }
								try { reader.IOStreamAddress = mServers[2].NotificationHost; } catch{ }
								try { reader.TagListMillis = "On"; } catch{ }
								try { reader.AutoMode = "On"; } catch{ }

								// cusotmize these properties (and any of other related ones) as you desire
								try { reader.NotifyTime = "5"; } catch{ }
								try { reader.NotifyFormat = "Text"; } catch{ }
								try { reader.NotifyHeader = "Off"; } catch{ } 
								try { reader.TagStreamFormat = "Terse"; } catch{ }
								try { reader.IOStreamFormat = "Text"; } catch{ }
								try { reader.IOStreamKeepAliveTime = "30"; } catch{ }
								try { reader.TagStreamKeepAliveTime = "30"; } catch{ } 
								try { reader.AutoWaitOutput = "-1"; } catch{ }
								try { reader.AutoWorkOutput = "-1"; } catch{ }
								try { reader.AutoTrueOutput = "-1"; } catch{ }
								try { reader.AutoFalseOutput = "-1"; } catch{ }

								this.Cursor = Cursors.Default;
							}
							e.Node.Expand();
						}
					}// release lock
				}
				else
				{
					e.Node.Checked = true;
				}
			}
			else	// Start / Stop automatic messages from the reader
			{
				tag = e.Node.Parent.Tag as String;
				lock (moCurrentReadersLock)
				{
					if (!mClients.ContainsKey(tag))
						e.Node.Parent.Checked = true;

					clsReader reader = mClients[tag] as clsReader;
					if ((reader != null) && !(reader.IsConnected))
					{
						connect((mStoredStates[tag] as MyStoredReaderState), ref reader);
						if (!reader.IsConnected)
						{
							MessageBox.Show("Can't connect to the reader.");
							treeView1.Nodes.Remove(e.Node.Parent);
							lblReadersCount.Text = (--miReadersCount).ToString();
							return;
						}
					}
					string cmd = e.Node.Text + "Mode";
					string strToSend = "Set " + cmd + " = " + (e.Node.Checked ? "On" : "Off");

					try { reader.SendReceive(strToSend, false); } 
					catch (Exception ex)
					{ 
						if (e.Node.Checked)
						{
							MessageBox.Show(ex.Message);
							e.Node.Checked = false;
						}
					}
				} // release lock
			}
		}


		private void treeView1_MouseMove(object sender, System.Windows.Forms.MouseEventArgs e)
		{											// Different tooltips for different nodes.

			TreeNode tn = this.treeView1.GetNodeAt(e.X, e.Y); 
 
			if(tn != null) 
			{ 
				int currentNodeIndex = tn.Index; 
				if(currentNodeIndex != miOldNodeIndex) 
				{ 
					miOldNodeIndex = currentNodeIndex; 
					if(this.toolTip1 != null && this.toolTip1.Active) 
						this.toolTip1.Active = false; //turn it off 
 
					string textToShow = "";
					if (tn.Tag == null)
					{
						if (tn.Checked)
							textToShow = "Uncheck to set the " + tn.Text + "Mode Off.";
						else
							textToShow = "Check to set the " + tn.Text + "Mode On";
					}
					else if (!tn.Checked)
					{
						textToShow = "Check to configure reader.";
					}
					else
						textToShow = "";

					this.toolTip1.SetToolTip(this.treeView1, textToShow ); 
					this.toolTip1.Active = true; //make it active so it can show 
				} 
			} 
		}
	}
}
