using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Diagnostics; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Data; using Tango.BL; using Tango.BL.Entities; using Tango.BL.Enumerations; using Tango.Core.Commands; using Tango.Core.DI; using Tango.DragAndDrop; using Tango.PPC.Common; using Tango.PPC.Common.Messages; using Tango.PPC.Jobs.Dialogs; using Tango.PPC.Jobs.Messages; using Tango.PPC.Jobs.Views; using System.Data.Entity; using Tango.BL.Builders; using Tango.PPC.Jobs.NavigationObjects; using Tango.PPC.Storage; using Tango.Explorer; using System.IO; using Google.Protobuf; using Tango.PMR.Exports; using Tango.Settings; using Tango.Integration.ExternalBridge; using System.Windows.Media; using Tango.PMR.TCC; using Tango.Pulse; using System.Windows.Media.Imaging; using Tango.Touch.Components; using Tango.PPC.Jobs.ViewContracts; using Tango.Core.ExtensionMethods; using Tango.PPC.Common.Synchronization; using Tango.PPC.Jobs.NotificationItems; using Tango.PPC.Storage.Models; using Tango.BL.Helpers; using Tango.ColorConversion; using Tango.PPC.Jobs.Models; using Tango.PPC.Shared.RemoteJobUpload; using Tango.PPC.Common.Notifications; using Tango.PPC.Common.Notifications.NotificationItems; namespace Tango.PPC.Jobs.ViewModels { /// /// Represents the jobs list view model. /// /// public class JobsViewVM : PPCViewModel { private ObservablesContext _db; //Holds the db context for the job list. private ObservableCollection _catalogs; //Holds the available color catalogs for the site. private ObservableCollection _rmls; //Holds the available RML for the site. private ObservableCollection _spoolTypes; private List _colorSpaces; //Holds the available color spaces. private bool _isJobsSynchronizationNotificationActive; public enum JobsCategory { Draft, History } #region Properties private ObservableCollection _jobs; /// /// Gets or sets the collection of jobs. /// public ObservableCollection Jobs { get { return _jobs; } set { _jobs = value; RaisePropertyChangedAuto(); } } private ICollectionView _draftJobsCollectionView; /// /// Gets or sets the jobs collection view. /// public ICollectionView DraftJobsCollectionView { get { return _draftJobsCollectionView; } set { _draftJobsCollectionView = value; RaisePropertyChangedAuto(); } } private ICollectionView _historyJobsCollectionView; /// /// Gets or sets the jobs collection view. /// public ICollectionView HistoryJobsCollectionView { get { return _historyJobsCollectionView; } set { _historyJobsCollectionView = value; RaisePropertyChangedAuto(); } } private ObservableCollection _selectedJobs; /// /// Gets or sets the selected jobs. /// public ObservableCollection SelectedJobs { get { return _selectedJobs; } set { _selectedJobs = value; RaisePropertyChangedAuto(); } } private bool _isLoadingJobs; /// /// Gets or sets a value indicating whether this instance is loading jobs. /// public bool IsLoadingJobs { get { return _isLoadingJobs; } set { _isLoadingJobs = value; RaisePropertyChangedAuto(); } } private bool _isMultiSelecting; /// /// Gets or sets a value indicating whether this the jobs list is in multi select mode. /// public bool IsMultiSelecting { get { return _isMultiSelecting; } set { _isMultiSelecting = value; RaisePropertyChangedAuto(); } } private int _selectedCategoryIndex; /// /// Gets or sets the index of the selected category. /// public int SelectedCategoryIndex { get { return _selectedCategoryIndex; } set { _selectedCategoryIndex = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(SelectedCategory)); } } /// /// Gets or sets the selected category. /// public JobsCategory SelectedCategory { get { return (JobsCategory)SelectedCategoryIndex; } set { if (SelectedCategoryIndex != value.ToInt32()) { SelectedCategoryIndex = value.ToInt32(); Filter = null; } } } private String _filter; /// /// Gets or sets the search filter. /// public String Filter { get { return _filter; } set { _filter = value; RaisePropertyChangedAuto(); OnFilterChanged(); } } private ICollectionFilter _collectionFilter; public ICollectionFilter CollectionFilter { get { return _collectionFilter; } set { _collectionFilter = value; RaisePropertyChangedAuto(); } } private bool _selectAll; public bool SelectAll { get { return _selectAll; } set { _selectAll = value; RaisePropertyChangedAuto();} } #endregion #region Commands /// /// Gets or sets the job selected command. /// public RelayCommand JobSelectedCommand { get; set; } /// /// Gets or sets the job drag and drop command. /// public RelayCommand JobDragedDroppedCommand { get; set; } /// /// Gets or sets the clear selection command. /// public RelayCommand ClearSelectionCommand { get; set; } /// /// Gets or sets the add job command. /// public RelayCommand AddJobCommand { get; set; } /// /// Gets or sets the delete jobs command. /// public RelayCommand DeleteJobsCommand { get; set; } /// /// Gets or sets the clone jobs command. /// public RelayCommand CloneJobsCommand { get; set; } /// /// Gets or sets the export job command. /// public RelayCommand ExportJobCommand { get; set; } /// /// Gets or sets the move to list ( History or Draft) jobs command. /// public RelayCommand MoveToListJobsCommand { get; set; } public RelayCommand SelectAllJobsCommand { get; set; } #endregion #region Constructors /// /// Initializes a new instance of the class. /// public JobsViewVM() { Jobs = new ObservableCollection(); SelectedJobs = new ObservableCollection(); JobSelectedCommand = new RelayCommand((x) => SelectJob(x as Job)); JobDragedDroppedCommand = new RelayCommand((e) => { Job draggedJob = e.Draggable.DataContext as Job; Job droppedJob = e.Droppable.DataContext as Job; DragAndDropJob(draggedJob, droppedJob); }); ClearSelectionCommand = new RelayCommand(ClearSelection); AddJobCommand = new RelayCommand(() => AddNewJob()); DeleteJobsCommand = new RelayCommand(() => DeleteJobs(SelectedJobs)); CloneJobsCommand = new RelayCommand(() => CloneJobs(SelectedJobs)); ExportJobCommand = new RelayCommand(ExportJob); MoveToListJobsCommand = new RelayCommand(() => MoveToListJobs(SelectedJobs)); SelectAllJobsCommand = new RelayCommand(SelectAllJobs); RegisterForMessage(HandleJobRemovedMessage); RegisterForMessage(HandleJobSavedMessage); RegisterForMessage((x) => Filter = null); CollectionFilter = new DefaultCollectionFilter(); CollectionFilter.RegisterFilter(item => { var job = item as Job; if (job != null) { if (String.IsNullOrEmpty(Filter)) { return true; } else { return (job.Name.ToLower().Contains(Filter.ToLower()) || (job.Customer != null && job.Customer.Name.ToLower().StartsWith(Filter.ToLower()))); } } else { return true; } }); } #endregion #region Drag & Drop /// /// Called when a job has been dragged and dropped into another job. /// /// The dragged job. /// The dropped job. private void DragAndDropJob(Job draggedJob, Job droppedJob) { LogManager.Log($"Job Drag & Drop '{draggedJob.Name}' => '{droppedJob.Name}'."); if (draggedJob.JobIndex > droppedJob.JobIndex) { draggedJob.JobIndex = droppedJob.JobIndex - 1; } else { draggedJob.JobIndex = droppedJob.JobIndex + 1; } int index = 1; foreach (var job in Jobs.OrderBy(x => x.JobIndex)) { job.JobIndex = index++; } DraftJobsCollectionView.Refresh(); } #endregion #region Job Selection & Loading /// /// Selects the job. /// /// The job. public async void SelectJob(Job job, bool directlyToEdit = false) { //if (!ApplicationManager.IsInTechnicianMode && job.ColorSpace != null && job.ColorSpace.Code == ColorSpaces.Volume.ToInt32()) //{ // await NotificationProvider.ShowError("The selected job is supported only in technician mode."); // return; //} LogManager.Log($"Job '{job.Name}' selected."); RaiseMessage(new JobSelectedMessage() { Job = job, Context = _db }); if (BuildProvider.MachineType.IsXMachine()) { await NavigationManager.NavigateTo(nameof(JobEurekaView)); } else { if (!directlyToEdit && MachineProvider.MachineOperator.CanPrint) { await NavigationManager.NavigateWithObject(new JobSummeryNavigationObject() { Context = _db, Job = job, }); } else { await NavigationManager.NavigateTo(nameof(JobView)); } } } /// /// Loads the jobs from database. /// public void LoadJobs(Action onCompleted = null, bool animate = true) { try { LogManager.Log("Loading machine jobs..."); Task.Factory.StartNew(() => { if (animate) IsLoadingJobs = true; Thread.Sleep(500); _db = ObservablesContext.CreateDefault(); _colorSpaces = _db.ColorSpaces.ToList(); var jobs = new JobsCollectionBuilder(_db).Set(x => x.MachineGuid == MachineProvider.Machine.Guid).WithSegments().WithBrushStops().WithCustomer().WithColorSpace().WithSegmentsGroups().WithRmls().Build(); InvokeUI(() => { Jobs = jobs; DraftJobsCollectionView = new ListCollectionView(Jobs); DraftJobsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Job.LastUpdated), ListSortDirection.Descending)); DraftJobsCollectionView.Filter = new Predicate(x => { var job = x as Job; return job.JobStatus == JobStatuses.Draft; }); HistoryJobsCollectionView = new ListCollectionView(Jobs); HistoryJobsCollectionView.SortDescriptions.Add(new SortDescription(nameof(Job.LastUpdated), ListSortDirection.Descending)); HistoryJobsCollectionView.Filter = new Predicate(x => { var job = x as Job; return job.JobStatus != JobStatuses.Draft; }); IsLoadingJobs = false; LogManager.Log("Machine jobs loaded!"); onCompleted?.Invoke(); }); }); } catch (Exception ex) { LogManager.Log(ex); NotificationProvider.ShowError("An error occurred while trying to load the machine jobs."); } } /// /// Clears the job selection. /// public void ClearSelection() { SelectedJobs.Clear(); IsMultiSelecting = false; } private void SelectAllJobs() { SelectAll = !SelectAll; } /// /// Adds a new job. /// private async void AddNewJob(Color? colorProfile = null, TwnFile twnFile = null) { try { LogManager.Log("Adding new job..."); var settings = SettingsManager.Default.GetOrCreate(); var machine = MachineProvider.Machine; if (_rmls.Count == 0) { await Task.Delay(200); } var selectedRmlGuid = Settings.DefaultRmlGuid ?? _rmls.First().Guid; Job job = new Job(); job.LastUpdated = DateTime.UtcNow; job.JobSource = JobSource.Local; job.NumberOfHeads = 1; job.NumberOfUnits = 1; job.SampleUnitsOrMeters = 1; job.CreationDate = DateTime.UtcNow; job.JobStatus = JobStatuses.Draft; var selectedSpoolTypeGuid = Settings.SpoolTypeGuid ?? _spoolTypes.First().Guid; if (BuildProvider.IsEureka) { job.Name = "Unnamed"; job.EnableInterSegment = false; job.InterSegmentLength = 0; if (BuildProvider.MachineType == MachineTypes.Eureka) { job.NumberOfSpools = 4; } else { job.NumberOfSpools = 1; } job.NumberOfUnits = 1; } else { JobCreationViewVM vm = new JobCreationViewVM(_spoolTypes.ToList(), _rmls.ToList(), selectedRmlGuid, 0, false); vm.SelectedSpoolType = false == String.IsNullOrEmpty(selectedSpoolTypeGuid) ? _spoolTypes.FirstOrDefault(x => x.Guid == selectedSpoolTypeGuid) : _spoolTypes.FirstOrDefault(x => x.Type == SpoolTypes.StandardSpool); if (twnFile == null) { vm = await NotificationProvider.ShowDialog(vm); if (!vm.DialogResult) return; if (vm.SelectedRML != null) { selectedRmlGuid = vm.SelectedRML.Guid; } if (vm.SelectedSpoolType != null) { selectedSpoolTypeGuid = vm.SelectedSpoolType.Guid; } job.Name = vm.JobName; job.EnableInterSegment = vm.WhiteGap > 0; job.InterSegmentLength = vm.WhiteGap; } } //job.JobType = vm.SelectedJobType; job.EnableLubrication = true; //job.ColorSpaceGuid = Adapter.ColorSpaces.FirstOrDefault(x => x.Code == vm.SelectedColorSpace.ToInt32()).Guid; //job.ColorSpace = _colorSpaces.SingleOrDefault(x => x.Guid == job.ColorSpaceGuid); job.MachineGuid = MachineProvider.Machine.Guid; job.UserGuid = null; job.RmlGuid = selectedRmlGuid; job.WindingMethodGuid = Adapter.WindingMethods.FirstOrDefault().Guid; job.SpoolTypeGuid = selectedSpoolTypeGuid; if (Jobs.Count > 0) { job.JobIndex = Jobs.Max(x => x.JobIndex) + 1; } if (colorProfile == null) { var segment = job.AddSolidSegment(Settings.DefaultSegmentLength > 0 ? Settings.DefaultSegmentLength : 100); segment.BrushStops.Clear(); } else { var segment = job.AddSolidSegment(colorProfile.Value, Settings.DefaultSegmentLength > 0 ? Settings.DefaultSegmentLength : 100); segment.BrushStops.Clear(); job.Name = $"SnapMatch {colorProfile.Value.R}, {colorProfile.Value.G}, {colorProfile.Value.B}"; } if (twnFile != null) { job.Name = twnFile.Name; job.NumberOfUnits = Math.Max(twnFile.NumberOfCopies, 1); job.EmbroideryFileName = twnFile.Name + "." + twnFile.EmbroideryFileFormat; job.EmbroideryFileData = twnFile.EmbroideryFile; job.EmbroideryJpeg = twnFile.ThumbnailData; job.Segments.Clear(); int index = 1; foreach (var segment in twnFile.Segments) { Segment s = new Segment(); s.Job = job; s.SegmentIndex = index++; s.Name = "Embroidery Segment"; s.Length = segment.Length / 100d; int sIndex = 1; foreach (var stop in segment.BrushStops) { BrushStop st = new BrushStop(); st.Segment = s; st.StopIndex = sIndex++; st.OffsetPercent = stop.Offset * 100d; st.Red = stop.R; st.Green = stop.G; st.Blue = stop.B; st.ColorSpaceGuid = job.ColorSpaceGuid; s.BrushStops.Add(st); } job.Segments.Add(s); } } _db.Jobs.Add(job); await _db.SaveChangesAsync(); Jobs.Add(job); LogManager.Log($"Job {job.Name} added successfully."); RaiseMessage(new JobSelectedMessage() { Job = job, Context = _db }); await Task.Delay(200); if(BuildProvider.IsEureka) { await NavigationManager.NavigateWithObject(new JobNavigationObject() { Job = job, Intent = JobNavigationIntent.NewJob }); } else { await NavigationManager.NavigateWithObject(new JobNavigationObject() { Job = job, Intent = JobNavigationIntent.NewJob }); } } catch (Exception ex) { LogManager.Log(ex, "Error creating new job."); await NotificationProvider.ShowError("An error occurred while trying to add a new job."); } } /// /// Deletes the specified jobs from db. /// /// The jobs. private async void DeleteJobs(ObservableCollection jobs) { try { LogManager.Log($"Removing selected jobs:\n{jobs.Select(x => x.Name).ToList().ToJsonString()}"); if (await NotificationProvider.ShowQuestion("Are you sure you want to delete the selected jobs")) { foreach (var job in jobs) { await job.DeleteCascadeAsync(_db); Jobs.Remove(job); } await _db.SaveChangesAsync(); ClearSelection(); } } catch (Exception ex) { LogManager.Log(ex, "Error removing selected jobs."); await NotificationProvider.ShowError("An error occurred while trying to remove the selected jobs."); } } /// /// Clones the specified jobs. /// /// The jobs. private async void CloneJobs(ObservableCollection jobs) { try { LogManager.Log($"Cloning selected jobs:\n{jobs.Select(x => x.Name).ToList().ToJsonString()}"); int index = Jobs.Max(x => x.JobIndex); List clonedJobs = new List(); foreach (var job in SelectedJobs) { var cloned = job.Clone(); cloned.JobIndex = ++index; _db.Jobs.Add(cloned); clonedJobs.Add(cloned); } await _db.SaveChangesAsync(); foreach (var job in clonedJobs) { Jobs.Add(job); } ClearSelection(); } catch (Exception ex) { LogManager.Log(ex, "Error cloning selected jobs."); await NotificationProvider.ShowError("An error occurred while trying to clone the selected jobs."); } } /// /// Moves to list (Draft/History) jobs. /// /// The jobs. private async void MoveToListJobs(ObservableCollection jobs) { bool isHistory = SelectedCategory == JobsCategory.History; string list = isHistory ? "Draft" : "History"; try { LogManager.Log($"Move To {list} selected jobs:\n{jobs.Select(x => x.Name).ToList().ToJsonString()}"); foreach (var job in SelectedJobs) { if(isHistory) { if(job.JobStatus != JobStatuses.Draft) { job.JobStatus = JobStatuses.Draft; job.LastUpdated = DateTime.UtcNow; } } if(!isHistory)//draft { if(job.JobStatus == JobStatuses.Draft) { job.JobStatus = JobStatuses.Completed; job.LastUpdated = DateTime.UtcNow; } } } await _db.SaveChangesAsync(); HistoryJobsCollectionView.Refresh(); DraftJobsCollectionView.Refresh(); ClearSelection(); } catch (Exception ex) { LogManager.Log(ex, $"Error Move To {list} selected jobs."); await NotificationProvider.ShowError($"An error occurred while trying to Move To {list} the selected jobs."); } } /// /// Called when the search filter has been changed /// private void OnFilterChanged() { if (DraftJobsCollectionView != null && HistoryJobsCollectionView != null) { CollectionFilter.RaiseFilterChanged(); View.ScrollToTop(); } } #endregion #region Message Handling /// /// Handles the job removed message. /// /// The MSG. private void HandleJobRemovedMessage(JobRemovedMessage msg) { try { LogManager.Log("JobRemovedMessage message received, removing job from list..."); var job = Jobs.SingleOrDefault(x => x.Guid == msg.Job.Guid); Jobs.Remove(job); _db.Entry(job).State = System.Data.Entity.EntityState.Detached; } catch (Exception ex) { LogManager.Log(ex, "Could not remove job"); } } /// /// Handles the job saved message. /// /// The MSG. private void HandleJobSavedMessage(JobSavedMessage msg) { LogManager.Log("JobSavedMessage message received."); LoadJobs(); } #endregion #region Override Methods /// /// Called when the application has been started. /// public override void OnApplicationStarted() { BrushStop.ColorSynchronizationMode = BrushStop.ColorSynchronizationModes.None; LoadJobs(); ExternalBridgeService.ColorProfileRequest += ExternalBridgeService_ColorProfileRequest; } public async override void OnApplicationReady() { base.OnApplicationReady(); StorageProvider.RegisterFileHandler(ExplorerFileDefinition.Job.Extension, HandleJobFileLoaded); StorageProvider.RegisterFileHandler(ExplorerFileDefinition.ColorProfile.Extension, HandleColorProfileFileLoaded); StorageProvider.RegisterFileHandler(ExplorerFileDefinition.Pulse.Extension, HandlePulseFileLoaded); StorageProvider.RegisterFileHandler(ExplorerFileDefinition.CsvFile.Extension, HandleCsvJobFileLoaded); //Load catalogs. using (ObservablesContext db = ObservablesContext.CreateDefault()) { _catalogs = await new CatalogsCollectionBuilder(db).SetAll().ForSite(MachineProvider.Machine.SiteGuid).BuildAsync(); _rmls = (await new RmlsCollectionBuilder(db).SetAll().WithSpools().ForHeadType(MachineProvider.Machine.MachineHeadType).ForSite(MachineProvider.Machine.SiteGuid).BuildAsync()).OrderBy(x => x.FinalName).ToObservableCollection(); //_rmls = (await new RmlsCollectionBuilder(db).SetAll().WithSpools().BuildAsync()).OrderBy(x => x.FinalName).ToObservableCollection(); _spoolTypes = await MachineProvider.Machine.GetSiteSpoolTypes(db); } MachineDataSynchronizer.SynchronizationEnded += MachineDataSynchronizer_SynchronizationEnded; RemoteJobUploadService.JobReceived += RemoteJobUploadService_JobReceived; } public override void OnNavigatedTo() { base.OnNavigatedTo(); JobViewVM._start_printing_btn?.Pop(); Filter = null; } #endregion #region Job Export private async void ExportJob() { var selected_job = SelectedJobs.FirstOrDefault(); if (selected_job == null) return; var selectedJobs = SelectedJobs.ToList(); ClearSelection(); var result = await NavigationManager. NavigateForResult( new StorageNavigationRequest() { Intent = selectedJobs.Count == 1 ? StorageNavigationIntent.SaveFile : StorageNavigationIntent.SaveFiles, DefaultFileName = selected_job.Name, Filter = ExplorerFileDefinition.Job.Extension, Title = selectedJobs.Count == 1 ? "Save Job File" : "Save Job Files", }); if (result != null) { if (selectedJobs.Count == 1) { try { var jobFile = await selected_job.ToJobFile(); using (FileStream fs = new FileStream(result.Path + ExplorerFileDefinition.Job.Extension, FileMode.Create)) { jobFile.WriteTo(fs); } await NotificationProvider.ShowSuccess("Job saved successfully."); } catch (Exception ex) { LogManager.Log(ex, $"Error saving job {selected_job.Name} to file."); await NotificationProvider.ShowError($"An error occurred while trying to save the job.\n{ex.Message}"); } } else { foreach (var job in selectedJobs) { try { var jobFile = await job.ToJobFile(); using (FileStream fs = new FileStream(Path.Combine(result.Path, jobFile.Name.ToValidFileName()) + ExplorerFileDefinition.Job.Extension, FileMode.Create)) { jobFile.WriteTo(fs); } } catch (Exception ex) { LogManager.Log(ex, $"Error saving job {job.Name} to file."); await NotificationProvider.ShowError($"An error occurred while trying to save the job.\n{ex.Message}"); } } await NotificationProvider.ShowSuccess("Jobs saved successfully."); } } } #endregion #region Handle Job File Loading From Storage private async void HandleJobFileLoaded(List jobFiles) { var vm = await NotificationProvider.ShowDialog(); if (vm.DialogResult) { using (ObservablesContext jobContext = ObservablesContext.CreateDefault()) { foreach (var jobFile in jobFiles) { try { JobFile jFile = JobFile.Parser.ParseFrom(File.ReadAllBytes(jobFile.Path)); var job = await Job.FromJobFile(jFile, MachineProvider.Machine.Guid, null); job.JobSource = JobSource.Local; jobContext.Jobs.Add(job); await jobContext.SaveChangesAsync(); } catch (Exception ex) { LogManager.Log(ex, $"Error occurred while trying to import job from file {jobFile.Path}."); await NotificationProvider.ShowError($"An error occurred while trying to import the selected job file.\n{ex.Message}"); } } LoadJobs(() => { //Editing of a job is currently deprecated due to enabling multiple job imports. //if (vm.ImportAndEdit) //{ // var postJob = Jobs.SingleOrDefault(x => x.Guid == job.Guid); // if (postJob != null) // { // SelectJob(postJob, true); // } //} }); } } } #endregion #region Handle CSV Job File Loading From Storage private async void HandleCsvJobFileLoaded(List files) { var item = files.FirstOrDefault(); if (item == null) return; var vm = new ImportCsvJobViewVM(); vm.Name = Path.GetFileNameWithoutExtension(item.Name); await vm.Init(); await NotificationProvider.ShowDialog(vm); if (vm.DialogResult && vm.SelectedRml != null) { try { NotificationProvider.SetGlobalBusyMessage("Importing job from file..."); using (ObservablesContext db = ObservablesContext.CreateDefault()) { var result = await SegmentsCsvHelper.FromFile(item.Path, MachineProvider.Machine, db); var segments = result.Segments; Job job = new Job(); job.LastUpdated = DateTime.UtcNow; job.JobSource = JobSource.Local; job.Name = vm.Name; job.NumberOfHeads = 1; job.NumberOfUnits = 1; job.NumberOfSpools = BuildProvider.MachineType == MachineTypes.Eureka ? 4 : 1; job.SampleUnitsOrMeters = 1; job.CreationDate = DateTime.UtcNow; job.JobStatus = JobStatuses.Draft; job.JobType = JobTypes.Knitting; job.EnableLubrication = true; job.MachineGuid = MachineProvider.Machine.Guid; job.RmlGuid = vm.SelectedRml.Guid; job.Machine = await new MachineBuilder(db).Set(job.MachineGuid).WithCats().WithConfiguration().BuildAsync(); job.Rml = await new RmlBuilder(db).Set(job.RmlGuid).WithActiveParametersGroup().WithCAT(MachineProvider.Machine.Guid).WithCCT().WithGbdAndLub().WithLiquidFactors().BuildAsync(); job.WindingMethodGuid = Adapter.WindingMethods.FirstOrDefault().Guid; job.SpoolTypeGuid = Settings.SpoolTypeGuid != null ? Settings.SpoolTypeGuid : Adapter.SpoolTypes.FirstOrDefault().Guid; foreach (var segment in segments) { segment.Job = job; job.Segments.Add(segment); } IColorConverter converter = new DefaultColorConverter(); foreach (var stop in segments.SelectMany(x => x.BrushStops)) { var output = converter.Convert(stop, false); var suggestion = output.CreateSingleSuggestion(); stop.Red = suggestion.Color.R; stop.Green = suggestion.Color.G; stop.Blue = suggestion.Color.B; stop.BestMatchR = suggestion.Color.R; stop.BestMatchG = suggestion.Color.G; stop.BestMatchB = suggestion.Color.B; } db.Jobs.Add(job); await db.SaveChangesAsync(); LoadJobs(); } NotificationProvider.ReleaseGlobalBusyMessage(); } catch (Exception ex) { NotificationProvider.ReleaseGlobalBusyMessage(); LogManager.Log(ex, "Error importing job from CSV."); await NotificationProvider.ShowError($"Error importing job from csv file.\n{ex.FlattenMessage()}"); } } } #endregion #region Handle CSV Job File Received By Remote Job Upload Service private void RemoteJobUploadService_JobReceived(object sender, Common.RemoteJobUpload.RemoteJobReceivedEventArgs e) { if (e.Type == RemoteJobUploadType.CSV) { Task.Factory.StartNew(async () => { try { using (ObservablesContext db = ObservablesContext.CreateDefault()) { var result = await SegmentsCsvHelper.FromFile(e.FilePath, MachineProvider.Machine, db); var segments = result.Segments; String rmlGuid = null; if (result.Rml != null) { rmlGuid = result.Rml.Guid; } else { rmlGuid = Settings.DefaultRmlGuid; } var machine = await new MachineBuilder(db).SetFirst().WithConfiguration().BuildAsync(); Job job = new Job(); job.LastUpdated = DateTime.UtcNow; job.JobSource = JobSource.Local; job.Name = e.Name; job.NumberOfHeads = 1; job.NumberOfUnits = 1; job.SampleUnitsOrMeters = 1; job.NumberOfSpools = BuildProvider.MachineType == MachineTypes.Eureka ? 4 : 1; job.CreationDate = DateTime.UtcNow; job.JobStatus = JobStatuses.Draft; job.JobType = JobTypes.Knitting; job.EnableLubrication = true; job.MachineGuid = MachineProvider.Machine.Guid; job.RmlGuid = rmlGuid; job.Machine = await new MachineBuilder(db).Set(job.MachineGuid).WithCats().WithConfiguration().BuildAsync(); job.Rml = await new RmlBuilder(db).Set(job.RmlGuid).WithActiveParametersGroup().WithCAT(MachineProvider.Machine.Guid).WithCCT().WithGbdAndLub().WithLiquidFactors().BuildAsync(); job.WindingMethodGuid = Adapter.WindingMethods.FirstOrDefault().Guid; job.SpoolTypeGuid = Settings.SpoolTypeGuid != null ? Settings.SpoolTypeGuid : Adapter.SpoolTypes.FirstOrDefault().Guid; foreach (var segment in segments) { segment.Job = job; job.Segments.Add(segment); } IColorConverter converter = new DefaultColorConverter(); int segmentIndex = 0; foreach (var stop in segments.SelectMany(x => x.BrushStops).Where(x => x.BrushColorSpace != ColorSpaces.RGB)) { segmentIndex++; var output = converter.Convert(stop, false); var suggestion = output.CreateSingleSuggestion(); stop.Red = suggestion.Color.R; stop.Green = suggestion.Color.G; stop.Blue = suggestion.Color.B; stop.BestMatchR = suggestion.Color.R; stop.BestMatchG = suggestion.Color.G; stop.BestMatchB = suggestion.Color.B; stop.SetLiquidVolumes(machine.Configuration, job.Rml, job.Rml.GetActiveProcessGroup().ProcessParametersTables[suggestion.ProcessParametersTableIndex]); if (stop.IsLiquidVolumesOutOfRange) { throw new InvalidOperationException($"Volumes out of range for thread '{job.Rml.FinalName}' at segment {segmentIndex}."); } } db.Jobs.Add(job); await db.SaveChangesAsync(); } LoadJobs(() => { NotificationProvider.PushNotification(new MessageNotificationItem($"Csv job '{e.Name}' received successfully.", "", MessageNotificationItem.MessageNotificationItemTypes.Success, () => { }, NotificationItem.NotificationPriority.Low)); e.Confirm(); }, false); } catch (Exception ex) { LogManager.Log(ex, "Error occurred on remote job upload."); e.Abort(ex.FlattenMessage()); } }); } } #endregion #region Handle TCC File Loading From Storage private async void HandleColorProfileFileLoaded(List tccFiles) { var tccFile = tccFiles.FirstOrDefault(); try { DetectionColorFile tcc = DetectionColorFile.Parser.ParseFrom(File.ReadAllBytes(tccFile.Path)); var vm = await NotificationProvider.ShowDialog(new ImportColorProfileViewVM() { Color = Color.FromRgb( (byte)tcc.ProcessedColor.R, (byte)tcc.ProcessedColor.G, (byte)tcc.ProcessedColor.B), }); if (vm.DialogResult) { AddNewJob(vm.Color); } } catch (Exception ex) { LogManager.Log(ex, $"Error occurred while trying to import detection color from file {tccFile.Path}."); await NotificationProvider.ShowError($"An error occurred while trying to import the selected detection color.\n{ex.Message}"); } } #endregion #region Handle Pulse TWN Loading From Storage private async void HandlePulseFileLoaded(List twnFiles) { var twnFile = twnFiles.FirstOrDefault(); TwnFile twn = TwnFile.FromFile(twnFile.Path); BitmapSource preview = twn.Thumbnail.ToBitmapSource(); var vm = await NotificationProvider.ShowDialog(new ImportTwnFileViewVM() { Thumbnail = preview, }); if (vm.DialogResult) { AddNewJob(null, twn); } } #endregion #region Handle New Synchronized Jobs private void MachineDataSynchronizer_SynchronizationEnded(object sender, SynchronizationEndedEventArgs e) { if (e.NewChangedJobs > 0 && !_isJobsSynchronizationNotificationActive) { _isJobsSynchronizationNotificationActive = true; var item = NotificationProvider.PushNotification(); item.Pressed += (_, __) => { _isJobsSynchronizationNotificationActive = false; LoadJobs(() => { NotificationProvider.ShowSuccess("Your job list is now synchronized."); }); }; item.Closed += (_, __) => { _isJobsSynchronizationNotificationActive = false; }; } } #endregion #region Color Profile Request private void ExternalBridgeService_ColorProfileRequest(object sender, ColorProfileRequestEventArgs e) { InvokeUI(async () => { var vm = await NotificationProvider.ShowDialog(new ColorProfileReceivedViewVM() { Color = Color.FromRgb( (byte)e.Request.DetectionColor.R, (byte)e.Request.DetectionColor.G, (byte)e.Request.DetectionColor.B), }); if (vm.DialogResult) { e.Approve(); AddNewJob(vm.Color); } else { e.Decline(); } }); } #endregion } }