using Google.Protobuf;
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Tango.Core.Commands;
using Tango.Scripting;
using Tango.Settings;
using Tango.SharedUI;
using Tango.Stubs.UI.Views;
using Tango.Transport.Adapters;
namespace Tango.Stubs.UI.ViewModels
{
///
/// Represents the script execution utility main view model.
///
///
public class MainViewVM : ViewModel
{
private UsbTransportAdapter _adapter; //Holds the USB transport adapter.
private StubManager _stubManager;
private TextBox _logTextBox;
#region Properties
///
/// Gets or sets the code tabs.
///
public ObservableCollection CodeTabs { get; set; }
///
/// Gets or sets the additional highlight C# types.
///
public ObservableCollection> HighlightTypes { get; set; }
///
/// Gets or sets the collection of stub snippets.
///
public ObservableCollection StubSnippets { get; set; }
private StubSnippetVM _selectedStubSnippet;
///
/// Gets or sets the selected stub snippet.
///
public StubSnippetVM SelectedStubSnippet
{
get { return _selectedStubSnippet; }
set { _selectedStubSnippet = value; RaisePropertyChanged(nameof(SelectedStubSnippet)); }
}
private CodeTabVM _selectedCodeTab;
///
/// Gets or sets the selected code tab.
///
public CodeTabVM SelectedCodeTab
{
get { return _selectedCodeTab; }
set { _selectedCodeTab = value; RaisePropertyChanged(nameof(SelectedCodeTab)); InvalidateRelayCommands(); }
}
private bool _isConnected;
///
/// Gets or sets a value indicating whether the USB adapter is connected.
///
public bool IsConnected
{
get { return _isConnected; }
set { _isConnected = value; RaisePropertyChanged(nameof(IsConnected)); InvalidateRelayCommands(); }
}
private List _ports;
///
/// Gets or sets the available USB ports.
///
public List Ports
{
get { return _ports; }
set { _ports = value; RaisePropertyChanged(nameof(Ports)); }
}
private String _selectedPort;
///
/// Gets or sets the selected USB port.
///
public String SelectedPort
{
get { return _selectedPort; }
set { _selectedPort = value; RaisePropertyChanged(nameof(SelectedPort)); InvalidateRelayCommands(); }
}
private String _status;
///
/// Gets or sets the current status bar text.
///
public String Status
{
get { return _status; }
set { _status = value; RaisePropertyChanged(nameof(Status)); }
}
private bool _isRunning;
///
/// Gets or sets a value indicating whether a stub is currently running.
///
public bool IsRunning
{
get { return _isRunning; }
set { _isRunning = value; RaisePropertyChanged(nameof(IsRunning)); InvalidateRelayCommands(); }
}
private bool _appendLogAuto;
public bool AppendLogAuto
{
get { return _appendLogAuto; }
set { _appendLogAuto = value; RaisePropertyChangedAuto(); }
}
#endregion
#region Commands
///
/// Gets or sets the new command.
///
public RelayCommand NewCommand { get; set; }
///
/// Gets or sets the close tab command.
///
public RelayCommand CloseTabCommand { get; set; }
///
/// Gets or sets the run command.
///
public RelayCommand RunCommand { get; set; }
///
/// Gets or sets the stop command.
///
public RelayCommand StopCommand { get; set; }
///
/// Gets or sets the toggle connection command.
///
public RelayCommand ToggleConnectionCommand { get; set; }
///
/// Gets or sets the open command.
///
public RelayCommand OpenCommand { get; set; }
///
/// Gets or sets the save command.
///
public RelayCommand SaveCommand { get; set; }
///
/// Gets or sets the save as command.
///
public RelayCommand SaveAsCommand { get; set; }
///
/// Gets or sets the clear command.
///
public RelayCommand ClearCommand { get; set; }
///
/// Gets or sets the stub snippet selected command.
///
public RelayCommand StubSnippetSelectedCommand { get; set; }
///
/// Gets or sets the insert snippet command.
///
public RelayCommand InsertSnippetCommand { get; set; }
///
/// Gets or sets the exit command.
///
public RelayCommand ExitCommand { get; set; }
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public MainViewVM()
{
AppendLogAuto = true;
CodeTabs = new ObservableCollection();
NewCommand = new RelayCommand(CreateNewTab);
CloseTabCommand = new RelayCommand(OnTabClosing);
RunCommand = new RelayCommand(RunTab, (x) => IsConnected && !IsRunning && SelectedCodeTab != null);
StopCommand = new RelayCommand(StopTab, (x) => IsConnected && IsRunning && SelectedCodeTab != null);
InsertSnippetCommand = new RelayCommand((x) => { });
HighlightTypes = new ObservableCollection>();
HighlightTypes.Add(new KeyValuePair("stubManager", typeof(StubManager)));
foreach (var stubType in StubBase.GetAvailableRequestResponseStubs())
{
HighlightTypes.Add(new KeyValuePair(stubType.GetType().Name, stubType));
}
StubSnippets = new ObservableCollection();
foreach (var stubType in StubBase.GetAvailableRequestStubs())
{
StubSnippetVM snippet = new StubSnippetVM();
snippet.Name = stubType.Name.Replace("Stub_", "");
snippet.Code = String.Empty;
snippet.Code += "// " + "Request ----" + Environment.NewLine;
foreach (var prop in stubType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
snippet.Code += "// " + prop.PropertyType.Name + " : " + prop.Name + Environment.NewLine;
}
Type responseType = StubBase.GetAvailableRequestResponseStubs().SingleOrDefault(x => x.Name == stubType.Name.Replace("Request", "Response"));
if (responseType != null)
{
snippet.Code += Environment.NewLine + "// " + "Response ----" + Environment.NewLine;
foreach (var prop in responseType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
snippet.Code += "// " + prop.PropertyType.Name + " : " + prop.Name + Environment.NewLine;
}
}
snippet.Code += String.Format("var response = stubManager.Run<{2}>(\"{0}\" ,{1});", stubType.Name, String.Join(", ", stubType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Select(x => x.PropertyType.Name == "string" ? "\"string\"" : x.PropertyType.Name)), stubType.Name.Replace("Request", "Response"));
StubSnippets.Add(snippet);
}
ToggleConnectionCommand = new RelayCommand(ToggleConnection, (x) => !IsRunning);
OpenCommand = new RelayCommand(OpenFile);
SaveCommand = new RelayCommand(SaveFile);
SaveAsCommand = new RelayCommand(SaveAsFile);
StubSnippetSelectedCommand = new RelayCommand(OnStubSnippetSelected);
ExitCommand = new RelayCommand(() => Application.Current.Shutdown());
ClearCommand = new RelayCommand(ClearLog);
Ports = new List()
{
"COM1",
"COM2",
"COM3",
"COM4",
"COM5",
"COM6",
"COM7",
"COM8",
"COM9",
};
SelectedPort = SettingsManager.Default.StubsUI.SelectedPort != null ? SettingsManager.Default.StubsUI.SelectedPort : Ports.First();
Status = "Ready";
if (SettingsManager.Default.StubsUI.LastTabs.Count > 0)
{
foreach (var file in SettingsManager.Default.StubsUI.LastTabs)
{
if (File.Exists(file))
{
OpenFile(file);
}
}
}
else
{
CreateNewTab();
}
Application.Current.Exit += Current_Exit;
}
#endregion
#region Virtual Methods
///
/// Called when a stub snippet is double clicked.
///
protected virtual void OnStubSnippetSelected()
{
if (SelectedStubSnippet != null)
{
if (InsertSnippetCommand != null)
{
InsertSnippetCommand.Execute(SelectedStubSnippet.Code);
}
}
}
///
/// Called when user closes a script tab.
///
/// The code tab.
protected virtual void OnTabClosing(CodeTabVM codeTab)
{
CodeTabs.Remove(codeTab);
}
#endregion
#region Private Methods
///
/// Clears the log.
///
private void ClearLog()
{
_logTextBox.Clear();
}
///
/// Saves the selected script file.
///
private void SaveFile()
{
if (SelectedCodeTab != null)
{
if (SelectedCodeTab.File == null)
{
SaveAsFile();
}
else
{
File.WriteAllText(SelectedCodeTab.File, SelectedCodeTab.Code);
}
}
}
///
/// Saves the selected script file.
///
private void SaveAsFile()
{
if (SelectedCodeTab != null)
{
SaveFileDialog dlg = new SaveFileDialog();
dlg.Filter = "C# Script Files|*.cs";
dlg.DefaultExt = ".cs";
if (dlg.ShowDialog().Value)
{
File.WriteAllText(dlg.FileName, SelectedCodeTab.Code);
SelectedCodeTab.File = dlg.FileName;
}
}
}
///
/// Opens a script from HD.
///
private void OpenFile()
{
OpenFileDialog dlg = new OpenFileDialog();
dlg.Filter = "C# Script Files|*.cs";
dlg.Multiselect = true;
if (dlg.ShowDialog().Value)
{
foreach (var file in dlg.FileNames)
{
OpenFile(file);
}
}
}
///
/// Opens the file.
///
/// The file.
private void OpenFile(String file)
{
var newTab = new CodeTabVM();
newTab.File = file;
newTab.Code = File.ReadAllText(file);
CodeTabs.Add(newTab);
SelectedCodeTab = newTab;
}
///
/// Toggles the USB adapter connection.
///
private void ToggleConnection()
{
try
{
if (!IsConnected)
{
_adapter = new UsbTransportAdapter(SelectedPort);
_adapter.Connect().Wait();
IsConnected = true;
}
else
{
_adapter.Disconnect().Wait();
IsConnected = false;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString(), "Tango");
}
}
///
/// Creates a new script tab.
///
private void CreateNewTab()
{
var newTab = new CodeTabVM();
CodeTabs.Add(newTab);
SelectedCodeTab = newTab;
}
///
/// Runs the selected script tab.
///
private async void RunTab()
{
IsRunning = true;
SelectedCodeTab.IsRunning = true;
_logTextBox.Text = (DateTime.Now.ToTimeString() + ": ") + "Executing script '" + SelectedCodeTab.Title + "'..." + Environment.NewLine;
await Task.Factory.StartNew(async () =>
{
try
{
_stubManager = new StubManager(_adapter, (txt) =>
{
AppendTextLog(txt + Environment.NewLine);
}, (txt) =>
{
AppendTextLog(txt);
}, () =>
{
});
var thisStubManager = _stubManager;
_stubManager.Completed += Manager_Completed;
_stubManager.Failed += Manager_Failed;
_stubManager.Executed += Manager_Executed;
ScriptEngine engine = new ScriptEngine(new StubOnExecuteParameters(_stubManager));
engine.ReferencedAssemblies.Add(this.GetType());
engine.ReferencedAssemblies.Add(typeof(PMR.Stubs.CalculateRequest));
engine.ReferencedAssemblies.Add(typeof(IMessage));
await engine.Run(SelectedCodeTab.Code);
if (!thisStubManager.Aborted)
{
IsRunning = false;
SelectedCodeTab.IsRunning = false;
}
}
catch (Exception ex)
{
IsRunning = false;
SelectedCodeTab.IsRunning = false;
MessageBox.Show(ex.Message, "Tango");
}
});
}
///
/// Stops the currently current script.
///
private void StopTab()
{
if (_stubManager != null)
{
_stubManager.Abort();
IsRunning = false;
SelectedCodeTab.IsRunning = false;
Status = "Stopped!";
AppendTextLog((DateTime.Now.ToTimeString() + ": ") + "Stopped!" + Environment.NewLine);
}
}
#endregion
#region Public Methods
public void SetLogTextBox(TextBox logTextBox)
{
_logTextBox = logTextBox;
}
#endregion
#region Event Handlers
///
/// Handled the Executed event.
///
/// The sender.
/// Name of the stub.
private void Manager_Executed(object sender, string stubName)
{
if (AppendLogAuto)
{
AppendTextLog((DateTime.Now.ToTimeString() + ": ") + "Executing '" + stubName + "'..." + Environment.NewLine);
}
Status = "Executing " + stubName + "...";
}
///
/// Handled the Failed event.
///
/// The sender.
/// The exception.
private void Manager_Failed(object sender, Exception ex)
{
if (IsRunning)
{
if (AppendLogAuto)
{
AppendTextLog((DateTime.Now.ToTimeString() + ": ") + ex.Message + Environment.NewLine);
}
Status = "Failed!";
}
}
///
/// Handled the Completed event.
///
/// The sender.
/// The response.
private void Manager_Completed(object sender, string response)
{
if (AppendLogAuto)
{
AppendTextLog((DateTime.Now.ToTimeString() + ": ") + "Response Received:" + Environment.NewLine);
AppendTextLog((DateTime.Now.ToTimeString() + ": ") + response + Environment.NewLine);
}
Status = "Completed";
}
private void Current_Exit(object sender, ExitEventArgs e)
{
SettingsManager.Default.StubsUI.SelectedPort = SelectedPort;
SettingsManager.Default.StubsUI.LastTabs = CodeTabs.Select(x => x.File).ToList();
SettingsManager.SaveDefaultSettings();
}
private void AppendTextLog(String log)
{
InvokeUI(() =>
{
_logTextBox.AppendText(log);
});
}
private void ClearTextLog()
{
InvokeUI(() =>
{
_logTextBox.Text = String.Empty;
});
}
#endregion
}
}