using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using AT288Lib.Net;
using Microsoft.Win32;
using System.Reflection;
using AT288Demo.Net.Dialog;
using ATUtil.Diagnostics;
using System.Management;
namespace AT288Demo.Net
{
    public partial class MainFrame : Form
    {
        #region 상수선언
        private const int DEFAULT_SERIAL_PORT = 3;

        private const int DBT_DEVTYP_DEVICEINTERFACE = 5;
        private const int DBT_DEVTYP_HANDLE = 6;
        private const int BROADCAST_QUERY_DENY = 0x424D5144;
        private const int WM_DEVICECHANGE = 0x0219;
        private const int DEVICE_NOTIFY_SERVICE_HANDLE = 0x00000001;
        private const int DBT_DEVTYP_VOLUME = 0x00000002;
        private const int DBT_DEVTYP_PORT = 0x00000003;
        private const int DBT_DEVICEARRIVAL = 0x8000;
        private const int DBT_DEVICEQUERYREMOVE = 0x8001;
        private const int DBT_DEVICEREMOVECOMPLETE = 0x8004;
        private const string DEFAULT_DEVICE_ADDRESS = "";
        
        private const string AT288N_INVENTORY_FORMAT_0 = "Pc+Epc";
        private const string AT288N_INVENTORY_FORMAT_1 = "Serial+Pc+Epc";
        private const string AT288N_INVENTORY_FORMAT_2 = "Epc";
        private const string AT288N_INVENTORY_FORMAT_3 = "Serial+Epc";
        private const string AT288N_MA_INVENTORY_FORMAT_0 = "Data";
        private const string AT288N_MA_INVENTORY_FORMAT_1 = "Serial+Data";
        #endregion

        // private Action<string> m_fnOutputLog;

        #region 열거형 선언
        [Flags]
        private enum EventFlag
        {
            None = 0x00000000,
            ContinueMode = 0x00000001,
            SwitchingTime = 0x00000003,
            SleepTime = 0x00000004,
            GlobalBand = 0x00000008,
            TagType = 0x00000010,
            InventoryMode = 0x00000020,
            Power = 0x00000040,
            ConnectionType = 0x00000080,
            StoredMode = 0x00000100,
            ShowSerialNo = 0x00000200,
        }
        #endregion

        #region 멤버변수
        private bool m_isEventBlock;

        private string m_strLastAddress;


        private Reader m_Reader;
        //private TagItemList m_lstTags;
        //private int m_nFirstItem;
        //private ListViewItem[] m_lstTagItems;

        private Dictionary<string, TagItem> m_mapTags;
        private List<TagItem> m_lstTags;
        private long m_lTotalCount;
        private ListViewItem[] m_lstCache;
        private int m_nFirstItem;



        private MemoryType m_ReadBank;
        private int m_nReadOffset;
        private int m_nReadLength;

        private MemoryType m_WriteBank;
        private int m_nWriteOffset;
        private string m_strWriteValue;

        private AccessPermType m_LockKillPassword;
        private AccessPermType m_LockAccessPassword;
        private AccessPermType m_LockEPC;
        private AccessPermType m_LockTID;
        private AccessPermType m_LockUser;

        private string m_strSelectionMask;

        private EventHandler<ActionEventArgs> m_fnAction;
        private EventHandler<ResponseEventArgs> m_fnResponse;
        private EventHandler<ReadTagEventArgs> m_fnReadTag;
        private EventHandler<PropertyEventArgs> m_fnProperty;
        private EventHandler<PropertyExEventArgs> m_fnPropertyEx;

        //private List<int> m_TimeValues = new List<int>(){4000, 3000, 2000, 1000, 600, 500, 400, 350, 300, 250, 200, 150, 100, 80, 50, 10};
        private List<int> m_OnTimeValues = new List<int>() { 4000, 3000, 2000, 1000, 600, 500, 400, 350, 300, 250, 200, 150, 100, 80, 50, 10 };

        private List<int> m_OffTimeValues = new List<int>() { 4000, 3000, 2000, 1000, 600, 500, 400, 300, 250, 200, 150, 100, 80, 50, 30, 20, 10};

        private IntPtr m_DeviceNotifyHandle;
        #endregion
        bool bInventoryMemory = false;
        bool m_isLoadingStoredTags = false;

        #region 생성자
        public MainFrame()
        {
            m_DeviceNotifyHandle = IntPtr.Zero;

            InitializeComponent();

            m_isEventBlock = false;

            //m_lstTags = new TagItemList();
            //m_nFirstItem = 0;
            //m_lstTagItems = null;

            m_mapTags = new Dictionary<string, TagItem>();
            m_lstTags = new List<TagItem>();
            m_lTotalCount = 0;
            m_lstCache = null;
            m_nFirstItem = 0;


            m_fnAction = new EventHandler<ActionEventArgs>(Reader_Action);
            m_fnResponse = new EventHandler<ResponseEventArgs>(Reader_Response);
            m_fnReadTag = new EventHandler<ReadTagEventArgs>(Reader_ReadTag);
            m_fnProperty = new EventHandler<PropertyEventArgs>(Reader_Property);
            m_fnPropertyEx = new EventHandler<PropertyExEventArgs>(Reader_PropertyEx);

            m_ReadBank = MemoryType.EPC;
            m_nReadOffset = 2;
            m_nReadLength = 4;

            m_WriteBank = MemoryType.EPC;
            m_nWriteOffset = 2;
            m_strWriteValue = "";

            m_LockKillPassword = AccessPermType.NoChange;
            m_LockAccessPassword = AccessPermType.NoChange;
            m_LockEPC = AccessPermType.NoChange;
            m_LockTID = AccessPermType.NoChange;
            m_LockUser = AccessPermType.NoChange;

            m_strSelectionMask = "";

            m_strLastAddress = DEFAULT_DEVICE_ADDRESS;

        }
        #endregion

        private void MainFrame_Load(object sender, EventArgs e)
        {

            m_isEventBlock = false;

            // Initialize controls
            InitControls();

            // Get Serial Port
            GetSerialPortName();

            // Load Configuration
            LoadConfig();

            // get SDK version
            lblSdkVersion.Text = Reader.GetSDKVersion();

            // Init controls enable
            EnableControl();

        }
        private void MainFrame_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (m_Reader != null)
            {
                if (m_Reader.GetState() == (int)AT288Lib.Net.CommandType.Busy)
                {
                    e.Cancel = true;
                    return;
                }

                //if (m_Reader.IsAction())
                m_Reader.StopOperation();
                m_Reader.Close();
                m_Reader = null;
            }

            // Save Configuration
            SaveConfig();
        }

        private void MainFrame_Resize(object sender, EventArgs e)
        {
            // Initialize Tag List 
            int w = lstTags.ClientSize.Width;
            lstTags.Columns[1].Width = w - 207;
        }

