From ee43b90abff1fe5b23a73f2cd955b96652f7962d Mon Sep 17 00:00:00 2001
From: Markus Quaritsch <markus.quaritsch@tugraz.at>
Date: Thu, 7 May 2020 18:09:27 +0200
Subject: [PATCH] taking over code for running the simulation from old vecto 
 gui. basic functionality works..

---
 VECTO3GUI/ViewModel/Impl/JoblistViewModel.cs  | 310 ++++++++++++++++++
 .../ViewModel/Interfaces/IJoblistViewModel.cs |   2 +-
 VECTO3GUI/Views/JoblistView.xaml              |   3 +-
 .../CompletedBusFactorMethodTest.cs           |   2 +-
 4 files changed, 314 insertions(+), 3 deletions(-)

diff --git a/VECTO3GUI/ViewModel/Impl/JoblistViewModel.cs b/VECTO3GUI/ViewModel/Impl/JoblistViewModel.cs
index a7d8cf6461..d9bfa4d9a8 100644
--- a/VECTO3GUI/ViewModel/Impl/JoblistViewModel.cs
+++ b/VECTO3GUI/ViewModel/Impl/JoblistViewModel.cs
@@ -1,24 +1,37 @@
 using System;
 using System.Collections;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Collections.Specialized;
 using System.ComponentModel;
 using System.Diagnostics;
 using System.IO;
 using System.Linq;
+using System.Threading;
 using System.Windows;
+using System.Windows.Forms;
 using System.Windows.Input;
 using System.Xml;
+using System.Xml.Linq;
 using Castle.Core.Internal;
 using Ninject;
 using TUGraz.VectoCommon.InputData;
+using TUGraz.VectoCommon.Models;
+using TUGraz.VectoCommon.Resources;
+using TUGraz.VectoCore;
+using TUGraz.VectoCore.Configuration;
+using TUGraz.VectoCore.InputData.FileIO.JSON;
 using TUGraz.VectoCore.InputData.FileIO.XML;
 using TUGraz.VectoCore.InputData.FileIO.XML.Declaration.DataProvider;
+using TUGraz.VectoCore.Models.Simulation.Impl;
+using TUGraz.VectoCore.OutputData;
+using TUGraz.VectoCore.OutputData.FileIO;
 using VECTO3GUI.Util;
 using VECTO3GUI.ViewModel.Interfaces;
 using VECTO3GUI.Helper;
 using VECTO3GUI.Model;
 using VECTO3GUI.Views;
+using MessageBox = System.Windows.MessageBox;
 
 
 namespace VECTO3GUI.ViewModel.Impl
@@ -52,6 +65,8 @@ namespace VECTO3GUI.ViewModel.Impl
 		private ICommand _startSimulationCommand;
 		private ICommand _openInFolderCommand;
 		private ICommand _doubleClickCommand;
+		private ICommand _runSimulationCommand;
+		private BackgroundWorker SimulationWorker;
 
 		#endregion
 
@@ -106,6 +121,14 @@ namespace VECTO3GUI.ViewModel.Impl
 		{
 			_settings = new SettingsModel();
 			SetJobEntries();
+
+			SimulationWorker = new BackgroundWorker();
+			SimulationWorker.DoWork += RunVectoSimulation;
+			SimulationWorker.ProgressChanged += VectoSimulationProgressChanged;
+			SimulationWorker.RunWorkerCompleted += VectoSimulationCompleted;
+			SimulationWorker.WorkerReportsProgress = true;
+			SimulationWorker.WorkerSupportsCancellation = true;
+
 		}
 
 		private void SetJobEntries()
@@ -140,10 +163,18 @@ namespace VECTO3GUI.ViewModel.Impl
 		#region Commands
 
 
+		
+
+		public ICommand RunSimulation
+		{
+			get { return _runSimulationCommand ?? (_runSimulationCommand = new RelayCommand(DoRunSimulation, CanRunSimulation)); }
+		}
+
 		public ICommand DoubleClickCommand
 		{
 			get { return _doubleClickCommand ?? (_doubleClickCommand = new RelayCommand<JobEntry>(DoDoubleClick)); }
 		}
