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; namespace Tango.MachineStudio.MachineDesigner.ViewModels { public class MainViewVM : StudioViewModel { private INotificationProvider _notification; private ActionTimer _machines_action_timer; private ActionTimer _dispensers_action_timer; #region Properties private ObservablesStaticCollections _machinesAdapter; public ObservablesStaticCollections MachinesAdapter { get { return _machinesAdapter; } set { _machinesAdapter = value; RaisePropertyChangedAuto(); } } private ObservablesStaticCollections _activeMachineAdapter; public ObservablesStaticCollections ActiveMachineAdapter { get { return _activeMachineAdapter; } set { _activeMachineAdapter = value; RaisePropertyChangedAuto(); } } private Machine _selectedMachine; /// /// Gets or sets the selected machine from the drop down. /// public Machine 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 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(); } } #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; } #endregion #region Constructors public MainViewVM() { } /// /// Initializes a new instance of the class. /// public MainViewVM(INotificationProvider notification) { MachinesAdapter = new ObservablesStaticCollections(ObservablesContext.CreateDefault()); _notification = notification; _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 < 8); 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); MachineUpdatesViewVM = new MachineUpdatesViewVM(_notification); TupViewVM = new TupViewVM(_notification); } #endregion #region Application Ready public override async void OnApplicationReady() { MachinesAdapter.MachineVersions = (await MachinesAdapter.Context.MachineVersions.ToListAsync()).ToObservableCollection(); } #endregion 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())).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, MachineVersion selectedVersion = null) { 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()).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()).ToObservableCollection(); ActiveMachineAdapter.MachineVersions = (await ActiveMachineAdapter.Context.MachineVersions.ToListAsync()).ToObservableCollection(); ActiveMachineAdapter.Organizations = (await ActiveMachineAdapter.Context.Organizations.ToListAsync()).ToObservableCollection(); if (!newMachine) { ActiveMachine = (await new MachineBuilder(ActiveMachineAdapter.Context).Set(SelectedMachine.Guid).WithOrganization().WithConfiguration().WithSpools().BuildAsync()); if (clone) { ActiveMachine = ActiveMachine.Clone(); ActiveMachine.Name = ""; ActiveMachine.SerialNumber = ""; ActiveMachine.IsDeviceRegistered = false; ActiveMachine.DeviceId = null; ActiveMachine.DeviceName = null; ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); } } else { if (selectedVersion == null) { ActiveMachine = new Machine(); ActiveMachine.Configuration = new Configuration(); ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); } else { ActiveMachine = selectedVersion.CreatePrototypeMachine(ActiveMachineAdapter.Context); ActiveMachineAdapter.Context.Machines.Add(ActiveMachine); } } ColorCalibrationViewVM = new ColorCalibrationViewVM(_notification, ActiveMachine, _activeMachineAdapter.Context) { Rmls = ActiveMachineAdapter.Rmls, LiquidTypesRmls = ActiveMachineAdapter.Rmls.FirstOrDefault().LiquidTypesRmls, SelectedRML = ActiveMachineAdapter.Rmls.FirstOrDefault(), }; HardwareConfigurationViewVM = new HardwareConfigurationViewVM(_notification); HardwareConfigurationViewVM.Init(ActiveMachine.Configuration); await MachineUpdatesViewVM.Init(ActiveMachine, ActiveMachineAdapter.Context); TupViewVM.Init(ActiveMachine); ActiveMachine.Configuration.HardwareVersionChanged += Configuration_HardwareVersionChanged; 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 { 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."); } 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.ProductionDate = DateTime.UtcNow; ColorCalibrationViewVM.Save(); var hwConfig = HardwareConfigurationViewVM.GetResultingHardwareConfiguration(); ActiveMachine.Configuration.SetHardwareConfiguration(hwConfig); await ActiveMachineAdapter.Context.SaveChangesAsync(); if (SelectedMachine != null) { await SelectedMachine.Reload(MachinesAdapter.Context); } 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 void AddNewMachine() { MachineCreationDialogVM vm = new MachineCreationDialogVM(); vm.MachineVersions = MachinesAdapter.MachineVersions.ToList(); _notification.ShowModalDialog(vm, (x) => { if (vm.SelectedMachineVersion != null && String.IsNullOrWhiteSpace(vm.SelectedMachineVersion.PrototypeMachineData)) { _notification.ShowError("The selected version does not contain any prototype machine data."); return; } LoadSelectedMachine(true, false, vm.SelectedMachineVersion); }, () => { }); } private async void RemoveSelectedMachine() { if (_notification.ShowQuestion("Are you sure you want to delete the selected machine?")) { using (_notification.PushTaskItem("Removing machine...")) { try { IsFree = false; await SelectedMachine.DeleteCascadeAsync(MachinesAdapter.Context); MachinesAdapter.Context.Machines.Remove(SelectedMachine); } catch (Exception ex) { LogManager.Log(ex, $"Error removing machine {SelectedMachine.SerialNumber}."); _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; } } #endregion private void CloneMachine() { LoadSelectedMachine(false, true); } 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 void OnFilterChanged() { if (Filter != null) { _machines_action_timer.ResetReplace(() => { Task.Factory.StartNew(() => { try { IsFree = false; MachinesAdapter.Machines = MachinesAdapter.Context.Machines.Where(x => x.SerialNumber.StartsWith(Filter)).Include(x => x.Organization).Include(x => x.MachineVersion).ToSynchronizedObservableCollection(); } catch { } finally { IsFree = true; } }); }); } } } }