        private void cbPort_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnOpen.Enabled = cbPort.SelectedIndex >= 0;
            // Save Configuration
            SaveConfig();
        }




        private void btnOpen_Click(object sender, EventArgs e)
        {
            lblFwVersion.Text = string.Empty;
            lblDeviceFirmware.Text = string.Empty;

            string portName = cbPort.Text;
            cbPort.Enabled = btnOpen.Enabled = false;

            m_Reader = new Reader();
            m_Reader.Action += m_fnAction;
            m_Reader.Response += m_fnResponse;
            m_Reader.ReadTag += m_fnReadTag;
            m_Reader.Property += m_fnProperty;
            m_Reader.PropertyEx += m_fnPropertyEx;

            // Open Reader
            if (!m_Reader.Open(portName, 115200))
            {

                m_Reader.Action -= m_fnAction;
                m_Reader.Response -= m_fnResponse;
                m_Reader.ReadTag -= m_fnReadTag;
                m_Reader.Property -= m_fnProperty;
                m_Reader.PropertyEx -= m_fnPropertyEx;
                m_Reader.Close();
                m_Reader = null;

                OutputMessage("Open reader ({0}, 115200) Failed...", portName);
                cbPort.Enabled = btnOpen.Enabled = true;
                EnableControl();

                return;
            }
            OutputMessage("Open reader ({0}, 115200) OK!!!", portName);

            EnableControl();

            
            lblResult.Text = "";
            //lblValue.Text = "";
            txtValue.Text = "";
            lblTagCount.Text = "0";
            btnClose.Focus();

        }

        private void btnClose_Click(object sender, EventArgs e)
        {

            if (m_Reader != null)
            {
                if (!m_Reader.IsOpened) return;

                // Close Reader
                // if (m_Reader.IsAction())
                m_Reader.StopOperation();

                m_Reader.Action -= m_fnAction;
                m_Reader.Response -= m_fnResponse;
                m_Reader.ReadTag -= m_fnReadTag;
                m_Reader.Property -= m_fnProperty;
                m_Reader.PropertyEx -= m_fnPropertyEx;
                m_Reader.Close();
                m_Reader = null;
                m_strSelectionMask = "";
                OutputMessage("Close() reader OK!!!");
            }

            EnableControl();
            lblMask.Text = "";
            lblResult.Text = "";
            //lblValue.Text = "";
            txtValue.Text = "";
            lblTagCount.Text = "0";
            btnOpen.Focus();

        }

        private void btnInventory_Click(object sender, EventArgs e)
        {
            // Start Inventory...
            if (m_strSelectionMask != "")
            {
                if (m_Reader.Inventory(m_strSelectionMask))
                    OutputMessage("Start Invenotry({0}) OK!!!", m_strSelectionMask);
                else
                    OutputMessage("Start Inventory({0}) Failed...", m_strSelectionMask);
            }
            else
            {
                if (m_Reader.Inventory())
                    OutputMessage("Start Invenotry OK!!!");
                else
                    OutputMessage("Start Inventory Failed...");
            }
            EnableControl();
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            bInventoryMemory = false;
            // Stop Operation
            m_Reader.StopOperation();
            EnableControl();
        }

        private void btnStoredInventory_Click(object sender, EventArgs e)
        {
            ClearTagList();
            // Get Stored Inventory List
            if (m_Reader.RequestStoredInventoryList())
            {
                m_isLoadingStoredTags = true;
                OutputMessage("Request Stored Inventory List OK!!!");
                OutputMessage("Waits for the job to finish...");
            }
            else
                OutputMessage("Request Stored Inventory List Failed...");
            EnableControl();
        }

        private void btnRemoveStoredInventory_Click(object sender, EventArgs e)
        {
            if (m_isLoadingStoredTags)
                return;

            ClearTagList();
            //Cursor.Current = Cursors.WaitCursor;
            // Remove Stored Inventory List
            if (m_Reader.RemoveStoredInventoryList())
            {
                OutputMessage("Remove Stored Inventory List OK!!!");
                OutputMessage("Waits for the job to finish...");
            }
            else
                OutputMessage("Remove Stored Inventory List Failed...");
            //Cursor.Current = Cursors.Default;
            EnableControl();
        }

        private void btnReadMemory_Click(object sender, EventArgs e)
        {
            ReadMemoryDialog dlg = new ReadMemoryDialog();
            
            dlg.Bank = m_ReadBank;
            dlg.Offset = m_nReadOffset;
            dlg.Length = m_nReadLength;
            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                m_ReadBank = dlg.Bank;
                m_nReadOffset = dlg.Offset;
                m_nReadLength = dlg.Length;

                // read memory
                if (m_strSelectionMask != "")
                {
                    if (m_Reader.ReadMemory(m_ReadBank, m_nReadOffset, m_nReadLength, m_strSelectionMask))
                        OutputMessage("Read Memory({0}) OK!!!", m_strSelectionMask);
                    else
                        OutputMessage("Read Memory({0}) Failed...", m_strSelectionMask);
                }
                else
                {
                    if (m_Reader.ReadMemory(m_ReadBank, m_nReadOffset, m_nReadLength))
                        OutputMessage("Read Memory OK!!!");
                    else
                        OutputMessage("Read Memory Failed...");
                }
                EnableControl();
            }
        }

        private void btnWriteMemory_Click(object sender, EventArgs e)
        {
            WriteMemoryDialog dlg = new WriteMemoryDialog();

            dlg.Bank = m_WriteBank;
            dlg.Offset = m_nWriteOffset;
            dlg.Value = m_strWriteValue;

            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                m_WriteBank = dlg.Bank;
                m_nWriteOffset = dlg.Offset;
                m_strWriteValue = dlg.Value;

                // write memory
                if (m_strSelectionMask != "")
                {
                    if (m_Reader.WriteMemory(m_WriteBank, m_nWriteOffset, m_strWriteValue, m_strSelectionMask))
                        OutputMessage("Write Memory({0}) OK!!!", m_strSelectionMask);
                    else
                        OutputMessage("Write Memory({0}) Failed", m_strSelectionMask);
                }
                else
                {
                    if (m_Reader.WriteMemory(m_WriteBank, m_nWriteOffset, m_strWriteValue))
                        OutputMessage("Write Memory OK!!!");
                    else
                        OutputMessage("Write Memory Failed");
                }
                EnableControl();
            }

        }

        private void btnLockTag_Click(object sender, EventArgs e)
        {
            LockTagDialog dlg = new LockTagDialog();

            dlg.KillPassword = m_LockKillPassword;
            dlg.AccessPassword = m_LockAccessPassword;
            dlg.EPC = m_LockEPC;
            dlg.TID = m_LockTID;
            dlg.User = m_LockUser;
            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                m_LockKillPassword = dlg.KillPassword;
                m_LockAccessPassword = dlg.AccessPassword;
                m_LockEPC = dlg.EPC;
                m_LockTID = dlg.TID;
                m_LockUser = dlg.User;

                // lock memory
                if (m_strSelectionMask != "")
                {
                    if (m_Reader.Lock(m_LockKillPassword, m_LockAccessPassword,
                        m_LockEPC, m_LockTID, m_LockUser, m_strSelectionMask))
                    {
                        OutputMessage("Lock ({0}, {1}, {2}, {3}, {4}, {5}) OK!!!",
                            m_LockKillPassword, m_LockAccessPassword,
                            m_LockEPC, m_LockTID, m_LockUser, m_strSelectionMask);
                    }
                    else
                    {
                        OutputMessage("Lock ({0}, {1}, {2}, {3}, {4}, {5}) Failed...",
                            m_LockKillPassword, m_LockAccessPassword,
                            m_LockEPC, m_LockTID, m_LockUser, m_strSelectionMask);
                    }
                }
                else
                {
                    if (m_Reader.Lock(m_LockKillPassword, m_LockAccessPassword,
                        m_LockEPC, m_LockTID, m_LockUser))
                    {
                        OutputMessage("Lock ({0}, {1}, {2}, {3}, {4}) OK!!!",
                            m_LockKillPassword, m_LockAccessPassword,
                            m_LockEPC, m_LockTID, m_LockUser);
                    }
                    else
                    {
                        OutputMessage("Lock ({0}, {1}, {2}, {3}, {4}) Failed...",
                            m_LockKillPassword, m_LockAccessPassword,
                            m_LockEPC, m_LockTID, m_LockUser);
                    }
                }
                EnableControl();

            }
        }

        private void btnKillTag_Click(object sender, EventArgs e)
        {
            KillPasswordDialog dlg = new KillPasswordDialog();

            dlg.Title = "Kill Password";
            dlg.Password = null;
            if (dlg.ShowDialog(this) == DialogResult.OK) {
                if (m_Reader != null)
                {
                    if (dlg.Password == "") return;

                    if (m_strSelectionMask != "")
                    {
                        if(m_Reader.Kill(dlg.Password, m_strSelectionMask)){
                            OutputMessage("Kill Tag OK!!!");
                        }
                        else OutputMessage("Kill Tag Failed...");
                    }
                    else
                    {
                        if (m_Reader.Kill(dlg.Password))
                        {
                            OutputMessage("Kill Tag OK!!!");
                        }
                        else OutputMessage("Kill Tag Failed...");
                    }
                }
                EnableControl();
            }

        }


        private void btnClear_Click(object sender, EventArgs e)
        {
            ClearTagList();
            ClearResult();
            //lblValue.Text = "";
            txtValue.Text = "";
            lstOutput.Items.Clear();
        }

        private void btnAccessPassword_Click(object sender, EventArgs e)
        {
            PasswordDialog dlg = new PasswordDialog();

            dlg.Title = "Access Password";
            dlg.Password = m_Reader.GetAccessPassword();

            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                //2015.10.21 USB, Bluetooth 연결이 끊어져도 실행이되서 애러남
                if (m_Reader != null)
                {
                    m_Reader.SetAccessPassword(dlg.Password);
                    m_Reader.RequestAccessPassword();
                }

                lstOutput.Focus();
            }
        }

        private void btnSelectionMask_Click(object sender, EventArgs e)
        {
            SelectionMaskDialog dlg = new SelectionMaskDialog();

            dlg.Bank = m_Reader.GetSelectionBank();
            dlg.Offset = (int)(m_Reader.GetSelectionOffset() / 16);
            dlg.Mask = m_strSelectionMask;
            dlg.Action = m_Reader.GetSelectionAction();

            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                if (m_Reader != null)
                {
                    m_Reader.SetSelectionBank(dlg.Bank);
                    m_Reader.SetSelectionOffset(dlg.Offset * 16);
                    m_strSelectionMask = dlg.Mask;
                    m_Reader.SetSelectionAction(dlg.Action);

                    m_Reader.RequestSelectionBank();
                    m_Reader.RequestSelectionOffset();
                    lblMask.Text = m_strSelectionMask;
                    m_Reader.RequestSelectionAction();
                }

                lstOutput.Focus();
            }

        }

        private void chkStoredMode_CheckedChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            // Set Storead Mode
            if (m_Reader.SetStoredMode(chkStoredMode.Checked))
                OutputMessage("Set Stored Mode({0}) OK!!!", chkStoredMode.Checked);
            else
                OutputMessage("Set Stored Mode({0}) Failed...", chkStoredMode.Checked);
        }

        private void cbShowSerialNo_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;
            if (m_Reader.setInventoryFormat(cbShowSerialNo.SelectedIndex))
                OutputMessage("Set PC/EPC/SERIAL({0}) OK!!!", cbShowSerialNo.SelectedIndex);
            else
                OutputMessage("Set PC/EPC/SERIAL({0}) Failed!!!...", cbShowSerialNo.SelectedIndex);
        }


        private void cbTagType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            // Set Tag Type
            if (m_Reader.SetTagType(cbTagType.SelectedIndex == 0 ? TagType.ISO18000_6C_GEN2 : TagType.ISO18000_6B))
                OutputMessage("Set Tag Type({0}) OK!!!", (TagType)cbTagType.SelectedIndex);
            else
                OutputMessage("Set Tag Type({0}) Failed...", (TagType)cbTagType.SelectedIndex);
        }

        private void cbInventoryMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            // Set Inventory Mode
            if (m_Reader.SetInventoryType((InventoryType)cbInventoryMode.SelectedIndex))
                OutputMessage("Set Inventory Mode({0}) OK!!!", (InventoryType)cbInventoryMode.SelectedIndex);
            else
                OutputMessage("Set Inventory Mode({0}) Failed...", (InventoryType)cbInventoryMode.SelectedIndex);
            
        }

        private void cbPower_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            // Set Power Gain
            if (m_Reader.SetPowerEx(cbPower.SelectedIndex))
                OutputMessage("Set PowerEx({0}) OK!!!", cbPower.SelectedIndex);
            else
                OutputMessage("Set PowerEx({0}) Failed...", cbPower.SelectedIndex);
        }

        private void cbSwitchingTime_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            // Set Antenna Switching Time
            int value = Convert.ToInt32(cbSwitchingTime.Text);
            if (m_Reader.SetAntennaSwitchingTime(value))
                OutputMessage("Set Antenna Switching Time({0}) OK!!!", value);
            else
                OutputMessage("Set Antenna Switching Time({0}) Failed...", value);
        }

        private void cbSleepTime_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            // Set Antenna Idle Time
            int value = Convert.ToInt32(cbSleepTime.Text);
            if (m_Reader.SetAntennaIdleTime(value))
                OutputMessage("Set Antenna Idle Time({0}) OK!!!", value);
            else
                OutputMessage("Set Antenna Idle Time({0}) Failed...", value);
        }

        private void cbConnectionType_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            // Set Connection Type
            if (m_Reader.SetConnectionType(cbConnectionType.SelectedIndex == 0 ? ConnectType.Bluetooth : ConnectType.USB))
                OutputMessage("Set Connection Type({0}) OK!!!", (ConnectType)cbConnectionType.SelectedIndex);
            else
                OutputMessage("Set Connection Type({0}) Failed...", (ConnectType)cbConnectionType.SelectedIndex);
        }

        private void btnLBTChannel_Click(object sender, EventArgs e)
        {
            LBTChannelDialog dlg = new LBTChannelDialog();
            dlg.LBTChannel = m_Reader.GetLBTChannel();
            OutputMessage("Get LBT Channel - [{0}]", dlg.LBTChannel);

            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                if (m_Reader.SetLBTChannel(dlg.LBTChannel))
                    OutputMessage("Set LBT Channel({0}) OK!!!", dlg.LBTChannel);
                else
                    OutputMessage("Set LBT Channel({0}) Failed...", dlg.LBTChannel);
            }
        }

        private void btnDefault_Click(object sender, EventArgs e)
        {
            btnDefault.Enabled = false;
            // Set Default...
            if (m_Reader.SetDefault())
                OutputMessage("Set Default() OK!!!");
            else
                OutputMessage("Set Default() Failed...");
            m_strSelectionMask = "";
            // Request Properties...
            RequestInitProperty();
            btnDefault.Enabled = true;
        }

        private void lstTags_RetrieveVirtualItem(object sender, RetrieveVirtualItemEventArgs e)
        {
            int index = 0;
            if (m_lstCache != null && e.ItemIndex >= m_nFirstItem && e.ItemIndex < m_nFirstItem + m_lstCache.Length)
            {
                index = e.ItemIndex - m_nFirstItem;
                e.Item = m_lstCache[index];
                e.Item.SubItems[1].Text = m_lstTags[e.ItemIndex].SerialNo;
                e.Item.SubItems[2].Text = m_lstTags[e.ItemIndex].Value;
                e.Item.SubItems[3].Text = m_lstTags[e.ItemIndex].Count.ToString();
            }
            else
            {
                index = e.ItemIndex;
                e.Item = new ListViewItem(new string[]
                {
                    String.Format("{0}", index+1),
                    //m_lstTags[index].Index.ToString(),
                    m_lstTags[index].SerialNo,
                    m_lstTags[index].Value,
                    m_lstTags[index].Count.ToString()
                });
            }

        }

        private void lstTags_CacheVirtualItems(object sender, CacheVirtualItemsEventArgs e)
        {
            if (m_lstCache != null && e.StartIndex >= m_nFirstItem && e.EndIndex <= m_nFirstItem + m_lstCache.Length)
            {
                return;
            }

            m_nFirstItem = e.StartIndex;
            int length = e.EndIndex - e.StartIndex + 1;
            m_lstCache = new ListViewItem[length];

            int index;

            for (int i = 0; i < length; i++)
            {
                index = m_nFirstItem + i;
                m_lstCache[i] = new ListViewItem(new string[]
                {
                    String.Format("{0}", index+1),
                    m_lstTags[index].Index.ToString(),
                    m_lstTags[index].SerialNo,
                    m_lstTags[index].Value,
                    m_lstTags[index].Count.ToString()
                });
            }
        }

        private void lstTags_SizeChanged(object sender, EventArgs e)
        {
            ResizeTagList();
        }

        private void Reader_Action(object sender, ActionEventArgs e)
        {
            if (InvokeRequired)
            {
                BeginInvoke(m_fnAction, sender, e);
                return;
            }

            switch (e.Command)
            {

                case AT288Lib.Net.CommandType.Connected:
                    // Activate reader...
                    if (!m_Reader.Activate())
                    {
                        OutputMessage("Activate Reader failed....");
                        break;
                    }
                    OutputMessage("Activate Reader OK!!!");
                    InitPowerGain();
                    break;
                case AT288Lib.Net.CommandType.Activate:
                    // request reader properties...
                    RequestInitProperty();
                    break;
                case AT288Lib.Net.CommandType.Inventory6BMultiple:
                case AT288Lib.Net.CommandType.Inventory6BSingle:
                case AT288Lib.Net.CommandType.Inventory6CMultiple:
                case AT288Lib.Net.CommandType.Inventory6CSingle:
                case AT288Lib.Net.CommandType.InventoryMemory:
                case AT288Lib.Net.CommandType.InventorySelect:
                    if(!m_isLoadingStoredTags)
                        ClearTagList();
                    break;
                case AT288Lib.Net.CommandType.ReadMemory:
                    ClearResult();
                    //lblValue.Text = "";
                    txtValue.Text = "";
                    break;
                case AT288Lib.Net.CommandType.WriteMemory:
                case AT288Lib.Net.CommandType.LockTag:
                case AT288Lib.Net.CommandType.KillTag:
                    ClearResult();
                    break;
            }
            OutputMessage("EVENT. Action : {0}", e.Command);

            EnableControl();
        }

        private void Reader_Response(object sender, ResponseEventArgs e)
        {
            if (InvokeRequired)
            {
                BeginInvoke(m_fnResponse, sender, e);
                return;
            }

            //if (!bInventoryMemory)
            //{
                OutputMessage("EVENT. Response : {0}, {1}", e.Code, e.Message);

                lblResult.Text = e.Message;
                lblResult.BackColor = e.Code == 1 ? Color.Blue : Color.Red;
                EnableControl();

                //m_Reader.StopOperation();
            //}
        }


        private void Reader_ReadTag(object sender, ReadTagEventArgs e)
        {
            if (InvokeRequired)
            {
                BeginInvoke(m_fnReadTag, sender, e);
                return;
            }

            OutputMessage("EVENT. Read Tag : {0}, {1}, {2}", e.State, e.SerialNo, e.TagValue);
            if (e.State == AT288Lib.Net.CommandType.ReadMemory)
            {
                StringBuilder value = new StringBuilder();
                for (int i = 0; i < e.TagValue.Length; i += 4)
                {
                    if (e.TagValue.Length - i < 4)
                        value.Append(e.TagValue.Substring(i));
                    else
                        value.Append(e.TagValue.Substring(i, 4));
                    value.Append(" ");
                }

                //lblValue.Text = value.ToString();
                txtValue.Text = value.ToString();
                lblResult.Text = Reader.GetResponseMessage(1);
                lblResult.BackColor = Color.Blue;
                EnableControl();
                //m_Reader.StopOperation();
            }
            else
            {
                TagItem item;
                if (m_mapTags.ContainsKey(e.TagValue))
                {
                    item = m_mapTags[e.TagValue];
                    lock (m_lstTags)
                    {
                        item.Increase();
                        //if (!chkContinueMode.Checked)
                        //{
                            int index = m_lstTags.IndexOf(item);
                            lstTags.RedrawItems(index, index, false);
                        //}
                    }
                }
                else
                {
                    item = new TagItem(e.SerialNo, e.TagValue);
                    lock (m_lstTags)
                    {
                        m_mapTags.Add(e.TagValue, item);
                        m_lstTags.Add(item);
                       // if (!chkContinueMode.Checked)
                        //{
                            lstTags.VirtualListSize = m_mapTags.Count;
                            lblTagCount.Text = m_mapTags.Count.ToString();
                        //}
                    }
                }             
            }
        }

        private void Reader_Property(object sender, PropertyEventArgs e)
        {

            if (InvokeRequired)
            {
                BeginInvoke(m_fnProperty, sender, e);
                return;
            }

            switch (e.Property)
            {
                case PropertyType.Version:
                    lblFwVersion.Text = e.String;
                    OutputMessage("EVENT. Property Version : {0}", e.String);
                    if (m_Reader.IsUsedSerialNo())
                    {
                        m_Reader.RequestSerialNo();
                        m_Reader.RequestNationalCode();
                    }
                    break;
                case PropertyType.ContinuousMode:
                    OutputMessage("EVENT. Property Continue Mode : {0}", e.Enabled);
                    break;
                case PropertyType.AntennaSwitchingTime:
                    m_isEventBlock = true;
                    Util.SetComboBoxInteger(cbSwitchingTime, e.Value);
                    m_isEventBlock = false;
                    OutputMessage("EVENT. Property Antenna Switching Time : {0}", e.Value);
                    break;
                case PropertyType.PowerGain:
                    m_isEventBlock = true;
                    cbPower.SelectedIndex = e.Value;
                    m_isEventBlock = false;
                    OutputMessage("EVENT. Property Power Gain : {0}", e.Value);
                    break;
                case PropertyType.StartQValue:
                    OutputMessage("EVENT. Property Start Q Value : {0}", e.Value);
                    break;
                case PropertyType.PowerIdleTime:
                    m_isEventBlock = true;
                    int value = e.Value < 10 ? 10 : e.Value;
                    Util.SetComboBoxInteger(cbSleepTime, value);
                    m_isEventBlock = false;
                    OutputMessage("EVENT. Property Power Idle Time : {0}", e.Value);
                    break;
                case PropertyType.Baudrate:
                    OutputMessage("EVENT. Property Baudrate : {0}", e.BaudRate);
                    break;
                case PropertyType.RepeatTagReportTime:
                    OutputMessage("EVENT. Property Repeat Tag Report Time : {0}", e.Value);
                    break;
                case PropertyType.MinQValue:
                    OutputMessage("EVENT. Property Min Q Value : {0}", e.Value);
                    break;
                case PropertyType.MaxQValue:
                    OutputMessage("EVENT. Property Max Q Value : {0}", e.Value);
                    break;
                case PropertyType.GlobalBand:
                    lblGlobalBand.Text = GetGlobalBand(e.GlobalBand);
                    OutputMessage("EVENT. Property Global Band : {0}", e.GlobalBand);
                    break;
                case PropertyType.SelectBank:
                    lblBank.Text = Util.GetMemoryTypeString(e.MemoryType);
                    OutputMessage("EVENT. Property Selection Bank : {0}", e.MemoryType);
                    break;
                case PropertyType.SelectOffset:
                    lblOffset.Text = String.Format("{0} word", e.Value / 16);
                    OutputMessage("EVENT. Property Selection Offset : {0}", e.Value / 16);
                    break;
                case PropertyType.SelectAction:
                    lblAction.Text = Util.GetSelectionActionTypeString(e.SelectionAction);
                    OutputMessage("EVENT. Property Selection Action : {0}", e.SelectionAction);
                    break;
                case PropertyType.SelectSession:
                    OutputMessage("EVENT. Property Selection Session : {0}", e.SelectionSession);
                    break;
                case PropertyType.PacketOption:
                    OutputMessage("EVENT. Property Packet Option : {0}", e.Value);
                    break;
                case PropertyType.AccessPassword:
                    lblAccessPassword.Text = e.String;
                    OutputMessage("EVENT. Property Access Password : {0}", e.String);
                    break;
                case PropertyType.Buzzer:
                    m_isEventBlock = true;
                    cbBeepMode.SelectedIndex = e.Value;
                    m_isEventBlock = false;
                    OutputMessage("EVENT. Property Buzzer : {0}", e.Value);
                    break;
                case PropertyType.AutoPowerOff:
                    m_isEventBlock = true;
                    Util.SetComboBoxInteger(cbAutoPowerOff, e.Value);
                    m_isEventBlock = false;
                    OutputMessage("EVENT. Property AutoPowerOff : {0}", e.Value);
                    break;
            }
        }

        private void Reader_PropertyEx(object sender, PropertyExEventArgs e)
        {
            if (InvokeRequired)
            {
                BeginInvoke(m_fnPropertyEx, sender, e);
                return;
            }

            switch (e.Property)
            {
                case PropertyExType.Power:
                    EnableControl();
                    OutputMessage("EVENT. PropertyEx Power : {0}", e.Enabled);
                    break;
                case PropertyExType.PowerGain:
                    m_isEventBlock = true;
                    cbPower.SelectedIndex = e.Value;
                    m_isEventBlock = false;
                    OutputMessage("EVENT. PropertyEx Power Gain : {0}", e.Value);
                    break;
                case PropertyExType.TagType:
                    m_isEventBlock = true;
                    cbTagType.SelectedIndex = e.TagType == TagType.ISO18000_6B ? 1 : 0;
                    m_isEventBlock = false;
                    ATrace.WriteLine("count ::::::::::::::::::::::::::::::::::::" + cbInventoryMode.Items.Count);
                    if (m_Reader.IsAT288N_MA && m_Reader.TagType == TagType.ISO18000_6B)
                    {
                        cbShowSerialNo.Items.Clear();
                        cbShowSerialNo.Items.Add(AT288N_MA_INVENTORY_FORMAT_0);
                        cbShowSerialNo.Items.Add(AT288N_MA_INVENTORY_FORMAT_1);
                    }
                    else
                    {
                        cbShowSerialNo.Items.Clear();
                        cbShowSerialNo.Items.Add(AT288N_INVENTORY_FORMAT_0);
                        cbShowSerialNo.Items.Add(AT288N_INVENTORY_FORMAT_1);
                        cbShowSerialNo.Items.Add(AT288N_INVENTORY_FORMAT_2);
                        cbShowSerialNo.Items.Add(AT288N_INVENTORY_FORMAT_3);
                    }
                    m_Reader.setInventoryFormat(0);
                    EnableControl();
                    OutputMessage("EVENT. PropertyEx Tag Type : {0}", e.TagType);
                    break;
                case PropertyExType.ConnectType:
                    m_isEventBlock = true;
                    cbConnectionType.SelectedIndex = e.Connection == ConnectType.Bluetooth ? 0 : 1;
                    m_isEventBlock = false;
                    EnableControl();
                    OutputMessage("EVENT. PropertyEx Connect Type : {0}", e.Connection);
                    break;
                case PropertyExType.InventoryMode:
                    m_isEventBlock = true;
                    cbInventoryMode.SelectedIndex = (int)e.Inventory;
                    m_isEventBlock = false;
                    OutputMessage("EVENT. PropertyEx Inventory Mode : {0}", e.Inventory);
                    break;
                case PropertyExType.StoredMode:
                    m_isEventBlock = true;
                    chkStoredMode.Checked = e.Enabled;
                    m_isEventBlock = false;
                    OutputMessage("EVENT. PropertyEx Stored Mode : {0}", e.Enabled);
                    break;
                case PropertyExType.GetStoredData:
                    EnableControl();
                    m_isLoadingStoredTags = false;
                    OutputMessage("EVENT. PropertyEx Get Stored Data : {0}", e.Value);
                    break;
                case PropertyExType.DelStoredData:
                    EnableControl();
                    OutputMessage("EVENT. PropertyEx Delete Stored Data : {0}", e.Value);
                    break;
                case PropertyExType.ShowSeiralNo:
                    m_isEventBlock = true;
                    cbShowSerialNo.SelectedIndex = e.Value;
                    m_isEventBlock = false;
                    EnableControl();
                    OutputMessage("EVENT. PropertyEx Shwo Serial No : {0}", e.Value);
                    break;
                case PropertyExType.SerialNo:
                    lblSerialNo.Text = e.String;
                    EnableControl();
                    OutputMessage("EVENT. PropertyEx Serial No : {0}", e.String);
                    break;
                case PropertyExType.DeviceVersion:
                    lblDeviceFirmware.Text = e.String;
                    initInventoryTime();
                    //EnableControl();
                    m_Reader.RequestAutoPowerOff(); //AT288N Only Supported
                    if (m_Reader.IsAT288N)
                    {
                        if (m_Reader.IsAT288N_MA)
                        {
                            //AT288N MA Not Supported
                            btnReadMemory.Enabled =
                            btnWriteMemory.Enabled =
                            btnLockTag.Enabled =
                            btnInventoryMemory.Enabled =
                            btnAccessPassword.Enabled =
                            lblAccessPasswordLabel.Enabled =
                            lblAccessPassword.Enabled =
                            btnKillTag.Enabled =
                            grpSelectionMask.Enabled =
                            false;

                            if (cbInventoryMode.Items.Count >= 3)
                            {
                                cbInventoryMode.Items.RemoveAt(2); //AT288N Only InventoryMode :Filter Added
                            }

                            lblTagType.Enabled = true; //AT288N MA Only Supported
                            cbTagType.Enabled = true;  //AT288N MA Only Supported
                        }
                        else
                        {
                            if (!cbInventoryMode.Items.Contains("Filter"))
                                cbInventoryMode.Items.Add("Filter");

                            lblTagType.Enabled = false; //AT288N MA Only Supported
                            cbTagType.Enabled = false;  //AT288N MA Only Supported
                        }
                    }
                    else
                    {
                        if (cbInventoryMode.Items.Count >= 3)
                        {
                            cbInventoryMode.Items.RemoveAt(2); //AT288N Only InventoryMode :Filter Added
                        }
                        btnInventoryMemory.Enabled = false;
                    }

                    OutputMessage("EVENT. PropertyEx Device Version : {0} {1}", e.String, m_Reader.IsAT288N);
                    break;
                case PropertyExType.BatteryState:
                    String strData = e.Value == 0 ? "High" : "Low";
                    MessageBox.Show(strData, "Battery state");
                    break;
                
            }
        }

        // Request Init Property
        private void RequestInitProperty()
        {       
            m_Reader.RequestDeviceVersion();//2014.07.04 munhg
            m_Reader.RequestGlobalBand();

            lblMask.Text = m_strSelectionMask;
            m_Reader.SetSelectionAction(SelectionActionType.Matching);
            m_Reader.SetSelectionBank(MemoryType.EPC);
            m_Reader.SetSelectionOffset(16);

            //// Request continue mode        
            // if m_Reader.IsAT288N_MA is true, this is not supported.
            if (m_Reader.RequestContinueMode()) OutputMessage("Request continue mode OK!!!");
            else OutputMessage("Request continue mode Failed...");


            //// Request antenna switching time     
            if (m_Reader.RequestAntennaSwitchingTime()) OutputMessage("Request antenna switching time OK!!!");
            else OutputMessage("Request antenna switching time Failed...");


            //// Request antenna idle time
            if (m_Reader.RequestAntennaIdleTime()) OutputMessage("Request antenna idle time OK!!!");
            else OutputMessage("Request antenna idle time Failed...");


            //// Request global band
            if (m_Reader.RequestGlobalBand()) OutputMessage("Request global band OK!!!");
            else OutputMessage("Request global band Failed...");


            //// Request access password           
            if (m_Reader.RequestAccessPassword()) OutputMessage("Request access password OK!!!");
            else OutputMessage("Request access password Failed...");


            //// Request selection bank        
            if (m_Reader.RequestSelectionBank()) OutputMessage("Request selection bank OK!!!");
            else OutputMessage("Request selection bank Failed...");

            //// Request selection offset            
            if (m_Reader.RequestSelectionOffset()) OutputMessage("Request selection offset OK!!!");
            else OutputMessage("Request selection offset Failed...");

            //// Request selection action         
            if (m_Reader.RequestSelectionAction()) OutputMessage("Request selection action OK!!!");
            else OutputMessage("Request selection action Failed...");

            if (m_Reader.RequestBuzzer()) OutputMessage("Request Buzzer OK!!!");
            else OutputMessage("Request Buzzer Failed...");

            m_Reader.RequestAllPropertyEx();//2014.07.04 munhg         
            

        }

        // Get Serial Port
        private void GetSerialPortName()
        {
            ManagementObjectCollection ManObjReturn = null;
            ManagementObjectSearcher ManObjSearch = null;

            cbPort.Items.Clear();

            try
            {
                Cursor.Current = Cursors.WaitCursor;
                ManObjSearch = new ManagementObjectSearcher("root\\CIMV2", "Select * from Win32_PnPEntity WHERE ConfigManagerErrorCode = 0");
                ManObjReturn = ManObjSearch.Get();

                foreach (ManagementObject ManObj in ManObjReturn)
                {
                    Object obj = ManObj["Name"];
                    if (obj == null)
                        continue;

                    string msg = (string)obj;
                    if (msg.Contains("(COM"))
                    {
                        msg = (string)ManObj["Name"];
                        msg = msg.Substring(msg.LastIndexOf("(COM"));
                        msg = msg.Replace("(", string.Empty);
                        msg = msg.Replace(")", string.Empty);
                        if (!cbPort.Items.Contains(msg))
                            cbPort.Items.Add(msg);
                    }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
            finally
            {
                if(ManObjReturn != null)
                    ManObjReturn.Dispose();

                if(ManObjSearch != null)
                    ManObjSearch.Dispose();

                Cursor.Current = Cursors.Default;
            }
        }
        //private void GetSerialPortName()
        //{
        //    // Initialize Port ComboBox
        //    cbPort.Items.Clear();
        //    string[] portNames = SerialPort.GetPortNames();
        //    int length = 0;
        //    string port = null;
        //    char portNum;

        //    // 2015.10.20 노트북과 직접 Bluetooth 연결시 이름 잘못와서 자름
        //    foreach (string portName in portNames)
        //    {
        //        length = portName.Length;
        //        portNum = Convert.ToChar(portName.Substring(length - 1, 1));
        //        int portNums = Convert.ToInt32(portNum);
        //        if (portNums < 48 || portNums > 57)
        //        {
        //            port = portName.Substring(0, length - 1);
        //        }
        //        else
        //        {
        //            port = portName;
        //        }
        //        cbPort.Items.Add(port);
        //    }
        //}

        private void InitControls()
        {
            int i = 0;
            // Initialize Application Title
            string version = Assembly.GetExecutingAssembly().GetName().Version.ToString();
            this.Text = string.Format("AT288N Demo.Net Version {0}", version);

            // Initialize Power ComboBox
            cbPower.Items.Clear();
            for (i = 30; i >= 11; i--)
                cbPower.Items.Add(i.ToString());
        }

        private void InitPowerGain()
        {
            ModelType modelType = m_Reader.GetModelType();

            cbPower.Items.Clear();
            if (modelType == ModelType.AT288Japan)
            {
                for (int i = 24; i >= 5; i--)
                    cbPower.Items.Add(i.ToString());
            }
            else
            {
                for (int i = 30; i >= 11; i--)
                    cbPower.Items.Add(i.ToString());
            }
        }

        private void initInventoryTime()
        {
            cbSwitchingTime.Items.Clear();
            foreach (int timeValue in m_OnTimeValues)
            {
                if (m_Reader.IsAT288N_MA && timeValue > 400)
                    continue;
                else
                    cbSwitchingTime.Items.Add(timeValue.ToString());
            }
            cbSleepTime.Items.Clear();
            foreach (int timeValue in m_OffTimeValues)
            {
                if (m_Reader.IsAT288N_MA && timeValue > 1000)
                    continue;
                else
                    cbSleepTime.Items.Add(timeValue.ToString());
            }
        }

        #region Enable Control
        // Enabled Controls
        private void EnableControl()
        {
            #region m_Reader is null
            //OutputMessage("EnableControl");
            if (m_Reader == null)
            {
                lblSdkVersionLabel.Enabled =
                    lblSdkVersion.Enabled =
                    lblFwVersionLabel.Enabled =
                    lblFwVersion.Enabled =
                    lblDeviceFirmware_Label.Enabled =
                    lblDeviceFirmware.Enabled =
                    lblSerialNoLabel.Enabled =
                    lblSerialNo.Enabled =
                    btnClose.Enabled =
                    btnInventory.Enabled =
                    btnInventoryMemory.Enabled =
                    btnStop.Enabled =
                    chkStoredMode.Enabled =
                    btnStoredInventory.Enabled =
                    btnRemoveStoredInventory.Enabled =
                    btnReadMemory.Enabled =
                    btnWriteMemory.Enabled =
                    btnLockTag.Enabled =
                    btnClear.Enabled =
                    btnBattery.Enabled =
                    btnAccessPassword.Enabled =
                    lblAccessPasswordLabel.Enabled =
                    lblAccessPassword.Enabled =
                    grpProperties.Enabled =
                    btnKillTag.Enabled =
                    grpSelectionMask.Enabled = false;
                    cbPort.Enabled =
                    btnReSearch.Enabled =
                    //btBluetoothScan.Enabled = true;
                    
                    btnOpen.Enabled = true;
                return;
            }
            #endregion
            //OutputMessage("EnableControl, State:{0}", m_Reader.State);
            switch (m_Reader.State)
            {
                case AT288Lib.Net.CommandType.Disconnected:
                case AT288Lib.Net.CommandType.Timeout:
                    lblSdkVersionLabel.Enabled =
                    lblSdkVersion.Enabled =
                    lblFwVersionLabel.Enabled =
                    lblFwVersion.Enabled =
                    lblDeviceFirmware_Label.Enabled =
                    lblDeviceFirmware.Enabled =
                    lblSerialNoLabel.Enabled =
                    lblSerialNo.Enabled =
                    btnClose.Enabled =
                    btnInventory.Enabled =
                    btnInventoryMemory.Enabled =
                    btnStop.Enabled =
                    chkStoredMode.Enabled =
                    btnStoredInventory.Enabled =
                    btnRemoveStoredInventory.Enabled =
                    btnReadMemory.Enabled =
                    btnWriteMemory.Enabled =
                    btnLockTag.Enabled =
                    btnClear.Enabled =
                    btnAccessPassword.Enabled =
                    lblAccessPasswordLabel.Enabled =
                    lblAccessPassword.Enabled =
                    grpProperties.Enabled =
                    btnKillTag.Enabled =
                    grpSelectionMask.Enabled = false;
                    cbPort.Enabled =
                    btnReSearch.Enabled =
                    //btBluetoothScan.Enabled = true;
                    btnOpen.Enabled = true;
                    cbPort.Refresh();

                    break;
                case AT288Lib.Net.CommandType.Connected:
                case AT288Lib.Net.CommandType.Disconnecting:
                case AT288Lib.Net.CommandType.Connecting:
                    lblSdkVersionLabel.Enabled =
                    lblSdkVersion.Enabled =
                    lblFwVersionLabel.Enabled =
                    lblDeviceFirmware_Label.Enabled =
                    lblDeviceFirmware.Enabled =
                    lblFwVersion.Enabled =
                    lblSerialNoLabel.Enabled =
                    lblSerialNo.Enabled =
                    cbPort.Enabled =
                    btnReSearch.Enabled =
                    btnOpen.Enabled =
                    btnInventory.Enabled =
                    btnInventoryMemory.Enabled =
                    btnStop.Enabled =
                    chkStoredMode.Enabled =
                    btnStoredInventory.Enabled =
                    btnRemoveStoredInventory.Enabled =
                    btnReadMemory.Enabled =
                    btnWriteMemory.Enabled =
                    btnLockTag.Enabled =
                    btnClear.Enabled =
                    btnAccessPassword.Enabled =
                    lblAccessPasswordLabel.Enabled =
                    lblAccessPassword.Enabled =
                    grpProperties.Enabled =
                    btnKillTag.Enabled =
                    grpSelectionMask.Enabled = false;
                    //btBluetoothScan.Enabled = true;
                    btnClose.Enabled = true;

                    break;
                case AT288Lib.Net.CommandType.Activate:
                case AT288Lib.Net.CommandType.StopOperation:
                    lblSdkVersionLabel.Enabled =
                    lblSdkVersion.Enabled =
                    lblFwVersionLabel.Enabled =
                    lblFwVersion.Enabled =
                    lblDeviceFirmware_Label.Enabled =
                    lblDeviceFirmware.Enabled =
                    lblSerialNoLabel.Enabled =
                    lblSerialNo.Enabled =
                    btnClose.Enabled =
                    btnInventory.Enabled =
                    chkStoredMode.Enabled =
                    btnStoredInventory.Enabled =
                    btnRemoveStoredInventory.Enabled =
                    btnClear.Enabled =
                    btnBattery.Enabled =
                    grpProperties.Enabled = true;
                    if ((m_Reader != null) && (m_Reader.TagType != TagType.ISO18000_6B))
                    {   btnReadMemory.Enabled = 
                        btnWriteMemory.Enabled =
                        btnLockTag.Enabled =
                        btnAccessPassword.Enabled =
                        lblAccessPasswordLabel.Enabled =
                        lblAccessPassword.Enabled =
                        btnKillTag.Enabled =
                        grpSelectionMask.Enabled = true;
                    }
                    else {
                        btnReadMemory.Enabled =
                        btnWriteMemory.Enabled =
                        btnLockTag.Enabled =
                        btnAccessPassword.Enabled =
                        btnInventoryMemory.Enabled =
                        lblAccessPasswordLabel.Enabled =
                        lblAccessPassword.Enabled =
                        btnKillTag.Enabled =
                        grpSelectionMask.Enabled = false;
                    }

                    if (m_Reader != null && m_Reader.IsAT288N_MA)
                    {
                        btnInventoryMemory.Enabled =
                        btnKillTag.Enabled = false;
                    }
                    else
                    {
                        btnInventoryMemory.Enabled =
                        btnKillTag.Enabled = true;
                    }
                    cbPort.Enabled =
                    btnReSearch.Enabled =
                    btnOpen.Enabled =
                    btnStop.Enabled = false;
                    //btBluetoothScan.Enabled = false;

                    break;
                case AT288Lib.Net.CommandType.Inventory6BMultiple:
                case AT288Lib.Net.CommandType.Inventory6BSingle:
                case AT288Lib.Net.CommandType.Inventory6CMultiple:
                case AT288Lib.Net.CommandType.Inventory6CSingle:
                case AT288Lib.Net.CommandType.InventoryMemory:
                case AT288Lib.Net.CommandType.InventorySelect:
                case AT288Lib.Net.CommandType.ReadMemory:
                case AT288Lib.Net.CommandType.WriteMemory:
                case AT288Lib.Net.CommandType.LockTag:
                case AT288Lib.Net.CommandType.KillTag:
                    lblSdkVersionLabel.Enabled =
                    lblSdkVersion.Enabled =
                    lblFwVersionLabel.Enabled =
                    lblFwVersion.Enabled =
                    lblDeviceFirmware_Label.Enabled =
                    lblDeviceFirmware.Enabled =
                    lblSerialNoLabel.Enabled =
                    lblSerialNo.Enabled =
                    cbPort.Enabled =
                    btnReSearch.Enabled =
                    btnOpen.Enabled =
                    btnInventory.Enabled =
                    btnInventoryMemory.Enabled =
                    chkStoredMode.Enabled =
                    btnStoredInventory.Enabled =
                    btnRemoveStoredInventory.Enabled =
                    btnReadMemory.Enabled =
                    btnWriteMemory.Enabled =
                    btnLockTag.Enabled =
                    btnClear.Enabled =
                    btnAccessPassword.Enabled =
                    lblAccessPasswordLabel.Enabled =
                    lblAccessPassword.Enabled =
                    grpProperties.Enabled =
                    btnKillTag.Enabled =
                    grpSelectionMask.Enabled = false;
                    btnStop.Enabled =
                    btnClose.Enabled = true;
                    //btBluetoothScan.Enabled = false;
                    break;
                case AT288Lib.Net.CommandType.Busy:
                    lblSdkVersionLabel.Enabled =
                    lblSdkVersion.Enabled =
                    lblFwVersionLabel.Enabled =
                    lblFwVersion.Enabled =
                    lblDeviceFirmware_Label.Enabled =
                    lblDeviceFirmware.Enabled =
                    lblSerialNoLabel.Enabled =
                    lblSerialNo.Enabled =
                    cbPort.Enabled =
                    btnReSearch.Enabled =
                    btnOpen.Enabled =
                    btnInventory.Enabled =
                    btnInventoryMemory.Enabled =
                    chkStoredMode.Enabled =
                    btnStoredInventory.Enabled =
                    btnRemoveStoredInventory.Enabled =
                    btnReadMemory.Enabled =
                    btnWriteMemory.Enabled =
                    btnLockTag.Enabled =
                    btnClear.Enabled =
                    btnAccessPassword.Enabled =
                    lblAccessPasswordLabel.Enabled =
                    lblAccessPassword.Enabled =
                    grpProperties.Enabled =
                    btnKillTag.Enabled =
                    grpSelectionMask.Enabled =
                    btnStop.Enabled =
                    btnClose.Enabled = false;
                    break;
            }
            ResizeTagList();
            //lblNationalCodeLabel.Visible =
            //    lblNationalCode.Visible =
            //    lblSerialNoLabel.Visible =
            //    lblSerialNo.Visible =
            //   cbShowSerialNo.Enabled = m_Reader.IsUsedSerialNo();
            btnLBTChannel.Enabled = m_Reader.GetModelType() == ModelType.AT288Japan;

        }
        #endregion

        // Reszie Tag List Column
        private void ResizeTagList()
        {
            lstTags.BeginUpdate();

            if (cbShowSerialNo.SelectedIndex == 1 || cbShowSerialNo.SelectedIndex == 3) colSerialNo.Width = 160;
            else colSerialNo.Width = 0;
            colTag.Width = (lstTags.ClientSize.Width - 14) - (colNo.Width + colSerialNo.Width + colCount.Width);
            lstTags.EndUpdate();
        }

        // Clear Tag List
        private void ClearTagList()
        {
            //lstTags.VirtualListSize = 0;
            //m_lstTagItems = null;
            //m_lstTags.Clear();
            //lblTagCount.Text = "0";
            if(lstTags.VirtualListSize > 0)
                lstTags.EnsureVisible(0);

            m_mapTags.Clear();
            m_lstTags.Clear();
            m_lTotalCount = 0;
            lstTags.VirtualListSize = m_lstTags.Count;
            lblTagCount.Text = m_lstTags.Count.ToString();
            //lblTotalCount.Text = m_lTotalCount.ToString();
            m_lstCache = null;
            m_nFirstItem = -1;

        }

        // Clear Result
        private void ClearResult()
        {
            lblResult.Text = "";
            lblResult.BackColor = Color.Silver;
        }

        private string GetGlobalBand(GlobalBandType type)
        {
            switch (type)
            {
                case GlobalBandType.Korea: return "Korea";
               // case GlobalBandType.Japan: return "Japan";
                case GlobalBandType.Euro: return "Euro";
                case GlobalBandType.USA: return "USA";
                case GlobalBandType.China: return "China";
                case GlobalBandType.Taiwan: return "Taiwan";
                case GlobalBandType.Brazil: return "Brazil";
                case GlobalBandType.Malaysia: return "Malaysia";
                case GlobalBandType.Asia: return "Asia";
                case GlobalBandType.Japan_1W: return "Japan 1W";
                case GlobalBandType.Japan_250mW: return "Japan 250mW";
                case GlobalBandType.India: return "India";
                case GlobalBandType.Indonesia: return "Indonesia";
                case GlobalBandType.Japan_125mW: return "Japan 125mW";
                case GlobalBandType.Australia: return "Australia";
                case GlobalBandType.NewZealand: return "NewZealand";
                case GlobalBandType.Philippines: return "Philippines";
                case GlobalBandType.Singapore: return "Singapore";
                case GlobalBandType.Thailand: return "Thailand";
                case GlobalBandType.Uruguay: return "Uruguay";
                case GlobalBandType.Vietnam: return "Vietnam";
                case GlobalBandType.SouthAfrica: return "South Africa";
                case GlobalBandType.Chile_1W: return "Chile 1W";
                case GlobalBandType.Chile_05W: return "Chile 0.5W";
                case GlobalBandType.Canada: return "Canada";
                case GlobalBandType.Mexico: return "Mexico";
                case GlobalBandType.Argentina: return "Argentina";
                case GlobalBandType.Morocco: return "Morocco";
                case GlobalBandType.Peru: return "Peru";
            }
            return "";
        }

        #region Output Message
        // Output Message
        private void OutputMessage(string format, params object[] args)
        {
            OutputMessage(String.Format(format, args));
        }

        private void OutputMessage(string arg)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new Action<string>(OutputMessage), arg);
                return;
            }
            lstOutput.Items.Add(arg);
            lstOutput.SelectedIndex = lstOutput.Items.Count - 1;
        }
        #endregion

        #region Load/Save Config
        // Load Config
        private const string KEY_DEVICE_ADDRESS = "Device Address";


        //2015.10.20 Bluetooth update
        private void LoadConfig()
        {
            try
            {
                using (RegistryKey reg = Registry.CurrentUser.OpenSubKey(@"Software\ATID\AT288Demo.Net\Connection"))
                {
                    m_strLastAddress = (string)reg.GetValue(KEY_DEVICE_ADDRESS, DEFAULT_DEVICE_ADDRESS);
                    cbPort.SelectedIndex = (int)reg.GetValue("Port", DEFAULT_SERIAL_PORT);
                    reg.Close();
                }
            }
            catch (Exception)
            {

                m_strLastAddress = DEFAULT_DEVICE_ADDRESS;
                cbPort.SelectedIndex = -1;
            }
        }

        // Save Config
        private void SaveConfig()
        {
            try
            {
                using (RegistryKey reg = Registry.CurrentUser.CreateSubKey(@"Software\ATID\AT288Demo.Net\Connection"))
                {
                    reg.SetValue(KEY_DEVICE_ADDRESS, m_strLastAddress);
                    reg.SetValue("Port", cbPort.SelectedIndex);
                    reg.Close();
                }
            }
            catch (Exception)
            {
            }
        }
        #endregion

        #region Serial Port Detector
        //protected override void WndProc(ref Message m)
        //{
        //    if ((m.Msg == WM_DEVICECHANGE))
        //    {
        //        int devType = 0;

        //        switch (m.WParam.ToInt32())
        //        {
        //            case DBT_DEVICEARRIVAL: // Device Conntected...
        //                break;
        //            case DBT_DEVICEREMOVECOMPLETE: // Device Disconnected...
        //                break;
        //            default:
        //                base.WndProc(ref m);
        //                return;
        //        }
        //        try { devType = Marshal.ReadInt32(m.LParam, 4); }
        //        catch (Exception) { }
        //        if (devType == DBT_DEVTYP_PORT)
        //            GetSerialPortName();
        //    }
        //    base.WndProc(ref m);
        //}

        [StructLayout(LayoutKind.Sequential)]
        private struct DEV_BROADCAST_DEVICEINTERFACE
        {
            public int dbcc_size;
            public int dbcc_devicetype;
            public int dbcc_reserved;
            public Guid dbcc_classguid;
            public byte dbch_data;
            public byte dbch_data1;
        }

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr RegisterDeviceNotification(IntPtr hRecipient, IntPtr NotificationFilter, uint Flags);
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern uint UnregisterDeviceNotification(IntPtr hHandle);
        [DllImport("hid.dll", CharSet = CharSet.Auto)]
        private static extern void HidD_GetHidGuid(ref Guid guid);

        private void RegisterForDeviceChange()
        {
            if (m_DeviceNotifyHandle != IntPtr.Zero) return;

            Guid hidGuid = new Guid();

            HidD_GetHidGuid(ref hidGuid);

            DEV_BROADCAST_DEVICEINTERFACE data = new DEV_BROADCAST_DEVICEINTERFACE();
            data.dbcc_size = Marshal.SizeOf(data);
            data.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
            data.dbcc_classguid = hidGuid;
            IntPtr buffer = Marshal.AllocHGlobal(data.dbcc_size);
            Marshal.StructureToPtr(data, buffer, true);

            m_DeviceNotifyHandle = RegisterDeviceNotification(Handle, buffer, DEVICE_NOTIFY_SERVICE_HANDLE);
        }

        private void UnregisterForDeviceChange()
        {
            if (m_DeviceNotifyHandle == IntPtr.Zero) return;

            UnregisterDeviceNotification(m_DeviceNotifyHandle);
            m_DeviceNotifyHandle = IntPtr.Zero;
        }
        #endregion

        private void btnInventoryMemory_Click(object sender, EventArgs e)
        {
            bInventoryMemory = true;

            ReadMemoryDialog dlg = new ReadMemoryDialog();

            dlg.Bank = m_ReadBank;
            dlg.Offset = m_nReadOffset;
            dlg.Length = m_nReadLength;
            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                m_ReadBank = dlg.Bank;
                m_nReadOffset = dlg.Offset;
                m_nReadLength = dlg.Length;
               
                // read memory
                if (m_strSelectionMask != "")
                {
                    if (m_Reader.InventoryMemory(m_ReadBank, m_nReadOffset, m_nReadLength, m_strSelectionMask))
                        OutputMessage("Read Memory({0}) OK!!!", m_strSelectionMask);
                    else
                        OutputMessage("Read Memory({0}) Failed...", m_strSelectionMask);
                }
                else
                {
                    if (m_Reader.InventoryMemory(m_ReadBank, m_nReadOffset, m_nReadLength))
                        OutputMessage("Read Memory OK!!!");
                    else
                        OutputMessage("Read Memory Failed...");
                }
                EnableControl();
                lstOutput.Focus();
            }
        }
        private void btnBattery_Click(object sender, EventArgs e)
        {
            m_Reader.RequestBatteryState();
        }
        //2015.10.20  비정상 Device 종료시 close method
        private void close()
        {
            if (m_Reader != null)
            {
                if (!m_Reader.IsOpened) return;

                // Close Reader
                // if (m_Reader.IsAction())
                m_Reader.StopOperation();

                m_Reader.Action -= m_fnAction;
                m_Reader.Response -= m_fnResponse;
                m_Reader.ReadTag -= m_fnReadTag;
                m_Reader.Property -= m_fnProperty;
                m_Reader.PropertyEx -= m_fnPropertyEx;
                m_Reader.Close();
                m_Reader = null;
                OutputMessage("Close() reader OK!!!");
            }

            EnableControl();
            lblMask.Text = "";
            lblResult.Text = "";
            //lblValue.Text = "";
            txtValue.Text = "";
            lblTagCount.Text = "0";
            btnOpen.Focus();

        }

        private void cbBeepMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            
            if (m_Reader.SetBuzzer(cbBeepMode.SelectedIndex == 1 ? true:false))
                OutputMessage("Set Buzzer({0}) OK!!!", cbBeepMode.SelectedIndex);
            else
                OutputMessage("Set Buzzer({0}) Failed...", cbBeepMode.SelectedIndex);
        }

        private void cbAutoPowerOff_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (m_isEventBlock) return;

            int value = Convert.ToInt32(cbAutoPowerOff.Text);
            if (m_Reader.SetAutoPowerOff(value))
                OutputMessage("Set AutoPowerOff({0}) OK!!!", cbAutoPowerOff.Text);
            else
                OutputMessage("Set AutoPowerOff({0}) Failed...", cbAutoPowerOff.Text);
        }

        private void btnReSearch_Click(object sender, EventArgs e)
        {
            GetSerialPortName();
        }
    }
}
