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 } }