aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Synchronization/Images
diff options
context:
space:
mode:
authorRonen Sberlo <ronen.s@twine-s.com>2020-11-04 12:20:59 +0200
committerRonen Sberlo <ronen.s@twine-s.com>2020-11-04 12:20:59 +0200
commitdcdef4f8f4041a22dbfa9a09075a8ba51bb019ac (patch)
tree776bfe7c512a048b237ab3cfd877c7355c6d39e9 /Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Synchronization/Images
parent975f7174c6cd52882239ff2420300f151f3603e7 (diff)
downloadTango-dcdef4f8f4041a22dbfa9a09075a8ba51bb019ac.tar.gz
Tango-dcdef4f8f4041a22dbfa9a09075a8ba51bb019ac.zip
change fan too low alarm level
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.Synchronization/Images')
0 files changed, 0 insertions, 0 deletions
using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Data;
using Tango.BL;
using Tango.BL.Builders;
using Tango.BL.Calibration;
using Tango.BL.Entities;
using Tango.Core.Commands;
using Tango.MachineStudio.Common;
using Tango.MachineStudio.Common.Notifications;
using Tango.MachineStudio.RML.Contracts;
using Tango.MachineStudio.RML.Models;
using Tango.MachineStudio.RML.Views;
using Tango.PMR.ColorLab;
using System.Data.Entity;
using Tango.Core.ExtensionMethods;
using Tango.MachineStudio.Common.Authentication;
using Tango.BL.ActionLogs;
using Tango.BL.DTO;
using Tango.BL.Enumerations;
using Google.Protobuf;
using Tango.ColorConversion;
using Tango.CSV;

namespace Tango.MachineStudio.RML.ViewModels
{
    public class MainViewVM : StudioViewModel<IMainView>
    {
        private INotificationProvider _notification;
        private IAuthenticationProvider _authentication;
        private IActionLogManager _actionLogManager;
        private RmlDTO _rmlBeforeSave;

        private ObservablesContext _active_context;

