aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.FileSystem/FolderItem.cs
blob: 95b065a2d2c4ad1c6361ee734acf0a5a9f8a19da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Tango.FileSystem
{
    public class FolderItem : FileSystemItem, IFileSystemContainer
    {
        public ObservableCollection<FileSystemItem> Items { get; set; }

        public bool IsRoot { get; set; }

        public object Icon { get; set; } //Fake for binding error.

        public object SmallIcon { get; set; } //Fake for binding error.

        public FolderItem()
        {
            Type =  FileSystemItemType.Folder;
            Items = new ObservableCollection<FileSystemItem>();
        }

        public override string Description
        {
            get
            {
                return "Folder";
            }
        }
    }
}
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Reactive.Concurrency;
using System.Reactive.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using Google.Protobuf;
using Tango.BL.Entities;
using Tango.Core;
using Tango.Core.DI;
using Tango.Core.ExtensionMethods;
using Tango.Core.Threading;
using Tango.CSV;
using Tango.FSE.Common.Connection;
using Tango.FSE.Common.DataStore;
using Tango.FSE.Common.Diagnostics;
using Tango.FSE.Common.Notifications;
using Tango.FSE.Common.Threading;
using Tango.FSE.Procedures.Dialogs;
using Tango.FSE.Procedures.Helpers;
using Tango.Integration.Operation;
using Tango.PMR;
using Tango.Scripting.Basic;
using Tango.Scripting.Core;

namespace Tango.FSE.Procedures
{
    public class ProcedureContext : ExtendedObject, IProcedureContext
    {
        private IProcedureLogger _logger;
        private ProcedureProject _project;
        private Dictionary<String, ProcedureInput> _inputs;
        private DiagnosticsFrame _lastDiagnosticsFrame;

        public event EventHandler<TangoProgressChangedEventArgs<double>> Progress;

        public event EventHandler<BreakPointRequestEventArgs> BreakPointRequest;

        [TangoInject]
        private IMachineProvider MachineProvider { get; set; }

        [TangoInject]
        private INotificationProvider NotificationProvider { get; set; }

        [TangoInject]
        private IDispatcherProvider DispatcherProvider { get; set; }

        [TangoInject]
        private IDiagnosticsProvider DiagnosticsProvider { get; set; }

        [TangoInject]
        private IRemoteDataStoreManager RemoteDataStore { get; set; }

        public ReadOnlyCollection<Result> Results { get; private set; }

        public MachineConnectionTypes ConnectionType
        {
            get { return MachineProvider.ConnectionType; }
        }

        public bool IsConnected
        {
            get { return MachineProvider.IsConnected; }
        }

        public Machine ConnectedMachine
        {
            get { return MachineProvider.Machine; }
        }

        public ProcedureContext(ProcedureProject project, IProcedureLogger logger)
        {
            _project = project;
            _inputs = new Dictionary<string, ProcedureInput>();

            foreach (var input in _project.Inputs)
            {
                _inputs.Add(input.Key, input);
            }

            _logger = logger;
            Results = new ReadOnlyCollection<Result>(new List<Result>());
            TangoIOC.Default.Inject(this);
        }

        public IMessage Send(string messageName, TimeSpan? timeout = null, params object[] args)
        {
            var stubType = MessageFactory.GetAvailableRequestStubs().SingleOrDefault(x => x.Name.ToLower() == messageName.ToLower() || x.Name.Replace("Request", "").ToLower() == messageName.ToLower());
            if (stubType == null)
            {
                throw new ArgumentException($"Stub '{messageName}' could not be located on the PMR.");
            }

            var stubProps = stubType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            if (stubProps.Length > args.Length)
            {
                throw new ArgumentOutOfRangeException("Not enough arguments for " + stubType.Name + ".");
            }

            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 Send(request as IMessage, timeout != null ? (int?)timeout.Value.TotalSeconds : null);
        }

        public IMessage Send(string messageName, params object[] args)
        {
            return Send(messageName, null, args);
        }

        public T Send<T>(string messageName, TimeSpan? timeout = null, params object[] args) where T : class, IMessage
        {
            return Send(messageName, timeout, args) as T;
        }

        public T Send<T>(string messageName, params object[] args) where T : class, IMessage
        {
            return Send<T>(messageName, null, args);
        }

