using Google.Protobuf; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using Tango.Integration.Operation; using Tango.PMR; using Tango.PMR.Common; using Tango.Stubs.Windows; using Tango.Transport.Adapters; namespace Tango.Stubs { /// /// Represents a manager capable of executing stub scripts asynchronously. /// public class StubManager { private IMachineOperator _machineOperator; private Action _writeLine; private Action _write; private Action _clear; /// /// Occurs when the stub has failed to execute. /// public event EventHandler Failed; /// /// Occurs when the stub has completed successfully. /// public event EventHandler Completed; /// /// Occurs when the stub has been initialized and executed. /// public event EventHandler Executed; /// /// Gets a value indicating whether this is aborted. /// internal bool Aborted { get; private set; } /// /// Gets or sets a value indicating whether [automatic log]. /// public bool AutoLog { get; set; } /// /// Gets or sets the request timeout. /// public int RequestTimeout { get; set; } /// /// Initializes a new instance of the class. /// /// The adapter. public StubManager(IMachineOperator machineOperator, Action writeLine, Action write, Action clear) { _writeLine = writeLine; _write = write; _clear = clear; _machineOperator = machineOperator; RequestTimeout = 2; } /// /// Aborts the current script. /// internal void Abort() { Aborted = true; } /// /// Runs the specified stub name. /// /// Name of the stub. /// The arguments. public IMessage Run(String stubName, params Object[] args) { if (Aborted) return null; var stubType = MessageFactory.GetAvailableRequestStubs().SingleOrDefault(x => x.Name.ToLower() == stubName.ToLower() || x.Name.Replace("Request", "").ToLower() == stubName.ToLower()); if (stubType == null) { OnFailed(new ArgumentException("Invalid stub '" + stubName + "'.")); return null; } var stubProps = stubType.GetProperties(BindingFlags.Public | BindingFlags.Instance); if (stubProps.Length > args.Length) { OnFailed(new ArgumentOutOfRangeException("Not enough arguments for " + stubType.Name + ".")); return null; } Executed?.Invoke(this, stubType.Name); try { Object request = Activator.CreateInstance(stubType); int argIndex = 0; foreach (var prop in stubProps) { Object arg = args[argIndex++]; if (prop.PropertyType == typeof(UInt32)) { prop.SetValue(request, UInt32.Parse(arg.ToString())); } else if (prop.PropertyType == typeof(bool)) { prop.SetValue(request, bool.Parse(arg.ToString())); } else if (prop.PropertyType.IsPrimitive) { object converted = Convert.ChangeType(arg, prop.PropertyType); prop.SetValue(request, converted); } else { prop.SetValue(request, arg); } } return Run(request as IMessage); } catch (Exception ex) { OnFailed(ex); } return null; } /// /// Runs the specified stub name. /// /// Name of the stub. /// The arguments. public IMessage Run(IMessage stub) { if (Aborted) return null; Executed?.Invoke(this, stub.GetType().Name); try { try { IMessage response = null; bool done = false; Task.Factory.StartNew(() => { try { response = _machineOperator.SendRequest(stub, new Transport.TransportRequestConfig() { Timeout = TimeSpan.FromSeconds(RequestTimeout), ThreadingMode = Transport.TransportThreadingMode.ThreadPool }).Result; OnCompleted(JsonConvert.SerializeObject(response, Formatting.Indented)); done = true; } catch (Exception ex) { done = true; OnFailed(ex); } }); while (!done) { Thread.Sleep(2); } return response; } catch (Exception ex) { OnFailed(ex); return null; } } catch (Exception ex) { OnFailed(ex); return null; } } public T Run(String stubName, params Object[] args) where T : class, IMessage { return Run(stubName, args) as T; } public T Run(IMessage stub) where T : class, IMessage { return Run(stub) as T; } /// /// Runs the specified stub name. /// /// Name of the stub. /// The arguments. public void RunContinuous(IMessage stub, Action callback) where T : class, IMessage { if (Aborted) return; try { Type stubType = stub.GetType(); Executed?.Invoke(this, stubType.Name); try { _machineOperator.SendContinuousRequest(stub, new Transport.TransportContinuousRequestConfig() { Timeout = TimeSpan.FromSeconds(RequestTimeout), ThreadingMode = Transport.TransportThreadingMode.ThreadPool }).Subscribe((msg) => { callback?.Invoke(msg as T); if (AutoLog) { WriteLine(JsonConvert.SerializeObject(msg, Formatting.Indented)); } //Next }, (ex) => { OnFailed(ex); //Error }, () => { OnCompleted("Continuous request completed."); //Completed }); } catch (Exception ex) { OnFailed(ex); } } catch (Exception ex) { OnFailed(ex); } } /// /// /// Runs the specified stub name. /// /// Name of the stub. /// The arguments. public void RunContinuous(String stubName, Action callback, params Object[] args) where T : class, IMessage { if (Aborted) return; var stubType = MessageFactory.GetAvailableRequestStubs().SingleOrDefault(x => x.Name.ToLower() == stubName.ToLower() || x.Name.Replace("Request", "").ToLower() == stubName.ToLower()); if (stubType == null) { OnFailed(new ArgumentException("Invalid stub '" + stubName + "'.")); return; } var stubProps = stubType.GetProperties(BindingFlags.Public | BindingFlags.Instance); if (stubProps.Length > args.Length) { OnFailed(new ArgumentOutOfRangeException("Not enough arguments for " + stubType.Name + ".")); return; } try { Object request = Activator.CreateInstance(stubType); int argIndex = 0; foreach (var prop in stubProps) { Object arg = args[argIndex++]; if (prop.PropertyType == typeof(UInt32)) { prop.SetValue(request, UInt32.Parse(arg.ToString())); } else if (prop.PropertyType == typeof(bool)) { prop.SetValue(request, bool.Parse(arg.ToString())); } else if (prop.PropertyType.IsPrimitive) { object converted = Convert.ChangeType(arg, prop.PropertyType); prop.SetValue(request, converted); } else { prop.SetValue(request, arg); } } RunContinuous(request as IMessage, callback); } catch (Exception ex) { OnFailed(ex); } } public void WriteLine(Object obj) { _writeLine(obj != null ? obj.ToString() : "null"); } public void Write(Object obj) { _write(obj != null ? obj.ToString() : "null"); } public void WriteLineHex(Object number, int digits) { _writeLine("#" + Convert.ToInt32(number).ToString("X" + digits.ToString())); } public void WriteHex(Object number, int digits) { _write("#" + Convert.ToInt32(number).ToString("X" + digits.ToString())); } public void Clear() { _clear(); } public String ShowResponseWindow(String message, String defaultResponse) { String response = null; bool closed = false; Application.Current.Dispatcher.Invoke(() => { TextInputWindow dlg = new TextInputWindow(message, defaultResponse); dlg.WindowStartupLocation = WindowStartupLocation.CenterOwner; dlg.Owner = Application.Current.MainWindow; dlg.ShowDialog(); response = dlg.Response; closed = true; }); while (!closed) { Thread.Sleep(10); } return response; } public String ShowResponseWindow(String message) { return ShowResponseWindow(message, null); } public String ShowResponseWindow() { return ShowResponseWindow(null); } public void WriteToFile(String filePath, String content) { File.WriteAllText(filePath, content + Environment.NewLine); } public void AppendToFile(String filePath, String content) { File.AppendAllText(filePath, content + Environment.NewLine); } /// /// Raises the event. /// /// The exception. protected virtual void OnFailed(Exception ex) { Failed?.Invoke(this, ex); } /// /// Raises the event. /// /// The response. protected virtual void OnCompleted(String response) { Completed?.Invoke(this, response); } } }