+
 		private void DoDoubleClick(JobEntry jobEntry)
 		{
 			if (jobEntry == null || !IsJobFile(jobEntry.JobEntryFilePath))
@@ -597,5 +628,284 @@ namespace VECTO3GUI.ViewModel.Impl
 			
 			FirstContextMenu = $"View {contextMenuText}";
 		}
+
+		#region RunVECTOSimulation
+
+		private bool CanRunSimulation()
+		{
+			return !SimulationWorker.IsBusy;
+		}
+
+		private void DoRunSimulation()
+		{
+			if (!SimulationWorker.IsBusy) {
+				// change button to stop button
+				Messages.Clear();
+				SimulationWorker.RunWorkerAsync();
+			}
+		}
+
+		private void RunVectoSimulation(object theSender, DoWorkEventArgs e)
+		{
+			var sender = theSender as BackgroundWorker;
+			if (sender == null) {
+				return;
+			}
+
+			var jobs = Jobs.Where(x => x.Selected).ToArray();
+			if (jobs.Length == 0) {
+				sender.ReportProgress(100, new VectoSimulationProgress() {Target = VectoSimulationProgress.Targets.Message, Message = "No jobs selected for simulation"});
+				return;
+			}
+			var sumFileWriter = new FileOutputWriter(Path.GetDirectoryName(jobs.First().JobEntryFilePath));
+			var sumContainer = new SummaryDataContainer(sumFileWriter);
+			var jobContainer = new JobContainer(sumContainer);
+
+			var mode = ExecutionMode.Declaration;
+
+			var fileWriters = new Dictionary<int, FileOutputWriter>();
+			var finishedRuns = new List<int>();
+
+			
+			var kernel = new StandardKernel(new VectoNinjectModule());
+			var xmlReader = kernel.Get<IXMLInputDataReader>();
+
+			foreach (var jobEntry in jobs) {
+				try {
+					var fullFileName = Path.GetFullPath(jobEntry.JobEntryFilePath);
+					if (!File.Exists(fullFileName)) {
+						sender.ReportProgress(
+							0, new VectoSimulationProgress() {
+								Target = VectoSimulationProgress.Targets.Message,
+								Message =
+									$"File {jobEntry.JobEntryFilePath} not found!"
+							});
+						continue;
+					}
+
+					sender.ReportProgress(
+						0,
+						new VectoSimulationProgress() {
+							Target = VectoSimulationProgress.Targets.Message,
+							Message = $"Reading file {Path.GetFileName(fullFileName)}"
+						});
+					var extension = Path.GetExtension(jobEntry.JobEntryFilePath);
+					IInputDataProvider input = null;
+					switch (extension) {
+						case Constants.FileExtensions.VectoJobFile:
+							input = JSONInputDataFactory.ReadJsonJob(fullFileName);
+							var tmp = input as IDeclarationInputDataProvider;
+							mode = tmp?.JobInputData.SavedInDeclarationMode ?? false ? ExecutionMode.Declaration : ExecutionMode.Engineering;
+							break;
+						case ".xml":
+							var xdoc = XDocument.Load(fullFileName);
+							var rootNode = xdoc.Root?.Name.LocalName ?? "";
+							if (XMLNames.VectoInputEngineering.Equals(rootNode, StringComparison.InvariantCultureIgnoreCase)) {
+								input = xmlReader.CreateEngineering(fullFileName);
+							} else if (XMLNames.VectoInputDeclaration.Equals(rootNode, StringComparison.InvariantCultureIgnoreCase)) {
+								using (var reader = XmlReader.Create(fullFileName)) {
+									input = xmlReader.CreateDeclaration(reader);
+								}
+								mode = ExecutionMode.Engineering;
+							}
+							break;
+					}
+
+					if (input == null) {
+						sender.ReportProgress(
+							0,
+							new VectoSimulationProgress() {
+								Target = VectoSimulationProgress.Targets.Message,
+								Message = $"No input provider for job {Path.GetFileName(fullFileName)}"
+							});
+						continue;
+					}
+
+					var fileWriter = new FileOutputWriter(Path.GetDirectoryName(fullFileName));
+					var runsFactory = new SimulatorFactory(mode, input, fileWriter);
+					foreach (var runId in jobContainer.AddRuns(runsFactory)) {
+						fileWriters.Add(runId, fileWriter);
+					}
+
+					sender.ReportProgress(
+						0,
+						new VectoSimulationProgress() {
+							Target = VectoSimulationProgress.Targets.Message,
+							Message = $"Finished reading data for job {Path.GetFileName(fullFileName)}"
+						});
+				} catch (Exception ex) {
+					MessageBox.Show(
+						$"ERROR running job {Path.GetFileName(jobEntry.JobEntryFilePath)}: {ex.Message}", "Error", MessageBoxButton.OK,
+						MessageBoxImage.Exclamation);
+					sender.ReportProgress(0, new VectoSimulationProgress() {Target = VectoSimulationProgress.Targets.Message, Message = ex.Message});
+				}
+			}
+
+			foreach (var cycle in jobContainer.GetCycleTypes()) {
+				sender.ReportProgress(0, new VectoSimulationProgress() {Target = VectoSimulationProgress.Targets.Message, Message = $"Detected cycle {cycle.Name}: {cycle.CycleType}"});
+			}
+
+			sender.ReportProgress(0, new VectoSimulationProgress() {Target = VectoSimulationProgress.Targets.Message, Message = $"Starting simulation ({jobs.Length} jobs, {jobContainer.GetProgress().Count} runs)"});
+
+			var start = Stopwatch.StartNew();
+
+			jobContainer.Execute(true);
+
+			while (!jobContainer.AllCompleted) {
+				if (sender.CancellationPending) {
+					jobContainer.Cancel();
+					return;
+				}
+
+				var progress = jobContainer.GetProgress();
+				var sumProgress = progress.Sum(x => x.Value.Progress);
+				var duration = start.Elapsed.TotalSeconds;
+
+				sender.ReportProgress(
+					Convert.ToInt32(sumProgress * 100.0 / progress.Count), new VectoSimulationProgress() {
+						Target = VectoSimulationProgress.Targets.Status,
+						Message = string.Format(
+							"Duration: {0:F1}s, Curernt Progress: {1:P} ({2})", duration, sumProgress / progress.Count,
+							string.Join(", ", progress.Select(x => string.Format("{0,4:P}", x.Value.Progress))))
+					});
+				var justFinished = progress.Where(x => x.Value.Done & !finishedRuns.Contains(x.Key))
+											.ToDictionary(x => x.Key, x => x.Value);
+				PrintRuns(justFinished, fileWriters);
+				finishedRuns.AddRange(justFinished.Select(x => x.Key));
+				Thread.Sleep(100);
+			}
+			start.Stop();
+
+			var remainingRuns = jobContainer.GetProgress().Where(x => x.Value.Done && !finishedRuns.Contains(x.Key))
+											.ToDictionary(x => x.Key, x => x.Value);
+			PrintRuns(remainingRuns, fileWriters);
+
+			finishedRuns.Clear();
+			fileWriters.Clear();
+
+			foreach (var progressEntry in jobContainer.GetProgress()) {
+				sender.ReportProgress(100, new VectoSimulationProgress() {
+					Target = VectoSimulationProgress.Targets.Message, Message = 
+						string.Format("{0,-60} {1,8:P} {2,10:F2}s - {3}",
+									$"{progressEntry.Value.RunName} {progressEntry.Value.CycleName} {progressEntry.Value.RunSuffix}",
+						progressEntry.Value.Progress,
+						progressEntry.Value.ExecTime / 1000.0,
+						progressEntry.Value.Success ? "Success" : "Aborted")
+				});
+				if (!progressEntry.Value.Success) {
+					sender.ReportProgress(
+						100,
+						new VectoSimulationProgress() {
+							Target = VectoSimulationProgress.Targets.Message,
+							Message = progressEntry.Value.Error.Message
+						}
+					);
+				}
+			}
+
+			foreach (var jobEntry in jobs) {
+				var w = new FileOutputWriter(Path.GetFullPath(jobEntry.JobEntryFilePath));
+				foreach (var entry in new Dictionary<string, string>() { {w.XMLFullReportName,  "XML ManufacturereReport"}, {w.XMLCustomerReportName, "XML Customer Report"}, { w.XMLVTPReportName, "VTP Report"}, {w.XMLPrimaryVehicleReportName, "Primary Vehicle Information File"}  }) {
+					if (File.Exists(entry.Key)) {
+						sender.ReportProgress(
+							100,
+							new VectoSimulationProgress() {
+								Target = VectoSimulationProgress.Targets.Message,
+								Message = string.Format(
+									"{2} for '{0}' written to {1}", Path.GetFileName(jobEntry.JobEntryFilePath), entry.Key, entry.Value),
+								Link = "<XML>" + entry.Key
+							});
+					}	
+				}
+			}
+
+			if (File.Exists(sumFileWriter.SumFileName)) {
+				sender.ReportProgress(100, new VectoSimulationProgress() {
+					Target = VectoSimulationProgress.Targets.Message,
+					Message = string.Format("Sum file written to {0}", sumFileWriter.SumFileName),
+					Link = "<CSV>" + sumFileWriter.SumFileName
+				});
+			}
+
+			sender.ReportProgress(100, new VectoSimulationProgress() {
+				Target = VectoSimulationProgress.Targets.Message,
+				Message = string.Format("Simulation finished in {0:F1}s", start.Elapsed.TotalSeconds)
+			});
+		}
+
+		private void PrintRuns(Dictionary<int, JobContainer.ProgressEntry> progress, Dictionary<int, FileOutputWriter> fileWriters)
+		{
+			foreach (var p in progress) {
+				var modFilename = fileWriters[p.Key].GetModDataFileName(p.Value.RunName, p.Value.CycleName, p.Value.RunSuffix);
+				var runName = string.Format("{0} {1} {2}", p.Value.RunName, p.Value.CycleName, p.Value.RunSuffix);
+
+				if (p.Value.Error != null) {
+					SimulationWorker.ReportProgress(0, new VectoSimulationProgress() {
+						Target = VectoSimulationProgress.Targets.Message,
+						Message = string.Format("Finished Run {0} with ERROR: {1}", runName,
+												p.Value.Error.Message),
+						Link = "<CSV>" + modFilename
+					});
+				} else {
+					SimulationWorker.ReportProgress(0, new VectoSimulationProgress() {
+						Target = VectoSimulationProgress.Targets.Message,
+						Message = string.Format("Finished run {0} successfully.", runName)
+					});
+				}
+				if (File.Exists(modFilename)) {
+					SimulationWorker.ReportProgress(0, new VectoSimulationProgress() {
+						Target = VectoSimulationProgress.Targets.Message,
+						Message = string.Format("Run {0}: Modal results written to {1}", runName, modFilename),
+						Link = "<CSV>" + modFilename
+					});
+				}
+			}
+		}
+
+
+		private void VectoSimulationCompleted(object sender, RunWorkerCompletedEventArgs e)
+		{
+			// TODO!
+		}
+
+		private void VectoSimulationProgressChanged(object sender, ProgressChangedEventArgs e)
+		{
+			var progress = e.UserState as VectoSimulationProgress;
+			if (progress == null) {
+				return;
+			}
+
+			switch (progress.Target) {
+				case VectoSimulationProgress.Targets.Message:
+					//if (progress.Link == null) {
+						Messages.Add(new MessageEntry() {Message = progress.Message});
+					//}
+					break;
+				case VectoSimulationProgress.Targets.Status: break;
+				default: throw new ArgumentOutOfRangeException();
+			}
+		}
+
+
+		public class VectoSimulationProgress
+		{
+			public enum Targets
+			{
+				Message,
+				Status
+			}
+
+			public string Message { get; set; }
+
+			public Targets Target { get; set; }
+
+			public string Link { get; set; }
+		}
+
+
+#endregion
+
 	}