        public IMessage Send(IMessage message, int? timeout = null)
        {
            TimeSpan? timespan = null;

            if (timeout != null)
            {
                timespan = TimeSpan.FromMilliseconds(timeout.Value);
            }

            return MachineProvider.MachineOperator.SendRequest(message, new Transport.TransportRequestConfig()
            {
                Timeout = timespan,
            }).Result;
        }

        public T Send<T>(IMessage messageName, int? timeout = null) where T : class, IMessage
        {
            return Send(messageName, timeout) as T;
        }

        public void SendContinuous<T>(IMessage message, Action<T> callback, int? timeout = null) where T : class, IMessage
        {
            TaskCompletionSource<object> completion = new TaskCompletionSource<object>();

            TimeSpan? timespan = null;

            if (timeout != null)
            {
                timespan = TimeSpan.FromMilliseconds(timeout.Value);
            }

            MachineProvider.MachineOperator.SendContinuousRequest(message, new Transport.TransportContinuousRequestConfig()
            {
                Timeout = timespan,
                ContinuousTimeout = timespan
            }).ObserveOn(new NewThreadScheduler()).Subscribe((msg) =>
            {
                try
                {
                    callback?.Invoke(msg as T);
                }
                catch { }
            }, (ex) =>
            {
                completion.SetException(ex);
            }, () =>
            {
                completion.SetResult(true);
            });

            completion.Task.GetAwaiter().GetResult();
        }

        public void SendContinuous<T>(string messageName, Action<T> callback, TimeSpan? timeout = null, params object[] args) where T : class, IMessage
        {
            var stubType = MessageFactory.GetAvailableRequestStubs().SingleOrDefault(x => x.Name.ToLower() == messageName.ToLower() || x.Name.Replace("Request", "").ToLower() == messageName.ToLower());
            if (stubType == null)
            {
                throw new ArgumentException("Invalid stub '" + messageName + "'.");
            }

            var stubProps = stubType.GetProperties(BindingFlags.Public | BindingFlags.Instance);

            if (stubProps.Length > args.Length)
            {
                throw new ArgumentOutOfRangeException("Not enough arguments for " + stubType.Name + ".");
            }

            IMessage request = Activator.CreateInstance(stubType) as IMessage;

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

            SendContinuous<IMessage>(request, callback as Action<IMessage>, timeout != null ? (int?)timeout.Value.TotalSeconds : null);
        }

        public void SendContinuous<T>(string messageName, Action<T> callback, params object[] args) where T : class, IMessage
        {
            SendContinuous<T>(messageName, callback, null, args);
        }

        public void WriteLine()
        {
            _logger?.WriteLine(String.Empty);
        }

        public void WriteLine(object obj)
        {
            String line = "null";

            if (obj != null)
            {
                if (!obj.GetType().IsValueTypeOrString())
                {
                    line = obj.ToJsonString();
                }
                else
                {
                    line = obj.ToString();
                }
            }

            _logger?.WriteLine(line);
        }

        public void Write(object obj)
        {
            String line = "null";

            if (obj != null)
            {
                if (!obj.GetType().IsValueTypeOrString())
                {
                    line = obj.ToJsonString();
                }
                else
                {
                    line = obj.ToString();
                }
            }

            _logger?.WriteLine(line);
        }

        public void WriteLineHex(object number, int digits)
        {
            _logger?.WriteLine("#" + Convert.ToInt32(number).ToString("X" + digits.ToString()));
        }

        public void WriteHex(object number, int digits)
        {
            _logger?.Write("#" + Convert.ToInt32(number).ToString("X" + digits.ToString()));
        }

        public void Clear()
        {
            _logger?.Clear();
        }

        public void WriteToFile(string filePath, string content)
        {
            EnsureFileLocation(filePath);
            File.WriteAllText(filePath, content);
        }

        public void WriteToFile(string filePath, byte[] data)
        {
            EnsureFileLocation(filePath);
            File.WriteAllBytes(filePath, data);
        }

        public void AppendToFile(string filePath, string content)
        {
            EnsureFileLocation(filePath);
            File.AppendAllText(filePath, content);
        }

        public Result AddResult(ResultType type, string name, object value)
        {
            var result = new Result(type, name, value);
            return AddResult(result);
        }

