using Ion.Sdk.DemoApp.Components;
using Ion.Sdk.DemoApp.Framework;
using Ion.Sdk.Ici;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace Ion.Sdk.DemoApp.Views
{
    /// <summary>
    /// Interaction logic for AutoSequences.xaml
    /// </summary>
    public partial class AutoSequences : UserControl, IAppView
    {
        #region -=Instance members=-

        private readonly ViewModel viewModel;

        public Command UploadCommand { get; }
        public Command RefreshAvailablePortsCommand { get; }

        public IAppViewInfo Info => ViewInfo;

        public ProgressIndicator Progress { get => viewModel.Progress; }

        public AutoSequences(ViewModel viewModel)
        {
            UploadCommand = Command.CreateAsync(Upload, parameter => viewModel?.FileLoaders.Exists(_ => _ is AutoSequenceGroupFileLoader.Atmpx) == true && IsOnline.HasValue && IsOnline.Value);
            RefreshAvailablePortsCommand = Command.Create(parameter => AvailablePorts = System.IO.Ports.SerialPort.GetPortNames());

            InitializeComponent();

            Root.DataContext = this.viewModel = viewModel;
        }

        private async Task Upload(object parameter)
        {

            if (parameter is string port)
            {

                var atmpx = viewModel?.FileLoaders.FirstOrDefault(_ => _ is AutoSequenceGroupFileLoader.Atmpx);
                if (atmpx == null) return;


                var dialog = new OpenFileDialog
                {
                    CheckFileExists = true,
                    Filter = atmpx.OpenDialogFilter,
                    InitialDirectory = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "SampleFiles")
                };

                if (dialog.ShowDialog() == true)
                {
                    Progress.IsBusy = true;
                    try
                    {
                        Progress.OperationType = ProgressOperationMode.LoadingData;
                        var group = await atmpx.Load(dialog.FileName);
                        using (var channel = Channel.Serial.Open(port))
                        {
                            Progress.OperationType = ProgressOperationMode.TransferingData;
                            channel.Use(Progress);
                            await channel.UploadAutoSequenceGroup(group);
                        }
                    }
                    finally
                    {
                        Progress.IsBusy = false;
                    }
                }
            }

        }

        #endregion

        #region -=Dependency properties=-

        public string SelectedPort
        {
            get => (string)GetValue(SelectedPortProperty);
            set => SetValue(SelectedPortProperty, value);
        }

        public int SelectedBaudRate
        {
            get => (int)GetValue(SelectedBaudRateProperty);
            set => SetValue(SelectedBaudRateProperty, value);
        }

        public bool? IsOnline
        {
            get => (bool?)GetValue(IsOnlineProperty);
            set => SetValue(IsOnlineProperty, value);
        }

        public string[] AvailablePorts
        {
            get => GetValue(AvailablePortsProperty) as string[];
            set => SetValue(AvailablePortsProperty, value);
        }

        public int[] AvailableBaudRates => new[] { 9600, 57600, 115200 };

        public static readonly DependencyProperty AvailablePortsProperty = DependencyProperty.Register("AvailablePorts", typeof(string[]), typeof(AutoSequences), new PropertyMetadata(System.IO.Ports.SerialPort.GetPortNames()));

        public static readonly DependencyProperty SelectedPortProperty = DependencyProperty.Register(
            "SelectedPort", typeof(string), typeof(AutoSequences), new PropertyMetadata(default(string), OnSelectedPortPropertyChanged));

        public static readonly DependencyProperty SelectedBaudRateProperty = DependencyProperty.Register(
            "SelectedBaudRate", typeof(int), typeof(AutoSequences), new PropertyMetadata(115200));


        public static readonly DependencyProperty IsOnlineProperty = DependencyProperty.Register("IsOnline", typeof(bool?), typeof(AutoSequences),
            new UIPropertyMetadata(default(bool?), (sender, args) =>
            {
                if (sender is AutoSequences view)
                {
                    view.UploadCommand.RaiseCanExecuteChanged();
                }
            }));

        private static async void OnSelectedPortPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is AutoSequences view && e.NewValue is string port)
            {
                try
                {
                    view.IsOnline = null;
                    int baudRate = view.SelectedBaudRate;
                    using (var instrument = await Task.Run(() => Channel.Serial.Open(port, baudRate)))
                    {
                        var isOnline = await instrument.IsOnline();
                        if (port == view.SelectedPort)
                            view.IsOnline = isOnline;
                    }
                }
                catch (Exception ex)
                {
                    Trace.TraceError(ex.Message);
                    if (port == view.SelectedPort)
                        view.IsOnline = false;
                }
            }
        }

        #endregion


        #region -=Static members=-

        public static IAppViewInfo ViewInfo = new AppViewInfo { Id = nameof(AutoSequences), Name = "AutoSequences" };

        #endregion

        #region -=Definitions=-

        public sealed class ViewModel : BindableObject
        {
            public List<AutoSequenceGroupFileLoader> FileLoaders { get; }
            public ProgressIndicator Progress { get; } = new ProgressIndicator();

            public ViewModel(IEnumerable<AutoSequenceGroupFileLoader> fileLoaders)
            {
                FileLoaders = fileLoaders.ToList();
            }
        }

        #endregion


    }
}
