aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.RML/ViewModels/MainViewVM.cs
blob: ee21b9ac320a0969c6e8c9a23454299f5e506e2a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.BL.Entities;
using Tango.Core.Commands;
using Tango.MachineStudio.Common.Notifications;
using Tango.MachineStudio.Logging.Views;
using Tango.SharedUI;

namespace Tango.MachineStudio.Logging.ViewModels
{
    public class TimelineViewVM : ViewModel
    {
        private ObservableCollection<TimelineEventGroup> _timelineEventGroups;
        public ObservableCollection<TimelineEventGroup> TimelineEventGroups
        {
            get { return _timelineEventGroups; }
            set { _timelineEventGroups = value; RaisePropertyChangedAuto(); }
        }

        private TimeSpan _timelineMaxTime;
        public TimeSpan TimelineMaxTime
        {
            get { return _timelineMaxTime; }
            set { _timelineMaxTime = value; RaisePropertyChangedAuto(); }
        }

        private double _timelineScaleFactor;
        public double TimelineScaleFactor
        {
            get { return _timelineScaleFactor; }
            set
            {

                if (value < 0.1) value = 0.1;

                _timelineScaleFactor = value;
                RaisePropertyChangedAuto();
            }
        }

        private TimeSpan _currentPosition;

        public TimeSpan CurrentPosition
        {
            get { return _currentPosition; }
            set { _currentPosition = value; RaisePropertyChangedAuto(); }
        }

        private bool _enableTimeMarker;

        public bool EnableTimeMarker
        {
            get { return _enableTimeMarker; }
            set { _enableTimeMarker = value; RaisePropertyChangedAuto(); }
        }

        public RelayCommand<MachinesEvent> EventSelectedCommand { get; set; }


        public TimelineViewVM(INotificationProvider notification)
        {
            TimelineScaleFactor = 10;
            TimelineEventGroups = new ObservableCollection<TimelineEventGroup>();

            EventSelectedCommand = new RelayCommand<MachinesEvent>((ev) =>
            {
                notification.ShowModalDialog<EventDetailsViewVM, EventDetailsView>(new EventDetailsViewVM(ev), (x) => { }, () => { });
            });
        }

        public void Initialize(List<MachinesEvent> events)
        {
            TimelineEventGroups = new ObservableCollection<TimelineEventGroup>();

            if (events != null && events.Count > 0)
            {
                foreach (var group in events.GroupBy(x => x.Group))
                {
                    TimelineEventGroup evGroup = new TimelineEventGroup(group.Key.ToString().ToWords());

                    foreach (var e in group)
                    {
                        evGroup.Events.Add(e);
                    }

                    TimelineEventGroups.Add(evGroup);
                }

                TimelineMaxTime = events.Max(x => x.DateTime) - events.Min(x => x.DateTime);
            }
        }
    }
}
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864
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;

namespace Tango.MachineStudio.RML.ViewModels
{
    public class MainViewVM : StudioViewModel<IMainView>
    {
        private INotificationProvider _notification;

        private ObservablesContext _rmls_context;
        private ObservablesContext _active_context;

        private ObservableCollection<Rml> _rmls;
        public ObservableCollection<Rml> 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 Rml _selectedRML;
        public Rml 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<CctModel> _ccts;
        public ObservableCollection<CctModel> CCTS
        {
            get { return _ccts; }
            set { _ccts = value; RaisePropertyChangedAuto(); }
        }

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

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

        /// <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 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; }

        public MainViewVM(INotificationProvider notificationProvider)
        {
            _notification = notificationProvider;
            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);

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

        public override void OnApplicationReady()
        {
            LoadRmls();
        }

        private async void LoadRmls()
        {
            if (_rmls_context != null) _rmls_context.Dispose();

            _rmls_context = ObservablesContext.CreateDefault();
            Rmls = await new RmlsCollectionBuilder(_rmls_context).SetAll().WithLiquidFactors().WithMediaProperties().BuildAsync();

            //Load CCT file names...
            var ccts = await _rmls_context.Ccts.Select(x => new
            {
                x.Guid,
                x.FileName
            }).ToListAsync();

            foreach (var rml in Rmls)
            {
                var cct = ccts.SingleOrDefault(x => x.Guid == rml.CctGuid);

                if (cct != null)
                {
                    rml.Cct = new Cct()
                    {
                        Guid = cct.Guid,
                        FileName = cct.FileName,
                    };
                }
            }
        }

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

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

                _active_context = ObservablesContext.CreateDefault();

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

                    }).ToObservableCollection();

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

                LoadRmlProperties();

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

                if (ActiveRML.Cct != null)
                {
                    SelectedCCT = CCTS.SingleOrDefault(x => x.Guid == ActiveRML.Cct.Guid);
                }

                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;
                    }
                }

                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,
                    LiquidsCalibrationData = CalibrationDataViewVM.LiquidsCalibrationData,
                    LiquidTypesRmls = LiquidTypesRmls,
                };

                View.NavigateTo(RmlNavigationView.RmlView);

                InvalidateRelayCommands();

                IsFree = true;
            }
        }

        private async void OnSelectedCCTChanged()
        {
            if (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 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();
        }

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

            if (!String.IsNullOrWhiteSpace(name))
            {
                if (Rmls.ToList().Exists(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.Manufacturer = "Twine";
                    rml.Code = Rmls.Max(x => x.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();
                    LoadActiveRML(rml.Guid);

                    IsFree = true;
                }
            }
        }

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

                using (_notification.PushTaskItem("Removing RML..."))
                {
                    try
                    {
                        await SelectedRML.DeleteCascadeAsync(_rmls_context);
                        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.Message}");
                    }
                }

                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())
                        {
                            var rml = await new RmlBuilder(context).Set(SelectedRML.Guid).WithActiveParametersGroup().WithLiquidFactors().BuildAsync();

                            Rml cloned = new Rml();
                            rml.MapPrimitivesWithStrings(cloned);

                            cloned.Code = Rmls.Max(x => x.Code) + 1;
                            cloned.Guid = Guid.NewGuid().ToString();
                            cloned.ID = 0;
                            cloned.Name = name;

                            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);
                            }

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

                        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 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 (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;
                        }
                    }

                    await _active_context.SaveChangesAsync();
                }
            }
            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.Message}");
            }

            LoadActiveRML(ActiveRML.Guid);

            IsFree = true;
        }

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

        #region Import / Export Color Conversion Data

        private void ImportCCTData()
        {
            String file = GetCCTFileOpen();
            if (file != null)
            {
                CctModel cctModel = new CctModel();
                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 = GetCCTFileSave(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 String GetCCTFileOpen()
        {
            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Title = "Select color adjustment file";
            dlg.Filter = "Color Conversion Table|*.cct";
            if (dlg.ShowDialogCenter())
            {
                return dlg.FileName;
            }

            return null;
        }

        private String GetCCTFileSave(String fileName)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Title = "Select color adjustment file";
            dlg.Filter = "Color Conversion Table|*.cct";
            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);
                            }

                            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 rmlJsonFile = await SelectedRML.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
    }
}