        private List<RmlModel> _rmls;
        public List<RmlModel> Rmls
        {
            get { return _rmls; }
            set { _rmls = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<MediaMaterial> _materials;
        public ObservableCollection<MediaMaterial> Materials
        {
            get { return _materials; }
            set { _materials = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<MediaPurpos> _purposes;
        public ObservableCollection<MediaPurpos> Purposes
        {
            get { return _purposes; }
            set { _purposes = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<MediaCondition> _conditions;
        public ObservableCollection<MediaCondition> Conditions
        {
            get { return _conditions; }
            set { _conditions = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<LinearMassDensityUnit> _linearMassDensityUnits;
        public ObservableCollection<LinearMassDensityUnit> LinearMassDensityUnits
        {
            get { return _linearMassDensityUnits; }
            set { _linearMassDensityUnits = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<FiberShape> _fiberShapes;
        public ObservableCollection<FiberShape> FiberShapes
        {
            get { return _fiberShapes; }
            set { _fiberShapes = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<FiberSynth> _fiberSynths;
        public ObservableCollection<FiberSynth> FiberSynths
        {
            get { return _fiberSynths; }
            set { _fiberSynths = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<SpoolType> _spoolTypes;
        public ObservableCollection<SpoolType> SpoolTypes
        {
            get { return _spoolTypes; }
            set { _spoolTypes = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<BtsrApplicationType> _btsrApplicationTypes;
        public ObservableCollection<BtsrApplicationType> BtsrApplicationTypes
        {
            get { return _btsrApplicationTypes; }
            set { _btsrApplicationTypes = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<BtsrYarnType> _btsrYarnTypes;
        public ObservableCollection<BtsrYarnType> BtsrYarnTypes
        {
            get { return _btsrYarnTypes; }
            set { _btsrYarnTypes = value; RaisePropertyChangedAuto(); }
        }

        private RmlModel _selectedRML;
        public RmlModel SelectedRML
        {
            get { return _selectedRML; }
            set { _selectedRML = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
        }

        private Rml _activeRML;
        public Rml ActiveRML
        {
            get { return _activeRML; }
            set { _activeRML = value; RaisePropertyChangedAuto(); }
        }

        private CalibrationDataViewVM _calibrationDataViewVM;
        public CalibrationDataViewVM CalibrationDataViewVM
        {
            get { return _calibrationDataViewVM; }
            set { _calibrationDataViewVM = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<LiquidTypesRml> _liquidTypesRmls;
        public ObservableCollection<LiquidTypesRml> LiquidTypesRmls
        {
            get { return _liquidTypesRmls; }
            set { _liquidTypesRmls = value; RaisePropertyChangedAuto(); }
        }

        private ProcessParametersTablesGroup _activeProcessParametersGroup;
        public ProcessParametersTablesGroup ActiveProcessParametersGroup
        {
            get { return _activeProcessParametersGroup; }
            set { _activeProcessParametersGroup = value; RaisePropertyChangedAuto(); }
        }

        private ICollectionView _activeProcessParametersTableView;
        public ICollectionView ActiveProcessParametersTableView
        {
            get { return _activeProcessParametersTableView; }
            set { _activeProcessParametersTableView = value; RaisePropertyChangedAuto(); }
        }

        private ObservableCollection<DataFileModel> _ccts;
        public ObservableCollection<DataFileModel> CCTS
        {
            get { return _ccts; }
            set { _ccts = value; RaisePropertyChangedAuto(); }
        }

        private DataFileModel _selectedCCT;
        public DataFileModel SelectedCCT
        {
            get { return _selectedCCT; }
            set { _selectedCCT = value; RaisePropertyChangedAuto(); OnSelectedCCTChanged(); InvalidateRelayCommands(); }
        }

        private ObservableCollection<DataFileModel> _gbds;
        public ObservableCollection<DataFileModel> GBDS
        {
            get { return _gbds; }
            set { _gbds = value; RaisePropertyChangedAuto(); }
        }

        private DataFileModel _selectedGBD;
        public DataFileModel SelectedGBD
        {
            get { return _selectedGBD; }
            set { _selectedGBD = value; RaisePropertyChangedAuto(); OnSelectedGBDChanged(); InvalidateRelayCommands(); }
        }


        private ObservableCollection<DataFileModel> _lubs;
        public ObservableCollection<DataFileModel> LUBS
        {
            get { return _lubs; }
            set { _lubs = value; RaisePropertyChangedAuto(); }
        }

        private DataFileModel _selectedLUB;
        public DataFileModel SelectedLUB
        {
            get { return _selectedLUB; }
            set { _selectedLUB = value; RaisePropertyChangedAuto(); OnSelectedLUBChanged(); InvalidateRelayCommands(); }
        }

        private ColorConversionViewVM _colorConversionViewVM;
        public ColorConversionViewVM ColorConversionViewVM
        {
            get { return _colorConversionViewVM; }
            set { _colorConversionViewVM = value; RaisePropertyChangedAuto(); }
        }

        private RmlsSpool _selectedSpool;
        public RmlsSpool SelectedSpool
        {
            get { return _selectedSpool; }
            set { _selectedSpool = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
        }

        private ColorCalibrationViewVM _colorCalibrationVM;
        public ColorCalibrationViewVM ColorCalibrationVM
        {
            get { return _colorCalibrationVM; }
            set { _colorCalibrationVM = value; RaisePropertyChangedAuto(); }
        }

        private List<String> _manufacturers;
        public List<String> Manufacturers
        {
            get { return _manufacturers; }
            set
            {
                _manufacturers = value;
                RaisePropertyChangedAuto();
            }
        }

        private String _RMLFilter;
        /// <summary>
        /// Gets or sets the job filter.
        /// </summary>
        public String RMLFilter
        {
            get { return _RMLFilter; }
            set { _RMLFilter = value; RaisePropertyChangedAuto(); OnRMLFilterChanged(); }
        }

        /// <summary>
        /// Gets or sets the manage RML command.
        /// </summary>
        public RelayCommand ManageRmlCommand { get; set; }

        /// <summary>
        /// Gets or sets the add RML command.
        /// </summary>
        public RelayCommand AddRmlCommand { get; set; }

        /// <summary>
        /// Gets or sets the remove RML command.
        /// </summary>
        public RelayCommand RemoveRmlCommand { get; set; }

        public RelayCommand ImportForwardDataCommand { get; set; }

        public RelayCommand ExportForwardDataCommand { get; set; }

        public RelayCommand ImportGBDCommand { get; set; }

        public RelayCommand ExportGBDCommand { get; set; }

        public RelayCommand ImportLUBCommand { get; set; }

        public RelayCommand ExportLUBCommand { get; set; }

        public RelayCommand AddProcessParametersTableCommand { get; set; }

        public RelayCommand<ProcessParametersTable> RemoveProcessParametersTableCommand { get; set; }

        public RelayCommand AddLiquidFactorCommand { get; set; }

        public RelayCommand<LiquidTypesRml> RemoveLiquidFactorCommand { get; set; }

        public RelayCommand CreateCalibrationDataExcelTemplateCommand { get; set; }

        /// <summary>
        /// Gets or sets the back to RMLS command.
        /// </summary>
        public RelayCommand BackToRmlsCommand { get; set; }

        public RelayCommand SaveCommand { get; set; }

        public RelayCommand CloneRmlCommand { get; set; }

        public RelayCommand ExportRMLFileCommand { get; set; }

        public RelayCommand ImportRMLFileCommand { get; set; }

        /// <summary>
        /// Gets or sets the add spool command.
        /// </summary>
        public RelayCommand AddSpoolCommand { get; set; }

        /// <summary>
        /// Gets or sets the remove spool command.
        /// </summary>
        public RelayCommand RemoveSpoolCommand { get; set; }

        public RelayCommand BatchConversionCommand { get; set; }

        public MainViewVM(INotificationProvider notificationProvider, IAuthenticationProvider authentication, IActionLogManager actionLogManager)
        {
            _notification = notificationProvider;
            _authentication = authentication;
            _actionLogManager = actionLogManager;
            ManageRmlCommand = new RelayCommand(() => LoadActiveRML(SelectedRML.Guid), () => SelectedRML != null);
            RemoveRmlCommand = new RelayCommand(RemoveSelectedRml, () => SelectedRML != null);
            CloneRmlCommand = new RelayCommand(CloneSelectedRml, () => SelectedRML != null);
            AddRmlCommand = new RelayCommand(AddNewRml);
            BackToRmlsCommand = new RelayCommand(BackToRmls, () => IsFree);
            AddProcessParametersTableCommand = new RelayCommand(AddProcessParametersTable, () => IsFree);
            RemoveProcessParametersTableCommand = new RelayCommand<ProcessParametersTable>(RemoveProcessParametersTable, () => IsFree);
            AddLiquidFactorCommand = new RelayCommand(AddLiquidFactor, () => IsFree);
            RemoveLiquidFactorCommand = new RelayCommand<LiquidTypesRml>(RemoveLiquidFactor, () => IsFree);
            CreateCalibrationDataExcelTemplateCommand = new RelayCommand(CreateCalibrationDataExcelTemplate);
            SaveCommand = new RelayCommand(Save, () => IsFree);

            ImportForwardDataCommand = new RelayCommand(ImportCCTData, () => ActiveRML != null && IsFree);

            ExportForwardDataCommand = new RelayCommand(ExportCCTData, () => ActiveRML != null && SelectedCCT != null && IsFree);

            ImportGBDCommand = new RelayCommand(ImportGBDData, () => ActiveRML != null && IsFree);

            ExportGBDCommand = new RelayCommand(ExportGBDData, () => ActiveRML != null && SelectedGBD != null && IsFree);

            ImportLUBCommand = new RelayCommand(ImportLUBData, () => ActiveRML != null && IsFree);

            ExportLUBCommand = new RelayCommand(ExportLUBData, () => ActiveRML != null && SelectedLUB != null && IsFree);

            ExportRMLFileCommand = new RelayCommand(ExportRmlFile, () => SelectedRML != null && IsFree);
            ImportRMLFileCommand = new RelayCommand(ImportRmlFile, () => IsFree);

            AddSpoolCommand = new RelayCommand(AddNewSpool);
            RemoveSpoolCommand = new RelayCommand(RemoveSpool, () => SelectedSpool != null);

            BatchConversionCommand = new RelayCommand(BatchConversion);
        }

        public override void OnApplicationReady()
        {

        }

        private async Task LoadRmls()
        {
            var filter = RMLFilter.ToStringOrEmpty().ToLower();

            using (ObservablesContext db = ObservablesContext.CreateDefault())
            {
                var rmls = await db.Rmls.Where(x => x.Name.ToLower().Contains(filter) || x.DisplayName.ToLower().Contains(filter))
                    .Include(x => x.Cct.FileName)
                    .Include(x => x.LiquidTypesRmls.Select(y => y.LiquidType))
                    .Include(x => x.BtsrApplicationType.Name)
                    .Include(x => x.BtsrYarnType.Name)
                    .Select(x => new
                    {
                        x.Guid,
                        x.Name,
                        x.DisplayName,
                        x.Cct.FileName,
                        x.ColorConversionVersion,
                        x.UseColorLibGradients,
                        x.UseLightInks,
                        x.HeadType,
                        x.LastUpdated,
                        BtsrApplicationType = x.BtsrApplicationType != null ? x.BtsrApplicationType.Name : String.Empty,
                        BtsrYarnType = x.BtsrYarnType != null ? x.BtsrYarnType.Name : String.Empty,
                        LiquidTypes = x.LiquidTypesRmls.Select(y => y.LiquidType)
                    }).ToListAsync();

                List<RmlModel> models = new List<RmlModel>();

                foreach (var rml in rmls.OrderBy(x => x.Name).ToList())
                {
                    RmlModel model = new RmlModel();
                    model.Guid = rml.Guid;
                    model.Name = rml.Name;
                    model.LastUpdated = rml.LastUpdated;
                    model.DisplayName = rml.DisplayName;
                    model.CCT = rml.FileName + " v" + rml.ColorConversionVersion;
                    model.UseGradients = rml.UseColorLibGradients;
                    model.UseLightInks = rml.UseLightInks;
                    model.HeadType = (HeadTypes)rml.HeadType;
                    model.Btsr = (String.IsNullOrEmpty(rml.BtsrApplicationType) ? "N/A" : rml.BtsrApplicationType) + ", " + (String.IsNullOrEmpty(rml.BtsrYarnType) ? "N/A" : rml.BtsrYarnType);
                    model.LiquidTypes = rml.LiquidTypes.OrderBy(x => x.Code).Select(x => x.Color).ToList();

                    models.Add(model);
                }

                Rmls = models;
            }
        }

        private async void LoadActiveRML(String guid)
        {
            using (_notification.PushTaskItem("Loading RML..."))
            {
                try
                {
                    IsFree = false;

                    if (_active_context != null)
                    {
                        _active_context.Dispose();
                    }

                    _active_context = ObservablesContext.CreateDefault();

                    CCTS = _active_context.Ccts
                        .Select(x => new DataFileModel()
                        {
                            Guid = x.Guid,
                            FileName = x.FileName,

                        }).ToObservableCollection();

                    CCTS.Where(x => String.IsNullOrWhiteSpace(x.FileName)).ToList().ForEach(x => x.FileName = x.Guid);

                    GBDS = _active_context.Gbds
                        .Select(x => new DataFileModel()
                        {
                            Guid = x.Guid,
                            FileName = x.FileName,

                        }).ToObservableCollection();

                    LUBS = _active_context.Lubs
                        .Select(x => new DataFileModel()
                        {
                            Guid = x.Guid,
                            FileName = x.FileName,

                        }).ToObservableCollection();

                    LoadRmlProperties();

                    ActiveRML = await new RmlBuilder(_active_context)
                        .Set(guid)
                        .WithActiveParametersGroup()
                        .WithLiquidFactors()
                        .WithCCT()
                        .WithGbdAndLub()
                        .WithSpools()
                        .BuildAsync();

                    InvalidateRelayCommands();

                    if (ActiveRML.ProcessParametersTablesGroups.ToList().Count == 0)
                    {
                        if (!_notification.ShowQuestion("Could not find any process group for the selected RML. Would you like to create one?"))
                        {
                            _notification.ShowError("Cannot load an RML with no process group.");
                            IsFree = true;
                            return;
                        }
                        else
                        {
                            ProcessParametersTablesGroup group = new ProcessParametersTablesGroup();
                            group.Name = "Active Group";
                            group.Active = true;
                            group.ProcessParametersTables.Add(new ProcessParametersTable()
                            {
                                Name = "Process Table 1",
                            });

                            group.Rml = ActiveRML;

                            _active_context.ProcessParametersTablesGroups.Add(group);
                            _active_context.ProcessParametersTables.Add(group.ProcessParametersTables[0]);
                            await _active_context.SaveChangesAsync();
                            LoadActiveRML(ActiveRML.Guid);
                            return;
                        }
                    }

                    if (!String.IsNullOrEmpty(ActiveRML.Manufacturer) && false == Manufacturers.Any(x => x == ActiveRML.Manufacturer))
                    {
                        _active_context.YarnManufacturers.Add(new YarnManufacturer() { Name = ActiveRML.Manufacturer });
                        await _active_context.SaveChangesAsync();
                        Manufacturers.Add(ActiveRML.Manufacturer);
                    }

                    ActiveProcessParametersGroup = ActiveRML.ProcessParametersTablesGroups.ToList().FirstOrDefault();
                    ActiveProcessParametersTableView = CollectionViewSource.GetDefaultView(ActiveProcessParametersGroup.ProcessParametersTables);
                    ActiveProcessParametersTableView.SortDescriptions.Add(new SortDescription(nameof(ProcessParametersTable.TableIndex), ListSortDirection.Ascending));

                    CalibrationDataViewVM = new CalibrationDataViewVM(_notification);
                    LiquidTypesRmls = ActiveRML.LiquidTypesRmls;

                    foreach (var liquidTypeRml in LiquidTypesRmls)
                    {
                        CalibrationDataVM catVM = new CalibrationDataVM(liquidTypeRml.LiquidType);

                        if (liquidTypeRml.DefaultCatData != null)
                        {
                            catVM.CalibrationPoints = liquidTypeRml.GetCalibrationData().CalibrationPoints.Select(x => new CalibrationDataPointVM(x.X, x.Y)).ToObservableCollection();
                        }

                        CalibrationDataViewVM.LiquidsCalibrationData.Add(catVM);
                    }

                    ColorConversionViewVM = new ColorConversionViewVM(_notification)
                    {
                        RML = ActiveRML,
                        CCT = SelectedCCT,
                        GBD = SelectedGBD,
                        LUB = SelectedLUB,
                        LiquidsCalibrationData = CalibrationDataViewVM.LiquidsCalibrationData,
                        LiquidTypesRmls = LiquidTypesRmls,
                    };

                    if (ActiveRML.Cct != null)
                    {
                        _selectedCCT = CCTS.SingleOrDefault(x => x.Guid == ActiveRML.Cct.Guid);
                        await OnSelectedCCTChanged();
                        RaisePropertyChanged(nameof(SelectedCCT));
                    }

                    if (ActiveRML.Gbd != null)
                    {
                        _selectedGBD = GBDS.SingleOrDefault(x => x.Guid == ActiveRML.Gbd.Guid);
                        await OnSelectedGBDChanged();
                        RaisePropertyChanged(nameof(SelectedGBD));
                    }

                    if (ActiveRML.Lub != null)
                    {
                        _selectedLUB = LUBS.SingleOrDefault(x => x.Guid == ActiveRML.Lub.Guid);
                        await OnSelectedLUBChanged();
                        RaisePropertyChanged(nameof(SelectedLUB));
                    }

                    ColorCalibrationVM = new ColorCalibrationViewVM(_notification)
                    {
                        RML = ActiveRML,
                        LiquidTypes = LiquidTypesRmls.Where(x => x.LiquidType.HasPigment).ToList().Select(y => y.LiquidType).ToList(),
                    };

                    _rmlBeforeSave = RmlDTO.FromObservable(ActiveRML);

                    View.NavigateTo(RmlNavigationView.RmlView);

                    InvalidateRelayCommands();

                    IsFree = true;
                }
                catch (Exception ex)
                {
                    LogManager.Log($"Error loading RML '{ActiveRML.Name}'...");
                    _notification.ShowError($"Error loading the selected thread.\n{ex.FlattenMessage()}");
                }
                finally
                {
                    IsFree = true;
                }
            }
        }

        private async Task OnSelectedCCTChanged()
        {
            if (ColorConversionViewVM != null && SelectedCCT != null && !SelectedCCT.IsNew)
            {
                using (_notification.PushTaskItem("Loading CCT data..."))
                {
                    IsFree = false;

                    var cct = await _active_context.Ccts.SingleOrDefaultAsync(x => x.Guid == SelectedCCT.Guid);

                    if (cct != null)
                    {
                        SelectedCCT.Data = cct.Data;
                        ColorConversionViewVM.CCT = SelectedCCT;
                    }

                    IsFree = true;
                }
            }
        }

        private async Task OnSelectedGBDChanged()
        {
            if (ColorConversionViewVM != null && SelectedGBD != null && !SelectedGBD.IsNew)
            {
                using (_notification.PushTaskItem("Loading GBD data..."))
                {
                    IsFree = false;

                    var gbd = await _active_context.Gbds.SingleOrDefaultAsync(x => x.Guid == SelectedGBD.Guid);

                    if (gbd != null)
                    {
                        SelectedGBD.Data = gbd.Data;
                        ColorConversionViewVM.GBD = SelectedGBD;
                    }

                    IsFree = true;
                }
            }
        }

        private async Task OnSelectedLUBChanged()
        {
            if (ColorConversionViewVM != null && SelectedLUB != null && !SelectedLUB.IsNew)
            {
                using (_notification.PushTaskItem("Loading LUB data..."))
                {
                    IsFree = false;

                    var lub = await _active_context.Lubs.SingleOrDefaultAsync(x => x.Guid == SelectedLUB.Guid);

                    if (lub != null)
                    {
                        SelectedLUB.Data = lub.Data;
                        ColorConversionViewVM.LUB = SelectedLUB;
                    }

                    IsFree = true;
                }
            }
        }

        private void LoadRmlProperties()
        {
            Materials = _active_context.MediaMaterials.ToObservableCollection();
            Purposes = _active_context.MediaPurposes.ToObservableCollection();
            Conditions = _active_context.MediaConditions.ToObservableCollection();
            LinearMassDensityUnits = _active_context.LinearMassDensityUnits.ToObservableCollection();
            FiberShapes = _active_context.FiberShapes.ToObservableCollection();
            FiberSynths = _active_context.FiberSynths.ToObservableCollection();
            SpoolTypes = _active_context.SpoolTypes.ToObservableCollection();
            BtsrApplicationTypes = _active_context.BtsrApplicationTypes.ToObservableCollection();
            BtsrYarnTypes = _active_context.BtsrYarnTypes.ToObservableCollection();
            Manufacturers = _active_context.YarnManufacturers.Select(x => x.Name).ToList();
        }

        private async void AddNewRml()
        {
            var name = _notification.ShowTextInput("Please enter RML name", "Name");

            if (!String.IsNullOrWhiteSpace(name))
            {
                using (ObservablesContext db = ObservablesContext.CreateDefault())
                {
                    if (await db.Rmls.AnyAsync(x => x.Name == name))
                    {
                        _notification.ShowError("The specified RML name already exists. Please select a different name.");
                        return;
                    }
                }

                using (_notification.PushTaskItem("Creating new RML..."))
                {
                    IsFree = false;

                    if (_active_context != null)
                    {
                        _active_context.Dispose();
                    }

                    _active_context = ObservablesContext.CreateDefault();

                    LoadRmlProperties();

                    Rml rml = new Rml();
                    rml.Name = name;
                    rml.DisplayName = name;
                    rml.QualificationDate = DateTime.UtcNow;
                    rml.Manufacturer = "Twine";

                    using (ObservablesContext db = ObservablesContext.CreateDefault())
                    {
                        int count = db.Rmls.Count();

                        if (count > 0)
                        {
                            rml.Code = (await db.Rmls.MaxAsync(x => x.Code)) + 1;
                        }
                        else
                        {
                            rml.Code = 1;
                        }
                    }

                    rml.MediaMaterial = Materials.FirstOrDefault();
                    rml.MediaPurpose = Purposes.FirstOrDefault();
                    rml.MediaCondition = Conditions.FirstOrDefault();
                    rml.LinearMassDensityUnit = LinearMassDensityUnits.FirstOrDefault();
                    rml.FiberShape = FiberShapes.FirstOrDefault();
                    rml.FiberSynth = FiberSynths.FirstOrDefault();

                    ProcessParametersTablesGroup group = new ProcessParametersTablesGroup();
                    group.Name = "Active Group";
                    group.Active = true;
                    group.ProcessParametersTables.Add(new ProcessParametersTable()
                    {
                        Name = "Process Table 1",
                    });

                    group.Rml = rml;

                    _active_context.ProcessParametersTablesGroups.Add(group);
                    _active_context.ProcessParametersTables.Add(group.ProcessParametersTables[0]);
                    _active_context.Rmls.Add(rml);
                    await _active_context.SaveChangesAsync();

                    _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlCreated, _authentication.CurrentUser, rml.Name, rml, "Rml created using Machine Studio.");

                    LoadActiveRML(rml.Guid);

                    IsFree = true;
                }
            }
        }

        private async void RemoveSelectedRml()
        {
            if (_notification.ShowQuestion("Removing the selected thread will result in the loss of all related process parameters and default calibration data. Are you sure you want to delete the selected RML?"))
            {
                using (_notification.PushTaskItem("Removing RML..."))
                {
                    try
                    {
                        using (ObservablesContext db = ObservablesContext.CreateDefault())
                        {
                            IsFree = false;

                            var selectedRml = await db.Rmls.FirstAsync(x => x.Guid == SelectedRML.Guid);
                            var rml_jobs = await db.Jobs.Where(x => x.RmlGuid == SelectedRML.Guid).Include(x => x.Machine).OrderBy(x => x.Machine.SerialNumber).ToListAsync();

                            if (rml_jobs.Count > 0)
                            {
                                var vm = new RmlDeleteDialogViewVM(SelectedRML, Rmls.ToList(), rml_jobs.ToList());
                                _notification.ShowModalDialog<RmlDeleteDialogViewVM, RmlDeleteDialogView>(vm, (x) => { }, () => { });

                                if (!vm.DialogResult)
                                {
                                    return;
                                }

                                //Perform actions...
                                foreach (var jobAction in vm.JobsActions)
                                {
                                    if (jobAction.Action == RmlDeleteDialogViewVM.RmlDeleteJobAction.Delete)
                                    {
                                        _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.JobDeleted, _authentication.CurrentUser.Guid, jobAction.Job.Name, jobAction.Job.Guid, $"Job deleted due to RML '{SelectedRML.Name}' being removed.");
                                        await jobAction.Job.DeleteCascadeAsync(db);
                                    }
                                    else if (jobAction.Action == RmlDeleteDialogViewVM.RmlDeleteJobAction.Change)
                                    {
                                        var job = await db.Jobs.SingleOrDefaultAsync(x => x.Guid == jobAction.Job.Guid);
                                        job.RmlGuid = jobAction.TargetRml.Guid;
                                        _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.JobSaved, _authentication.CurrentUser.Guid, jobAction.Job.Name, jobAction.Job.Guid, $"Job RML changed to '{jobAction.TargetRml.Name}' due to RML '{SelectedRML.Name}' being removed.");
                                    }
                                }
                            }

                            await db.SaveChangesAsync();

                            await selectedRml.DeleteCascadeAsync(db);
                            _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlDeleted, _authentication.CurrentUser, selectedRml.Name, selectedRml, "RML deleted from Machine Studio.");

                            await LoadRmls();
                        }
                    }
                    catch (Exception ex)
                    {
                        LogManager.Log(ex, $"Error removing selected RML {SelectedRML?.Name}.");
                        _notification.ShowError($"An error occurred while trying to remove the selected RML.\n{ex.FlattenMessage()}");
                        await LoadRmls();
                    }
                    finally
                    {
                        IsFree = true;
                    }
                }
            }
        }

        private async void CloneSelectedRml()
        {
            String name = _notification.ShowTextInput("Enter thread name", "thread name");

            if (!String.IsNullOrWhiteSpace(name))
            {
                using (_notification.PushTaskItem("Cloning thread..."))
                {
                    try
                    {
                        IsFree = false;

                        using (var context = ObservablesContext.CreateDefault())
                        {
                            if (await context.Rmls.AnyAsync(x => x.Name == name))
                            {
                                _notification.ShowError("The specified RML name already exists. Please select a different name.");
                                IsFree = true;
                                return;
                            }

                            var rml = await new RmlBuilder(context).Set(SelectedRML.Guid).WithActiveParametersGroup().WithLiquidFactors().WithSpools().BuildAsync();

                            Rml cloned = new Rml();
                            rml.MapPropertiesTo(cloned, MappingFlags.NoReferenceTypes);

                            cloned.Code = (await context.Rmls.MaxAsync(x => x.Code)) + 1;
                            cloned.Guid = Guid.NewGuid().ToString();
                            cloned.ID = 0;
                            cloned.Name = name;
                            cloned.DisplayName = name;
                            cloned.RmlQualificationLevel = RmlQualifications.Provisional;
                            cloned.QualificationDate = DateTime.UtcNow;

                            ProcessParametersTablesGroup group = new ProcessParametersTablesGroup();
                            group.Name = rml.GetActiveProcessGroup().Name;
                            group.Active = true;

                            foreach (var p in rml.GetActiveProcessGroup().ProcessParametersTables)
                            {
                                var pc = new ProcessParametersTable();
                                p.MapPrimitivesTo(pc);
                                pc.Name = p.Name;

                                group.ProcessParametersTables.Add(pc);
                            }

                            cloned.ProcessParametersTablesGroups.Add(group);

                            foreach (var liquidFactor in rml.LiquidTypesRmls)
                            {
                                LiquidTypesRml l = new LiquidTypesRml();
                                l.DefaultCatData = liquidFactor.DefaultCatData;
                                l.LiquidType = liquidFactor.LiquidType;
                                l.MaxNlPerCm = liquidFactor.MaxNlPerCm;
                                cloned.LiquidTypesRmls.Add(l);
                            }

                            foreach (var spool in rml.RmlsSpools)
                            {
                                RmlsSpool s = new RmlsSpool();
                                spool.MapPropertiesTo(s, MappingFlags.ValueTypesOnly);
                                s.RmlGuid = cloned.Guid;
                                s.SpoolTypeGuid = spool.SpoolTypeGuid;
                                cloned.RmlsSpools.Add(s);
                            }

                            context.Rmls.Add(cloned);
                            await context.SaveChangesAsync();

                            _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlCreated, _authentication.CurrentUser, cloned.Name, cloned, "RML cloned from Machine Studio.");
                        }

                        await LoadRmls();
                    }
                    catch (Exception ex)
                    {
                        LogManager.Log(ex, "Error cloning thread.");
                        _notification.ShowError($"An error occurred while trying to clone the selected thread\n{ex.Message}");
                    }
                    finally
                    {
                        IsFree = true;
                    }
                }

            }
        }

        private void AddProcessParametersTable()
        {
            var name = _notification.ShowTextInput("Enter table name", "Name");

            if (!String.IsNullOrWhiteSpace(name))
            {
                _active_context.ProcessParametersTables.Add(new ProcessParametersTable()
                {
                    ProcessParametersTablesGroup = ActiveProcessParametersGroup,
                    Name = name,
                    TableIndex = ActiveProcessParametersGroup.ProcessParametersTables.Max(x => x.TableIndex) + 1,
                });
            }
        }

        public void OnProcessParametersTableDropped(ProcessParametersTable dragged, ProcessParametersTable dropped)
        {
            if (dragged.TableIndex > dropped.TableIndex)
            {
                dragged.TableIndex = dropped.TableIndex - 1;
            }
            else
            {
                dragged.TableIndex = dropped.TableIndex + 1;
            }

            int index = 0;

            foreach (var table in ActiveProcessParametersGroup.ProcessParametersTables.OrderBy(x => x.TableIndex))
            {
                table.TableIndex = index++;
            }

            ActiveProcessParametersTableView.Refresh();
        }

        private async void OnRMLFilterChanged()
        {
            await LoadRmls();
        }

        private void RemoveLiquidFactor(LiquidTypesRml liquidFactor)
        {
            if (_notification.ShowQuestion("Removing this liquid factor will remove the liquid type association with the RML and will drop the calibration data. Are you sure?"))
            {
                var catVM = CalibrationDataViewVM.LiquidsCalibrationData.SingleOrDefault(x => x.LiquidType == liquidFactor.LiquidType);
                CalibrationDataViewVM.LiquidsCalibrationData.Remove(catVM);
                _active_context.LiquidTypesRmls.Remove(liquidFactor);
            }
        }

        private void AddLiquidFactor()
        {
            AddLiquidFactorViewVM vm = new AddLiquidFactorViewVM(_active_context);
            _notification.ShowModalDialog<AddLiquidFactorViewVM, AddLiquidFactorView>(vm, (_) =>
            {
                if (LiquidTypesRmls.ToList().Exists(x => x.LiquidType == vm.SelectedLiquidType))
                {
                    _notification.ShowError("The selected liquid type is already associated with this RML.");
                    return;
                }

                LiquidTypesRml liquidFactor = new LiquidTypesRml()
                {
                    LiquidType = vm.SelectedLiquidType,
                    Rml = ActiveRML,
                };

                _active_context.LiquidTypesRmls.Add(liquidFactor);

                CalibrationDataVM catVM = new CalibrationDataVM(liquidFactor.LiquidType);

                CalibrationDataViewVM.LiquidsCalibrationData.Add(catVM);

            }, () => { });
        }

        private void RemoveProcessParametersTable(ProcessParametersTable processParametersTable)
        {
            if (ActiveProcessParametersGroup.ProcessParametersTables.Count == 1)
            {
                _notification.ShowError("The process group must contain at least one table.");
                return;
            }

            if (_notification.ShowQuestion("Are you sure you want to remove this process parameters table?"))
            {
                _active_context.ProcessParametersTables.Remove(processParametersTable);
            }
        }

        private void CreateCalibrationDataExcelTemplate()
        {
            SaveFileDialog dlg = new SaveFileDialog();
            try
            {
                dlg.Title = $"Create excel template file";
                dlg.Filter = "Excel Files|*.xlsx";
                dlg.DefaultExt = ".xlsx";
                dlg.FileName = "Calibration File Template";
                if (dlg.ShowDialog().Value)
                {
                    CalibrationHelper.CreateCalibrationDataExcelTemplate(dlg.FileName);
                }
            }
            catch (Exception ex)
            {
                LogManager.Log(ex, "Error generating excel calibration template file " + dlg.FileName);
                _notification.ShowError("An error occurred while trying to generate the calibration file.");
            }
        }

        private async void Save()
        {
            IsFree = false;

            try
            {
                using (_notification.PushTaskItem("Saving RML..."))
                {
                    foreach (var calDataVM in CalibrationDataViewVM.LiquidsCalibrationData)
                    {
                        var liquidTypeRml = LiquidTypesRmls.SingleOrDefault(x => x.LiquidType == calDataVM.LiquidType);
                        CalibrationData calData = new CalibrationData();
                        calData.LiquidType = (PMR.ColorLab.LiquidType)liquidTypeRml.LiquidType.Code;
                        calData.CalibrationPoints.AddRange(calDataVM.CalibrationPoints.Select(x => new CalibrationPoint() { X = x.X, Y = x.Y }));
                        liquidTypeRml.PutCalibrationData(calData);
                    }

                    ActiveRML.LastUpdated = DateTime.UtcNow;

                    if (_rmlBeforeSave.QualificationLevel != ActiveRML.QualificationLevel)
                    {
                        ActiveRML.QualificationDate = DateTime.UtcNow;
                    }

                    if (SelectedCCT != null)
                    {
                        if (SelectedCCT.IsNew)
                        {
                            Cct cct = new Cct();
                            cct.Guid = SelectedCCT.Guid;
                            cct.FileName = SelectedCCT.FileName;
                            cct.Data = SelectedCCT.Data;
                            ActiveRML.Cct = cct;
                            SelectedCCT.IsNew = false;
                        }
                        else
                        {
                            ActiveRML.CctGuid = SelectedCCT.Guid;
                        }
                    }

                    if (SelectedGBD != null)
                    {
                        if (SelectedGBD.IsNew)
                        {
                            Gbd gbd = new Gbd();
                            gbd.Guid = SelectedGBD.Guid;
                            gbd.FileName = SelectedGBD.FileName;
                            gbd.Data = SelectedGBD.Data;
                            ActiveRML.Gbd = gbd;
                            SelectedGBD.IsNew = false;
                        }
                        else
                        {
                            ActiveRML.GbdGuid = SelectedGBD.Guid;
                        }
                    }

                    if (SelectedLUB != null)
                    {
                        if (SelectedLUB.IsNew)
                        {
                            Lub lub = new Lub();
                            lub.Guid = SelectedLUB.Guid;
                            lub.FileName = SelectedLUB.FileName;
                            lub.Data = SelectedLUB.Data;
                            ActiveRML.Lub = lub;
                            SelectedLUB.IsNew = false;
                        }
                        else
                        {
                            ActiveRML.LubGuid = SelectedLUB.Guid;
                        }
                    }

                    var rmlAfter = RmlDTO.FromObservable(ActiveRML);

                    await _active_context.SaveChangesAsync();

                    _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlSaved, _authentication.CurrentUser, _rmlBeforeSave.Name, _rmlBeforeSave, rmlAfter, "RML saved using Machine Studio.");

                    _rmlBeforeSave = rmlAfter;

                    LoadActiveRML(ActiveRML.Guid);
                }
            }
            catch (Exception ex)
            {
                LogManager.Log(ex, $"Error saving RML {ActiveRML.Name}");
                _notification.ShowError($"An error occurred while trying to save the current RML.\n{ex.FlattenMessage()}");
            }
            finally
            {
                IsFree = true;
            }
        }

        private void BackToRmls()
        {
            View.NavigateTo(RmlNavigationView.RmlsView);
            LoadRmls();
        }

        #region Batch Conversion

        private void BatchConversion()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "Select CSV file with LAB data";
            dlg.Filter = "CSV Files|*.csv";
            if (!dlg.ShowDialogCenter())
            {
                return;
            }

            String fileName = dlg.FileName;

            try
            {
                ConversionInput input = new ConversionInput();
                input.ColorSpace = PMR.ColorLab.ColorSpace.Lab;
                input.ForwardData = ByteString.CopyFrom(SelectedCCT.Data);

                input.InputCoordinates = new InputCoordinates();

                input.ThreadL = ActiveRML.WhitePointL;
                input.ThreadA = ActiveRML.WhitePointA;
                input.ThreadB = ActiveRML.WhitePointB;

                input.UseLightInks = ActiveRML.UseLightInks;
                input.VMax = ActiveRML.VMax;

                //Validate calibration data
                foreach (var vm in CalibrationDataViewVM.LiquidsCalibrationData.Where(x => x.LiquidType.HasPigment))
                {
                    if (vm.CalibrationPoints.Count == 0)
                    {
                        InvokeUI(() =>
                        {
                            _notification.ShowError($"No calibration data for liquid '{vm.LiquidType.Name}'. Could not convert source color.");
                        });
                        return;
                    }
                    else if (!(vm.CalibrationPoints.First().X == 0 && vm.CalibrationPoints.First().Y == 0 && vm.CalibrationPoints.Last().X >= 100 && vm.CalibrationPoints.Last().Y >= 100))
                    {
                        InvokeUI(() =>
                        {
                            _notification.ShowError($"Invalid calibration data for liquid '{vm.LiquidType.Name}'. Could not convert source color.");
                        });
                        return;
                    }
                }

                foreach (var vm in CalibrationDataViewVM.LiquidsCalibrationData)
                {
                    InputLiquid inputLiquid = new InputLiquid();


                    CalibrationData calData = new CalibrationData();
                    calData.LiquidType = (PMR.ColorLab.LiquidType)vm.LiquidType.Code;
                    calData.CalibrationPoints.AddRange(vm.CalibrationPoints.Select(x => new CalibrationPoint() { X = x.X, Y = x.Y }));

                    inputLiquid.CalibrationData = calData;

                    inputLiquid.LiquidType = (PMR.ColorLab.LiquidType)vm.LiquidType.Code;
                    inputLiquid.MaxNanoliterPerCentimeter = LiquidTypesRmls.SingleOrDefault(x => x.LiquidType.Code == vm.LiquidType.Code).MaxNlPerCm;

                    input.InputCoordinates.InputLiquids.Add(inputLiquid);
                }

                foreach (var process in ActiveRML.GetActiveProcessGroup().ProcessParametersTables)
                {
                    input.ProcessRanges.Add(new ProcessRange()
                    {
                        MinInkUptake = process.MinInkUptake,
                        MaxInkUptake = process.MaxInkUptake,
                    });
                }

                input.GenerateHive = false;

                IColorConverter converter = new DefaultColorConverter();

                List<BatchConversionCsvModelIn> labList = CsvFile.Read<BatchConversionCsvModelIn>(new CsvSource(fileName)).ToList();

                List<BatchConversionCsvModelOut> resultsList = new List<BatchConversionCsvModelOut>();

                using (_notification.PushTaskItem("Converting..."))
                {
                    foreach (var lab in labList)
                    {
                        input.InputCoordinates.L = lab.L;
                        input.InputCoordinates.A = lab.A;
                        input.InputCoordinates.B = lab.B;
                        input.ColorSpace = PMR.ColorLab.ColorSpace.Lab;
                        var output = converter.Convert(input, ActiveRML.ColorConversionVersion);

                        BatchConversionCsvModelOut result = new BatchConversionCsvModelOut();

                        result.Index = lab.Index;
                        result.L = lab.L;
                        result.A = lab.A;
                        result.B = lab.B;
                        result.SuggestionL = output.CreateSingleSuggestion().Coordinates.L;
                        result.SuggestionA = output.CreateSingleSuggestion().Coordinates.A;
                        result.SuggestionB = output.CreateSingleSuggestion().Coordinates.B;
                        var cyanVolume = output.CreateSingleSuggestion().Coordinates.OutputLiquids.FirstOrDefault(x => x.LiquidType == PMR.ColorLab.LiquidType.Cyan);

                        if (cyanVolume != null)
                        {
                            result.Cyan = cyanVolume.Volume;
                        }

                        var magentaVolume = output.CreateSingleSuggestion().Coordinates.OutputLiquids.FirstOrDefault(x => x.LiquidType == PMR.ColorLab.LiquidType.Magenta);

                        if (magentaVolume != null)
                        {
                            result.Magenta = magentaVolume.Volume;
                        }

                        var yellowVolume = output.CreateSingleSuggestion().Coordinates.OutputLiquids.FirstOrDefault(x => x.LiquidType == PMR.ColorLab.LiquidType.Yellow);

                        if (yellowVolume != null)
                        {
                            result.Yellow = yellowVolume.Volume;
                        }

                        var blackVolume = output.CreateSingleSuggestion().Coordinates.OutputLiquids.FirstOrDefault(x => x.LiquidType == PMR.ColorLab.LiquidType.Black);

                        if (blackVolume != null)
                        {
                            result.Black = blackVolume.Volume;
                        }

                        var lightCyanVolume = output.CreateSingleSuggestion().Coordinates.OutputLiquids.FirstOrDefault(x => x.LiquidType == PMR.ColorLab.LiquidType.LightCyan);

                        if (lightCyanVolume != null)
                        {
                            result.LightCyan = lightCyanVolume.Volume;
                        }

                        var lightMagentaVolume = output.CreateSingleSuggestion().Coordinates.OutputLiquids.FirstOrDefault(x => x.LiquidType == PMR.ColorLab.LiquidType.LightMagenta);

                        if (lightMagentaVolume != null)
                        {
                            result.LightMagenta = lightMagentaVolume.Volume;
                        }

                        var lightYellowVolume = output.CreateSingleSuggestion().Coordinates.OutputLiquids.FirstOrDefault(x => x.LiquidType == PMR.ColorLab.LiquidType.LightYellow);

                        if (lightYellowVolume != null)
                        {
                            result.LightYellow = lightYellowVolume.Volume;
                        }
                        foreach (var item in input.InputCoordinates.InputLiquids)
                        {
                            switch (item.LiquidType)
                            {
                                case PMR.ColorLab.LiquidType.Cyan:
                                    item.Volume = result.Cyan;
                                    break;
                                case PMR.ColorLab.LiquidType.Magenta:
                                    item.Volume = result.Magenta;
                                    break;
                                case PMR.ColorLab.LiquidType.Yellow:
                                    item.Volume = result.Yellow;
                                    break;
                                case PMR.ColorLab.LiquidType.Black:
                                    item.Volume = result.Black;
                                    break;
                                case PMR.ColorLab.LiquidType.TransparentInk:
                                    break;
                                case PMR.ColorLab.LiquidType.Lubricant:
                                    break;
                                case PMR.ColorLab.LiquidType.Cleaner:
                                    break;
                                case PMR.ColorLab.LiquidType.LightCyan:
                                    item.Volume = result.LightCyan;
                                    break;
                                case PMR.ColorLab.LiquidType.LightMagenta:
                                    item.Volume = result.LightMagenta;
                                    break;
                                case PMR.ColorLab.LiquidType.LightYellow:
                                    item.Volume = result.LightYellow;
                                    break;
                                default:
                                    break;
                            }
                        }

                        result.OutOfGamut = output.OutOfGamut;
                        input.ColorSpace = PMR.ColorLab.ColorSpace.Volume;
                        output = converter.Convert(input, ActiveRML.ColorConversionVersion);
                        result.OutputL = output.CreateSingleSuggestion().Coordinates.L;
                        result.OutputA = output.CreateSingleSuggestion().Coordinates.A;
                        result.OutputB = output.CreateSingleSuggestion().Coordinates.B;
                        result.SuggestionDeltaE = BatchConversionCsvModelOut.MirtaDeltaE(result.L, result.A, result.B, result.SuggestionL, result.SuggestionA, result.SuggestionB);
                        result.OutputDeltaE = BatchConversionCsvModelOut.MirtaDeltaE(result.L, result.A, result.B, result.OutputL, result.OutputA, result.OutputB);


                        resultsList.Add(result);
                    }
                }

                SaveFileDialog dlgOut = new SaveFileDialog();
                dlgOut.Title = "Select results CSV file";
                dlgOut.Filter = "CSV Files|*.csv";
                dlgOut.FileName = Path.GetFileNameWithoutExtension(fileName) + " - Results";
                dlgOut.DefaultExt = ".csv";
                if (!dlgOut.ShowDialogCenter())
                {
                    return;
                }

                using (CsvFile<BatchConversionCsvModelOut> outFile = new CsvFile<BatchConversionCsvModelOut>(new CsvDestination(dlgOut.FileName)))
                {
                    foreach (var result in resultsList)
                    {
                        outFile.Append(result);
                    }
                }
            }
            catch (Exception ex)
            {
                _notification.ShowError($"Error converting the selected file. Please check all data is valid.\n{ex.FlattenMessage()}");
            }

            _notification.ShowInfo("Batch Conversion Completed.");
        }

        #endregion

        #region Import / Export Color Conversion Data

        private void ImportCCTData()
        {
            String file = GetDataFileOpen("Select color adjustment file", "Color Conversion Table|*.cct");
            if (file != null)
            {
                if (CCTS.ToList().Exists(x => x.FileName == Path.GetFileName(file)))
                {
                    _notification.ShowError("The selected CCT file already exists on the database. Please select the CCT file from the dropdown box.");
                    return;
                }

                DataFileModel cctModel = new DataFileModel();
                cctModel.Guid = Guid.NewGuid().ToString();
                cctModel.IsNew = true;

                cctModel.FileName = Path.GetFileName(file);
                cctModel.Data = File.ReadAllBytes(file);

                CCTS.Insert(0, cctModel);
                SelectedCCT = cctModel;

                ColorConversionViewVM.CCT = SelectedCCT;
            }
        }

        private void ExportCCTData()
        {
            if (SelectedCCT != null)
            {
                String file = GetDataFileSave("Select color adjustment file", "Color Conversion Table|*.cct", ActiveRML.Cct.FileName);
                if (file != null)
                {
                    using (_notification.PushTaskItem("Exporting CCT file..."))
                    {
                        try
                        {
                            IsFree = false;

                            if (SelectedCCT.IsNew)
                            {
                                File.WriteAllBytes(file, SelectedCCT.Data);
                            }
                            else
                            {
                                var cct = _active_context.Ccts.SingleOrDefault(x => x.Guid == SelectedCCT.Guid);

                                if (cct != null)
                                {
                                    File.WriteAllBytes(file, cct.Data);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            LogManager.Log(ex, "Error exporting CCT file.");
                            _notification.ShowError($"An error occurred while trying to export the CCT file.\n{ex.Message}");
                        }
                        finally
                        {
                            IsFree = true;
                        }
                    }
                }
            }
        }

        private void ExportLUBData()
        {
            if (SelectedLUB != null)
            {
                String file = GetDataFileSave("Select lubrication transformation file", "Lubrication Transformation File|*.lub", ActiveRML.Lub.FileName);
                if (file != null)
                {
                    using (_notification.PushTaskItem("Exporting LUB file..."))
                    {
                        try
                        {
                            IsFree = false;

                            if (SelectedLUB.IsNew)
                            {
                                File.WriteAllBytes(file, SelectedLUB.Data);
                            }
                            else
                            {
                                var lub = _active_context.Lubs.SingleOrDefault(x => x.Guid == SelectedLUB.Guid);

                                if (lub != null)
                                {
                                    File.WriteAllBytes(file, lub.Data);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            LogManager.Log(ex, "Error exporting LUB file.");
                            _notification.ShowError($"An error occurred while trying to export the LUB file.\n{ex.Message}");
                        }
                        finally
                        {
                            IsFree = true;
                        }
                    }
                }
            }
        }

        private void ImportLUBData()
        {
            String file = GetDataFileOpen("Select lubrication transformation file", "Lubrication Transformation File|*.lub");
            if (file != null)
            {
                if (LUBS.ToList().Exists(x => x.FileName == Path.GetFileName(file)))
                {
                    _notification.ShowError("The selected LUB file already exists on the database. Please select the LUB file from the dropdown box.");
                    return;
                }

                DataFileModel lubModel = new DataFileModel();
                lubModel.Guid = Guid.NewGuid().ToString();
                lubModel.IsNew = true;

                lubModel.FileName = Path.GetFileName(file);
                lubModel.Data = File.ReadAllBytes(file);

                LUBS.Insert(0, lubModel);
                SelectedLUB = lubModel;

                ColorConversionViewVM.LUB = SelectedLUB;
            }
        }

        private void ExportGBDData()
        {
            if (SelectedGBD != null)
            {
                String file = GetDataFileSave("Select gamut boundary descriptor file", "Gamut Boundary Descriptor File|*.gbd", ActiveRML.Gbd.FileName);
                if (file != null)
                {
                    using (_notification.PushTaskItem("Exporting GBD file..."))
                    {
                        try
                        {
                            IsFree = false;

                            if (SelectedGBD.IsNew)
                            {
                                File.WriteAllBytes(file, SelectedGBD.Data);
                            }
                            else
                            {
                                var gbd = _active_context.Gbds.SingleOrDefault(x => x.Guid == SelectedGBD.Guid);

                                if (gbd != null)
                                {
                                    File.WriteAllBytes(file, gbd.Data);
                                }
                            }
                        }
                        catch (Exception ex)
                        {
                            LogManager.Log(ex, "Error exporting GBD file.");
                            _notification.ShowError($"An error occurred while trying to export the GBD file.\n{ex.Message}");
                        }
                        finally
                        {
                            IsFree = true;
                        }
                    }
                }
            }
        }

        private void ImportGBDData()
        {
            String file = GetDataFileOpen("Select gamut boundary description file", "Gamut Boundary Description File|*.gbd");
            if (file != null)
            {
                if (GBDS.ToList().Exists(x => x.FileName == Path.GetFileName(file)))
                {
                    _notification.ShowError("The selected GBD file already exists on the database. Please select the GBD file from the dropdown box.");
                    return;
                }

                DataFileModel gbdModel = new DataFileModel();
                gbdModel.Guid = Guid.NewGuid().ToString();
                gbdModel.IsNew = true;

                gbdModel.FileName = Path.GetFileName(file);
                gbdModel.Data = File.ReadAllBytes(file);

                GBDS.Insert(0, gbdModel);
                SelectedGBD = gbdModel;

                ColorConversionViewVM.GBD = SelectedGBD;
            }
        }

        private String GetDataFileOpen(String title, String filter)
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = title;
            dlg.Filter = filter;
            if (dlg.ShowDialogCenter())
            {
                return dlg.FileName;
            }

            return null;
        }

        private String GetDataFileSave(String title, String filter, String fileName)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Title = title;
            dlg.Filter = filter;
            dlg.FileName = fileName;
            dlg.DefaultExt = ".cct";
            if (dlg.ShowDialogCenter())
            {
                return dlg.FileName;
            }

            return null;
        }

        #endregion

        #region RML Import / Export

        private async void ImportRmlFile()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "Import Thread Files";
            dlg.Filter = "Twine Thread Files|*.rml";
            dlg.Multiselect = true;

            if (dlg.ShowDialog().Value)
            {
                using (_notification.PushTaskItem($"Importing thread files..."))
                {
                    try
                    {
                        IsFree = false;

                        LogManager.Log($"Importing thread files...");

                        using (ObservablesContext db = ObservablesContext.CreateDefault())
                        {
                            foreach (var file in dlg.FileNames)
                            {
                                var json = File.ReadAllText(file);
                                var rmlFile = await Rml.FromRmlFile(db, json);

                                db.Rmls.Add(rmlFile);

                                _actionLogManager.InsertLog(BL.Enumerations.ActionLogType.RmlImported, _authentication.CurrentUser, rmlFile.Name, rmlFile, "RML imported from Machine Studio.");
                            }

                            await db.SaveChangesAsync();
                        }

                        IsFree = true;

                        _notification.ShowInfo($"Threads imported successfully.");

                        LoadRmls();
                    }
                    catch (Exception ex)
                    {
                        LogManager.Log(ex, "Error importing thread file.");
                        _notification.ShowError($"An error occurred while trying to import the selected thread file.\n{ex.FlattenMessage()}");
                    }
                    finally
                    {
                        IsFree = true;
                    }
                }
            }
        }

        private async void ExportRmlFile()
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Title = "Export Thread File";
            dlg.Filter = "Twine Thread Files|*.rml";
            dlg.DefaultExt = ".rml";
            dlg.FileName = SelectedRML.Name;

            if (dlg.ShowDialog().Value)
            {
                using (_notification.PushTaskItem($"Exporting Thread '{SelectedRML.Name}'..."))
                {
                    try
                    {
                        LogManager.Log($"Exporting Thread file {SelectedRML.Name}");

                        using (ObservablesContext db = ObservablesContext.CreateDefault())
                        {
                            var rml = await db.Rmls.FirstAsync(x => x.Guid == SelectedRML.Guid);
                            var rmlJsonFile = await rml.ToRmlFile(db);
                            File.WriteAllText(dlg.FileName, rmlJsonFile);
                        }
                    }
                    catch (Exception ex)
                    {
                        LogManager.Log(ex, "Error exporting Thread file.");
                        _notification.ShowError($"An error occurred while trying to export thread '{SelectedRML.Name}'.\n{ex.FlattenMessage()}");
                    }
                }
            }
        }

        #endregion

        #region Spools

        private void AddNewSpool()
        {
            _active_context.RmlsSpools.Add(new RmlsSpool()
            {
                Rml = ActiveRML,
            });
        }

        private void RemoveSpool()
        {
            if (SelectedSpool != null)
            {
                _active_context.RmlsSpools.Remove(SelectedSpool);
                ActiveRML.RmlsSpools.Remove(SelectedSpool);
            }
        }

        #endregion
    }
}