aboutsummaryrefslogtreecommitdiffstats
path: root/Software/Visual_Studio/MachineStudio/Tango.MachineStudio.Common/Video/DefaultVideoCaptureProvider.cs
blob: f710cf0828c51aa38fd07cfb72c90bbf9c36d12b (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
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.Video.DirectCapture;

namespace Tango.MachineStudio.Common.Video
{
    /// <summary>
    /// Represents the default implementation of <see cref="IVideoCaptureProvider"/>.
    /// </summary>
    /// <seealso cref="Tango.MachineStudio.Common.Video.IVideoCaptureProvider" />
    public class DefaultVideoCaptureProvider : IVideoCaptureProvider
    {
        /// <summary>
        /// Gets the available capture devices.
        /// </summary>
        public ObservableCollection<CaptureDevice> AvailableCaptureDevices { get; private set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="DefaultVideoCaptureProvider"/> class.
        /// </summary>
        public DefaultVideoCaptureProvider()
        {
            AvailableCaptureDevices = new ObservableCollection<CaptureDevice>();

            var availableDevices = CaptureDevice.GetAvailableCaptureDevices();

            for (int i = 0; i < availableDevices.Count; i++)
            {
                AvailableCaptureDevices.Add(new CaptureDevice() { Device = availableDevices[i] });
            }

            while (AvailableCaptureDevices.Count < 3)
            {
                AvailableCaptureDevices.Add(new CaptureDevice()
                {
                    Device = null,
                });
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Tango.BL.Entities;
using Tango.Core;
using Tango.PMR.Printing;

namespace Tango.Integration.Operation
{
    /// <summary>
    /// Represents a <see cref="MachineOperator"/> job handler.
    /// </summary>
    /// <seealso cref="Tango.Core.ExtendedObject" />
    public class JobHandler : ExtendedObject
    {
        private Action _cancelAction;
        private List<Segment> _effectiveSegments;
        private String _lastStatusMessage;
        private int _last_unit;
        private bool _finalizing;
        private JobHandlerModes _mode;

        #region Events

        /// <summary>
        /// Occurs when a job status has been received.
        /// </summary>
        public event EventHandler<RunningJobStatus> StatusChanged;

        /// <summary>
        /// Occurs when the job has failed.
        /// </summary>
        public event EventHandler<Exception> Failed;

        /// <summary>
        /// Occurs when the job has completed successfully.
        /// </summary>
        public event EventHandler Completed;

        /// <summary>
        /// Occurs when the job has been canceled.
        /// </summary>
        public event EventHandler Canceled;

        /// <summary>
        /// Occurs when the job has been canceled, failed or completed.
        /// </summary>
        public event EventHandler Stopped;

        /// <summary>
        /// Occurs when rolling the dryer buffer.
        /// </summary>
        public event EventHandler Finalizing;

        /// <summary>
        /// Occurs when a segment has started.
        /// </summary>
        public event EventHandler<Segment> SegmentStarted;

        /// <summary>
        /// Occurs when a segment has completed.
        /// </summary>
        public event EventHandler<Segment> SegmentCompleted;

        /// <summary>
        /// Occurs when a unit completes.
        /// </summary>
        public event EventHandler<int> UnitCompleted;

        #endregion

        #region Properties

        /// <summary>
        /// Gets a value indicating whether this handler job has been canceled.
        /// </summary>
        public bool IsCanceled { get; internal set; }

        /// <summary>
        /// Gets the process parameters.
        /// </summary>
        public ProcessParametersTable ProcessParameters { get; private set; }

        private RunningJobStatus _Status;
        /// <summary>
        /// Gets the current status.
        /// </summary>
        public RunningJobStatus Status
        {
            get { return _Status; }
            private set { _Status = value; RaisePropertyChangedAuto(); }
        }

        /// <summary>
        /// Gets the job.
        /// </summary>
        public Job Job { get; private set; }

        /// <summary>
        /// Gets the PMR job ticket.
        /// </summary>
        public JobTicket JobTicket { get; private set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="JobHandler"/> class.
        /// </summary>
        public JobHandler()
        {

        }

        /// <summary>
        /// Initializes a new instance of the <see cref="JobHandler"/> class.
        /// </summary>
        /// <param name="cancelAction">The cancel action.</param>
        internal JobHandler(Action cancelAction, Job job, JobTicket jobTicket, ProcessParametersTable processParameters, JobHandlerModes mode) : this()
        {
            _mode = mode;

            ProcessParameters = processParameters;
            Job = job;
            JobTicket = jobTicket;

            foreach (var s in Job.Segments)
            {
                s.Started = false;
                s.Completed = false;
                s.RemainingTime = TimeSpan.FromSeconds(0);
            }

            _effectiveSegments = Job.EffectiveSegments.ToList();

            _cancelAction = () => { IsCanceled = true; cancelAction(); };

            Status = new RunningJobStatus();

            Status.TotalTime = job.GetEstimatedDuration(processParameters);
            Status.RemainingUnits = job.NumberOfUnits;
            Status.TotalProgress = Job.LengthIncludingNumberOfUnits + processParameters.DryerBufferLength;
            Status.FinalizingTotalProgress = processParameters.DryerBufferLength;
            Status.TotalProgressWithoutFinalization = Job.LengthIncludingNumberOfUnits;
            Status.Progress = 0;
            Status.RemainingTime = Status.TotalTime;
            Status.RemainingProgress = Status.TotalProgress;
            Status.CurrentUnitSegments = _effectiveSegments.ToList();
            Status.SettingUpTotalProgress = processParameters.DryerBufferLength;
            Status.TotalProgressMinusSettingUp = Job.LengthIncludingNumberOfUnits;
            Status.IsSettingUp = true;

            if (mode == JobHandlerModes.Finalization)
            {
                Status.CurrentUnitTotalProgress = Job.Length;
            }
            else
            {
                Status.CurrentUnitTotalProgress = Status.SettingUpTotalProgress;
            }

            if (Job.EnableInterSegment && Job.NumberOfUnits > 1)
            {
                Status.CurrentUnitSegments.Add(Job.CreateInterSegment(Job.InterSegmentLength));
            }

            //Create all segments
            int segment_index = 1;

            for (int j = 0; j < Job.NumberOfUnits; j++)
            {
                for (int i = 0; i < _effectiveSegments.Count; i++)
                {
                    Segment seg = _effectiveSegments[i].Clone();
                    seg.EstimatedDuration = seg.GetEstimatedDuration(processParameters);
                    seg.SegmentIndex = segment_index++;
                    Status.Segments.Add(seg);
                }

                if (Job.EnableInterSegment)
                {
                    var inter_segment = Job.CreateInterSegment(Job.InterSegmentLength);
                    inter_segment.SegmentIndex = segment_index++;
                    Status.Segments.Add(inter_segment);
                }
            }

            var last_segment = Status.Segments.Last();

            if (last_segment.IsInterSegment)
            {
                Status.Segments.Remove(last_segment);
            }

            Status.CurrentSegment = Status.Segments.First();
        }

        #endregion

        #region Internal Methods

        /// <summary>
        /// Raises the status received event.
        /// </summary>
        /// <param name="status">The status.</param>
        internal void RaiseStatusReceived(JobStatus status)
        {
            InvalidateJobProgress(status);
        }

        /// <summary>
        /// Raises the failed event.
        /// </summary>
        /// <param name="ex">The ex.</param>
        internal void RaiseFailed(Exception ex)
        {
            Status.IsFailed = true;
            StatusChanged?.Invoke(this, Status);
            RaisePropertyChanged(nameof(Status));
            Failed?.Invoke(this, ex);
            Stopped?.Invoke(this, new EventArgs());
        }

        /// <summary>
        /// Raises the completed event.
        /// </summary>
        internal void RaiseCompleted()
        {
            Status.Segments.Last().Completed = true;
            Status.RemainingUnits = 0;
            Status.IsFinalizing = false;
            Status.IsCompleted = true;
            StatusChanged?.Invoke(this, Status);
            RaisePropertyChanged(nameof(Status));
            Completed?.Invoke(this, new EventArgs());
            Stopped?.Invoke(this, new EventArgs());
        }

        /// <summary>
        /// Raises the canceled event.
        /// </summary>
        internal void RaiseCanceled()
        {
            Status.IsCanceled = true;
            StatusChanged?.Invoke(this, Status);
            RaisePropertyChanged(nameof(Status));
            Canceled?.Invoke(this, new EventArgs());
            Stopped?.Invoke(this, new EventArgs());
        }

        #endregion

        #region Private Methods

        private void InvalidateJobProgress(JobStatus s)
        {
            //Job Status
            if (IsCanceled)
            {
                Status.IsCanceled = IsCanceled;
                StatusChanged?.Invoke(this, Status);
                return;
            }

            List<Segment> unit_segments = new List<Segment>();
            double delta = s.Progress - Status.Progress;

            Status.Progress = s.Progress;
            Status.RemainingTime = Status.TotalTime - Job.TranslateProgressToTime(Status.Progress, ProcessParameters);
            Status.RemainingProgress = Status.TotalProgress - Status.Progress;

            if (Status.SettingUpProgress < Status.SettingUpTotalProgress)
            {
                Status.SettingUpProgress += delta;
            }
            else
            {
                if (Status.IsSettingUp)
                {
                    Status.IsSettingUp = false;
                }

                Status.ProgressMinusSettingUp += delta;
            }

            if (s.Progress < Job.LengthIncludingNumberOfUnits || _mode == JobHandlerModes.SettingUp)
            {
                Status.ProgressWithoutFinalization += delta;

                unit_segments = _effectiveSegments.ToList();

                if (Job.EnableInterSegment && Job.NumberOfUnits > 1 && Status.RemainingUnits > 1)
                {
                    unit_segments.Add(Job.CreateInterSegment(Job.InterSegmentLength));
                }

                if (unit_segments.Count != Status.CurrentUnitSegments.Count)
                {
                    Status.CurrentUnitSegments = unit_segments;
                }

                Status.CurrentUnitTotalProgress = Status.RemainingUnits > 1 && Job.EnableInterSegment ? Job.Length + (Job.InterSegmentLength) : Job.Length;

                if (_mode == JobHandlerModes.Finalization)
                {
                    Status.CurrentUnitProgress += delta;
                }
                else
                {
                    if (!Status.IsSettingUp)
                    {
                        Status.CurrentUnitProgress += delta;
                    }
                }

                if (Status.CurrentUnitProgress >= Status.CurrentUnitTotalProgress)
                {
                    Status.CurrentUnitProgress = 0;
                    Status.CurrentUnit++;
                }

                Status.RemainingUnits = Job.NumberOfUnits - Status.CurrentUnit;

                if (s.Message != _lastStatusMessage && s.Message != String.Empty)
                {
                    Status.Message = s.Message;
                }
                else
                {
                    Status.Message = null;
                }

                _lastStatusMessage = s.Message;

                StatusChanged?.Invoke(this, Status);

                //Segments Completion

                if (Status.CurrentUnit > _last_unit)
                {
                    foreach (var segment in Status.CurrentUnitSegments)
                    {
                        segment.Started = false;
                        segment.Completed = false;
                    }

                    if (Job.NumberOfUnits > 1)
                    {
                        UnitCompleted?.Invoke(this, _last_unit);
                    }
                }

                _last_unit = Status.CurrentUnit;


                for (int i = 0; i < Status.CurrentUnitSegments.Count; i++)
                {
                    Segment segment = Status.CurrentUnitSegments[i];
                    double previousSegmentsLengthWithThis = Status.CurrentUnitSegments.Take(i + 1).Sum(x => x.LengthWithFactor);
                    TimeSpan segmentsDuration = Job.TranslateProgressToTime(previousSegmentsLengthWithThis, ProcessParameters);
                    TimeSpan segmentRemainingTime = segmentsDuration - Job.TranslateProgressToTime(Status.CurrentUnitProgress, ProcessParameters);

                    if (i == 0 && Status.CurrentUnitProgress > 0)
                    {
                        if (!segment.Started)
                        {
                            segment.Started = true;
                            SegmentStarted?.Invoke(this, segment);
                        }
                    }

                    if (Status.CurrentUnitProgress >= previousSegmentsLengthWithThis)
                    {
                        if (!segment.Completed)
                        {
                            segment.Completed = true;
                            SegmentCompleted?.Invoke(this, segment);
                        }

                        if (i < Status.CurrentUnitSegments.Count - 1)
                        {
                            if (!Status.CurrentUnitSegments[i + 1].Started)
                            {
                                Status.CurrentUnitSegments[i + 1].Started = true;
                                SegmentStarted?.Invoke(this, Status.CurrentUnitSegments[i + 1]);
                            }
                        }
                    }

                    if (segment.Started && !segment.Completed)
                    {
                        segment.RemainingTime = segmentRemainingTime;
                    }
                }


                //Set Segment Completion for All Segments List
                for (int i = 0; i < Status.Segments.Count; i++)
                {
                    Segment segment = Status.Segments[i];
                    double previousSegmentsLengthWithThis = Status.Segments.Take(i + 1).Sum(x => x.LengthWithFactor);
                    TimeSpan segmentsDuration = Job.TranslateProgressToTime(previousSegmentsLengthWithThis, ProcessParameters);
                    TimeSpan segmentRemainingTime = segmentsDuration - Job.TranslateProgressToTime(Status.Progress, ProcessParameters);

                    segment.Progress = Math.Min(Math.Max((previousSegmentsLengthWithThis - segment.Length - Status.Progress) * -1, 0), segment.Length);

                    if (i == 0 && Status.Progress > 0)
                    {
                        if (!segment.Started)
                        {
                            segment.Started = true;
                            Status.CurrentSegment = segment;
                        }
                    }

                    if (Status.Progress >= previousSegmentsLengthWithThis)
                    {
                        if (!segment.Completed)
                        {
                            segment.Completed = true;
                        }

                        if (i < Status.Segments.Count - 1)
                        {
                            if (!Status.Segments[i + 1].Started)
                            {
                                Status.Segments[i + 1].Started = true;
                                Status.CurrentSegment = Status.Segments[i + 1];
                            }
                        }
                    }

                    if (segment.Started && !segment.Completed)
                    {
                        segment.RemainingTime = segmentRemainingTime;
                    }
                }
            }
            else
            {
                //Finalizing
                if (!_finalizing)
                {
                    _finalizing = true;
                    Status.IsFinalizing = true;
                    var last_Segment = _effectiveSegments.Last().Clone();
                    last_Segment.Length = ProcessParameters.DryerBufferLength;
                    Status.CurrentUnitSegments = new List<Segment> { last_Segment };
                    Status.CurrentUnitTotalProgress = last_Segment.Length;
                    Status.CurrentUnitProgress = 0;
                    Status.ProgressWithoutFinalization = Status.TotalProgressWithoutFinalization;
                    Finalizing?.Invoke(this, new EventArgs());
                }

                Status.CurrentUnitProgress += delta;
                Status.FinalizingProgress += delta;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Cancels the associated job.
        /// </summary>
        public void Cancel()
        {
            _cancelAction();
        }

        #endregion
    }
}