using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using Tango.BL.Interfaces;
using Tango.Core;
using Tango.Core.Threading;
namespace Tango.BL.Entities
{
public partial class Segment : SegmentBase, ISegment
{
private double _lastLength;
private LinearGradientBrush _brush;
private ActionTimer _brushStopCollectionChangedActionTimer;
#region Properties
private TimeSpan _remainingTime;
///
/// Gets or sets the remaining time for this segment to complete.
///
[NotMapped]
[JsonIgnore]
public TimeSpan RemainingTime
{
get { return _remainingTime; }
set { _remainingTime = value; RaisePropertyChangedAuto(); }
}
private TimeSpan _estimatedDuration;
///
/// Gets or sets the estimated duration for this segment to complete.
///
[NotMapped]
[JsonIgnore]
public TimeSpan EstimatedDuration
{
get { return _estimatedDuration; }
set { _estimatedDuration = value; }
}
private double _progress;
///
/// Gets or sets the segment progress within a running job.
///
[NotMapped]
[JsonIgnore]
public double Progress
{
get { return _progress; }
set { _progress = value; RaisePropertyChangedAuto(); }
}
private bool _started;
///
/// Gets or sets a value indicating whether this segment has started.
///
[NotMapped]
[JsonIgnore]
public bool Started
{
get { return _started; }
set { _started = value; RaisePropertyChangedAuto(); }
}
private bool _completed;
///
/// Gets or sets a value indicating whether this segment has completed.
///
[NotMapped]
[JsonIgnore]
public bool Completed
{
get { return _completed; }
set { _completed = value; RaisePropertyChangedAuto(); }
}
///
/// Gets the segment brush.
///
[NotMapped]
[JsonIgnore]
public Brush SegmentBrush
{
get
{
return GetSegmentBrush();
}
}
private bool _isInterSegment;
///
/// Gets or sets a value indicating whether this segment is an inter segment.
///
[NotMapped]
[JsonIgnore]
public bool IsInterSegment
{
get { return _isInterSegment; }
set { _isInterSegment = value; RaisePropertyChangedAuto(); }
}
///
/// Gets a value indicating whether this segment has any out of gamut brush stops.
///
[NotMapped]
[JsonIgnore]
public bool HasOutOfGamutBrushStop
{
get { return BrushStops.Any(x => x.IsOutOfGamut); }
}
///
/// Gets the length of this segment including the job length factor .
///
[NotMapped]
[JsonIgnore]
public double LengthWithFactor
{
get { return Job != null && !IsInterSegment ? (Length + Length * (Job.LengthPercentageFactor / 100)) : Length; }
}
[NotMapped]
[JsonIgnore]
public String DisplayLengthWithFactor
{
get {
double length = Job != null && !IsInterSegment ? (Length + Length * (Job.LengthPercentageFactor / 100)) : Length;
return length.ToString("N0") + "m";
}
}
#endregion
#region Constructors
///
/// Initializes a new instance of the class.
///
public Segment() : base()
{
}
#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();
}
//Item#7059 -
//if (BrushStops.Count > 0)
//{
// BrushStops.First().OffsetPercent = 0;
//}
//if (BrushStops.Count > 1)
//{
// BrushStops.Last().OffsetPercent = 100;
//}
RaiseSegmentBrushChanged();
});
}
#endregion
#region Properties Changed
///
/// Called when the Length has changed.
///
///
protected override void OnLengthChanged(double length)
{
base.OnLengthChanged(length);
if (_lastLength != length)
{
BrushStops.ToList().ForEach(x => x.RaiseOffsetChanged());
_lastLength = Length;
RaisePropertyChanged(nameof(LengthWithFactor));
}
}
///
/// Called when the BrushStops has changed.
///
///
protected override void OnBrushStopsChanged(SynchronizedObservableCollection brushstops)
{
base.OnBrushStopsChanged(brushstops);
if (brushstops != null)
{
brushstops.CollectionChanged -= BrushStops_CollectionChanged;
brushstops.CollectionChanged += BrushStops_CollectionChanged;
foreach (var stop in brushstops.ToList())
{
stop.RaiseOffsetChanged();
}
RaiseSegmentBrushChanged();
}
}
#endregion
#region Public Methods
///
/// Gets the segment brush.
///
///
public LinearGradientBrush GetSegmentBrush()
{
if (_brush == null || _brush.GradientStops.Count != BrushStops.Count)
{
GradientStopCollection stops = new GradientStopCollection();
foreach (var stop in BrushStops.ToList().OrderBy(x => x.StopIndex).ToList())
{
stops.Add(new GradientStop(stop.IsTransparent ? Colors.Transparent : stop.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++)
{
_brush.GradientStops[i].Color = BrushStops[i].IsTransparent ? Colors.Transparent : BrushStops[i].Color;
_brush.GradientStops[i].Offset = BrushStops[i].OffsetPercent / 100d;
}
return _brush;
}
}
public void UpdateMiddleColorBrush()
{
if (BrushStops.Count == 5)
{
BrushStops[2].Color = GetRelativeRGB(BrushStops[1].Color, BrushStops[3].Color, 0, 1, 0.5);
}
}
public BrushStop FirstBrushStop
{
get { if (BrushStops.Count == 1)//Intersegment?? - null
return BrushStops[0];
else if(BrushStops.Count >= 5)
return BrushStops[1];
else
return null; }
}
public static Color GetRelativeRGB(Color first, Color second, double firstOffset, double secondOffset, double offset)
{
var color = new Color();
var range = (secondOffset - firstOffset);
var realoffset = offset - firstOffset;
color.ScA = (float)(realoffset * (second.ScA - first.ScA) / range + first.ScA);
color.ScR = (float)(realoffset * (second.ScR - first.ScR) / range + first.ScR);
color.ScG = (float)(realoffset * (second.ScG - first.ScG) / range + first.ScG);
color.ScB = (float)(realoffset * (second.ScB - first.ScB) / range + first.ScB);
return color;
}
///
/// Raises the property changed event.
///
public void RaiseSegmentBrushChanged()
{
RaisePropertyChanged(nameof(SegmentBrush));
}
///
/// Raises the property changed event.
///
public void RaiseLengthWithFactorChanged()
{
RaisePropertyChanged(nameof(LengthWithFactor));
}
///
/// Adds a new brush stop to this segment.
///
///
public BrushStop AddBrushStop()
{
BrushStop stop = new BrushStop();
var lastStop = BrushStops.OrderBy(x => x.StopIndex).LastOrDefault();
if (lastStop != null && lastStop.ColorSpace != null)
{
stop.ColorSpace = lastStop.ColorSpace;
}
else if (Job != null)
{
if (Job.ColorSpace != null)
{
stop.ColorSpace = Job.ColorSpace;
}
else
{
stop.ColorSpaceGuid = Job.ColorSpaceGuid;
}
}
if (BrushStops.Count > 0)
{
stop.StopIndex = BrushStops.Max(x => x.StopIndex) + 1;
stop.OffsetPercent = 100;
}
else
{
stop.StopIndex = 1;
}
stop.Segment = this;
stop.Color = Colors.White;
if (stop.ColorSpace != null)
{
if (stop.BrushColorSpace == Enumerations.ColorSpaces.LAB)
{
stop.L = 100;
stop.A = 0;
stop.B = 0;
}
}
BrushStops.Add(stop);
return stop;
}
///
/// Gets the next segment.
///
///
public Segment GetNextSegment()
{
return Job.OrderedSegments.FirstOrDefault(x => x.SegmentIndex > SegmentIndex);
}
///
/// Gets the previous segment.
///
///
public Segment GetPreviousSegment()
{
return Job.OrderedSegments.LastOrDefault(x => x.SegmentIndex < SegmentIndex);
}
///
/// Gets the collection of previous segments.
///
///
public List GetPreviousSegments()
{
return Job.OrderedSegments.Where(x => x.SegmentIndex < SegmentIndex).ToList();
}
///
/// Gets the estimated duration for this segment by the specified process parameters.
///
/// The process parameters.
///
/// Process parameters dying speed cannot be zero.
public TimeSpan GetEstimatedDuration(ProcessParametersTable processParameters)
{
if (processParameters.DyeingSpeed == 0)
{
throw new ArgumentException("Process parameters dying speed cannot be zero.");
}
return TimeSpan.FromSeconds(Length / (processParameters.DyeingSpeed / 100d));
}
///
/// Creates a GDI version of this segment brush.
///
/// The width.
/// The height.
///
public System.Drawing.Brush CreateGdiBrush(int width, int height)
{
if (BrushStops.Count > 1)
{
System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(new System.Drawing.PointF(0, 0), new System.Drawing.Point(width, height), System.Drawing.Color.Black, System.Drawing.Color.Black);
System.Drawing.Drawing2D.ColorBlend blend = new System.Drawing.Drawing2D.ColorBlend();
List colors = new List();
List offsets = new List();
foreach (var stop in BrushStops.ToList().OrderBy(x => x.OffsetPercent))
{
colors.Add(stop.Color.ToGdiColor());
offsets.Add((float)stop.OffsetPercent / 100f);
}
blend.Colors = colors.ToArray();
blend.Positions = offsets.ToArray();
brush.InterpolationColors = blend;
return brush;
}
else if (BrushStops.Count == 1)
{
return new System.Drawing.SolidBrush(BrushStops.First().Color.ToGdiColor());
}
else
{
return System.Drawing.Brushes.White;
}
}
#endregion
#region Internal Methods
///
/// Raises the property changed event.
///
internal void RaiseHasOutOfGamutBrushStop()
{
RaisePropertyChanged(nameof(HasOutOfGamutBrushStop));
}
#endregion
#region Cloning
///
/// Clones this segment with its brush stops.
///
///
public override Segment Clone()
{
Segment cloned = base.Clone();
cloned.BrushStops = BrushStops.Select(x => x.Clone()).ToSynchronizedObservableCollection();
foreach (var stop in cloned.BrushStops)
{
stop.SegmentGuid = cloned.Guid;
stop.Segment = cloned;
}
return cloned;
}
///
/// Clones this segment and assigns it to the specified job.
///
/// The job.
///
public Segment Clone(Job job)
{
Segment cloned = base.Clone();
cloned.BrushStops = BrushStops.Select(x => x.Clone(cloned)).ToSynchronizedObservableCollection();
cloned.Job = job;
cloned.JobGuid = job.Guid;
return cloned;
}
///
/// Clones this segment with its brush stops.
///
///
ISegment ISegment.Clone()
{
return Clone() as ISegment;
}
///
/// Clones this segment and assigns it to the specified job.
///
/// The job.
///
ISegment ISegment.Clone(Job job)
{
return Clone(job) as ISegment;
}
#endregion
#region Delete
///
/// Removes this entity and all dependent entities from the specified db context.
///
/// The context.
public override void Delete(ObservablesContext context)
{
base.Delete(context);
if (BrushStops != null && BrushStops.Count > 0)
{
context.BrushStops.RemoveRange(BrushStops);
}
context.Segments.Remove(this);
}
#endregion
}
}