        public Result AddGraphResult(ResultType type, string name, IEnumerable<double> values)
        {
            return AddResult(new Result()
            {
                IsGraph = true,
                Name = name,
                Type = type,
                Value = values,
            });
        }

        public Result AddResult(Result result)
        {
            List<Result> results = new List<Result>(Results);
            results.Add(result);
            Results = new ReadOnlyCollection<Result>(results);
            return result;
        }

        public void RemoveResult(Result result)
        {
            List<Result> results = new List<Result>(Results);
            results.Remove(result);
            Results = new ReadOnlyCollection<Result>(results);
        }

        public void ClearResults()
        {
            Results = new ReadOnlyCollection<Result>(new List<Result>());
        }

        public T GetInput<T>(string key)
        {
            var value = GetInput(key);

            try
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
            catch
            {
                throw new InvalidCastException($"Error converting the specified input '{value}' to type '{typeof(T).Name}'.");
            }
        }

        public List<T> GetInputArray<T>(String key)
        {
            var value = GetInput(key);

            String[] arr = value.ToStringSafe().Split(',');
            var list = new List<T>(arr.Select(x => (T)Convert.ChangeType(x, typeof(T))));

            return list;
        }

        public object GetInput(string key)
        {
            ProcedureInput input = null;

            if (_inputs.TryGetValue(key, out input))
            {
                return input.Value;
            }
            else
            {
                throw new KeyNotFoundException($"Could no find input with key '{key}'.");
            }
        }

        public void Fail(string message)
        {
            throw new ProcedureFailedException(message);
        }

        public void ShowInfo(string message)
        {
            AutoInvoke(NotificationProvider.ShowInfo(message));
        }

        public void ShowWarning(string message)
        {
            AutoInvoke(NotificationProvider.ShowWarning(message));
        }

        public void ShowError(string message)
        {
            AutoInvoke(NotificationProvider.ShowError(message));
        }

        public bool ShowQuestion(string message)
        {
            return AutoInvoke(NotificationProvider.ShowQuestion(message));
        }

        public bool ShowWarningQuestion(string message)
        {
            return AutoInvoke(NotificationProvider.ShowWarningQuestion(message));
        }

        public T RequestUserInputFor<T>(string title, string message)
        {
            return RequestUserInputFor<T>(typeof(T).IsValueTypeOrString() ? default(T) : Activator.CreateInstance<T>(), title, message);
        }

        public T RequestUserInputFor<T>(T model, string title, string message)
        {
            Object obj = model;

            if (typeof(T) == typeof(String) && model == null)
            {
                obj = "";
            }

            UserInputDialogViewVM vm = new UserInputDialogViewVM(title, message, obj);
            vm.Init();

            TaskCompletionSource<Object> completion = new TaskCompletionSource<Object>();

            DispatcherProvider.Invoke(async () =>
            {
                await NotificationProvider.ShowDialog(vm);
                completion.SetResult(obj);
            });

            var result = completion.Task.GetAwaiter().GetResult();
            vm.FinalizeModel();
            return (T)vm.Model;
        }

        public void WriteLineArray(IEnumerable array, ArrayParsingStyle style)
        {
            String line = String.Empty;

            List<Object> list = new List<object>();

            foreach (var item in array)
            {
                list.Add(item);
            }

            if (style == ArrayParsingStyle.Comma)
            {
                line = String.Join(", ", list.Select(x => x.ToStringSafe()));
            }
            else
            {
                foreach (var item in list)
                {
                    line += $"[{item.ToStringSafe()}] ";
                }
            }

            WriteLine(line);
        }

        public DiagnosticsPackage GetDiagnosticsPackage(bool waitForNext = false)
        {
            if (waitForNext)
            {
                Stopwatch watch = new Stopwatch();
                watch.Start();

                while (_lastDiagnosticsFrame == DiagnosticsProvider.CurrentFrame)
                {
                    Thread.Sleep(10);

                    if (watch.Elapsed.TotalSeconds > 5)
                    {
                        throw new TimeoutException("Diagnostics package did not arrive within the given time of 5 seconds.");
                    }
                }
            }

            _lastDiagnosticsFrame = DiagnosticsProvider.CurrentFrame;

            return DiagnosticsProvider.CurrentFrame.ToPackage();
        }

