using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;

using nsAlienRFIDcf;



namespace nsAlienMobileSDK
{
    public partial class Form9 : Form
    {
        static readonly Color NOTIFICATION_COLOR = Color.Cyan;
        static readonly Color TAGSTREAM_COLOR = Color.Magenta;
        static readonly Color IOSTREAM_COLOR = Color.Yellow;

        bool mbDisposing = false;
        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;

        static readonly object moServersLock = new object();

        CAlienServer[] mServers = new CAlienServer[3];
        clsReaderMonitor mDiscoverer = null;
        AlienDataDirector mDataDirector = null;
        FormConnectToHost frmConnectToHost = 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 showMsg();

        public Form9()
        {
            InitializeComponent();
        }

        private void Form_Load(object sender, EventArgs e)
        {
            AlienLog.Path = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\AlienSDK\";

            AlienLog.WriteLine(true, "In Form_Load().");
            // If you have more than 1 IP Address on your PC (PPC) use the two-parameters' constructor instead.
            mServers[0] = new CAlienServer(7797);	// Notifications
            mServers[1] = new CAlienServer(7798);	// TagStream
            mServers[2] = new CAlienServer(7799);	// IOStream

            try
            {
                ListViewItem item = new ListViewItem("Notify Server");
                item.Checked = true;    //mServers[0].IsListening;
                item.ForeColor = Color.Cyan;
                lsvServers.Items.Add(item);
                item = new ListViewItem("TagStream Server");
                item.Checked = true;    // mServers[1].IsListening;
                item.ForeColor = Color.Magenta;
                lsvServers.Items.Add(item);
                item = new ListViewItem("IOStream Server");
                item.Checked = true;    // mServers[2].IsListening;
                item.ForeColor = Color.Yellow;
                lsvServers.Items.Add(item);
            }
            catch (Exception ex) { MessageBox.Show(ex.Message); }

            mClients = new Hashtable();
            for (int i = 0; i < 3; i++)
            {
                addServerEvents(i);
            }
            ColumnHeader columnHeader = new ColumnHeader();
            columnHeader.Text = "Alien Servers";
            lsvServers.Columns.Add(columnHeader);
            lsvMessages.Columns.Add(new ColumnHeader());

            mDiscoverer = new clsReaderMonitor();
            mDiscoverer.ReaderAdded += new nsAlienRFIDcf.clsReaderMonitor.ReaderAddedEventHandler(mDiscoverer_ReaderAdded);
            mDiscoverer.NetworkMonitoring = true;
            mDiscoverer.ComPortsMonitoring = false;
            mDiscoverer.StartListening();
        }

        private void Form_Closing(object sender, CancelEventArgs e)
        {
            mbDisposing = true;
            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)
        {
            switch (idx)
            {
                case 0: mServers[idx].ServerMessageReceived += new CAlienServer.ServerMessageReceivedEventHandler(notification_MessageReceived); break;
                case 1: mServers[idx].ServerMessageReceived += new CAlienServer.ServerMessageReceivedEventHandler(tagstream_MessageReceived); break;
                case 2: mServers[idx].ServerMessageReceived += new CAlienServer.ServerMessageReceivedEventHandler(iostream_MessageReceived); break;
                default: break;
            }
        }