+
+
 }
diff --git a/VECTO3GUI/ViewModel/Interfaces/IJoblistViewModel.cs b/VECTO3GUI/ViewModel/Interfaces/IJoblistViewModel.cs
index 0eb145dae9..6300e454c7 100644
--- a/VECTO3GUI/ViewModel/Interfaces/IJoblistViewModel.cs
+++ b/VECTO3GUI/ViewModel/Interfaces/IJoblistViewModel.cs
@@ -24,6 +24,6 @@ namespace VECTO3GUI.ViewModel.Interfaces
 		ICommand ExitMainCommand { get; }
 		ICommand OpenInFolder { get; }
 		ICommand DoubleClickCommand { get; }
-
+		ICommand RunSimulation { get; }
 	}
 }
diff --git a/VECTO3GUI/Views/JoblistView.xaml b/VECTO3GUI/Views/JoblistView.xaml
index d6fdaa9b7f..93a7f66d7b 100644
--- a/VECTO3GUI/Views/JoblistView.xaml
+++ b/VECTO3GUI/Views/JoblistView.xaml
@@ -33,7 +33,8 @@
         <Grid Grid.Row="1" Grid.Column="0">
 
             <StackPanel Orientation="Vertical">
-                <Button VerticalAlignment="Top" Margin="10,10,0,0">
+                <Button VerticalAlignment="Top" Margin="10,10,0,0"
+                        Command="{Binding RunSimulation}">
                     <StackPanel Orientation="Horizontal">
                         <iconPacks:PackIconModern Width="20" Height="15" Kind="ControlPlay" VerticalAlignment="Center" HorizontalAlignment="Center" Foreground="Green"/>
                         <TextBlock Text="Start " />
