using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
using Demo2.Properties;
using DemoLib.Model;
using DemoLib.Service;
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.CommandWpf;
using UnifiedAutomation.UaBase;

namespace Demo2.ViewModel
{
    public class MainViewModel : ViewModelBase
    {
        public MainViewModel()
        {
            ConnectCommand = new RelayCommand(ConnectCommandExecute, CanConnectCommand);
            DisconnectCommand = new RelayCommand(DisconnectCommandExecute, CanDisconnectCommand);
            ScanStartCommand = new RelayCommand(ScanStartCommandExecute, CanScanStartCommand);
            ScanStopCommand = new RelayCommand(ScanStopCommandExecute, CanScanStopCommand);
            RefreshReaderListCommand = new RelayCommand(RefreshReaderListCommandExecute, CanRefreshReaderListCommand);

            // Load user settings
            Server = Settings.Default.Server;
            Port = Settings.Default.Port.ToString();

            ReaderList = new ObservableCollection<Reader>();
            RunningConnect = false;
        }

        #region Commands

        #region Connect

        public RelayCommand ConnectCommand { get; }

        private async void ConnectCommandExecute()
        {
            RunningConnect = true;
            if (await OpcUaService.Instance.ConnectAsync(Server, int.Parse(Port)))
            {
                // Save user settings
                Settings.Default.Server = Server;
                Settings.Default.Port = int.Parse(Port);
                Settings.Default.Save();
                Connected = true;

                RefreshReaderListCommandExecute();
                OpcUaService.Instance.DataChange += Monitored_DataChange;

                CommandManager.InvalidateRequerySuggested();
            }
            else
            {
                Connected = false;
            }
            RunningConnect = false;
        }

        public bool CanConnectCommand()
        {
            return !String.IsNullOrEmpty(Server) && !String.IsNullOrEmpty(Port) && !Connected;
        }

        #endregion Connect

        #region Disconnect

        public RelayCommand DisconnectCommand { get; }

        private void DisconnectCommandExecute()
        {
            OpcUaService.Instance.Disconnect();
            OpcUaService.Instance.DataChange -= Monitored_DataChange;
            Connected = false;

            RunningScanStart = false;
            FoundTag = null;
            FoundTagAntenna = 0;
            FoundTagRssi = 0;
        }

        public bool CanDisconnectCommand()
        {
            return Connected;
        }

        #endregion Disconnect

        #region ScanStart

        public RelayCommand ScanStartCommand { get; private set; }

        private void ScanStartCommandExecute()
        {
            var result = OpcUaService.Instance.ScanStart(SelectedReader, true);
            if (result.Code == 0)
            {
                RunningScanStart = true;
            }
        }

        public bool CanScanStartCommand()
        {
            return Connected && SelectedReader != null && !RunningScanStart;
        }

        #endregion ScanStart

        #region ScanStop

        public RelayCommand ScanStopCommand { get; private set; }

        private void ScanStopCommandExecute()
        {
            var result = OpcUaService.Instance.ScanStop(SelectedReader);
            if (result.Code == 0)
            {
                RunningScanStart = false;
            }
        }

        public bool CanScanStopCommand()
        {
            return Connected && SelectedReader != null && RunningScanStart;
        }

        #endregion ScanStop

        #region RefreshReaderList

        public RelayCommand RefreshReaderListCommand { get; private set; }

        private void RefreshReaderListCommandExecute()
        {
            SelectedReader = null;
            ReaderList.Clear();
            ReaderList = OpcUaService.Instance.GetAllReader();
        }

        public bool CanRefreshReaderListCommand()
        {
            return Connected;
        }

        #endregion RefreshReaderList

        #endregion Commands

        #region Properties

        private bool _connected;

        public bool Connected
        {
            get => _connected;
            private set => Set(ref _connected, value);
        }

        private string _server;

        public string Server
        {
            get => _server;
            set => Set(ref _server, value);
        }

        private string _port;

        public string Port
        {
            get => _port;
            set => Set(ref _port, value);
        }

        private bool _runningConnect;

        public bool RunningConnect
        {
            get => _runningConnect;
            private set => Set(ref _runningConnect, value);
        }

        private bool _runningScanStart;

        public bool RunningScanStart
        {
            get => _runningScanStart;
            private set => Set(ref _runningScanStart, value);
        }

        private Reader _selectedReader;

        public Reader SelectedReader
        {
            get => _selectedReader;
            set
            {
                Set(ref _selectedReader, value);
                if (value != null)
                {
                    SetMonitoredItem();
                    FoundTag = OpcUaService.Instance.GetLastScanResult(value);
                }
            }
        }

        private ObservableCollection<Reader> _readerList;

        public ObservableCollection<Reader> ReaderList
        {
            get => _readerList;
            set => Set(ref _readerList, value);
        }

        private string _deviceStatus;

        public string DeviceStatus
        {
            get => _deviceStatus;
            set => Set(ref _deviceStatus, value);
        }

        private RfidTag _foundTag;

        public RfidTag FoundTag
        {
            get => _foundTag;
            set => Set(ref _foundTag, value);
        }

        private int _foundTagAntenna;

        public int FoundTagAntenna
        {
            get => _foundTagAntenna;
            set => Set(ref _foundTagAntenna, value);
        }

        private int _foundTagRssi;

        public int FoundTagRssi
        {
            get => _foundTagRssi;
            set => Set(ref _foundTagRssi, value);
        }

        #endregion Properties

        private void SetMonitoredItem()
        {
            OpcUaService.Instance.DeleteSubscriptions();
            OpcUaService.Instance.AddMonitoredItem(SelectedReader, "DeviceStatus");
        }

        private void Monitored_DataChange(string dataName, DataValue dataValue)
        {
            if (dataName.Equals("DeviceStatus"))
            {
                int state = (int)dataValue.Value;
                switch (state)
                {
                    case 0:
                        DeviceStatus = "Idle";
                        break;

                    case 1:
                        DeviceStatus = "Error";
                        break;

                    case 2:
                        DeviceStatus = "Scanning...";
                        break;

                    case 3:
                        DeviceStatus = "Busy";
                        break;
                }

                if (state == 0 && RunningScanStart)
                {
                    RunningScanStart = false;
                    FoundTag = OpcUaService.Instance.GetLastScanResult(SelectedReader);
                    FoundTagAntenna = OpcUaService.Instance.GetLastScanAntenna(SelectedReader);
                    FoundTagRssi = OpcUaService.Instance.GetLastScanRssi(SelectedReader);

                    Application.Current.Dispatcher.Invoke(CommandManager.InvalidateRequerySuggested);
                }
                else if (state == 2 && !RunningScanStart)
                {
                    RunningScanStart = true;

                    Application.Current.Dispatcher.Invoke(CommandManager.InvalidateRequerySuggested);
                }
            }
        }
    }
}