        void showEvent(string text, Color color)
        {
            if (mbDisposing) return;

            lock (this)
            {
                showMsg method = delegate 
                {
                    if (text != null)
                        addText(text, color);
                    else
                        lblStatus.ForeColor = color;
                }; 
                this.BeginInvoke(method);
            }
        }
        void mDiscoverer_ReaderAdded(IReaderInfo data)
        {
            if ((mbDisposing) || (data == null)) return;

            lock (this)
            {
                showMsg method = delegate 
                {
                    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);
                    }
                }; 
                this.BeginInvoke(method);
            }
        }

        void addNewReader(MyStoredReaderState rs)
        {
            bool found = false;
            foreach (TreeNode n in treeView1.Nodes)
            {
                if (n.Text == rs.readerAddress)
                {
                    found = true;
                    break;
                }
            }

            if (!found)
            {
                TreeNode node = new TreeNode(rs.readerAddress);

                node.Tag = rs.readerAddress;

                TreeNode[] nodeChildren = new TreeNode[3];
                nodeChildren[0] = new TreeNode("Notify");
                nodeChildren[1] = new TreeNode("TagStream");
                nodeChildren[2] = new TreeNode("IOStream");

                node.Nodes.Add(nodeChildren[0]);
                node.Nodes.Add(nodeChildren[1]);
                node.Nodes.Add(nodeChildren[2]);

                miReadersCount++;

                treeView1.Nodes.Add(node);
            }
        }

        void addText(string text, Color color)
        {
            ListViewItem item = new ListViewItem(text.Replace("\0", "").Replace("\r\n", ""));
            item.ForeColor = color;
            lsvMessages.Items.Add(item);
            lsvMessages.Refresh();
        }
        
        private void notification_MessageReceived(string msg)
        {
            showEvent(msg.Insert(msg.IndexOf(" ") + 1, "\r\n"), NOTIFICATION_COLOR);
        }
        private void tagstream_MessageReceived(string msg)
        {
            showEvent(msg.Insert(msg.IndexOf(" ") + 1, "\r\n"), TAGSTREAM_COLOR);
        }
        private void iostream_MessageReceived(string msg)
        {
            showEvent(msg.Insert(msg.IndexOf(" ") + 1, "\r\n"), IOSTREAM_COLOR);
        }





        private void chkConnect_CheckStateChanged(object sender, EventArgs e)
        {
            bool state = chkConnect.Checked;
            if (!state)
            {
                if (mDataDirector != null)
                    mDataDirector.Disconnect();
                lock (this) { lblStatus.ForeColor = Color.LightSlateGray; }
                return;
            }
            else
            {
                if (frmConnectToHost == null)
                {
                    frmConnectToHost = new FormConnectToHost();
                }
                if (frmConnectToHost.ShowDialog() != DialogResult.OK)
                {
                    chkConnect.Checked = false;
                    return;
                }
                IPAddress hostIPAddress = frmConnectToHost.HostIPAddress;
                int hostPort = frmConnectToHost.Port;

                if (mDataDirector == null)
                {
                    mDataDirector = new AlienDataDirector(hostPort, hostIPAddress, true);
                    mDataDirector.MessageForwardedOK += new AlienDataDirector.HostNotificationHandler(mDataDirector_MessageForwardedOK);
                    mDataDirector.MessageForwardFAILED += new AlienDataDirector.HostNotificationHandler(mDataDirector_MessageForwardFAILED);
                }

                if (!mDataDirector.IsConnectedToHost)
                    mDataDirector.ConnectToHost();

                try
                {
                    lock (moServersLock)
                    {
                        for (int i = 0; i < 3; i++)
                        {
                            string key = mServers[i].NotificationHost;
                            if (mServers[i].IsListening)
                            {
                                if (!mDataDirector.Contains(key))
                                    mDataDirector.AddServer(mServers[i]);
                            }
                            else if (mDataDirector.Contains(key))
                                mDataDirector.RemoveServer(key);
                        }
                    }
                }
                catch (Exception ex)
                {
                    MessageBox.Show("Exception in chkConnect_CheckStateChanged(): " + ex.Message);
                    chkConnect.Checked = false;
                }
            }
        }

        void mDataDirector_MessageForwardedOK(DateTime dataTime)
        {
            AlienLog.WriteLine(true, "MessageForwardedOK Event");
            showEvent(null, Color.Green);
        }
        void mDataDirector_MessageForwardFAILED(DateTime dataTime)
        {
            AlienLog.WriteLine(true, "MessageForwardedFAILED Event");
            showEvent(null, Color.Red);
        }

        
        
        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, EventArgs e)
        {
            lsvMessages.Clear();
        }

        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 lsvServers_ItemCheck(object sender, System.Windows.Forms.ItemCheckEventArgs e)
        {
            
            Cursor.Current = Cursors.WaitCursor;

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

            Cursor.Current = 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);
                            }
                            else
                            {
                                Cursor.Current = 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 { }

                                Cursor.Current = 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);
                            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
            }
        }
    }
}