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