using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.ComponentModel; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using System.Windows.Data; using Tango.Core.Commands; using Tango.Core.Helpers; using Tango.BL.Entities; using Tango.MachineStudio.Common.Notifications; using Tango.SharedUI; using SimpleValidator.Extensions; using Tango.MachineStudio.Common.StudioApplication; using Tango.MachineStudio.Common; using Tango.BL; using Tango.AutoComplete.Editors; using System.Data.Entity; using Tango.BL.Builders; using Tango.MachineStudio.MachineDesigner.Contracts; using System.Windows.Threading; using Tango.Core.Threading; using Tango.MachineStudio.RML.ViewModels; using Tango.Settings; using Tango.MachineStudio.RML.Models; using Tango.BL.ActionLogs; using Tango.MachineStudio.Common.Authentication; using Tango.BL.DTO; using Tango.Core.Cryptography; using Tango.BL.Enumerations; using Tango.MachineStudio.MachineDesigner.Models; namespace Tango.MachineStudio.MachineDesigner.ViewModels { public class MainViewVM : StudioViewModel { private INotificationProvider _notification; private IActionLogManager _actionLogManager; private IAuthenticationProvider _authentication; private ActionTimer _machines_action_timer; private ActionTimer _dispensers_action_timer; private MachineDTO _machineBeforeSave; private List _all_sites; #region Properties private bool _isNewMachine; public bool IsNewMachine { get { return _isNewMachine; } set { _isNewMachine = value; RaisePropertyChangedAuto(); } } private ObservablesStaticCollections _activeMachineAdapter; public ObservablesStaticCollections ActiveMachineAdapter { get { return _activeMachineAdapter; } set { _activeMachineAdapter = value; RaisePropertyChangedAuto(); } } private List _machines; /// /// Gets or sets the available filtered machines. /// public List Machines { get { return _machines; } set { _machines = value; RaisePropertyChangedAuto(); } } private MachineModel _selectedMachine; /// /// Gets or sets the selected machine from the drop down. /// public MachineModel SelectedMachine { get { return _selectedMachine; } set { if (_selectedMachine != value) { _selectedMachine = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } } private Machine _activeMachine; /// /// Gets or sets the active machine. /// public Machine ActiveMachine { get { return _activeMachine; } set { _activeMachine = value; RaisePropertyChangedAuto(); } } private IdsPack _selectedIds; /// /// Gets or sets the selected ids pack. /// public IdsPack SelectedIds { get { return _selectedIds; } set { _selectedIds = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } private String _dispensersFilter; /// /// Gets or sets the dispensers filter. /// public String DispensersFilter { get { return _dispensersFilter; } set { _dispensersFilter = value; RaisePropertyChangedAuto(); OnDispensersFilterChanged(); } } private String _filter; /// /// Gets or sets the machines filter. /// public String Filter { get { return _filter; } set { _filter = value; RaisePropertyChangedAuto(); OnFilterChanged(); } } private Spool _selectedSpool; public Spool SelectedSpool { get { return _selectedSpool; } set { _selectedSpool = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); } } private Site _selectedSite; public Site SelectedSite { get { return _selectedSite; } set { _selectedSite = value; RaisePropertyChangedAuto(); } } private List _sites; public List Sites { get { return _sites; } set { _sites = value; RaisePropertyChangedAuto(); } } private bool _isGen1Machine; public bool IsGen1Machine { get { return _isGen1Machine; } set { _isGen1Machine = value; RaisePropertyChangedAuto(); } } private ColorCalibrationViewVM _colorCalibrationViewVM; public ColorCalibrationViewVM ColorCalibrationViewVM { get { return _colorCalibrationViewVM; } set { _colorCalibrationViewVM = value; RaisePropertyChangedAuto(); } } private HardwareConfigurationViewVM _hardwareConfigurationViewVM; public HardwareConfigurationViewVM HardwareConfigurationViewVM { get { return _hardwareConfigurationViewVM; } set { _hardwareConfigurationViewVM = value; RaisePropertyChangedAuto(); } } private MachineUpdatesViewVM _machineUpdatesViewVM; public MachineUpdatesViewVM MachineUpdatesViewVM { get { return _machineUpdatesViewVM; } set { _machineUpdatesViewVM = value; RaisePropertyChangedAuto(); } } private TupViewVM _tupViewVM; public TupViewVM TupViewVM { get { return _tupViewVM; } set { _tupViewVM = value; RaisePropertyChangedAuto(); } } private List _tags; public List Tags { get { return _tags; } set { _tags = value; RaisePropertyChangedAuto(); } } #endregion #region Commands /// /// Gets or sets the save command. /// public RelayCommand SaveCommand { get; set; } /// /// Gets or sets the add ids command. /// public RelayCommand AddIdsCommand { get; set; } /// /// Gets or sets the remove ids command. /// public RelayCommand RemoveIdsCommand { get; set; } /// /// Gets or sets the remove machine command. /// public RelayCommand RemoveMachineCommand { get; set; } /// /// Gets or sets the add machine command. /// public RelayCommand AddMachineCommand { get; set; } /// /// Gets or sets the edit machine command. /// public RelayCommand EditMachineCommand { get; set; } /// /// Gets or sets the back to machines command. /// public RelayCommand BackToMachinesCommand { get; set; } /// /// Gets or sets the add spool command. /// public RelayCommand AddSpoolCommand { get; set; } /// /// Gets or sets the remove spool command. /// public RelayCommand RemoveSpoolCommand { get; set; } /// /// Gets or sets the clone machine command. /// public RelayCommand CloneMachineCommand { get; set; } /// /// Gets or sets the reset device registration command. /// public RelayCommand ResetDeviceRegistrationCommand { get; set; } /// /// Gets or sets the make prototype command. /// public RelayCommand MakePrototypeCommand { get; set; } public RelayCommand UpgradeToGen2Command { get; set; } #endregion #region Constructors public MainViewVM() { } /// /// Initializes a new instance of the class. /// public MainViewVM(INotificationProvider notification, IAuthenticationProvider authentication, IActionLogManager actionLogManager) { _notification = notification; _authentication = authentication; _actionLogManager = actionLogManager; Machines = new List(); _machines_action_timer = new ActionTimer(TimeSpan.FromMilliseconds(200)); _dispensers_action_timer = new ActionTimer(TimeSpan.FromMilliseconds(200)); AddIdsCommand = new RelayCommand(AddIds, (x) => ActiveMachine != null && ActiveMachine.Configuration != null && ActiveMachine.Configuration.IdsPacks.Count < 10); RemoveIdsCommand = new RelayCommand(RemoveIds, (x) => SelectedIds != null); EditMachineCommand = new RelayCommand(() => LoadSelectedMachine(), () => SelectedMachine != null); BackToMachinesCommand = new RelayCommand(() => View.NavigateTo(MachineDesignerNavigationView.MachinesView)); SaveCommand = new RelayCommand(SaveMachine); AddMachineCommand = new RelayCommand(AddNewMachine); RemoveMachineCommand = new RelayCommand(RemoveSelectedMachine, () => SelectedMachine != null); AddSpoolCommand = new RelayCommand(AddNewSpool); RemoveSpoolCommand = new RelayCommand(RemoveSpool, () => SelectedSpool != null); CloneMachineCommand = new RelayCommand(CloneMachine, () => SelectedMachine != null); ResetDeviceRegistrationCommand = new RelayCommand(ResetDeviceRegistration); MakePrototypeCommand = new RelayCommand(MakePrototype); MachineUpdatesViewVM = new MachineUpdatesViewVM(_notification); TupViewVM = new TupViewVM(_notification); UpgradeToGen2Command = new RelayCommand(UpgradeToGEN2); } #endregion public override void OnApplicationReady() { } private void OnDispensersFilterChanged() { if (!String.IsNullOrWhiteSpace(DispensersFilter)) { _dispensers_action_timer.ResetReplace(() => { Task.Factory.StartNew(() => { ActiveMachineAdapter.Dispensers = ActiveMachineAdapter.Context.Dispensers.Where(x => x.SerialNumber.ToLower().StartsWith(DispensersFilter.ToLower())).OrderBy(x => x.SerialNumber).ToSynchronizedObservableCollection(); }); }); } } #region Drag Drop Handlers /// /// Drops the ids pack. /// /// The ids pack1. /// The ids pack2. public void DropIdsPack(IdsPack idsPack1, IdsPack idsPack2) { ActiveMachine.Configuration.IdsPacks.Swap(idsPack1, idsPack2); ColorCalibrationViewVM.InvalidateCalibrationDataAndColorConversion(); } /// /// Drops the touch panel. /// /// The application display panel version. public void DropTouchPanel(ApplicationDisplayPanelVersion applicationDisplayPanelVersion) { ActiveMachine.Configuration.ApplicationDisplayPanelVersion = applicationDisplayPanelVersion; ActiveMachine.Configuration.ApplicationDisplayPanelVersionGuid = applicationDisplayPanelVersion.Guid; } /// /// Drops the application firmware version. /// /// The application firmware version. public void DropApplicationFirmwareVersion(ApplicationFirmwareVersion applicationFirmwareVersion) { ActiveMachine.Configuration.ApplicationFirmwareVersion = applicationFirmwareVersion; ActiveMachine.Configuration.ApplicationFirmwareVersionGuid = applicationFirmwareVersion.Guid; } /// /// Drops the hardware version. /// /// The hardware version. public void DropHardwareVersion(HardwareVersion hardwareVersion) { ActiveMachine.Configuration.HardwareVersion = hardwareVersion; ActiveMachine.Configuration.HardwareVersionGuid = hardwareVersion.Guid; } /// /// Drops the embedded firmware. /// /// The embedded firmware version. public void DropEmbeddedFirmware(EmbeddedFirmwareVersion embeddedFirmwareVersion) { ActiveMachine.Configuration.EmbeddedFirmwareVersion = embeddedFirmwareVersion; ActiveMachine.Configuration.EmbeddedFirmwareVersionGuid = embeddedFirmwareVersion.Guid; } /// /// Drops the application os version. /// /// The application os version. public void DropApplicationOsVersion(ApplicationOsVersion applicationOsVersion) { ActiveMachine.Configuration.ApplicationOsVersion = applicationOsVersion; ActiveMachine.Configuration.ApplicationOsVersionGuid = applicationOsVersion.Guid; } /// /// Drops the dispenser. /// /// The dispenser. /// The ids pack. public void DropDispenser(Dispenser dispenser, IdsPack idsPack) { idsPack.Dispenser = dispenser; idsPack.DispenserGuid = dispenser.Guid; } /// /// Drops the type of the cartridge. /// /// Type of the cartridge. /// The ids pack. public void DropCartridgeType(CartridgeType cartridgeType, IdsPack idsPack) { idsPack.CartridgeType = cartridgeType; idsPack.CartridgeTypeGuid = cartridgeType.Guid; } /// /// Drops the type of the mid tank. /// /// Type of the mid tank. /// The ids pack. public void DropMidTankType(MidTankType midTankType, IdsPack idsPack) { idsPack.MidTankType = midTankType; idsPack.MidTankTypeGuid = midTankType.Guid; } /// /// Drops the type of the liquid. /// /// Type of the liquid. /// The ids pack. public void DropLiquidType(LiquidType liquidType, IdsPack idsPack) { idsPack.LiquidType = liquidType; idsPack.LiquidTypeGuid = liquidType.Guid; ColorCalibrationViewVM.InvalidateCalibrationDataAndColorConversion(); } /// /// Drops the ids formula. /// /// The ids pack formula. /// The ids pack. /// public void DropIdsFormula(IdsPackFormula idsPackFormula, IdsPack idsPack) { idsPack.IdsPackFormula = idsPackFormula; idsPack.IdsPackFormulaGuid = idsPackFormula.Guid; } #endregion #region Private Methods /// /// Removes the selected IDS pack. /// private void RemoveIds() { ActiveMachineAdapter.Context.IdsPacks.Remove(SelectedIds); SelectedIds = null; ColorCalibrationViewVM.InvalidateCalibrationDataAndColorConversion(); } /// /// Adds a new IDS pack. /// private void AddIds() { ActiveMachineAdapter.Context.IdsPacks.Add(new IdsPack() { Configuration = ActiveMachine.Configuration }); InvalidateRelayCommands(); } private async void LoadSelectedMachine(bool newMachine = false, bool clone = false, MachineCreationDialogVM machineCreationDialogVM = null) { IsNewMachine = false; using (_notification.PushTaskItem("Loading machine details...")) { try { IsFree = false; if (ActiveMachineAdapter != null) { ActiveMachineAdapter.Context.Dispose(); } ActiveMachineAdapter = new ObservablesStaticCollections(ObservablesContext.CreateDefault()); ActiveMachineAdapter.Organizations = (await ActiveMachineAdapter.Context.Organizations.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.MachineVersions = (await ActiveMachineAdapter.Context.MachineVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.Rmls = (await ActiveMachineAdapter.Context.Rmls.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.ColorSpaces = (await ActiveMachineAdapter.Context.ColorSpaces.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.SpoolTypes = (await ActiveMachineAdapter.Context.SpoolTypes.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.ApplicationDisplayPanelVersions = (await ActiveMachineAdapter.Context.ApplicationDisplayPanelVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.ApplicationFirmwareVersions = (await ActiveMachineAdapter.Context.ApplicationFirmwareVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.ApplicationOsVersions = (await ActiveMachineAdapter.Context.ApplicationOsVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.EmbeddedFirmwareVersions = (await ActiveMachineAdapter.Context.EmbeddedFirmwareVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.DispenserTypes = (await ActiveMachineAdapter.Context.DispenserTypes.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.LiquidTypes = (await ActiveMachineAdapter.Context.LiquidTypes.ToListAsync()).OrderBy(x => x.PreferredIndex).ToObservableCollection(); ActiveMachineAdapter.MidTankTypes = (await ActiveMachineAdapter.Context.MidTankTypes.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.CartridgeTypes = (await ActiveMachineAdapter.Context.CartridgeTypes.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.IdsPackFormulas = (await ActiveMachineAdapter.Context.IdsPackFormulas.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.HardwareVersions = (await ActiveMachineAdapter.Context.HardwareVersions.ToListAsync()).OrderByDescending(x => x.Version).ToObservableCollection(); ActiveMachineAdapter.MachineVersions = (await ActiveMachineAdapter.Context.MachineVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.Organizations = (await ActiveMachineAdapter.Context.Organizations.ToListAsync()).ToObservableCollection(); var tags = (await ActiveMachineAdapter.Context.TangoVersions.Select(x => x.Tag).Where(x => x != null).Distinct().ToListAsync()); tags.Insert(0, String.Empty); Tags = tags; bool initHwConfig = true; Configuration machineConfigBeforeClone = null; if (!newMachine) { ActiveMachine = (await new MachineBuilder(ActiveMachineAdapter.Context).Set(SelectedMachine.Guid).WithOrganization().WithConfiguration().WithSpools().BuildAsync()); _machineBeforeSave = MachineDTO.FromObservable(ActiveMachine); if (clone) { machineConfigBeforeClone = ActiveMachine.Configuration; IsNewMachine = true; ActiveMachine = ActiveMachine.Clone(); ActiveMachine.Name = machineCreationDialogVM.Name; ActiveMachine.SerialNumber = machineCreationDialogVM.SerialNumber; ActiveMachine.IsDeviceRegistered = false; ActiveMachine.DeviceId = null; ActiveMachine.DeviceName = null; ActiveMachine.ActivationKey = null; ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); } } else { IsNewMachine = true; if (machineCreationDialogVM.SelectedPrototype == null) { ActiveMachine = new Machine(); ActiveMachine.Configuration = new Configuration(); ActiveMachine.SerialNumber = machineCreationDialogVM.SerialNumber; ActiveMachine.Name = machineCreationDialogVM.Name; ActiveMachine.Type = machineCreationDialogVM.MachineType; ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); } else { try { initHwConfig = false; ActiveMachine = machineCreationDialogVM.SelectedPrototype.CreateMachine(machineCreationDialogVM.SerialNumber, machineCreationDialogVM.Name); ActiveMachine.MachineVersion = ActiveMachineAdapter.MachineVersions.FirstOrDefault(x => x.Guid == ActiveMachine.MachineVersionGuid); if (machineCreationDialogVM.SelectedHardwareVersion != null) { ActiveMachine.Configuration.HardwareVersion = ActiveMachineAdapter.HardwareVersions.FirstOrDefault(x => x.Guid == machineCreationDialogVM.SelectedHardwareVersion.Guid); } ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); HardwareConfigurationViewVM = new HardwareConfigurationViewVM(_notification); var version = await new HardwareVersionBuilder(ActiveMachineAdapter.Context).Set(ActiveMachine.Configuration.HardwareVersionGuid).WithHardwareComponents().BuildAsync(); HardwareConfigurationViewVM.Init(ActiveMachine.Configuration); } catch (Exception ex) { _notification.ShowError($"Invalid machine prototype.\n{ex.FlattenMessage()}"); View.NavigateTo(MachineDesignerNavigationView.MachinesView); return; } } } ActiveMachine.OrganizationChanged -= ActiveMachine_OrganizationChanged; ActiveMachine.OrganizationChanged += ActiveMachine_OrganizationChanged; _all_sites = await ActiveMachineAdapter.Context.Sites.ToListAsync(); var sites = ActiveMachine.Organization != null ? _all_sites.Where(x => x.OrganizationGuid == ActiveMachine.OrganizationGuid).ToList() : new List(); sites.Insert(0, new Site() { Name = "NONE", ID = -1 }); Sites = sites; SelectedSite = Sites.SingleOrDefault(x => x.Guid == ActiveMachine.SiteGuid); ColorCalibrationViewVM = new ColorCalibrationViewVM(_notification, ActiveMachine, _activeMachineAdapter.Context, ActiveMachineAdapter.Rmls.FirstOrDefault()) { Rmls = ActiveMachineAdapter.Rmls, LiquidTypesRmls = ActiveMachineAdapter.Rmls.FirstOrDefault().LiquidTypesRmls, }; await ColorCalibrationViewVM.Invalidate(); if (initHwConfig) { HardwareConfigurationViewVM = new HardwareConfigurationViewVM(_notification); HardwareConfigurationViewVM.Init(ActiveMachine.Configuration); } if (!IsNewMachine) { await MachineUpdatesViewVM.Init(ActiveMachine, ActiveMachineAdapter.Context); TupViewVM.Init(ActiveMachine); } ActiveMachine.Configuration.HardwareVersionChanged += Configuration_HardwareVersionChanged; while (ActiveMachine.ActivationKey == null) //Generate a random password and make sure no machine matches it. { ActiveMachine.ActivationKey = PasswordGenerator.Generate(8, PasswordGenerator.PasswordType.Alpha, PasswordGenerator.PasswordCasing.Upper); if (await ActiveMachineAdapter.Context.Machines.Where(x => x.ActivationKey == ActiveMachine.ActivationKey).CountAsync() == 0) { break; } ActiveMachine.ActivationKey = null; } IsGen1Machine = !ActiveMachine.Configuration.NoneEmptyIdsPacks.Any(x => x.LiquidType.Type == LiquidTypes.LightCyan); View.NavigateTo(MachineDesignerNavigationView.MachineDetailsView); } catch (Exception ex) { LogManager.Log(ex, $"Error loading machine details for serial number {SelectedMachine.SerialNumber}"); _notification.ShowError($"An error occurred while trying to load the selected machine details.\n{ex.Message}"); } finally { IsFree = true; InvalidateRelayCommands(); } } } private async void Configuration_HardwareVersionChanged(object sender, HardwareVersion e) { var version = ActiveMachine.Configuration.HardwareVersion; if (version != null) { using (_notification.PushTaskItem("Loading hardware version...")) { try { if (HardwareConfigurationViewVM == null) { HardwareConfigurationViewVM = new HardwareConfigurationViewVM(_notification); } version = await new HardwareVersionBuilder(ActiveMachineAdapter.Context).Set(version.Guid).WithHardwareComponents().BuildAsync(); HardwareConfigurationViewVM.Init(ActiveMachine.Configuration); } catch (Exception ex) { LogManager.Log(ex); } } } } private async void SaveMachine() { foreach (var ids in ActiveMachine.Configuration.IdsPacks) { ids.PackIndex = ActiveMachine.Configuration.IdsPacks.IndexOf(ids); ids.Configuration = ActiveMachine.Configuration; ids.ConfigurationGuid = ActiveMachine.Configuration.Guid; } List errors = new List(); if (ActiveMachine.MachineVersion == null) { errors.Add("Machine version is required."); } if (ActiveMachine.Name.IsNullOrWhiteSpace()) { errors.Add("Machine name is required."); } if (ActiveMachine.Organization == null) { errors.Add("Machine organization is required."); } if (ActiveMachine.SerialNumber.IsNullOrWhiteSpace()) { errors.Add("Machine serial number is required."); } if (ActiveMachine.Configuration.ApplicationDisplayPanelVersion == null) { errors.Add("Touch Panel is required."); } if (ActiveMachine.Configuration.ApplicationFirmwareVersion == null) { errors.Add("Application firmware is required."); } if (ActiveMachine.Configuration.ApplicationOsVersion == null) { errors.Add("Application operation system is required."); } if (ActiveMachine.Configuration.EmbeddedFirmwareVersion == null) { errors.Add("Embedded firmware is required."); } if (ActiveMachine.Configuration.HardwareVersion == null) { errors.Add("Hardware version is required."); } if (ActiveMachine.Configuration.HardwareVersion != null) { if (ActiveMachine.Configuration.HardwareVersion.ForMachineType != ActiveMachine.Type) { errors.Add($"Hardware version '{ActiveMachine.Configuration.HardwareVersion.Name}' is intended only for {ActiveMachine.Configuration.HardwareVersion.ForMachineType} machines."); } } foreach (var pack in ActiveMachine.Configuration.IdsPacks) { if (pack.LiquidType != null || pack.CartridgeType != null || pack.Dispenser != null || pack.IdsPackFormula != null || pack.MidTankType != null) { if (pack.CartridgeType == null) { errors.Add(String.Format("Cartridge type is required on IDS pack '{0}'.", pack.PackIndex)); } if (pack.Dispenser == null) { errors.Add(String.Format("Dispenser is required on IDS pack '{0}'.", pack.PackIndex)); } if (pack.LiquidType == null) { errors.Add(String.Format("Liquid type is required on IDS pack '{0}'.", pack.PackIndex)); } if (pack.MidTankType == null) { errors.Add(String.Format("Mid Tank type is required on IDS pack '{0}'.", pack.PackIndex)); } if (pack.IdsPackFormula == null) { errors.Add(String.Format("Formula type is required on IDS pack '{0}'.", pack.PackIndex)); } pack.IsEmpty = false; } else { pack.IsEmpty = true; } } foreach (var pack in ActiveMachine.Configuration.IdsPacks.Where(x => x.Dispenser != null)) { if (ActiveMachine.Configuration.IdsPacks.Where(x => x.Dispenser == pack.Dispenser).Count() > 1) { errors.Add($"Dispenser '{pack.Dispenser.SerialNumber}' is installed on multiple IDS packs."); } if (ActiveMachineAdapter.Context.IdsPacks.Count(x => x.ConfigurationGuid != pack.ConfigurationGuid && x.DispenserGuid == pack.DispenserGuid) > 0) { errors.Add($"Dispenser '{pack.Dispenser.SerialNumber}' is already installed on a different machine."); } } if (ActiveMachine.Spools.GroupBy(x => x.SpoolType).Any(x => x.Count() > 1)) { errors.Add($"Same spool type is registered multiple times."); } if (errors.Count > 0) { String errorsString = "Please fix the following validation errors before trying to save." + Environment.NewLine + Environment.NewLine; errorsString += String.Join(Environment.NewLine, errors.Distinct()); _notification.ShowError(errorsString); return; } try { IsFree = false; using (_notification.PushTaskItem("Saving Machine Details...")) { ActiveMachine.ConfigurationGuid = ActiveMachine.Configuration.Guid; ActiveMachine.LastUpdated = DateTime.UtcNow; ActiveMachine.SiteGuid = SelectedSite == null ? null : (SelectedSite.ID == -1 ? null : SelectedSite.Guid); ColorCalibrationViewVM.Save(); var hwConfig = HardwareConfigurationViewVM.GetResultingHardwareConfiguration(); ActiveMachine.Configuration.SetHardwareConfiguration(hwConfig); await ActiveMachineAdapter.Context.SaveChangesAsync(); if (IsNewMachine) { _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.MachineCreated, _authentication.CurrentUser, ActiveMachine.Name, ActiveMachine, "New machine created using Machine Studio."); } else { var machineAfterDTO = MachineDTO.FromObservable(ActiveMachine); _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.MachineSaved, _authentication.CurrentUser, _machineBeforeSave.Name, _machineBeforeSave, machineAfterDTO, "Machine saved using Machine Studio."); _machineBeforeSave = machineAfterDTO; } if (SelectedMachine != null) { await LoadMachines(); } await ColorCalibrationViewVM.Invalidate(); } } catch (Exception ex) { LogManager.Log(ex, "Error saving machine details."); _notification.ShowError("An error occurred while trying to save the machine details" + Environment.NewLine + ex.Message); } finally { IsFree = true; InvalidateRelayCommands(); } } private async void AddNewMachine() { List prototypes = new List(); List hardwareVersions = new List(); try { IsFree = false; using (_notification.PushTaskItem("Loading machine creation data...")) { using (ObservablesContext db = ObservablesContext.CreateDefault()) { prototypes = await db.MachinePrototypes.ToListAsync(); hardwareVersions = await db.HardwareVersions.ToListAsync(); } } } catch (Exception ex) { LogManager.Log(ex, "Error loading machine creation data."); _notification.ShowError($"Error loading machine creation data\n{ex.FlattenMessage()}"); return; } finally { IsFree = true; } MachineCreationDialogVM vm = new MachineCreationDialogVM(); vm.IsNewMachine = true; vm.Prototypes = prototypes.ToList(); vm.HardwareVersions = hardwareVersions.OrderByDescending(x => x.Version).ToList(); vm.SelectedHardwareVersion = vm.HardwareVersions.FirstOrDefault(); _notification.ShowModalDialog(vm, (x) => { using (ObservablesContext db = ObservablesContext.CreateDefault()) { if (db.Machines.Any(y => y.SerialNumber == vm.SerialNumber || y.Name.ToLower() == vm.Name.ToLower())) { _notification.ShowError("Machine serial number or name already exists."); return; } } LoadSelectedMachine(true, false, vm); }, () => { }); } private async void RemoveSelectedMachine() { if (SelectedMachine == null) return; if (_notification.ShowQuestion("Are you sure you want to delete the selected machine?")) { using (_notification.PushTaskItem("Removing machine...")) { try { IsFree = false; var selectedMachine = SelectedMachine; using (ObservablesContext db = ObservablesContext.CreateDefault()) { var machineToDelete = await new MachineBuilder(db).Set(SelectedMachine.Guid).WithConfiguration().BuildAsync(); await machineToDelete.DeleteCascadeAsync(db); await machineToDelete.Configuration.DeleteCascadeAsync(db); foreach (var dispenser in machineToDelete.Configuration.NoneEmptyIdsPacks.Select(x => x.Dispenser)) { if (dispenser != null) { await dispenser.DeleteCascadeAsync(db); } } _actionLogManager.InsertLog(ActionLogType.MachineDeleted, _authentication.CurrentUser, selectedMachine.Name, machineToDelete, "Machine deleted using Machine Studio."); await LoadMachines(); } } catch (Exception ex) { LogManager.Log(ex, $"Error removing selected machine."); _notification.ShowError($"An error occurred while trying to delete the selected machine.\n{ex.Message}"); } finally { IsFree = true; } } } } private void ResetDeviceRegistration() { if (_notification.ShowQuestion("Are you sure you wish to reset this machine device registration?")) { ActiveMachine.IsDeviceRegistered = false; ActiveMachine.DeviceId = null; ActiveMachine.DeviceName = null; } } private async void MakePrototype() { String protoName = _notification.ShowTextInput("Enter prototype name", "name"); if (!protoName.IsNotNullOrWhiteSpace()) return; using (_notification.PushTaskItem($"Saving machine prototype '{protoName}'...")) { try { IsFree = false; using (var db = ObservablesContext.CreateDefault()) { MachinePrototype prototype = MachinePrototype.CreateNew(ActiveMachine, protoName, protoName); db.MachinePrototypes.Add(prototype); await db.SaveChangesAsync(); } } catch (Exception ex) { _notification.ShowError($"Error creating machine prototype\n{ex.FlattenMessage()}"); } finally { IsFree = true; } } } #endregion private void CloneMachine() { MachineCreationDialogVM vm = new MachineCreationDialogVM(); vm.IsNewMachine = false; _notification.ShowModalDialog(vm, (x) => { using (ObservablesContext db = ObservablesContext.CreateDefault()) { if (db.Machines.Any(y => y.SerialNumber == vm.SerialNumber || y.Name.ToLower() == vm.Name.ToLower())) { _notification.ShowError("Machine serial number or name already exists."); return; } } LoadSelectedMachine(false, true, vm); }, () => { }); } private void AddNewSpool() { _activeMachineAdapter.Context.Spools.Add(new Spool() { Machine = ActiveMachine, }); } private void RemoveSpool() { if (SelectedSpool != null) { _activeMachineAdapter.Context.Spools.Remove(SelectedSpool); ActiveMachine.Spools.Remove(SelectedSpool); } } private async void OnFilterChanged() { await LoadMachines(); } private async Task LoadMachines() { String filter = Filter.ToStringOrEmpty(); using (ObservablesContext db = ObservablesContext.CreateDefault()) { var machines = await db.Machines.Where(x => filter == String.Empty || x.SerialNumber.ToLower().StartsWith(filter.ToLower()) || x.Name.ToLower().Contains(filter.ToLower())) .Include(x => x.Configuration) .Include(x => x.MachineVersion.Name) .Include(x => x.Organization.Name) .Include(x => x.Configuration.HardwareVersion.Name) .Include(x => x.Configuration.HardwareVersion.Version).Select(x => new { x.Guid, x.SerialNumber, x.MachineType, x.Name, Organization = x.Organization.Name, MachineVersion = x.MachineVersion.Name, HardwareVersionName = x.Configuration.HardwareVersion.Name, HardwareVersionVersion = x.Configuration.HardwareVersion.Version, x.IsDeviceRegistered, x.IsDemo, x.LastUpdated }).OrderBy(x => x.SerialNumber).ToListAsync(); List models = new List(); foreach (var machine in machines) { MachineModel model = new MachineModel(); model.Guid = machine.Guid; model.SerialNumber = machine.SerialNumber; model.MachineType = (MachineTypes)machine.MachineType; model.Name = machine.Name; model.Organization = machine.Organization; model.HardwareVersion = machine.HardwareVersionName + " v" + machine.HardwareVersionVersion; model.MachineVersion = machine.MachineVersion; model.IsDeviceRegistered = machine.IsDeviceRegistered; model.IsDemo = machine.IsDemo; model.LastUpdated = machine.LastUpdated; models.Add(model); } Machines = models; } } private void ActiveMachine_OrganizationChanged(object sender, Organization e) { var sites = ActiveMachine.Organization != null ? _all_sites.Where(x => x.OrganizationGuid == ActiveMachine.OrganizationGuid).ToList() : new List(); sites.Insert(0, new Site() { Name = "NONE", ID = -1 }); Sites = sites; SelectedSite = Sites.SingleOrDefault(x => x.Guid == ActiveMachine.SiteGuid); } private async void UpgradeToGEN2() { if (!_notification.ShowQuestion("Are you sure you want to upgrade this machine configuration to GEN 2 standards?")) return; using (_notification.PushTaskItem("Upgrading this machine to GEN 2...")) { try { IsFree = false; var configuration = ActiveMachine.Configuration; InvalidOperationException noneGen1Exception = new InvalidOperationException("This machine configuration does not fit within the GEN 1 standard and cannot be upgraded."); var orderedPacks = configuration.IdsPacks.OrderBy(x => x.PackIndex).ToList(); try { if (!ValidateIdsPack(orderedPacks[0], LiquidTypes.Black, MidTankTypes.StandardMidTank, DispenserTypes.StandardDispenser, IdsPackFormulas.StandardColor)) throw noneGen1Exception; if (!ValidateIdsPack(orderedPacks[1], LiquidTypes.Cyan, MidTankTypes.StandardMidTank, DispenserTypes.StandardDispenser, IdsPackFormulas.StandardColor)) throw noneGen1Exception; if (!ValidateIdsPack(orderedPacks[2], LiquidTypes.Magenta, MidTankTypes.StandardMidTank, DispenserTypes.StandardDispenser, IdsPackFormulas.StandardColor)) throw noneGen1Exception; if (!ValidateIdsPack(orderedPacks[3], LiquidTypes.Yellow, MidTankTypes.StandardMidTank, DispenserTypes.StandardDispenser, IdsPackFormulas.StandardColor)) throw noneGen1Exception; if (!ValidateIdsPack(orderedPacks[4], LiquidTypes.TransparentInk, MidTankTypes.StandardMidTank, DispenserTypes.StandardDispenser, IdsPackFormulas.TransparentLiquid)) throw noneGen1Exception; if (!orderedPacks[5].IsEmpty) throw noneGen1Exception; if (!ValidateIdsPack(orderedPacks[6], LiquidTypes.Cleaner, MidTankTypes.StandardMidTank, DispenserTypes.StandardDispenser, IdsPackFormulas.CleanerLiquid)) throw noneGen1Exception; if (!ValidateIdsPack(orderedPacks[7], LiquidTypes.Lubricant, MidTankTypes.StandardMidTank, DispenserTypes.StandardDispenser, IdsPackFormulas.Lubricant)) throw noneGen1Exception; } catch { throw noneGen1Exception; } var cleanerPack = orderedPacks[6]; var lubricantPack = orderedPacks[7]; var emptyPack = orderedPacks[5]; cleanerPack.MidTankType = ActiveMachineAdapter.MidTankTypes.First(x => x.Type == MidTankTypes.NoMidTank); cleanerPack.IdsPackFormula = ActiveMachineAdapter.IdsPackFormulas.First(x => x.Type == IdsPackFormulas.LightInksCleanerLiquid); cleanerPack.Dispenser.DispenserType = ActiveMachineAdapter.DispenserTypes.First(x => x.Type == DispenserTypes.CleanerDispenser); cleanerPack.PackIndex = 8; lubricantPack.MidTankType = ActiveMachineAdapter.MidTankTypes.First(x => x.Type == MidTankTypes.LubricantMidTank); lubricantPack.IdsPackFormula = ActiveMachineAdapter.IdsPackFormulas.First(x => x.Type == IdsPackFormulas.LightInksLubricantLiquid); lubricantPack.Dispenser.DispenserType = ActiveMachineAdapter.DispenserTypes.First(x => x.Type == DispenserTypes.LubricantDispenser); lubricantPack.PackIndex = 9; var lightCyanDispenser = await ActiveMachineAdapter.Context.Dispensers.Include(x => x.IdsPacks).FirstOrDefaultAsync(x => x.SerialNumber.StartsWith(ActiveMachine.SerialNumber) && x.IdsPacks.Count == 0); int newDispenserStartIndex = 9; if (lightCyanDispenser == null) { lightCyanDispenser = new Dispenser(); lightCyanDispenser.NlPerPulse = orderedPacks[1].Dispenser.NlPerPulse; lightCyanDispenser.SerialNumber = $"{ActiveMachine.SerialNumber}-{newDispenserStartIndex++}"; lightCyanDispenser.DispenserType = ActiveMachineAdapter.DispenserTypes.First(x => x.Type == DispenserTypes.StandardDispenser); } IdsPack lightCyanPack = new IdsPack(); lightCyanPack.PackIndex = 5; lightCyanPack.LiquidType = ActiveMachineAdapter.LiquidTypes.First(x => x.Type == LiquidTypes.LightCyan); lightCyanPack.MidTankType = ActiveMachineAdapter.MidTankTypes.First(x => x.Type == MidTankTypes.StandardMidTank); lightCyanPack.IdsPackFormula = ActiveMachineAdapter.IdsPackFormulas.First(x => x.Type == IdsPackFormulas.LightColor); lightCyanPack.CartridgeType = ActiveMachineAdapter.CartridgeTypes.First(x => x.Type == CartridgeTypes.StandardCartridge); lightCyanPack.Dispenser = lightCyanDispenser; configuration.IdsPacks.Add(lightCyanPack); IdsPack lightMagentaPack = new IdsPack(); lightMagentaPack.PackIndex = 6; lightMagentaPack.LiquidType = ActiveMachineAdapter.LiquidTypes.First(x => x.Type == LiquidTypes.LightMagenta); lightMagentaPack.MidTankType = ActiveMachineAdapter.MidTankTypes.First(x => x.Type == MidTankTypes.StandardMidTank); lightMagentaPack.IdsPackFormula = ActiveMachineAdapter.IdsPackFormulas.First(x => x.Type == IdsPackFormulas.LightColor); lightMagentaPack.CartridgeType = ActiveMachineAdapter.CartridgeTypes.First(x => x.Type == CartridgeTypes.StandardCartridge); lightMagentaPack.Dispenser = new Dispenser() { NlPerPulse = orderedPacks[2].Dispenser.NlPerPulse, SerialNumber = $"{ActiveMachine.SerialNumber}-{newDispenserStartIndex++}", DispenserType = ActiveMachineAdapter.DispenserTypes.First(x => x.Type == DispenserTypes.StandardDispenser) }; configuration.IdsPacks.Add(lightMagentaPack); IdsPack lightYellowPack = new IdsPack(); lightYellowPack.PackIndex = 7; lightYellowPack.LiquidType = ActiveMachineAdapter.LiquidTypes.First(x => x.Type == LiquidTypes.LightYellow); lightYellowPack.MidTankType = ActiveMachineAdapter.MidTankTypes.First(x => x.Type == MidTankTypes.StandardMidTank); lightYellowPack.IdsPackFormula = ActiveMachineAdapter.IdsPackFormulas.First(x => x.Type == IdsPackFormulas.LightColor); lightYellowPack.CartridgeType = ActiveMachineAdapter.CartridgeTypes.First(x => x.Type == CartridgeTypes.StandardCartridge); lightYellowPack.Dispenser = new Dispenser() { NlPerPulse = orderedPacks[3].Dispenser.NlPerPulse, SerialNumber = $"{ActiveMachine.SerialNumber}-{newDispenserStartIndex++}", DispenserType = ActiveMachineAdapter.DispenserTypes.First(x => x.Type == DispenserTypes.StandardDispenser) }; configuration.IdsPacks.Add(lightYellowPack); configuration.IdsPacks.Remove(emptyPack); ActiveMachineAdapter.Context.IdsPacks.Remove(emptyPack); var packs = configuration.IdsPacks.ToList(); configuration.IdsPacks.Clear(); foreach (var pack in packs.OrderBy(x => x.PackIndex)) { configuration.IdsPacks.Add(pack); } ActiveMachine.LightInksInstalled = true; ActiveMachine.BtsrInstalled = true; IsGen1Machine = false; _notification.ShowInfo("Machine configuration successfully upgraded to GEN 2."); } catch (Exception ex) { LogManager.Log(ex, "Error upgrading machine to GEN 2."); _notification.ShowError($"Error upgrading this machine to GEN 2.\n{ex.FlattenMessage()}"); } finally { IsFree = true; } } } private bool ValidateIdsPack(IdsPack pack, LiquidTypes liquidType, MidTankTypes midTankType, DispenserTypes dispenserType, IdsPackFormulas formula) { if (pack.LiquidType.Type != liquidType) return false; if (pack.MidTankType.Type != midTankType) return false; if (pack.Dispenser.DispenserType.Type != dispenserType) return false; if (pack.IdsPackFormula.Type != formula) return false; return true; } } }