using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Text; using System.Threading.Tasks; using Tango.Core; using Tango.Core.Threading; using Tango.SharedUI; using System.Windows; using System.Windows.Media; using System.Collections.Specialized; using System.Reflection; using Tango.BL.Enumerations; using System.Diagnostics; using Tango.Core.Commands; using Tango.PPC.Jobs.UndoRedoCommands; using Newtonsoft.Json; namespace Tango.PPC.Jobs.Models { public class SegmentModel : ExtendedObject, ISegmentModel { private double _lastLength; private LinearGradientBrush _brush; private ActionTimer _brushStopCollectionChangedActionTimer; #region Properties public string GUID { get; set; } protected String _name; /// /// Gets or sets the SegmentModel name. /// public String Name { get { return _name; } set { if (_name != value) { _name = value; RaisePropertyChangedAuto(); } } } protected double _length; /// /// Gets or sets the length. /// public double Length { get { return _length; } set { if (_length != value) { _length = value; OnLengthChanged(value); RaisePropertyChangedAuto(); } } } public double FullLength { get { return _length; } } public bool IsGroupSegment { get { return SegmentsGroupModel != null; } } public void LengthBeforeChange(double value) { _lastLength = Length; } public void LengthChanged(double value) { UndoRedoManager.Instance.InsertAndExecuteCommand(new ChangeLengthCommand(this, _lastLength, value)); _lastLength = Length; } private double _weight; public double Weight { get { return _weight; } set { if (_weight != value) { _weight = value; OnWeightChanged(); RaisePropertyChangedAuto(); } } } protected Int32 _segmentindex; /// /// Gets or sets the index of the segment. /// public Int32 SegmentIndex { get { return _segmentindex; } set { if (_segmentindex != value) { _segmentindex = value; RaisePropertyChangedAuto(); } } } private bool _isInterSegment; /// /// Gets or sets a value indicating whether this segment is an inter segment. /// public bool IsInterSegment { get { return _isInterSegment; } set { _isInterSegment = value; RaisePropertyChangedAuto(); } } protected Boolean _enableintersegment; public Boolean EnableInterSegment { get { return _enableintersegment; } set { if (_enableintersegment != value) { _enableintersegment = value; RaisePropertyChangedAuto(); } RaisePropertyChanged(nameof(LengthWithInterSegment)); RaisePropertyChanged(nameof(InterSegmentLength)); RaisePropertyChanged(nameof(ShowGap)); } } [JsonIgnore] public bool ShowGap { get { return EnableInterSegment && !IsLast; } } public double LengthWithInterSegment { get { if (Job != null && !IsInterSegment) { // var length = Length;// + Length * (Job.LengthPercentageFactor / 100); return EnableInterSegment ? (Length + Job.InterSegmentLength) : Length; } return Length; // return Job != null && !IsInterSegment ? (Length + Length * (Job.LengthPercentageFactor / 100)) : Length; } } public double InterSegmentLength { get { return Job == null ? 0 : Job.InterSegmentLength; } } public double LengthWithFactor { get { return Job != null && !IsInterSegment ? (Length + Length * (Job.LengthPercentageFactor / 100)) : Length; } } protected SynchronizedObservableCollection _brushstops; /// /// Gets or sets the segmentbase brush stops. /// public SynchronizedObservableCollection BrushStops { get { return _brushstops; } set { if (_brushstops != value) { _brushstops = value; OnBrushStopsChanged(_brushstops); RaisePropertyChangedAuto(); } } } private JobModel _job; [JsonIgnore] public JobModel Job { get { return _job; } set { if (_job != value) { _job = value; } } } [JsonIgnore] public Brush SegmentBrush { get { return GetSegmentBrush(); } } [JsonIgnore] public bool IsOffsetChanged { get; set; } public double LeftOffset { get { return FirstBrushStop != null ? FirstBrushStop.OffsetPercent : 0; } set { if (FirstBrushStop != null && FirstBrushStop.OffsetPercent != value) { FirstBrushStop.OffsetPercent = value; RaisePropertyChangedAuto(); IsOffsetChanged = true; RaisePropertyChanged(nameof(SegmentBrush)); RaisePropertyChanged(nameof(LeftOffsetLabel)); IsOffsetChanged = false; } } } private double _leftOffsetChangeComleted; [JsonIgnore] public double LeftOffsetChangeComleted { get { return _leftOffsetChangeComleted; } set { if (_leftOffsetChangeComleted != value) { _leftOffsetChangeComleted = value; RaisePropertyChangedAuto(); UndoRedoManager.Instance.InsertAndExecuteCommand(new ChangeOffsetCommand(this, LeftOffsetStartChanging, _leftOffsetChangeComleted, OffsetType.Left)); } } } private double _leftOffsetStartChanging; [JsonIgnore] public double LeftOffsetStartChanging { get { return _leftOffsetStartChanging; } set { _leftOffsetStartChanging = value; RaisePropertyChangedAuto(); } } public double MiddleOffset { get { return (MiddleBrushStop != null) ? MiddleBrushStop.OffsetPercent : 50; } set { if (MiddleBrushStop != null && MiddleBrushStop.OffsetPercent != value) { MiddleBrushStop.OffsetPercent = value; RaisePropertyChangedAuto(); IsOffsetChanged = true; RaisePropertyChanged(nameof(SegmentBrush)); RaisePropertyChanged(nameof(MiddleOffsetLabel)); IsOffsetChanged = false; } } } private double _middleOffsetChangeComleted; [JsonIgnore] public double MiddleOffsetChangeComleted { get { return _middleOffsetChangeComleted; } set { if (_middleOffsetChangeComleted != value) { _middleOffsetChangeComleted = value; RaisePropertyChangedAuto(); UndoRedoManager.Instance.InsertAndExecuteCommand(new ChangeOffsetCommand(this, MiddleOffsetStartChanging, _middleOffsetChangeComleted, OffsetType.Middle)); } } } private double _middleOffsetStartChanging; [JsonIgnore] public double MiddleOffsetStartChanging { get { return _middleOffsetStartChanging; } set { _middleOffsetStartChanging = value; RaisePropertyChangedAuto(); } } public double RightOffset { get { return SecondBrushStop != null ? SecondBrushStop.OffsetPercent : 100; } set { if (SecondBrushStop != null && SecondBrushStop.OffsetPercent != value) { SecondBrushStop.OffsetPercent = value; RaisePropertyChangedAuto(); IsOffsetChanged = true; RaisePropertyChanged(nameof(SegmentBrush)); RaisePropertyChanged(nameof(RightOffsetLabel)); IsOffsetChanged = false; } } } private double _rightOffsetChangeComleted; [JsonIgnore] public double RightOffsetChangeComleted { get { return _rightOffsetChangeComleted; } set { if (_rightOffsetChangeComleted != value) { _rightOffsetChangeComleted = value; RaisePropertyChangedAuto(); UndoRedoManager.Instance.InsertAndExecuteCommand(new ChangeOffsetCommand(this, RightOffsetStartChanging, _rightOffsetChangeComleted, OffsetType.Right)); } } } private double _rightOffsetStartChanging; [JsonIgnore] public double RightOffsetStartChanging { get { return _rightOffsetStartChanging; } set { _rightOffsetStartChanging = value; RaisePropertyChangedAuto(); } } [JsonIgnore] public String LeftOffsetLabel { get { double length = Math.Round(LeftOffset * Length / 100, 1); return String.Format($"{Math.Round(LeftOffset, 0)}%({length}m)"); } } [JsonIgnore] public String RightOffsetLabel { get { double length = Math.Round((100 - RightOffset) * Length / 100, 1); return String.Format($"{Math.Round(RightOffset, 0)}%({length}m)"); } } [JsonIgnore] public String MiddleOffsetLabel { get { double offset = Math.Abs(MiddleOffset - 50); double length = Math.Round(offset * Length / 100, 1); double roundValue = Math.Round(MiddleOffset, 0); return String.Format($"{Math.Round(MiddleOffset, 0)}%({length}m)"); } } [JsonIgnore] public bool HasColors { get { return BrushStops.Count > 0; } } [JsonIgnore] public bool IsGradient { get { return BrushStops.Count > 1; } } /// /// Gets the second brush stop. /// [JsonIgnore] public BrushStopModel SecondBrushStop { get { if (BrushStops.Count > 1) return BrushStops.Where(x => x.Position == BrushStopModel.PositionStatus.SecondColor).FirstOrDefault(); return null; } } /// /// Gets the first brush stop. /// [JsonIgnore] public BrushStopModel FirstBrushStop { get { if (BrushStops.Count > 0) { var brushStop = BrushStops.Where(x => x.Position == BrushStopModel.PositionStatus.FirstColor).FirstOrDefault(); return brushStop; } return null; } } /// /// Gets the middle brush stop. /// [JsonIgnore] public BrushStopModel MiddleBrushStop { get { if (BrushStops.Count > 1) return BrushStops.Where(x => x.Position == BrushStopModel.PositionStatus.Middle).FirstOrDefault(); return null; } } [JsonIgnore] public bool HasOutOfGamutBrush { get { bool hasError = (FirstBrushStop != null && FirstBrushStop.IsOutOfGamut) || (SecondBrushStop != null && SecondBrushStop.IsOutOfGamut); return hasError; } } private bool _isSelected; [JsonIgnore] public bool IsSelected { get { return _isSelected; } set { _isSelected = value; RaisePropertyChangedAuto(); } } private bool _isLast; [JsonIgnore] public bool IsLast { get { return _isLast; } set { if (_isLast != value) { _isLast = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(ShowGap)); } } } public SegmentsGroupModel SegmentsGroupModel { get; set; } #endregion #region command [JsonIgnore] public RelayCommand AddGapCommand { get; set; } [JsonIgnore] public RelayCommand DeleteGapCommand { get; set; } #endregion #region construction public SegmentModel(JobModel jobModel, string guid) { InitnewSegment(); Job = jobModel; GUID = guid; IsLast = false; EnableInterSegment = jobModel.EnableInterSegment; } public SegmentModel() { GUID = ""; InitnewSegment(); } #endregion public void InitnewSegment() { BrushStops = new SynchronizedObservableCollection(); LeftOffset = 0; MiddleOffset = 50; RightOffset = 100; IsOffsetChanged = false; Length = 5; _lastLength = 5; IsSelected = false; IsLast = false; _enableintersegment = false; AddGapCommand = new RelayCommand(x => AddGap()); DeleteGapCommand = new RelayCommand(x => DeleteGap()); } #region Public Methods /// /// Gets the segment brush. /// /// public LinearGradientBrush GetSegmentBrush() { if (_brush == null || _brush.GradientStops.Count != BrushStops.Count || IsOffsetChanged) { GradientStopCollection stops = new GradientStopCollection(); foreach (var stop in BrushStops.ToList().OrderBy(x => x.StopIndex).ToList()) { //TODO test if displayed is valid stop.IsValid Color color = stop.BestMatchColor; stops.Add(new GradientStop(color, stop.OffsetPercent / 100d)); } LinearGradientBrush brush = new LinearGradientBrush(); brush.StartPoint = new Point(0, 0); brush.EndPoint = new Point(1, 0); brush.GradientStops = stops; _brush = brush; return brush; } else { for (int i = 0; i < BrushStops.Count; i++) { //TODO test if displayed is valid stop.IsValid Color color = BrushStops[i].BestMatchColor; _brush.GradientStops[i].Color = color; _brush.GradientStops[i].Offset = BrushStops[i].OffsetPercent / 100d; } return _brush; } } /// /// Clones this instance. /// /// public SegmentModel Clone() { var cloned = new SegmentModel(Job, GUID);//(SegmentModel)Activator.CreateInstance(typeof(SegmentModel), this.Job); cloned.Name = Name; cloned.LeftOffset = LeftOffset; cloned.MiddleOffset = MiddleOffset; cloned.RightOffset = RightOffset; cloned.IsOffsetChanged = IsOffsetChanged; cloned.Length = Length; cloned.IsSelected = false; cloned.IsInterSegment = IsInterSegment; cloned.EnableInterSegment = EnableInterSegment; cloned.BrushStops = BrushStops.Select(x => x.Clone()).ToSynchronizedObservableCollection(); cloned.BrushStops.ToList().ForEach(x => x.SegmentModel = cloned); cloned.SegmentIndex = SegmentIndex + 1; cloned.SegmentsGroupModel = SegmentsGroupModel; return cloned; } ISegmentModel ISegmentModel.Clone() { return Clone() as ISegmentModel; } public static SegmentModel CreateInterSegment(double length) { return new SegmentModel() { IsInterSegment = true, Length = length, Name = "Inter Segment", BrushStops = new SynchronizedObservableCollection() }; } /// /// Creates the gradient brushes. /// public void CreateGradientBrushes(BrushStopModel firstBrush, BrushStopModel secondBrush) { BrushStops.Clear(); BrushStopModel brushStop = firstBrush.Clone(); brushStop.StopIndex = 1; brushStop.OffsetPercent = 0; brushStop.Position = BrushStopModel.PositionStatus.First; brushStop.IsOutOfGamut = false; BrushStops.Add(brushStop); BrushStopModel colorbrushStop = firstBrush; colorbrushStop.Position = BrushStopModel.PositionStatus.FirstColor; colorbrushStop.StopIndex = 2; colorbrushStop.OffsetPercent = 0; BrushStops.Add(colorbrushStop); BrushStopModel middleBrushStop = firstBrush.Clone(); middleBrushStop.StopIndex = 3; middleBrushStop.Position = BrushStopModel.PositionStatus.Middle; middleBrushStop.OffsetPercent = 50; middleBrushStop.IsOutOfGamut = false; middleBrushStop.Color = BrushStopModel.GetRelativeRGB(firstBrush.Color, secondBrush.Color, 0, 1, 0.5); middleBrushStop.BestMatchColor = BrushStopModel.GetRelativeRGB(firstBrush.BestMatchColor, secondBrush.BestMatchColor, 0, 1, 0.5); BrushStops.Add(middleBrushStop); AddOrReplaceSecondBrush(secondBrush); } public void AddOrReplaceSecondBrush(BrushStopModel secondBrush) { RemoveSecondColorOfGradient(); BrushStopModel secondbrushStop = secondBrush; secondbrushStop.StopIndex = 4; secondbrushStop.Position = BrushStopModel.PositionStatus.SecondColor; secondbrushStop.OffsetPercent = 100; BrushStops.Add(secondbrushStop); BrushStopModel lastSecondBrushStop = secondBrush.Clone(); lastSecondBrushStop.StopIndex = 5; lastSecondBrushStop.OffsetPercent = 100; lastSecondBrushStop.IsOutOfGamut = false; lastSecondBrushStop.Position = BrushStopModel.PositionStatus.Last; ; BrushStops.Add(lastSecondBrushStop); } public void SetNewColor(BrushStopModel target, BrushStopModel source) { target.SetNewColor(source); target.IsOutOfGamut = source.IsOutOfGamut; if (target.Position == BrushStopModel.PositionStatus.FirstColor) { BrushStopModel first = BrushStops.Where(x => x.Position == BrushStopModel.PositionStatus.First).FirstOrDefault(); if (first != null) { first.SetNewColor(source); first.IsOutOfGamut = source.IsOutOfGamut; } } else if (target.Position == BrushStopModel.PositionStatus.SecondColor) { BrushStopModel last = BrushStops.Where(x => x.Position == BrushStopModel.PositionStatus.Last).FirstOrDefault(); if (last != null) { last.SetNewColor(source); last.IsOutOfGamut = source.IsOutOfGamut; } } UpdateMiddleColorBrush(); RaiseSegmentBrushChanged(); } public void UpdateMiddleColorBrush() { if (MiddleBrushStop != null && SecondBrushStop != null && FirstBrushStop != null) { MiddleBrushStop.Color = BrushStopModel.GetRelativeRGB(FirstBrushStop.Color, SecondBrushStop.Color, 0, 1, 0.5); MiddleBrushStop.BestMatchColor = BrushStopModel.GetRelativeRGB(FirstBrushStop.BestMatchColor, SecondBrushStop.BestMatchColor, 0, 1, 0.5); } } public void RemoveSecondColorOfGradient() { if (BrushStops.Count < 5) return; BrushStops.RemoveAt(4); BrushStops.RemoveAt(3); } public void ArrangeBrushStopsIndexes() { for (int i = 0; i < BrushStops.Count; i++) { BrushStops[i].StopIndex = i + 1; } ArrangeBrushStopsPosition(); } public void ArrangeBrushStopsPosition() { if (BrushStops.Count == 1) { BrushStops.FirstOrDefault().Position = BrushStopModel.PositionStatus.FirstColor; } else if (BrushStops.Count > 1) BrushStops.ToList().ForEach(x => x.Position = (BrushStopModel.PositionStatus)x.StopIndex); } public void SwapBrushStops() { if (BrushStops.Count > 1) { int index = 0; int lastIndex = BrushStops.Count - 1; for (; index < lastIndex; index++, lastIndex--) { var left_temp = BrushStops[index]; var right_stopIndex = BrushStops[lastIndex].StopIndex; var right_offsetPercent = BrushStops[lastIndex].OffsetPercent; BrushStops[index] = BrushStops[lastIndex]; BrushStops[index].StopIndex = left_temp.StopIndex; BrushStops[index].OffsetPercent = left_temp.OffsetPercent; BrushStops[lastIndex] = left_temp; BrushStops[lastIndex].StopIndex = right_stopIndex; BrushStops[lastIndex].OffsetPercent = right_offsetPercent; } ArrangeBrushStopsIndexes(); UpdateMiddleColorBrush(); } } #endregion #region Brush Stops Collection Changed private void BrushStops_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { if (_brushStopCollectionChangedActionTimer == null) { _brushStopCollectionChangedActionTimer = new ActionTimer(TimeSpan.FromMilliseconds(100)); } _brushStopCollectionChangedActionTimer.ResetReplace(() => { foreach (var stop in BrushStops.ToList()) { stop.RaiseOffsetChanged(); } RaiseSegmentBrushChanged(); }); } /// /// Raises the property changed event. /// public void RaiseSegmentBrushChanged() { RaisePropertyChanged(nameof(SegmentBrush)); RaisePropertyChanged(nameof(HasColors)); RaisePropertyChanged(nameof(IsGradient)); RaisePropertyChanged(nameof(FirstBrushStop)); RaisePropertyChanged(nameof(SecondBrushStop)); RaisePropertyChanged(nameof(HasOutOfGamutBrush)); RaisePropertyChanged(nameof(Length)); } #endregion #region Properties Changed /// /// Called when the Length has changed. protected void OnLengthChanged(double length) { if (Job != null && Job.Rml != null) { var gramPerlength = Job.Rml.GetGramPer1000mLength; var weight = (Length * gramPerlength) / (1000);//(kg) _weight = weight; RaisePropertyChanged(nameof(Weight)); //if (_lastLength != length) { BrushStops.ToList().ForEach(x => x.RaiseOffsetChanged()); //_lastLength = Length; //RaisePropertyChanged(nameof(LengthWithFactor)); RaisePropertyChanged(nameof(LengthWithInterSegment)); RaisePropertyChanged(nameof(LeftOffsetLabel)); RaisePropertyChanged(nameof(MiddleOffsetLabel)); RaisePropertyChanged(nameof(RightOffsetLabel)); } } } /// /// Called when [weight changed]. /// private void OnWeightChanged() { if (Job != null && Job.Rml != null) { var gramPerlength = Job.Rml.GetGramPer1000mLength; var length = (Weight * 1000) / gramPerlength;//(m) weight in gr _length = length; RaisePropertyChanged(nameof(Length)); BrushStops.ToList().ForEach(x => x.RaiseOffsetChanged()); RaisePropertyChanged(nameof(LengthWithInterSegment)); RaisePropertyChanged(nameof(LeftOffsetLabel)); RaisePropertyChanged(nameof(MiddleOffsetLabel)); RaisePropertyChanged(nameof(RightOffsetLabel)); } } /// /// Called when the BrushStops has changed. /// /// protected void OnBrushStopsChanged(SynchronizedObservableCollection brushstops) { if (brushstops != null) { brushstops.CollectionChanged -= BrushStops_CollectionChanged; brushstops.CollectionChanged += BrushStops_CollectionChanged; foreach (var stop in brushstops.ToList()) { stop.RaiseOffsetChanged(); } RaiseSegmentBrushChanged(); } } private void AddGap() { EnableInterSegment = true; } private void DeleteGap() { EnableInterSegment = false; } public void UpdateBrushStops() { foreach (var stop in BrushStops.Where(x => x.ColorSpace == BL.Enumerations.ColorSpaces.RGB || x.ColorSpace == BL.Enumerations.ColorSpaces.LAB).ToList()) { try { stop.OnBrushStopFieldValueChanged(); stop.InitColorsFromBestmatch(); //TODO ASK ROY!!!!!! //output.ApplyOnBrushStopVolumesOnly(stop); } catch (Exception ex) { LogManager.Log(ex, $"Error updating stop volumes after changing thread on segment {stop.SegmentModel.SegmentIndex}, stop {stop.StopIndex}."); } } foreach (var stop in BrushStops.Where(x => x.ColorSpace == ColorSpaces.Volume)) { stop.InitLiquidVolumes(); } } public void UpdateWeightOnRMLChange(bool isWeightView) { if (isWeightView) { OnWeightChanged(); } else { OnLengthChanged(Length); } } #endregion } }