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; /// /// Gets or sets the JobModel creation date. /// [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; /// /// Gets or sets the JobModel length percentage factor. /// public Double LengthPercentageFactor { get { return _lengthpercentagefactor; } set { if (_lengthpercentagefactor != value) { _lengthpercentagefactor = value; RaisePropertyChangedAuto(); } } } protected Int32 _numberofunits; /// /// Gets or sets the JobModel number of units. /// 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; /// /// Gets or sets the JobModel inter segment length. /// 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(); } } /// /// Gets the total job segments length multiplied by number of units if it is an embroidery job. /// [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; /// /// Gets or sets the JobModel rml. /// [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; /// /// Gets or sets the JobModel color spaces. /// [JsonIgnore] public virtual ColorSpace ColorSpace { get { return _colorspace; } set { if (_colorspace != value) { _colorspace = value; RaisePropertyChangedAuto(); } } } /// /// Gets or sets the available color spaces. /// [JsonIgnore] public List ColorSpacesList { get; set; } protected Customer _customer; /// /// Gets or sets the JobModel customer. /// [JsonIgnore] public virtual Customer Customer { get { return _customer; } set { if (_customer != value) { _customer = value; RaisePropertyChangedAuto(); } } } protected Machine _machine; /// /// Gets or sets the JobModel machine. /// [JsonIgnore] public virtual Machine Machine { get { return _machine; } set { if (_machine != value) { _machine = value; RaisePropertyChangedAuto(); } } } protected SpoolType _spooltype; /// /// Gets or sets the JobModel spool types. /// [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 Math.Max(_numberSpools, 1); } set { if (_numberSpools != value) { _numberSpools = Math.Max(value, 1); 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; /// /// Gets or sets the JobModel user. /// [JsonIgnore] public virtual User User { get { return _user; } set { if (_user != value) { _user = value; RaisePropertyChangedAuto(); } } } public JobTypes JobType { get; set; } protected SynchronizedObservableCollection _segments; /// /// Gets or sets the JobModel segments. /// [JsonIgnore] public SynchronizedObservableCollection Segments { get { return _segments; } set { if (_segments != value) { _segments = value; RaisePropertyChangedAuto(); OnSegmentsChanged(); } } } protected SynchronizedObservableCollection _segmentsGroups; /// /// Gets or sets the JobModel segments. /// [JsonIgnore] public SynchronizedObservableCollection 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 _effectiveSegments; [JsonIgnore] public ObservableCollection EffectiveSegments { get { return _effectiveSegments; } } protected SynchronizedObservableCollection _groupingSegments; /// /// Gets or sets the display segments. /// [JsonIgnore] public SynchronizedObservableCollection 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 _segmentsToCopy; [JsonIgnore] public List 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().ToList(); return groups.Count() == 0 ? 0 : groups.Max(x => x.SegmentIndex); } } /// /// Gets the ordered segments with groups. /// public List OrderedSegmentsWithGroups { get { if (Segments == null) return null; List orderedSegmentsWithGroups = new List(); 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 list, bool isEureka) { TangoIOC.Default.Inject(this); ColorSpacesList = list; _segments = new SynchronizedObservableCollection(); _segmentsGroups = new SynchronizedObservableCollection(); _groupingSegments = new SynchronizedObservableCollection(); SegmentsToCopy = new List(); _effectiveSegments = new ObservableCollection(); 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(); } /// /// Loads the grouping segments. /// public void LoadGroupingSegments() { _groupingSegments.Clear(); //List segmentsWithGroups = new List(); //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)); } /// /// Arranges the segment indixes in groups. /// public void ArrangeSegmentIndixesInGroups() { foreach (var group in SegmentsGroups) { int index = 1; foreach (var segm in Segments) { segm.SegmentIndex = index; index++; } } } /// /// Arranges the segments indixes. /// 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(); } /// /// Creates the inter segment. /// /// The length. /// 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; } /// /// Adds the new segment. /// /// The length. /// Index of the segment. /// 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 stops = new List(); 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 effectiveSegments = new ObservableCollection(); 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 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 effectiveSegments = new ObservableCollection(); 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 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)); } /// /// Handles the CollectionChanged event of the Segments collection. /// 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(); } /// /// Handles the PropertyChanged event of all job segments. /// 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)); } /// /// Called when the property has been changed /// 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().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 } }