diff --git a/VectoCore/VectoCoreTest/Integration/CompletedBus/CompletedBusFactorMethodTest.cs b/VectoCore/VectoCoreTest/Integration/CompletedBus/CompletedBusFactorMethodTest.cs
index bae9b04154..168b3e09ab 100644
--- a/VectoCore/VectoCoreTest/Integration/CompletedBus/CompletedBusFactorMethodTest.cs
+++ b/VectoCore/VectoCoreTest/Integration/CompletedBus/CompletedBusFactorMethodTest.cs
@@ -958,7 +958,7 @@ namespace TUGraz.VectoCore.Tests.Integration.CompletedBus
 		[TestCase(JobFile_Group41, 0, TestName = "PrintVectoRunData CompletedBus Group 41/32b CO/LL"),
 		 TestCase(JobFile_Group42, 1, TestName = "PrintVectoRunData CompletedBus Group 42/33b HU/RL"),
 		TestCase(@"TestData\Integration\Buses\FactorMethod\CompletedBus_41-32b_AT-P.vecto", 0, TestName = "PrintVectoRunData CompletedBus Group 41/32b AT-P CO/LL"),
-		TestCase(@"TestData\Integration\Buses\FactorMethod\CompletedBus_41-32b_ES-AUX.vecto", 0, TestName = "PrintVectoRunData CompletedBus Group 41/32b ES-Aux CO/LL"),
+		TestCase(@"TestData\Integration\Buses\FactorMethod\CompletedBus_41-32b_ES-AUX.vecto", 0, TestName = "PrintVectoRunData CompletedBus Group 41/32b ES-Aux CO/LL"),]
 		public void PrintModelParametersCompletedBus(string jobFile, int pairIdx)
 		{
 			var runs = GetVectoRunData(jobFile);
-- 
GitLab