using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using Tango.BL.Entities;
using Tango.Core.Commands;
using Tango.Core.DI;
using Tango.Core.Threading;
using Tango.Emulations.ExternalBridge;
using Tango.FSE.BL;
using Tango.FSE.Common;
using Tango.FSE.Common.FSEApplication;
using Tango.Integration.ExternalBridge;
using Tango.Settings;
using Tango.SharedUI;
namespace Tango.FSE.UI.Panes
{
///
/// Represents the machine connection pane view model.
///
///
public class MachineConnectionPaneVM : FSEViewModel
{
private const string WEB_DEBUG_ADDRESS = "http://localhost:1111";
private ExternalBridgeScanner _scanner;
private EmulatorExternalBridge _emulator;
private List _allowedMachines;
private ICollectionView _tcpMachinesView;
private ICollectionView _signalRMachinesView;
private String _filter;
public String Filter
{
get { return _filter; }
set
{
_filter = value; RaisePropertyChangedAuto();
_tcpMachinesView?.Refresh();
_signalRMachinesView?.Refresh();
OnFilterChanged();
}
}
///
/// Occurs when a machine has been selected for connection.
///
public event EventHandler MachineSelected;
///
/// Gets or sets the available machines via USB.
///
public ObservableCollection UsbMachines { get; set; }
///
/// Gets or sets the available machines via local WiFi network.
///
public ObservableCollection TcpMachines { get; set; }
///
/// Gets or sets the available machine via Internet connection (SignalR).
///
public ObservableCollection SignalRMachines { get; set; }
///
/// Gets or sets the available emulated machines.
///
public ObservableCollection EmulatorMachines { get; set; }
///
/// Gets or sets the connect to machine command.
///
public RelayCommand ConnectToMachineCommand { get; set; }
private IExternalBridgeClient _selectedMachine;
///
/// Gets or sets the selected machine.
///
public IExternalBridgeClient SelectedMachine
{
get { return _selectedMachine; }
set { _selectedMachine = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
}
///
/// Initializes a new instance of the class.
///
public MachineConnectionPaneVM()
{
TangoIOC.Default.Inject(this);
ConnectToMachineCommand = new RelayCommand(ConnectToMachine, () => SelectedMachine != null);
UsbMachines = new ObservableCollection();
TcpMachines = new ObservableCollection();
SignalRMachines = new ObservableCollection();
EmulatorMachines = new ObservableCollection();
_tcpMachinesView = CollectionViewSource.GetDefaultView(TcpMachines);
_signalRMachinesView = CollectionViewSource.GetDefaultView(SignalRMachines);
_tcpMachinesView.Filter = OnFilterMachines;
_signalRMachinesView.Filter = OnFilterMachines;
_scanner = new ExternalBridgeScanner();
_scanner.MachineDiscovered += _scanner_MachineDiscovered;
_scanner.MachineLost += _scanner_MachineLost;
ApplicationManager.ApplicationReady += ApplicationManager_ApplicationReady;
}
private void ApplicationManager_ApplicationReady(object sender, EventArgs e)
{
_allowedMachines = null;
}
///
/// Connects to the selected machine.
///
internal void ConnectToMachine()
{
if (SelectedMachine != null)
{
Settings.LastSelectedMachine = SelectedMachine.GetUniqueString();
Settings.Save();
MachineSelected?.Invoke(this, SelectedMachine);
}
}
///
/// Handles the external bridge scanner machine lost event.
///
/// The sender.
/// The machine.
private void _scanner_MachineLost(object sender, IExternalBridgeClient machine)
{
InvokeUI(() =>
{
if (machine is ExternalBridgeUsbClient)
{
UsbMachines.Remove(machine as ExternalBridgeUsbClient);
}
else if (machine is ExternalBridgeSignalRClient)
{
SignalRMachines.Remove(machine as ExternalBridgeSignalRClient);
}
else if (machine is ExternalBridgeTcpClient)
{
TcpMachines.Remove(machine as ExternalBridgeTcpClient);
}
});
}
///
/// Handles the external bridge scanner machine discovered event.
///
/// The sender.
/// The machine.
private void _scanner_MachineDiscovered(object sender, IExternalBridgeClient machine)
{
if (machine is ExternalBridgeTcpClient)
{
if (!_allowedMachines.Exists(x => x.SerialNumber == machine.SerialNumber))
{
return;
}
}
InvokeUI(() =>
{
bool insert = false;
try
{
if (Settings.LastSelectedMachine != null)
{
if (machine.GetUniqueString() == Settings.LastSelectedMachine)
{
insert = true;
}
}
}
catch { }
if (machine is ExternalBridgeUsbClient && !BuildProvider.IsTwineRSM)
{
if (insert)
{
UsbMachines.Insert(0, machine as ExternalBridgeUsbClient);
}
else
{
UsbMachines.Add(machine as ExternalBridgeUsbClient);
}
}
else if (machine is ExternalBridgeSignalRClient && !BuildProvider.IsTwineRSM)
{
if (!CurrentUser.PreventRemoteMachineAccess)
{
if (insert)
{
SignalRMachines.Insert(0, machine as ExternalBridgeSignalRClient);
}
else
{
SignalRMachines.Add(machine as ExternalBridgeSignalRClient);
}
}
}
else if (machine is ExternalBridgeTcpClient)
{
if (insert)
{
TcpMachines.Insert(0, machine as ExternalBridgeTcpClient);
}
else
{
TcpMachines.Add(machine as ExternalBridgeTcpClient);
}
}
TryAutoSelectMachine();
});
}
///
/// Tries to automatically select a machine by the last connected machine stored on settings.
///
private void TryAutoSelectMachine()
{
if (SelectedMachine == null && Settings.LastSelectedMachine != null)
{
SelectedMachine = UsbMachines.Select(x => x.As())
.Concat(TcpMachines.Select(x => x.As()))
.Concat(SignalRMachines.Select(x => x.As()))
.Concat(EmulatorMachines.Select(x => x.As()))
.ToList().SingleOrDefault(x => x.GetUniqueString() == Settings.LastSelectedMachine);
if (SelectedMachine != null)
{
this.SetFocus(() => ConnectToMachineCommand);
}
}
}
///
/// Starts scanning for machines.
///
public async void Start()
{
LogManager.Log("Starting machine scanning...");
if (_allowedMachines == null)
{
_allowedMachines = await Services.MachinesService.GetAllMachines();
_scanner.KnownMachines = _allowedMachines;
}
TcpMachines.Clear();
SignalRMachines.Clear();
EmulatorMachines.Clear();
SelectedMachine = null;
if (Settings.EnableMachineEmulator)
{
ThreadFactory.StartNew(() =>
{
try
{
LogManager.Log("Initializing machine emulator...");
if (_emulator != null)
{
_emulator.Disconnect().Wait();
}
_emulator = new EmulatorExternalBridge();
InvokeUI(() =>
{
EmulatorMachines.Add(_emulator);
});
}
catch (Exception ex)
{
LogManager.Log(ex, "Error initializing machine emulator.");
}
});
}
TryAutoSelectMachine();
_scanner.SignalRConfiguration.Enabled = Settings.EnableExternalBridgeSignalR && !BuildProvider.IsTwineRSM;
if (ApplicationManager.IsWebDebugMode)
{
LogManager.Log($"Application is in web debug mode. Scanning for SignalR machine on address '{WEB_DEBUG_ADDRESS}'...");
_scanner.SignalRConfiguration.Address = WEB_DEBUG_ADDRESS;
}
else
{
_scanner.SignalRConfiguration.Address = AuthenticationProvider.CurrentEnvironment.MachineServiceAddress;
}
_scanner.SignalRConfiguration.Hub = Settings.ExternalBridgeSignalRHub;
LogManager.Log("Starting external bridge scanner...");
_scanner.Start();
}
///
/// Stops scanning for machines.
///
public void Stop()
{
LogManager.Log("Stopping external bridge scanner...");
_scanner.Stop();
}
private bool OnFilterMachines(object obj)
{
var machine = obj as ExternalBridgeTcpClient;
if (machine != null)
{
return machine.SerialNumber.ToLower().Contains(Filter.ToStringOrEmpty().ToLower()) || (machine.GetType() == typeof(ExternalBridgeTcpClient) && machine.IPAddress == Filter);
}
return true;
}
private void OnFilterChanged()
{
if (Filter.IsNotNullOrEmpty())
{
Task.Factory.StartNew(() =>
{
_scanner.TryGetMachineByIP(Filter);
});
}
}
}
}