using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Windows.Forms;

/*
    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>
    /// Job Dialog.
    /// </summary>
    public partial class JobDialog : Form
    {
        #region Fields

        private ConfigurationInfo _config = new ConfigurationInfo();
        private bool _isLoading = false;
        private JobInfo _job = new JobInfo();
        private List<JobInfo> _jobs = null;
        private bool _previewIsRunning = false;

        #endregion

        #region Properites

        /// <summary>
        /// Sets the configuration info for the job.
        /// </summary>
        public ConfigurationInfo Config
        {
            set
            {
                _config = value;
            }
        }
        /// <summary>
        /// Gets the job info.
        /// </summary>
        public JobInfo Job
        {
            get
            {
                return _job;
            }
        }
        /// <summary>
        /// Sets the jobs list.
        /// </summary>
        public List<JobInfo> Jobs
        {
            set
            {
                _jobs = value;
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Creates a new instance of the JobDialog.
        /// </summary>
        /// <param name="config">The configuration info.</param>
        /// <exception cref="System.ArgumentNullException">Thrown when config is null.</exception>
        public JobDialog(ConfigurationInfo config)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }

            InitializeComponent();

            // Button Image property does not support transparent images. Load the images
            // from Resources into an ImageList - which does support transparency. 
            imageList1.Images.Add(Properties.Resources.Folder);
            imageList1.Images.Add(Properties.Resources.FolderDown);
            imageList1.TransparentColor = System.Drawing.Color.Fuchsia;
            buttonBrowseVideoSource.Image = imageList1.Images[0];

            _config.Copy(config);
            buttonBrowseVideoSource.Visible = true;
            comboBoxCropAspectRatio.Items.AddRange(FicSprout.Bacicworx.Media.Utility.VideoAspectRatioNames);
            comboBoxCropAspectRatio.Text = FicSprout.Bacicworx.Media.Utility.GetVideoAspectRatioName(
                        FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78);
            comboBoxCropMode.Items.AddRange(Utility.CropModeNames);
            comboBoxCropMode.Text = Utility.GetCropModeName(_config.Crop);
            comboBoxProcessingOverride.Items.AddRange(FicSprout.Bacicworx.Media.Utility.VideoProcessingTypeNames);
            comboBoxProcessingOverride.Text = FicSprout.Bacicworx.Media.Utility.VideoProcessingTypeNames[0];
            SetTrimLabel(_job.TrimStartTimecode, _job.TrimEndTimecode);

            UpdateUI();
            textBoxVideoInput.Focus();
        }

        /// <summary>
        /// Creates a new instance of the JobDialog populating the form with
        /// the supplied values.
        /// </summary>
        /// <param name="config">The configuration info.</param>
        /// <param name="job">A JobInfo instance containing the values
        /// to populate the form with.</param>
        /// <exception cref="System.ArgumentNullException">Thrown when config is null.</exception>
        /// <exception cref="System.ArgumentNullException">Thrown when job is null.</exception>
        public JobDialog(ConfigurationInfo config, JobInfo job)
        {
            if (config == null)
            {
                throw new ArgumentNullException("config");
            }
            if (job == null)
            {
                throw new ArgumentNullException("job");
            }

            InitializeComponent();

            _isLoading = true;
            _config.Copy(config);
            _job.Copy(job);

            // Fill in dialog with job values.
            buttonBrowseVideoSource.Visible = false;
            textBoxVideoInput.Text = _job.SourceFilename;
            textBoxVideoOutput.Text = _job.BaseFilename;
            checkBoxAnimation.Checked = _job.IsAnimation;
            checkBoxProcessingOverride.Checked = _job.ProcessingOverrideEnabled;
            checkBoxTrim.Checked = _job.Trim;
            if (job.DisplayAspectRatio == FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_33)
            {
                comboBoxAspect.SelectedIndex = 0;
            }
            if (job.DisplayAspectRatio == FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78)
            {
                comboBoxAspect.SelectedIndex = 1;
            }
            comboBoxCropAspectRatio.Items.AddRange(FicSprout.Bacicworx.Media.Utility.VideoAspectRatioNames);
            comboBoxCropAspectRatio.Text = FicSprout.Bacicworx.Media.Utility.GetVideoAspectRatioName(_job.CropAspectRatio);
            comboBoxCropMode.Items.AddRange(Utility.CropModeNames);
            comboBoxCropMode.Text = Utility.GetCropModeName(_job.Crop);
            comboBoxProcessingOverride.Text = FicSprout.Bacicworx.Media.Utility.GetVideoProcessingTypeName(_job.ProcessingOverride);
            comboBoxProcessingOverride.Items.AddRange(FicSprout.Bacicworx.Media.Utility.VideoProcessingTypeNames);
            SetTrimLabel(_job.TrimStartTimecode, _job.TrimEndTimecode);
            numericUpDownBottom.Value = job.CropBottom;
            numericUpDownLeft.Value = job.CropLeft;
            numericUpDownRight.Value = job.CropRight;
            numericUpDownTop.Value = job.CropTop;

            listViewAudioTracks.Items.Clear();
            for (int i = 0; i < _job.AudioTracks.Count; i++)
            {
                ListViewItem item = new ListViewItem(System.IO.Path.GetFileNameWithoutExtension(_job.AudioTracks[i].Filename));
                item.SubItems.Add(_job.AudioTracks[i].Delay.ToString());
                item.SubItems.Add(Utility.GetAudioFormatName(_job.AudioTracks[i].Format));
                item.SubItems.Add(Utility.GetAudioFormatName(_job.AudioTracks[i].OutputFormat));
                listViewAudioTracks.Items.Add(item);
            }

            openFileDialog.InitialDirectory = System.IO.Path.GetDirectoryName(_job.SourceFilename);

            ShowVideoFormatInfo();

            UpdateUI();
            textBoxVideoInput.Focus();
            _isLoading = false;
        }

        /// <summary>
        /// Raised when DGIndex finishes the preview.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The event arguments.</param>
        void dgindex_Completed(object sender, EventArgs e)
        {
            _previewIsRunning = false;
        }

        /// <summary>
        /// Performs a quick index of the video to get basic information.
        /// </summary>
        private void IndexVideo()
        {
            // Preview video.
            _previewIsRunning = true;
            DgindexBackgroundWorker dgindex = new DgindexBackgroundWorker(Application.StartupPath +
                "\\Tools\\DGIndex.exe", _job.SourceFilename, true);
            dgindex.Completed += new EventHandler(dgindex_Completed);
            dgindex.Start();

            while (_previewIsRunning)
            {
                Thread.Sleep(100);
            }

            // Copy data.
            _job.DisplayAspectRatio = dgindex.DisplayAspectRatio;
            _job.FieldOrder = dgindex.FieldOrder;
            _job.FrameCount = dgindex.FrameCount;
            _job.Framerate = dgindex.Framerate;
            _job.FrameType = dgindex.FrameType;
            _job.OutputFramerate = dgindex.Framerate;
            _job.SourceFilename = dgindex.SourceFilename;
            _job.SourceHeight = dgindex.SourceHeight;
            _job.SourceWidth = dgindex.SourceWidth;
            _job.VideoType = dgindex.VideoType;
            _job.VideoTypePercentage = dgindex.VideoTypePercentage;

            // Cleanup.
            dgindex = null;
            System.IO.File.Delete(System.IO.Path.ChangeExtension(_job.SourceFilename, "log"));
        }

        /// <summary>
        /// Loads audio streams based on the openDialog filename.
        /// </summary>
        /// <param name="filenames">A string array containing the filenames of audio tracks.</param>
        /// <exception cref="System.ArgumentNullException">Thrown when filenames is null.</exception>
        private void LoadAudioTracks(string[] filenames)
        {
            if (filenames == null)
            {
                throw new ArgumentNullException("filenames");
            }

            for (int i = 0; i < filenames.Length; i++)
            {
                string filename = filenames[i];

                bool isDuplicate = false;
                for (int x = 0; x < Job.AudioTracks.Count; x++)
                {
                    if (Job.AudioTracks[x].Filename == filename)
                    {
                        isDuplicate = true;
                        break;
                    }
                }

                if (!isDuplicate)
                {
                    // Examples:
                    // VTS_02_PGC_02_1 - 0x80 - Audio - AC3 - 2ch - 48kHz - DRC - English - DELAY 0ms.AC3
                    // VTS_01_PGC_01_1 - 0x82 - Audio - AC3 - 2ch - 48kHz - DRC - English - Alternate Director's Comments - DELAY 0ms.AC3
                    // VTS_02_PGC_01_1 T80 2_0ch 192Kbps DELAY 0ms.ac3

                    AudioTrackInfo track = new AudioTrackInfo();
                    track.Downmix = _config.DownmixAudio;
                    track.DynamicRangeCompression = _config.AudioDynamicRangeCompression;
                    track.Filename = filename;
                    track.Normalize = _config.NormalizeAudio;
                    track.OutputFormat = _config.AudioFormat;
                    filename = filename.ToUpperInvariant();

                    // Parse delay.
                    Int32 indexDelay = filename.IndexOf("DELAY");
                    if (indexDelay != -1)
                    {
                        Int32 indexDelayMs = filename.IndexOf("MS", indexDelay);
                        if (indexDelayMs != -1)
                        {
                            track.Delay = Convert.ToInt32(filename.Substring(indexDelay + 6, indexDelayMs - indexDelay - 6));
                        }
                    }

                    // Only added if filename is not empty.
                    if (track.Filename.Length > 0)
                    {
                        _job.AudioTracks.Add(track);

                        ListViewItem item = new ListViewItem(System.IO.Path.GetFileNameWithoutExtension(track.Filename));
                        item.SubItems.Add(track.Delay.ToString());
                        item.SubItems.Add(Utility.GetAudioFormatName(track.Format));
                        item.SubItems.Add(Utility.GetAudioFormatName(track.OutputFormat));
                        listViewAudioTracks.Items.Add(item);
                    }
                }
            }
        }

        /// <summary>
        /// Updates the trim label.
        /// </summary>
        /// <param name="start">The start timecode.</param>
        /// <param name="end">The end timecopde. A timecode of zero frames means render to the end of the video.</param>
        private void SetTrimLabel(FicSprout.Bacicworx.Media.SmpteTimecode start,
            FicSprout.Bacicworx.Media.SmpteTimecode end)
        {
            if (end.TotalFrames == 0)
            {
                labelTrimValues.Text = "[" + start.ToString() + "]  --->  [End Of Video]";
            }
            else
            {
                labelTrimValues.Text = "[" + start.ToString() + "]  --->  [" + end.ToString() + "]";
            }
        }

        /// <summary>
        /// Displays brief info about the video and updates the labelFormatInfo control.
        /// </summary>
        private void ShowVideoFormatInfo()
        {

            if (_job.VideoType == FicSprout.Bacicworx.Media.VideoType.NtscFilm ||
                _job.VideoType == FicSprout.Bacicworx.Media.VideoType.NtscHybridFilm ||
                _job.VideoType == FicSprout.Bacicworx.Media.VideoType.NtscHybridVideo ||
                _job.VideoType == FicSprout.Bacicworx.Media.VideoType.NtscVideo)
            {
                if (_job.DisplayAspectRatio == FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_33)
                {
                    labelFormatInfo.Text = "NTSC Fullscreen (" + _job.SourceWidth.ToString() + "x" +
                        _job.SourceHeight.ToString() + "),  Resize 720x544";
                    comboBoxAspect.SelectedIndex = 0;
                }
                if (_job.DisplayAspectRatio == FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78)
                {
                    labelFormatInfo.Text = "NTSC Widescreen (" + _job.SourceWidth.ToString() + "x" +
                        _job.SourceHeight.ToString() + "),  Resize 864x480";
                    comboBoxAspect.SelectedIndex = 1;
                }
            }
            if (_job.VideoType == FicSprout.Bacicworx.Media.VideoType.PalVideo)
            {
                if (_job.DisplayAspectRatio == FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_33)
                {
                    labelFormatInfo.Text = "PAL Fullscreen (" + _job.SourceWidth.ToString() + "x" +
                        _job.SourceHeight.ToString() + "),  Resize 768x576";
                    comboBoxAspect.SelectedIndex = 0;
                }
                if (_job.DisplayAspectRatio == FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78)
                {
                    labelFormatInfo.Text = "PAL Widescreen (" + _job.SourceWidth.ToString() + "x" +
                        _job.SourceHeight.ToString() + "),  Resize 1024x576";
                    comboBoxAspect.SelectedIndex = 1;
                }
            }
        }

        /// <summary>
        /// Updates the UI.
        /// </summary>
        private void UpdateUI()
        {
            // Disable UI controls.
            checkBoxAnimation.Enabled = false;
            checkBoxProcessingOverride.Enabled = false;
            checkBoxTrim.Enabled = false;
            comboBoxAspect.Visible = false;
            comboBoxCropAspectRatio.Visible = false;
            comboBoxCropMode.Enabled = false;
            comboBoxProcessingOverride.Enabled = false;
            labelCropAspectRatio.Visible = false;
            labelCropMode.Enabled = false;
            labelCropResolution.Visible = false;
            labelFormat.Enabled = false;
            listViewAudioTracks.Enabled = false;
            numericUpDownBottom.Visible = false;
            numericUpDownLeft.Visible = false;
            numericUpDownRight.Visible = false;
            numericUpDownTop.Visible = false;
            toolStripButtonAddAudioTrack.Enabled = false;
            toolStripButtonMoveAudioTrackDown.Enabled = false;
            toolStripButtonMoveAudioTrackUp.Enabled = false;
            toolStripButtonRemoveAudioTrack.Enabled = false;
            toolStripButtonEditAudioTrack.Enabled = false;

            if (textBoxVideoInput.Text.Length > 0)
            {
                toolStripButtonAddAudioTrack.Enabled = true;
                toolStripButtonMoveAudioTrackDown.Enabled = true;
                toolStripButtonMoveAudioTrackUp.Enabled = true;
                toolStripButtonRemoveAudioTrack.Enabled = true;
                checkBoxAnimation.Enabled = true;
                checkBoxProcessingOverride.Enabled = true;
                checkBoxTrim.Enabled = true;
                comboBoxAspect.Visible = true;
                comboBoxCropMode.Enabled = true;
                labelCropMode.Enabled = true;
                labelFormat.Enabled = true;
                listViewAudioTracks.Enabled = true;

                if (checkBoxProcessingOverride.Checked)
                {
                    comboBoxProcessingOverride.Enabled = true;
                }

                if (comboBoxCropMode.Text == "Aspect")
                {
                    comboBoxCropAspectRatio.Visible = true;
                    labelCropAspectRatio.Visible = true;
                    labelCropResolution.Visible = true;

                    // Update crop resolution.
                    Int32 videoHeight = _job.ResizeHeight;
                    Int32 videoWidth = _job.ResizeWidth;

                    if (videoHeight > 0 && videoWidth > 0)
                    {
                        FicSprout.Bacicworx.Media.Utility.GetVideoCroppedResolution(ref videoWidth, ref videoHeight,
                            _job.DisplayAspectRatio, _job.CropAspectRatio, 16);

                        if (!_isLoading)
                        {
                            _job.CropHeight = videoHeight;
                            _job.CropWidth = videoWidth;
                        }
                        labelCropResolution.Text = "[ " + videoWidth.ToString() + " x " + videoHeight.ToString() + " ]";
                    }
                }

                if (comboBoxCropMode.Text == "Manual")
                {
                    labelCropResolution.Visible = true;
                    numericUpDownBottom.Visible = true;
                    numericUpDownLeft.Visible = true;
                    numericUpDownRight.Visible = true;
                    numericUpDownTop.Visible = true;

                    // Update crop resolution.
                    labelCropResolution.Text = "[ " + (_job.ResizeWidth - _job.CropLeft - _job.CropRight).ToString() + " x " +
                       (_job.ResizeHeight - _job.CropBottom - _job.CropTop).ToString() + " ]";
                }

                if (listViewAudioTracks.Items.Count > 0 && listViewAudioTracks.SelectedIndices.Count == 1)
                {
                    toolStripButtonEditAudioTrack.Enabled = true;
                }
            }
        }

        #endregion

        #region Events

        private void buttonBrowseVideoInput_Click(object sender, EventArgs e)
        {
            // file exists?
            openFileDialog.Title = "Open Video";
            openFileDialog.Filter = Utility.SupporteVideoDialogFilters;
            openFileDialog.Multiselect = false;
            labelFormatInfo.Text = string.Empty;

            if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
            {
                return;
            }
            if (string.IsNullOrEmpty(openFileDialog.FileName))
            {
                return;
            }

            _job.SourceFilename = openFileDialog.FileName;
            _job.BaseFilename = System.IO.Path.GetFileNameWithoutExtension(_job.SourceFilename);

            textBoxVideoInput.Text = _job.SourceFilename;
            textBoxVideoOutput.Text = _job.BaseFilename;

            // Update job info.
            IndexVideo();
            Utility.GetVideoResizeValues(_job);

            ShowVideoFormatInfo();

            _job.CropAspectRatio = _job.DisplayAspectRatio;
            comboBoxCropAspectRatio.Text = FicSprout.Bacicworx.Media.Utility.GetVideoAspectRatioName(
                _job.CropAspectRatio);

            // Try to auto-load audio tracks by finding all files that start with the same text
            // as the video filename, up to the first space in the name.
            _job.AudioTracks.Clear();
            listViewAudioTracks.Items.Clear();

            // Base filename used when searching for audio tracks.
            string baseFilename = string.Empty;
            if (_job.SourceFilename.IndexOf(' ') > -1)
            {
                baseFilename = System.IO.Path.GetFileNameWithoutExtension(_job.SourceFilename).Substring(
                     0, System.IO.Path.GetFileNameWithoutExtension(_job.SourceFilename).IndexOf(' '));
            }
            else
            {
                baseFilename = System.IO.Path.GetFileNameWithoutExtension(_job.SourceFilename);
            }

            // Find AC3...
            string[] files = System.IO.Directory.GetFiles(System.IO.Path.GetDirectoryName(_job.SourceFilename),
                baseFilename + "*.ac3", SearchOption.TopDirectoryOnly);

            LoadAudioTracks(files);
            files = null;

            // Find DTS...
            files = System.IO.Directory.GetFiles(System.IO.Path.GetDirectoryName(_job.SourceFilename),
                baseFilename + "*.dts", SearchOption.TopDirectoryOnly);

            LoadAudioTracks(files);
            files = null;

            UpdateUI();
        }

        private void buttonBrowseVideoSource_MouseDown(object sender, MouseEventArgs e)
        {
            buttonBrowseVideoSource.Image = imageList1.Images[1];
        }

        private void buttonBrowseVideoSource_MouseUp(object sender, MouseEventArgs e)
        {
            buttonBrowseVideoSource.Image = imageList1.Images[0];
        }

        private void checkBoxAnimation_CheckedChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {
                _job.IsAnimation = checkBoxAnimation.Checked;
            }

            checkBoxAnimation.Checked = _job.IsAnimation;
        }

        private void checkBoxProcessingOverride_CheckedChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {
                _job.ProcessingOverrideEnabled = checkBoxProcessingOverride.Checked;
            }

            UpdateUI();
        }

        private void checkBoxTrim_CheckedChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {
                _job.Trim = checkBoxTrim.Checked;
            }

            labelTrimValues.Visible = checkBoxTrim.Checked;
        }

        private void comboBoxAspect_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {
                if (comboBoxAspect.SelectedIndex == 0)
                {
                    _job.DisplayAspectRatio = FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_33;
                }
                if (comboBoxAspect.SelectedIndex == 1)
                {
                    _job.DisplayAspectRatio = FicSprout.Bacicworx.Media.VideoAspectRatio.Aspect_1_78;
                }

                _job.CropAspectRatio = _job.DisplayAspectRatio;
                Utility.GetVideoResizeValues(_job);
            }

            comboBoxCropAspectRatio.Text = FicSprout.Bacicworx.Media.Utility.GetVideoAspectRatioName(_job.CropAspectRatio);
            ShowVideoFormatInfo();
            UpdateUI();
        }

        private void comboBoxCropAspectRatio_TextChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {

                _job.CropAspectRatio = FicSprout.Bacicworx.Media.Utility.GetVideoAspectRatio(comboBoxCropAspectRatio.Text);
            }

            UpdateUI();
        }

        private void comboBoxCropMode_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {
                _job.Crop = Utility.GetCropMode(comboBoxCropMode.Text);
            }

            UpdateUI();
        }

        private void comboBoxOverride_TextChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {
                _job.ProcessingOverride = FicSprout.Bacicworx.Media.Utility.GetVideoProcessingType(comboBoxProcessingOverride.Text);
            }
        }

        private void JobDialog_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (DialogResult == System.Windows.Forms.DialogResult.Cancel)
            {
                return;
            }

            // If manual crop values are not mod 16, artifacts can occur in encoded video.
            if (_job.Crop == CropMode.Manual)
            {
                if ((_job.CropLeft + _job.CropRight) % 16 != 0 || (_job.CropTop + _job.CropBottom) % 16 != 0)
                {
                    MessageBox.Show("Crop Left+Right or Top+Bottom is not a multiple of 16.\n" +
                        "Artifacting can occur in encoded video.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);

                    e.Cancel = true;
                    return;
                }
            }

            // Duplicates?
            bool ouputFilenameAlreadyInUse = false;
            bool sourceFilenameExists = false;

            for (int i = 0; i < _jobs.Count; i++)
            {
                if (System.IO.Path.GetDirectoryName(_jobs[i].SourceFilename) + "\\" + _jobs[i].BaseFilename
                    == _job.SourceFilename + "\\" + _job.OutputFilename)
                {
                    ouputFilenameAlreadyInUse = true;
                }
                if (_jobs[i].SourceFilename == _job.SourceFilename)
                {
                    sourceFilenameExists = true;
                }
            }

            // Adding/editing a job and the output filename is already used by another job?
            if (ouputFilenameAlreadyInUse)
            {
                MessageBox.Show("The output filename is already used by another\njob. Change the output filename.",
                     "Duplicate Filename", MessageBoxButtons.OK, MessageBoxIcon.Error);

                e.Cancel = true;
                return;
            }

            // Adding a job and the source filename is already in the jobs list?
            if (Text == "Add Job" && sourceFilenameExists && MessageBox.Show("The video source is already in the jobs list.\n\n" +
                    "Add it anyway?", "Duplicate Filename", MessageBoxButtons.YesNo, MessageBoxIcon.Question) ==
                    System.Windows.Forms.DialogResult.No)
            {

                e.Cancel = true;
                return;
            }
        }

        private void labelTrimValues_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            JobTrimDialog dialog = new JobTrimDialog(_job.TrimStartTimecode, _job.TrimEndTimecode);

            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                _job.TrimStartTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(dialog.TrimStartTimecode);
                _job.TrimEndTimecode = new FicSprout.Bacicworx.Media.SmpteTimecode(dialog.TrimEndTimecode);

                SetTrimLabel(_job.TrimStartTimecode, _job.TrimEndTimecode);
            }

            dialog.Close();
            dialog.Dispose();
        }

        private void listViewAudioTracks_SelectedIndexChanged(object sender, EventArgs e)
        {
            toolStripButtonEditAudioTrack.Enabled = false;
            if (listViewAudioTracks.Items.Count > 0 && listViewAudioTracks.SelectedIndices.Count == 1)
            {
                toolStripButtonEditAudioTrack.Enabled = true;
            }
        }

        private void numericUpDownBottom_ValueChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {
                _job.CropBottom = (Int32)numericUpDownBottom.Value;
                _job.CropLeft = (Int32)numericUpDownLeft.Value;
                _job.CropRight = (Int32)numericUpDownRight.Value;
                _job.CropTop = (Int32)numericUpDownTop.Value;
            }

            UpdateUI();
        }

        private void textBoxVideoOutput_TextChanged(object sender, EventArgs e)
        {
            if (!_isLoading)
            {
                _job.BaseFilename = System.IO.Path.GetFileNameWithoutExtension(textBoxVideoOutput.Text);
            }
        }

        private void toolStripButtonAddAudioTrack_Click(object sender, EventArgs e)
        {
            // file exists?
            openFileDialog.Title = "Add Audio Tracks";
            openFileDialog.Filter = Utility.SupportedAudioDialogFilters;
            openFileDialog.FilterIndex = 2;
            openFileDialog.Multiselect = true;

            if (openFileDialog.ShowDialog() == System.Windows.Forms.DialogResult.Cancel)
            {
                return;
            }

            LoadAudioTracks(openFileDialog.FileNames);

            UpdateUI();
        }

        private void toolStripButtonEditAudioTrack_Click(object sender, EventArgs e)
        {
            if (listViewAudioTracks.SelectedIndices.Count != 1)
            {
                return;
            }

            EditAudioTrackDialog dialog = new EditAudioTrackDialog(
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].Format,
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].OutputFormat,
                _config.ContainerFormat,
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].Delay,
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].DynamicRangeCompression,
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].Normalize);

            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].Delay = dialog.AudioDelay;
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].DynamicRangeCompression = dialog.AudioDynamicRangeCompression;
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].Normalize = dialog.AudioNormalize;
                _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].OutputFormat = dialog.AudioOutputFormat;

                ListViewItem item = listViewAudioTracks.Items[listViewAudioTracks.SelectedIndices[0]];
                item.SubItems[1].Text = _job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].Delay.ToString();
                item.SubItems[2].Text = Utility.GetAudioFormatName(_job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].Format);
                item.SubItems[3].Text = Utility.GetAudioFormatName(_job.AudioTracks[listViewAudioTracks.SelectedIndices[0]].OutputFormat);
            }

            dialog.Close();
            dialog.Dispose();
        }

        private void toolStripButtonMoveAudioTrackDown_Click(object sender, EventArgs e)
        {
            if (listViewAudioTracks.SelectedIndices.Count == 1 &&
                listViewAudioTracks.SelectedIndices[0] < listViewAudioTracks.Items.Count - 1)
            {
                Int32 index = listViewAudioTracks.SelectedIndices[0];

                AudioTrackInfo info = new AudioTrackInfo();
                info.Copy(_job.AudioTracks[index + 1]);

                _job.AudioTracks[index + 1].Copy(_job.AudioTracks[index]);
                _job.AudioTracks[index].Copy(info);

                listViewAudioTracks.Items[index + 1].SubItems[0].Text = System.IO.Path.GetFileNameWithoutExtension(
                    _job.AudioTracks[index + 1].Filename);
                listViewAudioTracks.Items[index + 1].SubItems[1].Text = _job.AudioTracks[index + 1].Delay.ToString();
                listViewAudioTracks.Items[index + 1].SubItems[2].Text = Utility.GetAudioFormatName(_job.AudioTracks[index + 1].Format);
                listViewAudioTracks.Items[index + 1].SubItems[3].Text = Utility.GetAudioFormatName(_job.AudioTracks[index + 1].OutputFormat);

                listViewAudioTracks.Items[index].SubItems[0].Text = System.IO.Path.GetFileNameWithoutExtension(
                    _job.AudioTracks[index].Filename);
                listViewAudioTracks.Items[index].SubItems[1].Text = _job.AudioTracks[index].Delay.ToString();
                listViewAudioTracks.Items[index].SubItems[2].Text = Utility.GetAudioFormatName(_job.AudioTracks[index].Format);
                listViewAudioTracks.Items[index].SubItems[3].Text = Utility.GetAudioFormatName(_job.AudioTracks[index].OutputFormat);

                listViewAudioTracks.SelectedIndices.Clear();
                listViewAudioTracks.SelectedIndices.Add(index + 1);
            }
        }

        private void toolStripButtonMoveAudioTrackUp_Click(object sender, EventArgs e)
        {
            if (listViewAudioTracks.SelectedIndices.Count == 1 &&
                listViewAudioTracks.SelectedIndices[0] > 0)
            {
                Int32 index = listViewAudioTracks.SelectedIndices[0];

                AudioTrackInfo info = new AudioTrackInfo();
                info.Copy(_job.AudioTracks[index - 1]);

                _job.AudioTracks[index - 1].Copy(_job.AudioTracks[index]);
                _job.AudioTracks[index].Copy(info);

                listViewAudioTracks.Items[index - 1].SubItems[0].Text = System.IO.Path.GetFileNameWithoutExtension(
                    _job.AudioTracks[index - 1].Filename);
                listViewAudioTracks.Items[index - 1].SubItems[1].Text = _job.AudioTracks[index - 1].Delay.ToString();
                listViewAudioTracks.Items[index - 1].SubItems[2].Text = Utility.GetAudioFormatName(_job.AudioTracks[index - 1].Format);
                listViewAudioTracks.Items[index - 1].SubItems[3].Text = Utility.GetAudioFormatName(_job.AudioTracks[index - 1].OutputFormat);

                listViewAudioTracks.Items[index].SubItems[0].Text = System.IO.Path.GetFileNameWithoutExtension(
                    _job.AudioTracks[index].Filename);
                listViewAudioTracks.Items[index].SubItems[1].Text = _job.AudioTracks[index].Delay.ToString();
                listViewAudioTracks.Items[index].SubItems[2].Text = Utility.GetAudioFormatName(_job.AudioTracks[index].Format);
                listViewAudioTracks.Items[index].SubItems[3].Text = Utility.GetAudioFormatName(_job.AudioTracks[index].OutputFormat);

                listViewAudioTracks.SelectedIndices.Clear();
                listViewAudioTracks.SelectedIndices.Add(index - 1);
            }
        }

        private void toolStripButtonRemoveAudioTrack_Click(object sender, EventArgs e)
        {
            if (listViewAudioTracks.SelectedIndices.Count == 1 && listViewAudioTracks.SelectedIndices[0] != -1)
            {
                _job.AudioTracks.RemoveAt(listViewAudioTracks.SelectedIndices[0]);
                listViewAudioTracks.Items.RemoveAt(listViewAudioTracks.SelectedIndices[0]);
            }
        }

        #endregion
    }
}
