using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

using com.atid.lib.diagnostics;
using com.atid.lib.types;
using com.atid.lib.transport;
using com.atid.lib.transport.types;
using com.atid.lib.util;
using com.atid.lib.util.diagnotics;
using com.atid.lib.util.wifi;
using com.atid.lib.reader;
using com.atid.lib.reader.parameters;
using com.atid.lib.reader.types;
using com.atid.lib.atx88;
using com.atid.lib.reader.events;
using com.atid.lib.module.barcode;
using com.atid.lib.module.barcode.events;
using com.atid.lib.module.barcode.parameters;
using com.atid.lib.module.barcode.types;
using com.atid.lib.module.rfid.uhf;
using com.atid.lib.module.rfid.uhf.events;
using com.atid.lib.module.rfid.uhf.parameters;
using com.atid.lib.module.rfid.uhf.types;
using System.Collections.ObjectModel;
using Windows.Devices.Enumeration;
using Windows.Devices.Bluetooth;
using Windows.Devices.SerialCommunication;
using Windows.Networking.Connectivity;

namespace testApp
{
    public class ReaderViewModel : INotifyPropertyChanged, IATEAReaderEventListener, IATRfidUhfEventListener, IATBarcodeEventListener
    {
        private ATEAReader _reader;
        private ICommand _connectClickCommand;
        private ICommand _inventoryClickCommand;
        private ICommand _decodeClickCommand;
        private ICommand _clearClickCommand;
        private bool _canExecute;
        private string _portName;
        private int _deviceIndex;
        private ConnectState _connState;
        private string _battState;
        private string _version;
        private string _serialNumber;
        private int _totCount;
        private ActionState _actionState;

        private ObservableCollection<TagItem> _TagList = new ObservableCollection<TagItem>();

        public event PropertyChangedEventHandler PropertyChanged;

        public ReaderViewModel()
        {
            _reader = null;
            _canExecute = true;
            _portName = "COM6";
            _deviceIndex = 0;
            _connState = ConnectState.Disconnected;
            _battState = "";
            _version = "";
            _serialNumber = "";
            _totCount = 0;
            _actionState = ActionState.Stop;
        }

        public ObservableCollection<TagItem> TagList
        {
            get
            {
                return _TagList;
            }
        }

        public string PortName
        {
            get
            {
                return _portName;
            }
            set
            {
                if(value != _portName)
                {
                    _portName = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("PortName"));
                }
            }
        }

        public int DeviceIndex
        {
            get
            {
                return _deviceIndex;
            }
            set
            {
                if(value != _deviceIndex)
                {
                    _deviceIndex = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DeviceIndex"));
                }
            }
        }

        public string ConnState
        {
            get
            {
                return _connState.ToString();
            }
        }
        public string BattState
        {
            get
            {
                return _battState;
            }
        }
        public string ActState
        {
            get
            {
                return _actionState.ToString();
            }
        }
        public string Version
        {
            get
            {
                return _version;
            }
        }
        public string SerialNumber
        {
            get
            {
                return _serialNumber;
            }
        }
        public int TotalCount
        {
            get
            {
                return _totCount;
            }
        }
        public string ConnectStateTextForButton
        {
            get
            {
                if (_connState == ConnectState.Connected)
                    return "Disconnect";
                else if (_connState == ConnectState.Disconnected)
                    return "Connect";
                else
                    return "...";
            }
        }
        public string InventoryStateTextForButton
        {
            get
            {
                if (_actionState == ActionState.Stop)
                    return ActionState.Inventory6c.ToString();
                else if (_actionState == ActionState.Inventory6c)
                    return ActionState.Stop.ToString();

                return "";
            }
        }
        public string DecodeStateTextForButton
        {
            get
            {
                if (_actionState == ActionState.Stop)
                    return ActionState.Decoding.ToString();
                else if (_actionState == ActionState.Decoding)
                    return ActionState.Stop.ToString();

                return "";
            }
        }

        public ICommand ConnectClick
        {
            get
            {
                return _connectClickCommand ?? (_connectClickCommand = new CommandHandler(() => Connect(), _canExecute));
            }
        }
        public ICommand InventoryClick
        {
            get
            {
                return _inventoryClickCommand ?? (_inventoryClickCommand = new CommandHandler(() => Inventory(), _canExecute));
            }
        }
        public ICommand DecodeClick
        {
            get
            {
                return _decodeClickCommand ?? (_decodeClickCommand = new CommandHandler(() => Decode(), _canExecute));
            }
        }
        public ICommand ClearClick
        {
            get
            {
                return _clearClickCommand ?? (_clearClickCommand = new CommandHandler(() => Clear(), _canExecute));
            }
        }
        

