using System;
using System.Collections.Generic;

/*
    Copyright (c) 2010 flixmonk. (http://DVDSwarm.codeplex.com)
    All Rights Reserved.
        
    Redistribution and use in source and binary forms, with or without modification,
    are permitted provided that the following conditions are met:
        
    * Redistributions of source code must retain the above copyright notice, this list
      of conditions and the following disclaimer.
        
    * Redistributions in binary form must reproduce the above copyright notice, this
    list of conditions and the following disclaimer in the documentation and/or other
    materials provided with the distribution. 
        
    * Neither the name of The Flixmonk nor the names of its contributors may be used to
    endorse or promote products derived from this software without specific prior written
    permission.
        
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
    OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
    SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
    OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
    TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace DVDSwarm
{
    /// <summary>
    /// Contains information about a conversion job.
    /// </summary>
    sealed public class JobInfo
    {
        #region Fields

        private List<AudioTrackInfo> _audioTracks = new List<AudioTrackInfo>();
        private string _baseFilename = string.Empty;
        private CropMode _crop = CropMode.Auto;
        private FicSprout.Bacicworx.Media.VideoAspectRatio _cropAspectRatio = FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78;
        private Int32 _cropBottom = 0;
        private Int32 _cropHeight = 0;
        private Int32 _cropLeft = 0;
        private Int32 _cropRight = 0;
        private Int32 _cropTop = 0;
        private Int32 _cropWidth = 0;
        private FicSprout.Bacicworx.Media.VideoAspectRatio _displayAspectRatio = FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78;
        private DateTime _endTime = DateTime.Now;
        private FicSprout.Bacicworx.Media.VideoFieldOrder _fieldOrder = FicSprout.Bacicworx.Media.VideoFieldOrder.TopFieldFirst;
        private Int32 _frameCount = 0;
        private FicSprout.Bacicworx.Media.VideoFramerate _framerate = FicSprout.Bacicworx.Media.VideoFramerate.Fps30;
        private FicSprout.Bacicworx.Media.VideoFrameType _frameType = FicSprout.Bacicworx.Media.VideoFrameType.Interlaced;
        private bool _isAnimation = false;
        private string _outputFilename = string.Empty;
        private Int32 _outputFrameCount = 0;
        private FicSprout.Bacicworx.Media.VideoFramerate _outputFramerate = FicSprout.Bacicworx.Media.VideoFramerate.Fps30;
        private Int32 _outputHeight = 0;
        private Int32 _outputWidth = 0;
        private FicSprout.Bacicworx.Media.VideoProcessingType _processing = FicSprout.Bacicworx.Media.VideoProcessingType.None;
        private FicSprout.Bacicworx.Media.VideoProcessingType _processingOverride = FicSprout.Bacicworx.Media.VideoProcessingType.None;
        private bool _processingOverrideEnabled = false;
        private Int32 _resizeHeight = 0;
        private Int32 _resizeWidth = 0;
        private string _sourceFilename = string.Empty;
        private Int32 _sourceHeight = 0;
        private Int32 _sourceWidth = 0;
        private DateTime _startTime = DateTime.Now;
        private FicSprout.Bacicworx.IO.JobStatus _status = FicSprout.Bacicworx.IO.JobStatus.Inactive;
        private bool _trim = false;
        private FicSprout.Bacicworx.Media.SmpteTimecode _trimEndTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(
             FicSprout.Bacicworx.Media.VideoFramerate.Fps30, true);
        private FicSprout.Bacicworx.Media.SmpteTimecode _trimOutputEndTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(
             FicSprout.Bacicworx.Media.VideoFramerate.Fps30, true);
        private FicSprout.Bacicworx.Media.SmpteTimecode _trimOutputStartTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(
             FicSprout.Bacicworx.Media.VideoFramerate.Fps30, true);
        private FicSprout.Bacicworx.Media.SmpteTimecode _trimStartTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(
             FicSprout.Bacicworx.Media.VideoFramerate.Fps30, true);
        private FicSprout.Bacicworx.Media.VideoType _videoType = FicSprout.Bacicworx.Media.VideoType.NtscVideo;
        private double _videoTypePercentage = 0;
        private FicSprout.Snapzworx.Video.X264.InputTuning _x264InputTuning = FicSprout.Snapzworx.Video.X264.InputTuning.Film;
              
        #endregion

        #region Properties

        /// <summary>
        /// Gets the list of audio tracks for the job.
        /// </summary>
        public List<AudioTrackInfo> AudioTracks
        {
            get
            {
                return _audioTracks;
            }
        }
        /// <summary>
        /// Gets and sets the user determined video output filename for the job. The filename has no path and no extension.
        /// </summary>
        public string BaseFilename
        {
            get
            {
                return _baseFilename;
            }
            set
            {
                _baseFilename = value;
            }
        }
        /// <summary>
        /// Gets and sets the cropping mode.
        /// </summary>
        public CropMode Crop
        {
            get
            {
                return _crop;
            }
            set
            {
                _crop = value;
            }
        }
        /// <summary>
        /// Gets and sets the cropping aspect ratio for the source video.
        /// </summary>
        /// <remarks>
        /// DisplayAspectRatio is the value specified by the video stream. CropAspectRatio is the 
        /// value used to remove letterboxing from the video. For example: a 2.35 widescreen video
        /// stored in a fullscreeen video stream would have a DisplayAspectRatio of 1.33 and use a
        /// CropAspectRatio of 2.35 to remove the black borders.
        /// </remarks>
        public FicSprout.Bacicworx.Media.VideoAspectRatio CropAspectRatio
        {
            get
            {
                return _cropAspectRatio;
            }
            set
            {
                _cropAspectRatio = value;
            }
        }
        /// <summary>
        /// Gets and sets the manual cropping in pixels. The value must be a positive number evenly 
        /// divisible by 4.
        /// </summary>
        /// <exception cref="System.ArgumentException">Thrown when value is not mod 4 and positive.</exception>
        public Int32 CropBottom
        {
            get
            {
                return _cropBottom;
            }
            set
            {
                if (value % 4 != 0 || value < 0)
                {
                    throw new ArgumentException("value is not mod 4 or positive.");
                }

                _cropBottom = value;
            }
        }
        /// <summary>
        /// Gets and sets the cropped video height.
        /// </summary>
        public Int32 CropHeight
        {
            get
            {
                return _cropHeight;
            }
            set
            {
                _cropHeight = value;
            }
        }
        /// <summary>
        /// Gets and sets the manual cropping in pixels. The value must be a positive number evenly 
        /// divisible by 4.
        /// </summary>
        /// <exception cref="System.ArgumentException">Thrown when value is not mod 4 and positive.</exception>
        public Int32 CropLeft
        {
            get
            {
                return _cropLeft;
            }
            set
            {
                if (value % 4 != 0 || value < 0)
                {
                    throw new ArgumentException("value is not mod 4 or positive.");
                }

                _cropLeft = value;
            }
        }
        /// <summary>
        /// Gets and sets the manual cropping in pixels. The value must be a positive number evenly 
        /// divisible by 4.
        /// </summary>
        /// <exception cref="System.ArgumentException">Thrown when value is not mod 4 and positive.</exception>
        public Int32 CropRight
        {
            get
            {
                return _cropRight;
            }
            set
            {
                if (value % 4 != 0 || value < 0)
                {
                    throw new ArgumentException("value is not mod 4 or positive.");
                }

                _cropRight = value;
            }
        }
        /// <summary>
        /// Gets and sets the manual cropping in pixels. The value must be a positive number evenly 
        /// divisible by 4.
        /// </summary>
        /// <exception cref="System.ArgumentException">Thrown when value is not mod 4 and positive.</exception>
        public Int32 CropTop
        {
            get
            {
                return _cropTop;
            }
            set
            {
                if (value % 4 != 0 || value < 0)
                {
                    throw new ArgumentException("value is not mod 4 or positive.");
                }

                _cropTop = value;
            }
        }
        /// <summary>
        /// Gets and sets the cropped video width.
        /// </summary>
        public Int32 CropWidth
        {
            get
            {
                return _cropWidth;
            }
            set
            {
                _cropWidth = value;
            }
        }
        /// <summary>
        /// Gets and sets the display aspect ratio for the source video as specified in the
        /// transport stream. This value is independent of the CropAspectRatio.
        /// </summary>
        /// <remarks>
        /// DisplayAspectRatio is the value specified by the video stream. CropAspectRatio is the 
        /// value used to remove letterboxing from the video. For example: a 2.35 widescreen video
        /// stored in a fullscreeen video stream would have a DisplayAspectRatio of 1.33 and use a
        /// CropAspectRatio of 2.35 to remove the black borders.
        /// </remarks>
        public FicSprout.Bacicworx.Media.VideoAspectRatio DisplayAspectRatio
        {
            get
            {
                return _displayAspectRatio;
            }
            set
            {
                _displayAspectRatio = value;
            }
        }
        /// <summary>
        /// Gets and sets the end time for the job.
        /// </summary>
        public DateTime EndTime
        {
            get
            {
                return _endTime;
            }
            set
            {
                _endTime = value;
            }
        }
        /// <summary>
        /// Gets and sets the video field order.
        /// </summary>
        public FicSprout.Bacicworx.Media.VideoFieldOrder FieldOrder
        {
            get
            {
                return _fieldOrder;
            }
            set
            {
                _fieldOrder = value;
            }
        }
        /// <summary>
        /// Gets and sets the video frame count.
        /// </summary>
        public Int32 FrameCount
        {
            get
            {
                return _frameCount;
            }
            set
            {
                _frameCount = value;
            }
        }
        /// <summary>
        /// Gets and sets the video frame rate.
        /// </summary>
        public FicSprout.Bacicworx.Media.VideoFramerate Framerate
        {
            get
            {
                return _framerate;
            }
            set
            {
                _framerate = value;
            }
        }
        /// <summary>
        /// Gets and sets the video frame type.
        /// </summary>
        public FicSprout.Bacicworx.Media.VideoFrameType FrameType
        {
            get
            {
                return _frameType;
            }
            set
            {
                _frameType = value;
            }
        }
        /// <summary>
        /// Gets and sets a value indicating whether the video is animation.
        /// </summary>
        public bool IsAnimation
        {
            get
            {
                return _isAnimation;
            }
            set
            {
                _isAnimation = value;
            }
        }
        /// <summary>
        /// Gets and sets the video output video filename including the full path and file extension.
        /// </summary>
        public string OutputFilename
        {
            get
            {
                return _outputFilename;
            }
            set
            {
                _outputFilename = value;
            }
        }
        /// <summary>
        /// Gets and sets the approximate video frame count based on the output framerate.
        /// </summary>
        public Int32 OutputFrameCount
        {
            get
            {
                return _outputFrameCount;
            }
            set
            {
                _outputFrameCount = value;
            }
        }
        /// <summary>
        /// Gets and sets the output frame rate after processing the video.
        /// </summary>
        public FicSprout.Bacicworx.Media.VideoFramerate OutputFramerate
        {
            get
            {
                return _outputFramerate;
            }
            set
            {
                _outputFramerate = value;
            }
        }
        /// <summary>
        /// Gets and sets the output video height.
        /// </summary>
        public Int32 OutputHeight
        {
            get
            {
                return _outputHeight;
            }
            set
            {
                _outputHeight = value;
            }
        }
        /// <summary>
        /// Gets and sets the output video width.
        /// </summary>
        public Int32 OutputWidth
        {
            get
            {
                return _outputWidth;
            }
            set
            {
                _outputWidth = value;
            }
        }
        /// <summary>
        /// Gets and sets automatic video processing.
        /// </summary>
        public FicSprout.Bacicworx.Media.VideoProcessingType Processing
        {
            get
            {
                return _processing;
            }
            set
            {
                _processing = value;
            }
        }
        /// <summary>
        /// Gets and sets video processing that will override automatic processing.
        /// </summary>
        public FicSprout.Bacicworx.Media.VideoProcessingType ProcessingOverride
        {
            get
            {
                return _processingOverride;
            }
            set
            {
                _processingOverride = value;
            }
        }
        /// <summary>
        /// Gets and sets a value indicating whether automatic video processing will be overriden.
        /// </summary>
        public bool ProcessingOverrideEnabled
        {
            get
            {
                return _processingOverrideEnabled;
            }
            set
            {
                _processingOverrideEnabled = value;
            }
        }
        /// <summary>
        /// Gets and sets the height to which the video will be resized to.
        /// </summary>
        public Int32 ResizeHeight
        {
            get
            {
                return _resizeHeight;
            }
            set
            {
                _resizeHeight = value;
            }
        }
        /// <summary>
        /// Gets and sets the width to which the video will be resized to.
        /// </summary>
        public Int32 ResizeWidth
        {
            get
            {
                return _resizeWidth;
            }
            set
            {
                _resizeWidth = value;
            }
        }
        /// <summary>
        /// Gets and sets the source video filename for the job.
        /// </summary>
        public string SourceFilename
        {
            get
            {
                return _sourceFilename;
            }
            set
            {
                _sourceFilename = value;
            }
        }
        /// <summary>
        /// Gets and sets the source video height.
        /// </summary>
        public Int32 SourceHeight
        {
            get
            {
                return _sourceHeight;
            }
            set
            {
                _sourceHeight = value;
            }
        }
        /// <summary>
        /// Gets and sets the source video width.
        /// </summary>
        public Int32 SourceWidth
        {
            get
            {
                return _sourceWidth;
            }
            set
            {
                _sourceWidth = value;
            }
        }
        /// <summary>
        /// Gets and sets the start time for the job.
        /// </summary>
        public DateTime StartTime
        {
            get
            {
                return _startTime;
            }
            set
            {
                _startTime = value;
            }
        }
        /// <summary>
        /// Gets and sets the status of the job.
        /// </summary>
        public FicSprout.Bacicworx.IO.JobStatus Status
        {
            get
            {
                return _status;
            }
            set
            {
                _status = value;
            }
        }
        /// <summary>
        /// Gets and sets a value indicating whether to trim the video to a specified range.
        /// </summary>
        public bool Trim
        {
            get
            {
                return _trim;
            }
            set
            {
                _trim = value;
            }
        }
        /// <summary>
        /// Gets and sets the end timecode for the trimmed video. A timecode of zero frames
        /// means the trim extends to the end of the video.
        /// </summary>
        public FicSprout.Bacicworx.Media.SmpteTimecode TrimEndTimecode
        {
            get
            {
                return _trimEndTimecode;
            }
            set
            {
                _trimEndTimecode = value;
            }
        }
        /// <summary>
        /// Gets and sets the end timecode for the trimmed video and is based on the OutputFramerate.
        /// A timecode of zero frames means the trim extends to the end of the video.
        /// </summary>
        public FicSprout.Bacicworx.Media.SmpteTimecode TrimOutputEndTimecode
        {
            get
            {
                return _trimOutputEndTimecode;
            }
            set
            {
                _trimOutputEndTimecode = value;
            }
        }
        /// <summary>
        /// Gets and sets the start timecode where trimming will begin and is based on the OutputFramerate.
        /// </summary>
        public FicSprout.Bacicworx.Media.SmpteTimecode TrimOutputStartTimecode
        {
            get
            {
                return _trimOutputStartTimecode;
            }
            set
            {
                _trimOutputStartTimecode = value;
            }
        }
        /// <summary>
        /// Gets and sets the start timecode where trimming will begin.
        /// </summary>
        public FicSprout.Bacicworx.Media.SmpteTimecode TrimStartTimecode
        {
            get
            {
                return _trimStartTimecode;
            }
            set
            {
                _trimStartTimecode = value;
            }
        }
        /// <summary>
        /// Gets and sets the video type.
        /// </summary>
        public FicSprout.Bacicworx.Media.VideoType VideoType
        {
            get
            {
                return _videoType;
            }
            set
            {
                _videoType = value;
            }
        }
        /// <summary>
        /// Gets and sets the VideoType percentage.
        /// </summary>
        public double VideoTypePercentage
        {
            get
            {
                return _videoTypePercentage;
            }
            set
            {
                _videoTypePercentage = value;
            }
        }
        /// <summary>
        /// Gets and sets the x264 input tuning.
        /// </summary>
        public FicSprout.Snapzworx.Video.X264.InputTuning X264InputTuning
        {
            get
            {
                return _x264InputTuning;
            }
            set
            {
                _x264InputTuning = value;
            }
        }
        
        #endregion

        #region Methods

        /// <summary>
        /// Clears internal values.
        /// </summary>
        public void Clear()
        {
            _audioTracks.Clear();
            _baseFilename = string.Empty;
            _crop = CropMode.Auto;
            _cropAspectRatio = FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78;
            _cropBottom = 0;
            _cropHeight = 0;
            _cropLeft = 0;
            _cropRight = 0;
            _cropTop = 0;
            _cropWidth = 0;
            _displayAspectRatio = FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78;
            _endTime = DateTime.Now;
            _fieldOrder = FicSprout.Bacicworx.Media.VideoFieldOrder.TopFieldFirst;
            _frameCount = 0;
            _framerate = FicSprout.Bacicworx.Media.VideoFramerate.Fps30;
            _frameType = FicSprout.Bacicworx.Media.VideoFrameType.Interlaced;
            _isAnimation = false;
            _outputFilename = string.Empty;
            _outputFrameCount = 0;
            _outputFramerate = FicSprout.Bacicworx.Media.VideoFramerate.Fps30;
            _outputHeight = 0;
            _outputWidth = 0;
            _processing = FicSprout.Bacicworx.Media.VideoProcessingType.None;
            _processingOverride = FicSprout.Bacicworx.Media.VideoProcessingType.None;
            _processingOverrideEnabled = false;
            _trim = false;
            _trimEndTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(FicSprout.Bacicworx.Media.VideoFramerate.Fps30, true);
            _trimOutputEndTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(FicSprout.Bacicworx.Media.VideoFramerate.Fps30, true);
            _trimOutputStartTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(FicSprout.Bacicworx.Media.VideoFramerate.Fps30, true);
            _trimStartTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(FicSprout.Bacicworx.Media.VideoFramerate.Fps30, true);
            _resizeHeight = 0;
            _resizeWidth = 0;
            _sourceFilename = string.Empty;
            _sourceHeight = 0;
            _sourceWidth = 0;
            _startTime = DateTime.Now;
            _status = FicSprout.Bacicworx.IO.JobStatus.Inactive;
            _videoType = FicSprout.Bacicworx.Media.VideoType.NtscVideo;
            _videoTypePercentage = 0;
            _x264InputTuning = FicSprout.Snapzworx.Video.X264.InputTuning.Film;
        }

        /// <summary>
        /// Copies data from another instance to this instance.
        /// </summary>
        /// <param name="job">A JobInfo instance to copy values from.</param>
        /// <exception cref="System.ArgumentNullException">Thrown when job is null.</exception>
        public void Copy(JobInfo job)
        {
            if (job == null)
            {
                throw new ArgumentNullException("job");
            }

            Clear();

            for (int i = 0; i < job._audioTracks.Count; i++)
            {
                AudioTrackInfo newTrack = new AudioTrackInfo();
                newTrack.Copy(job._audioTracks[i]);
                _audioTracks.Add(newTrack);
            }

            _baseFilename = job._baseFilename;
            _crop = job._crop;
            _cropAspectRatio = job._cropAspectRatio;
            _cropBottom = job._cropBottom;
            _cropHeight = job._cropHeight;
            _cropLeft = job._cropLeft;
            _cropRight = job._cropRight;
            _cropTop = job._cropTop;
            _cropWidth = job._cropWidth;
            _displayAspectRatio = job._displayAspectRatio;
            _endTime = new DateTime(job._endTime.Ticks);
            _fieldOrder = job._fieldOrder;
            _frameCount = job._frameCount;
            _framerate = job._framerate;
            _frameType = job._frameType;
            _isAnimation = job._isAnimation;
            _outputFilename = job._outputFilename;
            _outputFrameCount = job._outputFrameCount;
            _outputFramerate = job._outputFramerate;
            _outputHeight = job._outputHeight;
            _outputWidth = job._outputWidth;
            _processing = job._processing;
            _processingOverride = job._processingOverride;
            _processingOverrideEnabled = job._processingOverrideEnabled;
            _trim = job._trim;
            _trimEndTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(job._trimEndTimecode);
            _trimOutputEndTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(job._trimOutputEndTimecode);
            _trimOutputStartTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(job._trimOutputStartTimecode);
            _trimStartTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(job._trimStartTimecode);
            _resizeHeight = job._resizeHeight;
            _resizeWidth = job._resizeWidth;
            _sourceFilename = job._sourceFilename;
            _sourceHeight = job._sourceHeight;
            _sourceWidth = job._sourceWidth;
            _startTime = new DateTime(job._startTime.Ticks);
            _status = job._status;
            _videoType = job.VideoType;
            _videoTypePercentage = job._videoTypePercentage;
            _x264InputTuning = job._x264InputTuning;
        }

        /// <summary>
        /// Returns the audio track delays with the specified global delay added. The results are synced by
        /// index to the results of the GetAudoTrackFilenames method.
        /// </summary>
        /// <param name="value">The global delay in milliseconds to add to all track delay values.</param>
        /// <returns>An array of Int32 values representing the audio delays in milliseconds. If there are no
        /// audio tracks, an empty array is returned.</returns>
        public Int32[] GetAudoTrackDelays(Int32 value)
        {
            Int32[] result = new Int32[_audioTracks.Count];

            for (int i = 0; i < _audioTracks.Count; i++)
            {
                result[i] = _audioTracks[i].Delay + value;
            }

            return result;
        }

        /// <summary>
        /// Returns the audio track output filenames. The results are synced by index to the results of the
        /// GetAudoTrackDelays method.
        /// </summary>
        /// <returns>An array of strings containing the audio filenames. If there are no audio tracks, an
        /// empty array is returned.</returns>
        public string[] GetAudoTrackOutputFilenames()
        {
            string[] result = new string[_audioTracks.Count];

            for (int i = 0; i < _audioTracks.Count; i++)
            {
                // No conversion to another format?
                if (_audioTracks[i].Format == _audioTracks[i].OutputFormat)
                {
                    result[i] = _audioTracks[i].Filename;
                }
                else
                {
                    result[i] = System.IO.Path.ChangeExtension(_audioTracks[i].Filename,
                        Utility.GetAudioFormatExtension(_audioTracks[i].OutputFormat));
                }
            }

            return result;
        }

        #endregion
    }
}
