aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/Tango.PMR/Stubs/StubFpgaWriteRegRequest.cs
blob: 36bfb94cd7c00e4394a6467761b8b9d741cb31a6 (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
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.Notifications;

namespace Tango.PPC.Jobs.Models
{
    public class JobModel : ExtendedObject
    {
        private bool _preventChange;

        #region Properties

        public String Guid { get; set; }

        public int ID { 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) - InterSegmentLength) : 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();
                    RaisePropertyChanged(nameof(LengthIncludingNumberOfUnits));
                    RaisePropertyChanged(nameof(LengthIncludingNumberOfUnitsAndSpools));
                    RaisePropertyChanged(nameof(GetEstimatedDuration));
                }
            }
        }
        
        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();
                var l = _lastLength * Math.Max(NumberOfUnits, 1);
                
                if (EnableInterSegment && NumberOfUnits > 1)
                {
                    l += ((NumberOfUnits - 1) * InterSegmentLength);
                }

                return l;
            }
        }

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

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

        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();
                    RaisePropertyChanged(nameof(Copies));
                    RaisePropertyChanged(nameof(LengthIncludingNumberOfUnits));
                    RaisePropertyChanged(nameof(LengthIncludingNumberOfUnitsAndSpools));
                }
            }
        }

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

            set
            {
                if (_copies != value)
                {
                    if (NumberSpools>=4)
                    {
                        if(value < NumberSpools)
                            _copies = NumberSpools;
                        else
                        {
                            int coeff = (int)(value + NumberSpools - 1) / NumberSpools;
                            _copies = coeff * NumberSpools;
                        }
                        NumberOfUnits = (int)_copies / NumberSpools;
                        RaisePropertyChanged(nameof(LengthIncludingNumberOfUnits));
                        RaisePropertyChanged(nameof(LengthIncludingNumberOfUnitsAndSpools));
                    }
                    else
                        _copies = 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;
            }
        }
       
        #endregion

        #region constructors

        public JobModel(List<ColorSpace> list, bool isEureka)
        {
            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 static SegmentModel CreateInterSegment(double length)
        {
            SegmentModel segment =  new SegmentModel()
            {
                IsInterSegment = true,
                Length = length,
                Name = "Inter Segment"
            };
            segment.BrushStops.Add(new BrushStopModel(segment)
            {
                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())
                            {
                                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())
                                {
                                    BrushStop bs = stop.CreateBrushStop();
                                    stops.Add(bs);
                                }
                            }
                        }
                    }
                    return _converter.GetRecommendedProcessParameters(Rml, Machine, stops, Rml.GetActiveProcessGroup(), useLightInks);
                }
                catch (Exception ex)
                {
                    LogManager.Log(ex, "Error calculating recommended process parameters.");
                    return null;
                }
        }
        #endregion

        #region changes

        private void OnEnableInterSegmentChanged()
        {
            _groupingSegments.ToList().ForEach(x => x.EnableInterSegment = EnableInterSegment);
            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;
                    //}
                }
                RaisePropertyChanged(nameof(Length));
                RaisePropertyChanged(nameof(LengthIncludingNumberOfUnits));
                RaisePropertyChanged(nameof(LengthIncludingNumberOfUnitsAndSpools));

            }
            RaisePropertyChanged(nameof(GetEstimatedDuration)); 
        }

        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);
            }
            _preventChange = false;
            OnLengthChanged();
        }
        
        private void OnNumberOfSpoolsChanged()
        {
            if(NumberSpools > 0)
            {
                int coeff = (int)(Copies + NumberSpools -1) / NumberSpools;
                Copies = coeff * NumberSpools;
            }
        }
        
        #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

    }
}