        public void Sleep(int milliseconds)
        {
            Thread.Sleep(milliseconds);
        }

        public Thread RunAsync(Action action)
        {
            return ThreadFactory.StartNew(action);
        }

        public string GetFileText(string path)
        {
            return File.ReadAllText(path);
        }

        public byte[] GetFileBytes(string path)
        {
            return File.ReadAllBytes(path);
        }

        public String RequestFileOpen(string message, string extension = "*.*")
        {
            OpenFileDialogViewVM vm = new OpenFileDialogViewVM(message, extension);

            TaskCompletionSource<String> completion = new TaskCompletionSource<String>();

            DispatcherProvider.Invoke(async () =>
            {
                await NotificationProvider.ShowDialog(vm);
                completion.SetResult(vm.SelectedFile);
            });

            var result = completion.Task.GetAwaiter().GetResult();
            return result;
        }

        public string RequestFileSave(string message, string extension = "*.*", string defaultFileName = null)
        {
            SaveFileDialogViewVM vm = new SaveFileDialogViewVM(message, extension, defaultFileName);

            TaskCompletionSource<String> completion = new TaskCompletionSource<String>();

            DispatcherProvider.Invoke(async () =>
            {
                await NotificationProvider.ShowDialog(vm);
                completion.SetResult(vm.SelectedFile);
            });

            var result = completion.Task.GetAwaiter().GetResult();
            return result;
        }

        public void UpdateProgress(string message, bool isIndeterminate = true, double value = 0, double maximum = 100)
        {
            Progress?.Invoke(this, new TangoProgressChangedEventArgs<double>()
            {
                Progress = new TangoProgress<double>()
                {
                    IsIndeterminate = isIndeterminate,
                    Message = message,
                    Maximum = maximum,
                    Value = value
                },
            });
        }

        public Result AddBitmapResult(ResultType type, String name, Bitmap bitmap)
        {
            return AddResult(new Result()
            {
                IsBitmap = true,
                Name = name,
                Type = type,
                Value = bitmap
            });
        }

        public Bitmap CreateBitmap(int width, int height)
        {
            return new Bitmap(width, height);
        }

        public Graphics GetDrawingContext(Bitmap bitmap)
        {
            return Graphics.FromImage(bitmap);
        }

        public IDialogController LoadDialog(string name)
        {
            var dialog = GetDialog(name);
            if (dialog == null)
            {
                throw new FileNotFoundException($"The specified dialog '{name}' could not be found in the project.");
            }

            DialogController controller = new DialogController(dialog.Xaml);
            controller.Init();
            return controller;
        }

        public IDialogController LoadDialogAsWindow(string name, String windowTitle)
        {
            var dialog = GetDialog(name);
            if (dialog == null)
            {
                throw new FileNotFoundException($"The specified dialog '{name}' could not be found in the project.");
            }

            WindowController controller = new WindowController(dialog.Xaml, windowTitle);
            controller.Init();
            return controller;
        }

        private ProcedureDialog GetDialog(String name)
        {
            name = Path.GetFileNameWithoutExtension(name);
            return _project.Dialogs.SingleOrDefault(x => x.Name.ToLower() == name.ToLower() + ".xaml");
        }

        private void AutoInvoke(Task task)
        {
            bool completed = false;

            if (Application.Current.Dispatcher.Thread == Thread.CurrentThread)
            {
                task.ContinueWith((x) =>
                {
                    completed = true;
                });

                DispatcherProvider.Invoke((Action)(async () =>
                {
                    await task;
                }));

                while (!completed)
                {
                    Thread.Sleep(2);
                    DispatcherProvider.DoEvents();
                }
            }
            else
            {
                task.ContinueWith((x) =>
                {
                    completed = true;
                });

                DispatcherProvider.Invoke((Action)(async () =>
                {
                    await task;
                }));

                while (!completed)
                {
                    Thread.Sleep(10);
                }
            }
        }

