aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.Editors/RelayCommand.cs
blob: 63a7762385bb1a940cb4753307d484ce6c19b270 (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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;

namespace Tango.Editors
{
    /// <summary>
    /// RelayCommand is a very easy-to-use implementation of ICommand. You can use a RelayCommand to expose viewmodel functionality as a command, and
    /// supply the condition that determines the command's availability. A control in the view bound to a command can execute an available command will</summary>
    /// update its enabled state in response to the availability of the command.
    /// <seealso cref="System.Windows.Input.ICommand" />
    public sealed class RelayCommand : ICommand
    {
        #region fields
        readonly Predicate<object> canExecute;
        readonly Action<object> execute;
        private Action<string> saveProject;
        private RelayCommand syncHardwareConfigurationCommand;
        #endregion fields

        #region constructors
        public RelayCommand(Action<object> execute) : this(execute, null) { }

        public RelayCommand(Action<object> execute, Predicate<object> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public RelayCommand(Action execute)
            : this((x) => execute())
        {

        }

        public RelayCommand(Action execute, Predicate<object> canExecute)
            : this((x) => execute(), canExecute)
        {

        }

        public RelayCommand(Action<string> saveProject)
        {
            this.saveProject = saveProject;
        }

        public RelayCommand(RelayCommand syncHardwareConfigurationCommand)
        {
            this.syncHardwareConfigurationCommand = syncHardwareConfigurationCommand;
        }

        #endregion constructors

        #region methods
        public void RaiseCanExecuteChanged()
        {
            if (this.CanExecuteChanged != null)
            {
                this.CanExecuteChanged(this, EventArgs.Empty);
            }
        }
        #endregion methods

        #region ICommand events
        public event EventHandler CanExecuteChanged;
        #endregion ICommand events

        #region ICommand methods
        public bool CanExecute(object parameter)
        {
            return this.canExecute != null ? this.canExecute(parameter) : true;
        }

        public void Execute(object parameter)
        {
            if (this.execute != null)
            {
                this.execute(parameter);
            }
        }
        #endregion ICommand methods
    }

    public sealed class RelayCommand<T> : ICommand
    {
        #region fields
        readonly Predicate<object> canExecute;
        readonly Action<T> execute;
        #endregion fields

        #region constructors

        public RelayCommand(Action<T> execute) : this(execute, null) { }

        public RelayCommand(Action<T> execute, Predicate<object> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public RelayCommand(Action execute)
            : this((x) => execute())
        {

        }
        #endregion constructors

        #region methods
        public void RaiseCanExecuteChanged()
        {
            if (this.CanExecuteChanged != null)
            {
                this.CanExecuteChanged(this, EventArgs.Empty);
            }
        }
        #endregion methods

        #region ICommand events
        public event EventHandler CanExecuteChanged;
        #endregion ICommand events

        #region ICommand methods
        public bool CanExecute(object parameter)
        {
            return this.canExecute != null ? this.canExecute(parameter) : true;
        }

        public void Execute(object parameter)
        {
            if (this.execute != null)
            {
                this.execute((T)parameter);
            }
        }
        #endregion ICommand methods
    }
}
using Newtonsoft.Json;
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.BL.Enumerations;
using Tango.ColorConversion;
using Tango.Core;
using Tango.Core.DI;
using Tango.PPC.Common.Build;
using Tango.PPC.Common.Notifications;

namespace Tango.PPC.Jobs.Models
{
    public class JobModel : ExtendedObject
    {
        [TangoInject]
        public IBuildProvider BuildProvider { get; set; }

        private bool _preventChange;

        #region Properties

        public String Guid { get; set; }

        public int ID { get; set; }

        [JsonIgnore]
        public Job Job { get; set; }

        protected String _name;

        public String Name
        {
            get
            {
                return _name;
            }

            set
            {
                if (_name != value)
                {
                    _name = value;
                    RaisePropertyChangedAuto();
                }
            }
        }
        protected DateTime _creationdate;

        /// <summary>
        /// Gets or sets the JobModel creation date.
        /// </summary>
        [JsonIgnore]
        public DateTime CreationDate
        {
            get
            {
                return _creationdate;
            }
            set
            {
                if (_creationdate != value)
                {
                    _creationdate = value;
                    RaisePropertyChangedAuto();
                }
            }
        }

        private double _lastLength;
        public double Length
        {
            get
            {
                _lastLength = GetLength();
                return _lastLength;
            }
        }

        private double GetLength()
        {
            if (Segments != null)
            {
                if ((EnableInterSegment && IsAllSegmentsPerSpool))
                    return GroupingSegments.Count > 0 ? (GroupingSegments.Sum(x => x.LengthWithInterSegment)) : 0;
                return GroupingSegments.Sum(x => x.FullLength);
                //return Segments.Sum(x => x.LengthWithInterSegment);
                // return Segments.Sum(x => x.LengthWithFactor) + ((EnableInterSegment && IsAllSegmentsPerSpool) ? (InterSegmentLength * (Segments.Count > 0 ? Segments.Count - 1 : Segments.Count)) : 0);
            }
            else
            {
                return 0;
            }
        }

        protected Double _lengthpercentagefactor;

        /// <summary>
        /// Gets or sets the JobModel length percentage factor.
        /// </summary>

        public Double LengthPercentageFactor
        {
            get
            {
                return _lengthpercentagefactor;
            }

            set
            {
                if (_lengthpercentagefactor != value)
                {
                    _lengthpercentagefactor = value;
                    RaisePropertyChangedAuto();
                }
            }
        }

        protected Int32 _numberofunits;
        /// <summary>
        /// Gets or sets the JobModel number of units.
        /// </summary>
        public Int32 NumberOfUnits
        {
            get
            {
                return _numberofunits;
            }

            set
            {
                if (_numberofunits != value)
                {
                    _numberofunits = value;
                    RaisePropertyChangedAuto();
                    OnUpdateLengthhWeight();
                    RaisePropertyChanged(nameof(GetEstimatedDuration));
                    RaisePropertyChanged(nameof(SpoolCopies));
                }
            }
        }

        public double SpoolCopies
        {
            get
            {
                if (BuildProvider.MachineType == MachineTypes.Eureka)
                {
                    return NumberOfUnits;
                }
                else
                {
                    return (double)NumberOfUnits / (double)NumberSpools;
                }
            }

        }

        protected Double _intersegmentlength;

        /// <summary>
        /// Gets or sets the JobModel inter segment length.
        /// </summary>
        public Double InterSegmentLength
        {
            get
            {
                return _intersegmentlength;
            }

            set
            {
                if (_intersegmentlength != value)
                {
                    _intersegmentlength = value;
                    RaisePropertyChangedAuto();
                    OnInterSegmentlengthChanged();
                }
            }
        }

        protected SpoolsDistributions _spoolsdistribution;
        public bool IsAllSegmentsPerSpool
        {
            get { return ((SpoolsDistributions)_spoolsdistribution) == SpoolsDistributions.AllSegments; }
            set
            {
                _spoolsdistribution = value ? SpoolsDistributions.AllSegments : SpoolsDistributions.SingleSegment;
                RaisePropertyChangedAuto();
            }
        }
        /// <summary>
        /// Gets the total job segments length multiplied by number of units if it is an embroidery job.
        /// </summary>
        [JsonIgnore]
        public double LengthIncludingNumberOfUnits
        {
            get
            {
                //JsonConvert.SerializeObject(this,Formatting.Indented);
                _lastLength = GetLength();

                if (BuildProvider.MachineType == MachineTypes.Eureka)
                {
                    var l = _lastLength * Math.Max(NumberOfUnits, 1);

                    if (EnableInterSegment && NumberOfUnits > 1)
                    {
                        l += ((NumberOfUnits - 1) * InterSegmentLength);
                    }

                    return l;
                }
                else
                {
                    return (_lastLength * Copies) / (double)_numberSpools;
                }
            }
        }

        [JsonIgnore]
        public double LengthIncludingNumberOfUnitsAndSpools
        {
            get
            {
                if (BuildProvider.MachineType == MachineTypes.Eureka)
                {
                    if (NumberSpools >= 4)
                    {
                        return LengthIncludingNumberOfUnits * NumberSpools;
                    }

                    return LengthIncludingNumberOfUnits;
                }
                else
                {
                    return _lastLength * Copies;
                }
            }
        }

        protected Rml _rml;

        /// <summary>
        /// Gets or sets the JobModel rml.
        /// </summary>
        [JsonIgnore]
        public virtual Rml Rml
        {
            get
            {
                return _rml;
            }

            set
            {
                if (_rml != value)
                {
                    _rml = value;
                    RaisePropertyChangedAuto();
                    RaisePropertyChanged(nameof(GetEstimatedDuration));
                    RaisePropertyChanged(nameof(GramPerLength));
                    OnUpdateLengthhWeight();
                }
            }
        }

        public string RmlGuid
        {
            get
            {
                return Rml.Guid;
            }
        }
        protected ColorSpace _colorspace;

        /// <summary>
        /// Gets or sets the JobModel color spaces.
        /// </summary>
        [JsonIgnore]
        public virtual ColorSpace ColorSpace
        {
            get
            {
                return _colorspace;
            }
            set
            {
                if (_colorspace != value)
                {
                    _colorspace = value;
                    RaisePropertyChangedAuto();
                }
            }
        }

        /// <summary>
        /// Gets or sets the available color spaces.
        /// </summary>
        [JsonIgnore]
        public List<ColorSpace> ColorSpacesList { get; set; }

        protected Customer _customer;

        /// <summary>
        /// Gets or sets the JobModel customer.
        /// </summary>
        [JsonIgnore]
        public virtual Customer Customer
        {
            get
            {
                return _customer;
            }
            set
            {
                if (_customer != value)
                {
                    _customer = value;
                    RaisePropertyChangedAuto();
                }
            }
        }
        protected Machine _machine;

        /// <summary>
        /// Gets or sets the JobModel machine.
        /// </summary>
        [JsonIgnore]
        public virtual Machine Machine
        {
            get
            {
                return _machine;
            }

            set
            {
                if (_machine != value)
                {
                    _machine = value;
                    RaisePropertyChangedAuto();
                }
            }
        }

        protected SpoolType _spooltype;

        /// <summary>
        /// Gets or sets the JobModel spool types.
        /// </summary>
        [JsonIgnore]
        public virtual SpoolType SpoolType
        {
            get
            {
                return _spooltype;
            }

            set
            {
                if (_spooltype != value)
                {
                    _spooltype = value;
                    RaisePropertyChangedAuto();

                }
            }
        }

        private string _spoolTypeName;

        public string SpoolTypeName
        {
            get { return _spoolTypeName; }
            set
            {
                _spoolTypeName = value;
                RaisePropertyChangedAuto();
            }
        }


        public string SpoolGuid
        {
            get { return SpoolType.Guid; }
        }

        private int _numberSpools;
        [JsonIgnore]
        public int NumberSpools
        {
            get { return _numberSpools; }
            set
            {
                if (_numberSpools != value)
                {
                    _numberSpools = value;
                    RaisePropertyChangedAuto();
                    OnNumberOfSpoolsChanged();
                    OnUpdateLengthhWeight();
                }
            }
        }

        protected Int32 _copies;
        [JsonIgnore]
        public Int32 Copies //_numberOfUnitsMultipliedBySpools
        {
            get
            {
                return _copies;
            }

            set
            {
                if (_copies != value)
                {
                    if (BuildProvider.MachineType == MachineTypes.Eureka)
                    {
                        if (NumberSpools >= 4)
                        {
                            if (value < NumberSpools)
                                _copies = NumberSpools;
                            else
                            {
                                int coeff = (int)(value + NumberSpools - 1) / NumberSpools;
                                _copies = coeff * NumberSpools;
                            }
                            NumberOfUnits = (int)_copies / NumberSpools;
                            OnUpdateLengthhWeight();
                        }
                        else
                            _copies = value;
                    }
                    else
                    {
                        _copies = value;
                        NumberOfUnits = value;
                    }
                    RaisePropertyChangedAuto();
                }
            }
        }

        protected User _user;

        /// <summary>
        /// Gets or sets the JobModel user.
        /// </summary>
        [JsonIgnore]
        public virtual User User
        {
            get
            {
                return _user;
            }

            set
            {
                if (_user != value)
                {
                    _user = value;
                    RaisePropertyChangedAuto();
                }
            }
        }
        public JobTypes JobType { get; set; }

        protected SynchronizedObservableCollection<SegmentModel> _segments;

        /// <summary>
        /// Gets or sets the JobModel segments.
        /// </summary>
        [JsonIgnore]
        public SynchronizedObservableCollection<SegmentModel> Segments
        {
            get
            {
                return _segments;
            }
            set
            {
                if (_segments != value)
                {
                    _segments = value;
                    RaisePropertyChangedAuto();
                    OnSegmentsChanged();
                }
            }
        }

        protected SynchronizedObservableCollection<SegmentsGroupModel> _segmentsGroups;

        /// <summary>
        /// Gets or sets the JobModel segments.
        /// </summary>
        [JsonIgnore]
        public SynchronizedObservableCollection<SegmentsGroupModel> SegmentsGroups
        {
            get
            {
                return _segmentsGroups;
            }
            set
            {
                if (_segmentsGroups != value)
                {
                    _segmentsGroups = value;
                    RaisePropertyChangedAuto();

                }
            }
        }

        private bool _enableintersegment;
        public bool EnableInterSegment
        {
            get
            {
                return _enableintersegment;
            }

            set
            {
                if (_enableintersegment != value)
                {
                    _enableintersegment = value;
                    RaisePropertyChangedAuto();
                    OnEnableInterSegmentChanged();
                }
            }
        }

        private ObservableCollection<SegmentModel> _effectiveSegments;
        [JsonIgnore]
        public ObservableCollection<SegmentModel> EffectiveSegments
        {
            get
            {
                return _effectiveSegments;
            }
        }

        protected SynchronizedObservableCollection<ISegmentModel> _groupingSegments;
        /// <summary>
        /// Gets or sets the display segments.
        /// </summary>
        [JsonIgnore]
        public SynchronizedObservableCollection<ISegmentModel> GroupingSegments
        {
            get
            {
                return _groupingSegments;
            }
            set
            {
                if (_groupingSegments != value)
                {
                    _groupingSegments = value;
                    RaisePropertyChangedAuto();
                }
            }
        }

        private bool _selectAllSegments;
        [JsonIgnore]
        public bool SelectAllSegments
        {
            get { return _selectAllSegments; }
            set
            {
                _selectAllSegments = value;
                OnSelectAllChanged();
                RaisePropertyChangedAuto();
            }
        }

        [JsonIgnore]
        public bool HasSelectedItems
        {
            get
            {
                return GroupingSegments.Any(x => x.IsSelected);
            }
        }

        [JsonIgnore]
        public bool IsReverseEnable
        {
            get
            {
                var items = GroupingSegments.Where(x => x.IsSelected).ToList();

                foreach (var item in items)
                {
                    if (item is SegmentModel seg)
                    {
                        if (seg.IsGradient)
                            return true;
                    }
                    else if (item is SegmentsGroupModel group)
                    {
                        foreach (var segment in group.Segments)
                        {
                            if (segment.IsGradient)
                            {
                                return true;
                            }
                        }
                    }
                }
                return false;
            }
        }

        private List<ISegmentModel> _segmentsToCopy;
        [JsonIgnore]
        public List<ISegmentModel> SegmentsToCopy
        {
            get
            {
                return _segmentsToCopy;
            }
            set
            {
                if (_segmentsToCopy != value)
                {
                    _segmentsToCopy = value;
                    RaisePropertyChanged(nameof(HasSegmentsToCopy));
                }
            }
        }

        [JsonIgnore]
        public int IndexToPasteCopySegments { get; set; }

        [JsonIgnore]
        public bool HasSegmentsToCopy
        {
            get
            {
                return SegmentsToCopy.Count > 0;
            }
        }


        ProcessParametersTable _processParametersTable;
        [JsonIgnore]
        public ProcessParametersTable ProcessParametersTable
        {
            get
            {
                InitializeProcessParameters();
                return _processParametersTable;
            }
            set
            {
                if (value != _processParametersTable)
                {
                    _processParametersTable = value;
                    RaisePropertyChangedAuto();
                }
            }
        }

        private void InitializeProcessParameters()
        {
            _processParametersTable = GetRecommendedProcessParameters();
        }

        [JsonIgnore]
        public TimeSpan GetEstimatedDuration
        {
            get
            {
                if (Rml == null || Rml.GetActiveProcessGroup().ProcessParametersTables == null)
                    return TimeSpan.Zero;
                var processParameters = ProcessParametersTable;
                if (processParameters == null)
                    processParameters = Rml.GetActiveProcessGroup().ProcessParametersTables.FirstOrDefault();

                if (processParameters.DyeingSpeed != 0)
                {
                    return TimeSpan.FromSeconds((LengthIncludingNumberOfUnits + processParameters.DryerBufferLengthMeters) / (processParameters.DyeingSpeed / 100d));
                }
                return TimeSpan.Zero;
            }
        }

        [JsonIgnore]
        public int LastGroupID
        {
            get
            {
                var groups = GroupingSegments.ToList().OfType<SegmentsGroupModel>().ToList();
                return groups.Count() == 0 ? 0 : groups.Max(x => x.SegmentIndex);
            }
        }

        /// <summary>
        /// Gets the ordered segments with groups.
        /// </summary>
        public List<ISegmentModel> OrderedSegmentsWithGroups
        {
            get
            {
                if (Segments == null)
                    return null;
                List<ISegmentModel> orderedSegmentsWithGroups = new List<ISegmentModel>();

                orderedSegmentsWithGroups.AddRange(Segments.Where(x => x.SegmentsGroupModel == null));
                orderedSegmentsWithGroups.AddRange(SegmentsGroups);
                return orderedSegmentsWithGroups.OrderBy(x => x.SegmentIndex).ToList();
            }
        }




        [JsonIgnore]
        public bool IsEureka { get; set; }

        [JsonIgnore]
        public double GramPerLength
        {
            get
            {
                if (Rml != null)
                    return Rml.GetGramPer1000mLength;
                return 0d;
            }
        }

        [JsonIgnore]
        public double WeightIncludingNumberOfUnits
        {
            get
            {
                if (Rml == null)
                    return 0;

                var gramPerlength = Rml.GetGramPer1000mLength;
                var weight = (LengthIncludingNumberOfUnits * gramPerlength) / (1000);//(g)
                return weight;
            }
        }

        [JsonIgnore]
        public double WeightIncludingNumberOfUnitsAndSpools
        {
            get
            {
                if (NumberSpools >= 4)
                {
                    return WeightIncludingNumberOfUnits * NumberSpools;
                }

                return WeightIncludingNumberOfUnits;
            }
        }

        #endregion

        #region constructors

        public JobModel(List<ColorSpace> list, bool isEureka)
        {
            TangoIOC.Default.Inject(this);
            ColorSpacesList = list;
            _segments = new SynchronizedObservableCollection<SegmentModel>();
            _segmentsGroups = new SynchronizedObservableCollection<SegmentsGroupModel>();
            _groupingSegments = new SynchronizedObservableCollection<ISegmentModel>();
            SegmentsToCopy = new List<ISegmentModel>();
            _effectiveSegments = new ObservableCollection<SegmentModel>();

            Segments.CollectionChanged -= Segments_CollectionChanged;
            Segments.CollectionChanged += Segments_CollectionChanged;

            GroupingSegments.CollectionChanged -= SegmentsGroup_CollectionChanged;
            GroupingSegments.CollectionChanged += SegmentsGroup_CollectionChanged;
            SelectAllSegments = false;
            //if not eurika
            if (!isEureka)
                NumberOfUnits = 1;
            else
                NumberOfUnits = 4;
            IsEureka = isEureka;
        }

        #endregion

        #region modifications

        private void OnSegmentsChanged()
        {
            LoadGroupingSegments();
        }

        /// <summary>
        /// Loads the grouping segments.
        /// </summary>
        public void LoadGroupingSegments()
        {
            _groupingSegments.Clear();
            //List<ISegmentModel> segmentsWithGroups = new List<ISegmentModel>();

            //segmentsWithGroups.AddRange(Segments.Where(x => x.SegmentsGroupModel == null));
            //segmentsWithGroups.AddRange(SegmentsGroups);
            OrderedSegmentsWithGroups.ForEach(x => _groupingSegments.Add(x));

            if (_groupingSegments.Count > 0)
                _groupingSegments.Last().IsLast = true;
            RaisePropertyChanged(nameof(GroupingSegments));
        }

        /// <summary>
        /// Arranges the segment indixes in groups.
        /// </summary>
        public void ArrangeSegmentIndixesInGroups()
        {
            foreach (var group in SegmentsGroups)
            {
                int index = 1;
                foreach (var segm in Segments)
                {
                    segm.SegmentIndex = index;
                    index++;
                }
            }
        }

        /// <summary>
        /// Arranges the segments indixes.
        /// </summary>
        public void ArrangeSegmentsIndixes()
        {
            int index = 1;
            int count = GroupingSegments.Count();
            ArrangeSegmentIndixesInGroups();
            foreach (var segment in GroupingSegments)
            {
                segment.IsLast = (index == count) ? true : false;
                segment.SegmentIndex = index++;
            }
            UpdateEffectiveSegments();
        }

        /// <summary>
        /// Creates the inter segment.
        /// </summary>
        /// <param name="length">The length.</param>
        /// <returns></returns>
        public SegmentModel CreateInterSegment(double length)
        {
            SegmentModel segment = new SegmentModel()
            {
                IsInterSegment = true,
                Length = length,
                Name = "Inter Segment",
                Job = this,
            };
            segment.BrushStops.Add(new BrushStopModel(segment, null)
            {
                ColorSpace = ColorSpaces.RGB,
                Color = System.Windows.Media.Colors.White,
                LastChangedColorSpace = ColorSpaces.RGB

            });
            return segment;
        }

        /// <summary>
        /// Adds the new segment.
        /// </summary>
        /// <param name="length">The length.</param>
        /// <param name="segmentIndex">Index of the segment.</param>
        /// <returns></returns>
        public SegmentModel AddNewSegment(double length, Int32 segmentIndex)
        {
            SegmentModel segment = new SegmentModel();
            segment.Name = "Standard Segment";
            segment.SegmentIndex = segmentIndex + 1;
            segment.Length = length;

            segment.Job = this;
            segment.EnableInterSegment = InterSegmentLength > 0;

            Segments.Add(segment);
            if (segmentIndex < GroupingSegments.Count())
            {
                GroupingSegments.Insert(segmentIndex, segment);
            }
            else
                GroupingSegments.Add(segment);
            ArrangeSegmentsIndixes();

            return segment;
        }

        protected ProcessParametersTable GetRecommendedProcessParameters()
        {
            try
            {
                IColorConverter _converter = new DefaultColorConverter();
                bool useLightInks = true;
                if (OrderedSegmentsWithGroups.Count > 1 && !EnableInterSegment)
                    useLightInks = false;
                List<BrushStop> stops = new List<BrushStop>();
                foreach (var segment in OrderedSegmentsWithGroups)
                {
                    if (segment is SegmentModel innerSegment)
                    {
                        foreach (var stop in innerSegment.BrushStops.OrderBy(x => x.StopIndex).ToList())
                        {
                            if (stop.BrushStop != null)
                            {
                                BrushStop bs = stop.CreateBrushStop();
                                stops.Add(bs);
                            }
                        }
                    }
                    else if (segment is SegmentsGroupModel group)
                    {
                        foreach (var segm_group in group.Segments.OrderBy(x => x.SegmentIndex))
                        {
                            foreach (var stop in segm_group.BrushStops.OrderBy(x => x.StopIndex).ToList())
                            {
                                if (stop.BrushStop != null)
                                {
                                    BrushStop bs = stop.CreateBrushStop();
                                    stops.Add(bs);
                                }
                            }
                        }
                    }
                }

                if (stops.Count > 0)
                {
                    return _converter.GetRecommendedProcessParameters(Rml, Machine, stops, Rml.GetActiveProcessGroup(), useLightInks);
                }
                else
                {
                    return Rml.GetActiveProcessGroup().ProcessParametersTables.FirstOrDefault();
                }
            }
            catch (Exception ex)
            {
                LogManager.Log(ex, "Error calculating recommended process parameters.");
                return null;
            }
        }
        #endregion

        #region changes

        private void OnEnableInterSegmentChanged()
        {
            if (EnableInterSegment == false && InterSegmentLength > 0)
            {
                _intersegmentlength = 0;
                RaisePropertyChanged(nameof(InterSegmentLength));
            }
            _groupingSegments.ToList().ForEach(x => x.EnableInterSegment = EnableInterSegment);
            OnLengthChanged();
            UpdateEffectiveSegments();
        }

        private void UpdateEffectiveSegments()
        {
            if (EnableInterSegment && IsAllSegmentsPerSpool)
            {
                int max = GroupingSegments.Count > 0 ? GroupingSegments.Max(x => x.SegmentIndex) : 0;

                ObservableCollection<SegmentModel> effectiveSegments = new ObservableCollection<SegmentModel>();

                foreach (var s in GroupingSegments.OrderBy(x => x.SegmentIndex))
                {
                    if (s is SegmentModel)
                    {
                        SegmentModel segment = s as SegmentModel;
                        effectiveSegments.Add(segment);
                        if (segment.SegmentIndex != max && segment.EnableInterSegment)
                        {
                            effectiveSegments.Add(CreateInterSegment(InterSegmentLength));
                        }
                    }
                    else if (s is SegmentsGroupModel)
                    {
                        SegmentsGroupModel segmentsGroup = s as SegmentsGroupModel;
                        List<SegmentModel> segments = segmentsGroup.Segments.ToList();
                        for (int repeats = 0; repeats < segmentsGroup.Repeats; ++repeats)
                        {
                            for (int i = 0; i < segments.Count; ++i)
                            {
                                //if (repeats > 0)
                                //{
                                //    effectiveSegments.Add(segments[i].Clone());
                                //}
                                //else
                                effectiveSegments.Add(segments[i]);
                                if (EnableInterSegment && !(repeats == (segmentsGroup.Repeats - 1) && i == (segments.Count - 1)))
                                {
                                    effectiveSegments.Add(CreateInterSegment(InterSegmentLength));
                                }
                            }
                        }
                        if (EnableInterSegment && segmentsGroup.SegmentIndex != max)
                        {
                            effectiveSegments.Add(CreateInterSegment(InterSegmentLength));
                        }
                    }
                }
                _effectiveSegments = effectiveSegments;
            }
            else
            {
                ObservableCollection<SegmentModel> effectiveSegments = new ObservableCollection<SegmentModel>();
                foreach (var s in GroupingSegments.OrderBy(x => x.SegmentIndex))
                {
                    if (s is SegmentModel)
                    {
                        SegmentModel segment = s as SegmentModel;
                        effectiveSegments.Add(segment);
                    }
                    else if (s is SegmentsGroupModel)
                    {
                        SegmentsGroupModel segmentsGroup = s as SegmentsGroupModel;
                        List<SegmentModel> segments = segmentsGroup.Segments.ToList();
                        for (int repeats = 0; repeats < segmentsGroup.Repeats; repeats++)
                        {
                            for (int i = 0; i < segments.Count; i++)
                            {
                                //if (repeats > 0)
                                //{
                                //    effectiveSegments.Add(segments[i].Clone());
                                //}
                                //else
                                effectiveSegments.Add(segments[i]);
                            }
                        }
                    }
                }
                _effectiveSegments = effectiveSegments;
            }
            RaisePropertyChanged(nameof(EffectiveSegments));
        }

        /// <summary>
        /// Handles the CollectionChanged event of the Segments collection.
        /// </summary>
        private void Segments_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            foreach (var segment in Segments.ToList())
            {
                segment.PropertyChanged -= Segment_PropertyChanged;
                segment.PropertyChanged += Segment_PropertyChanged;
            }

            OnLengthChanged();
            //UpdateEffectiveSegments();
        }

        /// <summary>
        /// Handles the PropertyChanged event of all job segments.
        /// </summary>
        private void Segment_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(SegmentModel.Length))
            {
                OnLengthChanged();
                UpdateEffectiveSegments();
            }
            else if (e.PropertyName == nameof(SegmentModel.SegmentIndex))
            {
                //UpdateEffectiveSegments();
            }
            else if (e.PropertyName == nameof(SegmentModel.EnableInterSegment))
            {
                OnLengthChanged();
                UpdateEffectiveSegments();
            }
            else if (e.PropertyName == nameof(SegmentModel.IsSelected))
            {
                if (_preventChange) return;
                if (Segments.ToList().TrueForAll(x => x.IsSelected))
                {
                    _selectAllSegments = true;
                }
                else
                {
                    _selectAllSegments = false;
                }
                RaisePropertyChanged(nameof(SelectAllSegments));
                UpdateSelectedButtons();
            }
        }

        private void SegmentsGroup_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            foreach (var group in GroupingSegments.ToList())
            {
                if (group is SegmentsGroupModel)
                {
                    (group as SegmentsGroupModel).PropertyChanged -= SegmentsGroup_PropertyChanged;
                    (group as SegmentsGroupModel).PropertyChanged += SegmentsGroup_PropertyChanged;
                }
            }
            OnLengthChanged();
            UpdateEffectiveSegments();
        }

        private void SegmentsGroup_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(SegmentsGroupModel.Repeats))
            {
                OnLengthChanged();
                UpdateEffectiveSegments();
            }
            else if (e.PropertyName == nameof(SegmentModel.IsSelected))
            {
                if (_preventChange) return;
                if (GroupingSegments.ToList().TrueForAll(x => x.IsSelected))
                {
                    _selectAllSegments = true;
                }
                else
                {
                    _selectAllSegments = false;
                }
                RaisePropertyChanged(nameof(SelectAllSegments));
                UpdateSelectedButtons();
            }
        }

        private void UpdateSelectedButtons()
        {
            RaisePropertyChanged(nameof(HasSelectedItems));
            RaisePropertyChanged(nameof(IsReverseEnable));
        }

        /// <summary>
        /// Called when the <see cref="Length"/> property has been changed
        /// </summary>
        public async void OnLengthChanged()
        {
            if (_lastLength != GetLength())
            {
                var maxLength = SpoolType.Length;
                var joblength = LengthIncludingNumberOfUnits;


                if (joblength > maxLength)
                {
                    var maxRep = (maxLength == 0 ? 999 : (maxLength / Length));

                    if (!IsEureka)
                        await TangoIOC.Default.GetInstance<INotificationProvider>().ShowError($"You have reached the maximum length for this job {maxLength}.");

                    //if(NumberOfUnits > 1 && NumberOfUnits > maxRep)
                    //{
                    //    NumberOfUnits = (int)maxRep;
                    //}
                }

                OnUpdateLengthhWeight();
                RaisePropertyChanged(nameof(Length));

            }
            RaisePropertyChanged(nameof(GetEstimatedDuration));
        }

        private void OnUpdateLengthhWeight()
        {
            RaisePropertyChanged(nameof(LengthIncludingNumberOfUnits));
            RaisePropertyChanged(nameof(LengthIncludingNumberOfUnitsAndSpools));
            RaisePropertyChanged(nameof(WeightIncludingNumberOfUnits));
            RaisePropertyChanged(nameof(WeightIncludingNumberOfUnitsAndSpools));
        }

        private void OnSelectAllChanged()
        {
            if (Segments != null)
            {
                _preventChange = true;
                GroupingSegments.ToList().ForEach(x => x.IsSelected = SelectAllSegments);
                _preventChange = false;
                UpdateSelectedButtons();
            }
        }

        private void OnInterSegmentlengthChanged()
        {
            _preventChange = true;
            if (GroupingSegments.Count > 0)
            {
                int max = GroupingSegments.Max(x => x.SegmentIndex);
                GroupingSegments.Where(i => i.SegmentIndex != max).ToList().ForEach(x => x.EnableInterSegment = InterSegmentLength > 0);
            }
            _enableintersegment = InterSegmentLength > 0;
            _preventChange = false;

            OnLengthChanged();
            UpdateEffectiveSegments();
        }

        private void OnNumberOfSpoolsChanged()
        {
            if (BuildProvider.MachineType == MachineTypes.Eureka)
            {
                if (NumberSpools >= 4)
                {
                    int coeff = (int)(Copies + NumberSpools - 1) / NumberSpools;
                    _copies = coeff * NumberSpools;
                    RaisePropertyChanged(nameof(Copies));
                }
            }
            else
            {
                RaisePropertyChanged(nameof(SpoolCopies));
            }
        }

        #endregion

        #region collapsed mode actions

        public void InsertWhiteGapToSelectedSegments()
        {
            if (false == Segments.ToList().Any(x => x.IsSelected))
                return;
            LogManager.Log("Copy selected segments.");
            int max = GroupingSegments.Max(x => x.SegmentIndex);
            GroupingSegments.Where(i => i.IsSelected && i.SegmentIndex != max).ToList().ForEach(y => y.EnableInterSegment = true);
        }

        public void SwapSegments(int index1, int index2)
        {
            if (index1 < 0 || index1 >= GroupingSegments.Count)
                return;
            if (index2 < 0 || index2 >= GroupingSegments.Count)
                return;
            var tmpIndex = GroupingSegments[index2];
            GroupingSegments[index2] = GroupingSegments[index1];
            GroupingSegments[index1] = tmpIndex;
        }

        #endregion

    }
}