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