        public async void Connect()
        {
            if (_reader == null)
            {
                await Task.Run(() =>
                {
                    switch (_deviceIndex)
                    {
                        case 0:
                            _reader = new AT188Reader(new ATransportVcp(DeviceType.AT188N, "ATID Reader", _portName));
                            break;
                        case 1:
                        case 2:
                            _reader = new AT388Reader(new ATransportVcp(DeviceType.AT388, "ATID Reader", _portName));
                            break;
                        case 3:
                            _reader = new ATD100Reader(new ATransportVcp(DeviceType.ATD100, "ATID Reader", _portName));
                            break;
                    }

                    _reader.addListener(this);
                    _reader.connect();
                });
            }
            else
            {
                _reader.disconnect();
            }
        }
        public void Inventory()
        {
            System.Diagnostics.Debug.WriteLine("+++ Inventory");
            if (_reader == null)
                return;

            if (_reader.getAction() == ActionState.Stop)
            {
                _reader.getRfidUhf()?.inventory6c();
            }
            else
            {
                _reader.getRfidUhf()?.stop();
            }
        }
        public void Decode()
        {
            System.Diagnostics.Debug.WriteLine("+++ Decode");
            if (_reader == null)
                return;

            if (_reader.getAction() == ActionState.Stop)
            {
                _reader.getBarcode()?.startDecode();
            }
            else
            {
                _reader.getBarcode()?.stop();
            }
        }
        public void Clear()
        {
            System.Diagnostics.Debug.WriteLine("+++ Clear");

            _TagList.Clear();
            _totCount = 0;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCount"));
        }

        public async void onReaderStateChanged(ATEAReader reader, ConnectState state, object objs)
        {
            await Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                if (state == ConnectState.Connecting)
                {
                }
                else if(state == ConnectState.Connected)
                {
                    _version = _reader.getVersion();
                    _serialNumber = _reader.getSerialNo();
                    _reader.getRfidUhf()?.addListener(this);
                    _reader.getBarcode()?.addListener(this);
                }
                else if(state == ConnectState.Disconnected)
                {
                    if (_reader != null)
                    {
                        _reader.getRfidUhf()?.removeListener(this);
                        _reader.getBarcode()?.removeListener(this);
                        _reader.removeListener(this);
                        _reader = null;
                    }

                    _version = "";
                    _serialNumber = "";
                }

                _connState = state;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ConnState"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ConnectStateTextForButton"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Version"));
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("SerialNumber"));
            });
        }

        public async void onReaderActionChanged(ATEAReader reader, ResultCode code, ActionState action, object objs)
        {
            await Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                _actionState = action;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("ActState"));
                if (action == ActionState.Stop)
                {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("InventoryStateTextForButton"));
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DecodeStateTextForButton"));
                }
                else if(action == ActionState.Inventory6c)
                {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("InventoryStateTextForButton"));
                }
                else if(action == ActionState.Decoding)
                {
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("DecodeStateTextForButton"));
                }
            });
        }

        public void onReaderOperationModeChanged(ATEAReader reader, OperationMode mode, object objs)
        {
            throw new NotImplementedException();
        }

        public async void onReaderBatteryState(ATEAReader reader, int batteryState, object objs)
        {
            await Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                _battState = batteryState.ToString();
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("BattState"));
            });
        }

        public void onKeyEvent(ATEAReader reader, byte keyCode, byte keyState)
        {
            throw new NotImplementedException();
        }

        public async void onRfidUhfReadTag(ATRfidUhf uhf, string tag, object parameters)
        {
            await Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                int index = _TagList.IndexOf(new TagItem(0, tag, 0));
                if (index >= 0)
                {
                    _TagList[index].Increase();
                }
                else
                {
                    _TagList.Add(new TagItem(_TagList.Count + 1, tag, 1));
                }
                ++_totCount;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCount"));
            });
        }

        public void onRfidUhfAccessResult(ATRfidUhf uhf, ResultCode code, ActionState action, string epc, string data, object parameters)
        {
            throw new NotImplementedException();
        }

        public void onRfidUhfPowerGainChanged(ATRfidUhf uhf, int power, object parameters)
        {
            throw new NotImplementedException();
        }

        public async void onBarcodeReadData(ATBarcode barcode, BarcodeType type, string codeId, string data, object parameters)
        {
            await Windows.ApplicationModel.Core.CoreApplication.MainView.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                string barcodeData = $"{type} - {data}";
                int index = _TagList.IndexOf(new TagItem(0, barcodeData, 0));
                if (index >= 0)
                {
                    _TagList[index].Increase();
                }
                else
                {
                    _TagList.Add(new TagItem(_TagList.Count + 1, barcodeData, 1));
                }
                ++_totCount;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TotalCount"));
            });
        }
    }

    public class CommandHandler : ICommand
    {
        private Action _action;
        private bool _canExecute;

        public CommandHandler(Action action, bool canExecute)
        {
            _action = action;
            _canExecute = canExecute;
        }

        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            return _canExecute;
        }

        public void Execute(object parameter)
        {
            _action();
        }
    }
}