        private T AutoInvoke<T>(Task<T> task)
        {
            bool completed = false;
            T result = default(T);

            if (Application.Current.Dispatcher.Thread == Thread.CurrentThread)
            {
                task.ContinueWith((x) =>
                {
                    result = x.Result;
                    completed = true;
                });

                DispatcherProvider.Invoke(async () =>
                {
                    await task;
                });

                while (!completed)
                {
                    Thread.Sleep(2);
                    DispatcherProvider.DoEvents();
                }

                return result;
            }
            else
            {
                task.ContinueWith((x) =>
                {
                    result = x.Result;
                    completed = true;
                });

                DispatcherProvider.Invoke(async () =>
                {
                    await task;
                });

                while (!completed)
                {
                    Thread.Sleep(10);
                }

                return result;
            }
        }

        public T GetService<T>()
        {
            return TangoIOC.Default.GetInstance<T>();
        }

        public byte[] GetResourceBytes(string resourceName)
        {
            var resource = _project.Resources.SingleOrDefault(x => x.Name.ToLower() == resourceName.ToLower());

            if (resource == null)
            {
                throw new FileNotFoundException($"The specified resource '{resourceName}' could not be found on the procedure project.");
            }

            return resource.Data;
        }

        public string GetResourceString(string resourceName)
        {
            byte[] data = GetResourceBytes(resourceName);
            return Encoding.Default.GetString(data);
        }

        public void OpenResource(string resourceName)
        {
            var data = GetResourceBytes(resourceName);
            var tempFolder = TemporaryManager.CreateFolder();
            var tempFile = Path.Combine(tempFolder, resourceName);
            File.WriteAllBytes(tempFile, data);
            Process.Start(tempFile);
        }

        public object GetVariable(string name)
        {
            ProcedureVariable variable = _project.Variables.SingleOrDefault(x => x.Name == name);

            if (variable == null)
            {
                throw new KeyNotFoundException($"The specified variable '{name}' could not found.");
            }

            return variable.Value;
        }

        public T GetVariable<T>(string name)
        {
            object value = GetVariable(name);

            try
            {
                return (T)Convert.ChangeType(value, typeof(T));
            }
            catch
            {
                throw new InvalidCastException($"Error converting the specified variable value '{value}' to type '{typeof(T).Name}'.");
            }
        }

        public List<T> GetVariableArray<T>(string name)
        {
            object value = GetVariable(name);

            String[] arr = value.ToStringSafe().Split(',');
            var list = new List<T>(arr.Select(x => (T)Convert.ChangeType(x, typeof(T))));

            return list;
        }

        public List<T> ReadCsv<T>(string file) where T : class, new()
        {
            var items = CsvFile.Read<T>(new CsvSource(file));
            return items.ToList();
        }

        public List<T> ReadCsv<T>(byte[] data) where T : class, new()
        {
            using (MemoryStream ms = new MemoryStream(data))
            {
                var items = CsvFile.Read<T>(new CsvSource(ms));
                return items.ToList();
            }
        }

        public void WriteCsv<T>(string file, List<T> items)
        {
            CsvFile<T> csvFile = new CsvFile<T>(new CsvDestination(file));

            foreach (var item in items)
            {
                csvFile.Append(item);
            }

            csvFile.Dispose();
        }

        public IRemoteDataStoreManager GetRemoteDataStoreManager()
        {
            return RemoteDataStore;
        }

        public void BreakPoint(string file, int lineNumber, params object[] symbolsMap)
        {
            if (BreakPointRequest != null && symbolsMap.Length > 0)
            {
                bool released = false;

                BreakPointRequestEventArgs args = new BreakPointRequestEventArgs(() =>
                {
                    released = true;
                });

                args.LineNumber = lineNumber;
                args.Script = _project.Scripts.SingleOrDefault(x => x.Name == file);

                for (int i = 0; i < symbolsMap.Length; i += 4)
                {
                    args.Symbols.Add(new ScriptBreakPointSymbol()
                    {
                        Name = symbolsMap[i].ToString(),
                        Offset = (int)symbolsMap[i + 1],
                        Length = (int)symbolsMap[i + 2],
                        SymbolObject = symbolsMap[i + 3],
                    });
                }

                DispatcherProvider.Invoke(() =>
                {
                    BreakPointRequest?.Invoke(this, args);
                });

                while (!released)
                {
                    Thread.Sleep(100);
                }
            }
        }

        private void EnsureFileLocation(String file)
        {
            String dir = Path.GetDirectoryName(file);

            if (!Directory.Exists(dir))
            {
                Directory.CreateDirectory(dir);
            }
        }
    }
}