void FeatureLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (string.IsNullOrEmpty(InputSourceTextBox.Text))
            {
                MessageBox.Show("Configure input source prior to retrieving features.", "Feature Retrieval", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
            }
            else
            {
                InitBackgroundWorker();
                eac3toArgs args = new eac3toArgs();
                features = new List <Feature>();
                FeatureDataGridView.DataSource = null;
                StreamDataGridView.DataSource  = null;

                args.eac3toPath    = eac3toPath;
                args.inputPath     = InputSourceTextBox.Text;
                args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
                args.resultState   = ResultState.FeatureCompleted;
                args.args          = string.Empty;

                backgroundWorker.ReportProgress(0, "Retrieving features");
                WriteToLog("Retrieving features");
                FeatureLinkLabel.Enabled = false;
                Cursor = Cursors.WaitCursor;

                backgroundWorker.RunWorkerAsync(args);
            }
        }
        void ExtractButton_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(FolderOutputTextBox.Text))
            {
                MessageBox.Show("Configure output target folder.", "Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (FeatureDataGridView.Rows.Count == 0)
            {
                MessageBox.Show("Retrieve features prior to extracting.", "Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (StreamDataGridView.Rows.Count == 0)
            {
                MessageBox.Show("Retrieve streams prior to extracting.", "Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (!IsStreamCheckedForExtract())
            {
                MessageBox.Show("Select stream(s) to extract.", "Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            eac3toArgs args = new eac3toArgs();

            args.eac3toPath    = eac3toPath;
            args.inputPath     = InputSourceTextBox.Text;
            args.featureNumber = ((Feature)FeatureDataGridView.SelectedRows[0].DataBoundItem).Number.ToString();
            args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
            args.resultState   = ResultState.ExtractCompleted;

            try
            {
                args.args = GenerateArguments();
            }
            catch (ApplicationException ex)
            {
                MessageBox.Show(ex.Message, "Stream Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            InitBackgroundWorker();
            backgroundWorker.ReportProgress(0, "Extracting streams");
            WriteToLog("Extracting streams");
            ExtractButton.Enabled = FileInputSourceButton.Enabled = FolderInputSourceButton.Enabled = FolderOutputSourceButton.Enabled
                                                                                                          = FeatureLinkLabel.Enabled = FeatureDataGridView.Enabled = StreamDataGridView.Enabled = false;
            CancelButton.Enabled = true;
            Cursor = Cursors.WaitCursor;

            backgroundWorker.RunWorkerAsync(args);
        }
        void FeatureDataGridView_SelectionChanged(object sender, EventArgs e)
        {
            // only fire after the Databind has completed on grid and a row is selected
            if (FeatureDataGridView.Rows.Count == features.Count && FeatureDataGridView.SelectedRows.Count == 1)
            {
                if (backgroundWorker.IsBusy) // disallow selection change
                {
                    //TODO: Disable selection change on processing
                    //this.FeatureDataGridView.SelectionChanged -= new System.EventHandler(this.FeatureDataGridView_SelectionChanged);

                    //FeatureDataGridView.CurrentRow.Selected = false;
                    //FeatureDataGridView.Rows[int.Parse(FeatureDataGridView.Tag.ToString())].Selected = true;

                    //this.FeatureDataGridView.SelectionChanged += new System.EventHandler(this.FeatureDataGridView_SelectionChanged);
                }
                else // backgroundworker is not busy, allow selection change
                {
                    Feature feature = FeatureDataGridView.SelectedRows[0].DataBoundItem as Feature;

                    // Check for Streams
                    if (feature.Streams == null || feature.Streams.Count == 0)
                    {
                        InitBackgroundWorker();
                        eac3toArgs args = new eac3toArgs();

                        args.eac3toPath    = eac3toPath;
                        args.inputPath     = InputSourceTextBox.Text;
                        args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
                        args.resultState   = ResultState.StreamCompleted;
                        args.args          = ((Feature)FeatureDataGridView.SelectedRows[0].DataBoundItem).Number.ToString();

                        backgroundWorker.ReportProgress(0, "Retrieving streams");
                        WriteToLog("Retrieving streams");
                        Cursor = Cursors.WaitCursor;

                        backgroundWorker.RunWorkerAsync(args);
                    }
                    else // use already collected streams
                    {
                        StreamDataGridView.DataSource = feature.Streams;
                    }
                }
            }
        }
        void FeatureLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (string.IsNullOrEmpty(InputSourceTextBox.Text))
            {
                MessageBox.Show("Configure input source prior to retrieving features.", "Feature Retrieval", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
            }
            else
            {
                InitBackgroundWorker();
                eac3toArgs args = new eac3toArgs();
                features = new List<Feature>();
                FeatureDataGridView.DataSource = null;
                StreamDataGridView.DataSource = null;

                args.eac3toPath = eac3toPath;
                args.inputPath = InputSourceTextBox.Text;
                args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
                args.resultState = ResultState.FeatureCompleted;
                args.args = string.Empty;

                backgroundWorker.ReportProgress(0, "Retrieving features");
                WriteToLog("Retrieving features");
                FeatureLinkLabel.Enabled = false;
                Cursor = Cursors.WaitCursor;

                backgroundWorker.RunWorkerAsync(args);
            }
        }
        void FeatureDataGridView_SelectionChanged(object sender, EventArgs e)
        {
            // only fire after the Databind has completed on grid and a row is selected
            if (FeatureDataGridView.Rows.Count == features.Count && FeatureDataGridView.SelectedRows.Count == 1)
            {
                if (backgroundWorker.IsBusy) // disallow selection change
                {
                    //TODO: Disable selection change on processing
                    //this.FeatureDataGridView.SelectionChanged -= new System.EventHandler(this.FeatureDataGridView_SelectionChanged);

                    //FeatureDataGridView.CurrentRow.Selected = false;
                    //FeatureDataGridView.Rows[int.Parse(FeatureDataGridView.Tag.ToString())].Selected = true;

                    //this.FeatureDataGridView.SelectionChanged += new System.EventHandler(this.FeatureDataGridView_SelectionChanged);
                }
                else // backgroundworker is not busy, allow selection change
                {
                    Feature feature = FeatureDataGridView.SelectedRows[0].DataBoundItem as Feature;

                    // Check for Streams
                    if (feature.Streams == null || feature.Streams.Count == 0)
                    {
                        InitBackgroundWorker();
                        eac3toArgs args = new eac3toArgs();

                        args.eac3toPath = eac3toPath;
                        args.inputPath = InputSourceTextBox.Text;
                        args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
                        args.resultState = ResultState.StreamCompleted;
                        args.args = ((Feature)FeatureDataGridView.SelectedRows[0].DataBoundItem).Number.ToString();

                        backgroundWorker.ReportProgress(0, "Retrieving streams");
                        WriteToLog("Retrieving streams");
                        Cursor = Cursors.WaitCursor;

                        backgroundWorker.RunWorkerAsync(args);
                    }
                    else // use already collected streams
                    {
                        StreamDataGridView.DataSource = feature.Streams;
                    }
                }
            }
        }
        void ExtractButton_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(FolderOutputTextBox.Text))
            {
                MessageBox.Show("Configure output target folder.", "Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (FeatureDataGridView.Rows.Count == 0)
            {
                MessageBox.Show("Retrieve features prior to extracting.", "Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (StreamDataGridView.Rows.Count == 0)
            {
                MessageBox.Show("Retrieve streams prior to extracting.", "Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (!IsStreamCheckedForExtract())
            {
                MessageBox.Show("Select stream(s) to extract.", "Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            eac3toArgs args = new eac3toArgs();

            args.eac3toPath = eac3toPath;
            args.inputPath = InputSourceTextBox.Text;
            args.featureNumber = ((Feature)FeatureDataGridView.SelectedRows[0].DataBoundItem).Number.ToString();
            args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
            args.resultState = ResultState.ExtractCompleted;

            try
            {
                args.args = GenerateArguments();
            }
            catch (ApplicationException ex)
            {
                MessageBox.Show(ex.Message, "Stream Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            InitBackgroundWorker();
            backgroundWorker.ReportProgress(0, "Extracting streams");
            WriteToLog("Extracting streams");
            ExtractButton.Enabled = FileInputSourceButton.Enabled = FolderInputSourceButton.Enabled = FolderOutputSourceButton.Enabled
                = FeatureLinkLabel.Enabled = FeatureDataGridView.Enabled = StreamDataGridView.Enabled = false;
            CancelButton.Enabled = true;
            Cursor = Cursors.WaitCursor;

            backgroundWorker.RunWorkerAsync(args);
        }
        private void FeatureDataGridView_SelectionChanged(object sender, EventArgs e)
        {
            // only fire after the Databind has completed on grid and a row is selected
            if (FeatureDataGridView.Rows.Count == features.Count && FeatureDataGridView.SelectedRows.Count == 1)
            {
                if (backgroundWorker.IsBusy) // disallow selection change
                {
                    this.FeatureDataGridView.SelectionChanged -= new System.EventHandler(this.FeatureDataGridView_SelectionChanged);

                    FeatureDataGridView.CurrentRow.Selected = false;
                    FeatureDataGridView.Rows[int.Parse(FeatureDataGridView.Tag.ToString())].Selected = true;

                    this.FeatureDataGridView.SelectionChanged += new System.EventHandler(this.FeatureDataGridView_SelectionChanged);
                }
                else // backgroundworker is not busy, allow selection change
                {
                    Feature feature = FeatureDataGridView.SelectedRows[0].DataBoundItem as Feature;

                    // Check for Streams
                    if (feature.Streams == null || feature.Streams.Count == 0)
                    {
                        InitBackgroundWorker();
                        eac3toArgs args = new eac3toArgs();

                        args.eac3toPath = eac3toPath;
                        args.inputPath = FolderInputTextBox.Text;
                        args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
                        args.resultState = ResultState.StreamCompleted;
                        args.args = ((Feature)FeatureDataGridView.SelectedRows[0].DataBoundItem).Number.ToString();

                        // create dummy input string for megui job
                        if (feature.Description.Contains("EVO"))
                        {
                            if (args.inputPath.ToUpper().Contains("HVDVD_TS"))
                                 dummyInput = args.inputPath + feature.Description.Substring(0, feature.Description.IndexOf(","));
                            else dummyInput = args.inputPath + "HVDVD_TS\\" + feature.Description.Substring(0, feature.Description.IndexOf(","));
                        }
                        else if (feature.Description.Contains("(angle"))
                        {
                            if (args.inputPath.ToUpper().Contains("BDMV\\PLAYLIST"))
                                 dummyInput = args.inputPath + feature.Description.Substring(0, feature.Description.IndexOf(" ("));
                            else if (args.inputPath.ToUpper().Contains("BDMV\\STREAM"))
                                 dummyInput = args.inputPath.Substring(0, args.inputPath.LastIndexOf("BDMV")) + "BDMV\\PLAYLIST\\" + feature.Description.Substring(0, feature.Description.IndexOf(" ("));
                            else dummyInput = args.inputPath + "BDMV\\PLAYLIST\\" + feature.Description.Substring(0, feature.Description.IndexOf(" ("));
                        }
                        else if (feature.Description.Substring(feature.Description.LastIndexOf(".") + 1, 4) == "m2ts")
                        {
                            string des = feature.Description.Substring(feature.Description.IndexOf(",") + 2, feature.Description.LastIndexOf(",") - feature.Description.IndexOf(",") - 2);

                            if (des.Contains("+")) // seamless branching
                            {
                                seamless = true;
                                if (args.inputPath.ToUpper().Contains("BDMV\\STREAM"))
                                     dummyInput = args.inputPath.Substring(0, args.inputPath.IndexOf("BDMV")) + "BDMV\\PLAYLIST\\" + feature.Description.Substring(0, feature.Description.IndexOf(","));
                                else
                                     dummyInput = args.inputPath + "BDMV\\PLAYLIST\\" + feature.Description.Substring(0, feature.Description.IndexOf(","));
                            }
                            else
                            {
                                if (args.inputPath.ToUpper().Contains("BDMV\\STREAM"))
                                     dummyInput = args.inputPath + des;
                                else dummyInput = args.inputPath + "BDMV\\STREAM\\" + des;
                            }
                        }
                        else
                        {
                            if (args.inputPath.ToUpper().Contains("BDMV\\PLAYLIST"))
                                 dummyInput = args.inputPath + feature.Description.Substring(0, feature.Description.IndexOf(","));
                            else dummyInput = args.inputPath + "BDMV\\PLAYLIST\\" + feature.Description.Substring(0, feature.Description.IndexOf(","));
                        }

                        backgroundWorker.ReportProgress(0, "Retrieving streams...");
                        WriteToLog("Retrieving streams...");
                        Cursor = Cursors.WaitCursor;

                        backgroundWorker.RunWorkerAsync(args);
                    }
                    else // use already collected streams
                    {
                        StreamDataGridView.DataSource = feature.Streams;
                    }
                }
            }
        }
        private void FeatureButton_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(FolderInputTextBox.Text))
            {
                MessageBox.Show("Configure input source folder prior to retrieving features.", "Feature Retrieval", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
            }
            else
            {
                InitBackgroundWorker();
                eac3toArgs args = new eac3toArgs();

                args.eac3toPath = eac3toPath;
                args.inputPath = FolderInputTextBox.Text;
                args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
                if (FolderSelection.Checked)
                {
                    args.resultState = ResultState.FeatureCompleted;
                    args.args = string.Empty;

                    features = new List<Feature>();
                    backgroundWorker.ReportProgress(0, "Retrieving features...");
                    WriteToLog("Retrieving features...");
                }
                else
                {
                    args.resultState = ResultState.StreamCompleted;
                    args.args = string.Empty;

                    streams = new List<Stream>();
                    backgroundWorker.ReportProgress(0, "Retrieving streams...");
                    WriteToLog("Retrieving streams...");

                }
                FeatureButton.Enabled = false;
                Cursor = Cursors.WaitCursor;

                backgroundWorker.RunWorkerAsync(args);
            }
        }
        private void QueueButton_Click(object sender, EventArgs e)
        {
            if (string.IsNullOrEmpty(FolderOutputTextBox.Text))
            {
                MessageBox.Show("Configure output target folder prior to enqueueing job.", "Enqueue Job", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (StreamDataGridView.Rows.Count == 0)
            {
                MessageBox.Show("Retrieve streams prior to enqueueing job.", "Enqueue Job", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (!IsStreamCheckedForExtract())
            {
                MessageBox.Show("Select stream(s) to extract prior to enqueueing job.", "Enqueue Job", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            if (!Drives.ableToWriteOnThisDrive(System.IO.Path.GetPathRoot(FolderOutputTextBox.Text)))
            {
                MessageBox.Show("MeGUI cannot write on " + System.IO.Path.GetPathRoot(FolderOutputTextBox.Text) +
                                "\nPlease, select another Output path.", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            if ((settings.EAC3toPath == "") || (settings.EAC3toPath == "eac3to.exe"))
            {
                MessageBox.Show("Select a correct EAC3to Path first in the MeGUI Settings to avoid issues...", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return;
            }

            eac3toArgs args = new eac3toArgs();
            HDStreamsExJob job;

            args.eac3toPath = eac3toPath;
            args.inputPath = FolderInputTextBox.Text;
            if (FolderSelection.Checked)
            {
                if (seamless)
                    args.featureNumber = "1"; // force the feature number
                else
                    args.featureNumber = ((Feature)FeatureDataGridView.SelectedRows[0].DataBoundItem).Number.ToString();
            }
            args.workingFolder = string.IsNullOrEmpty(FolderOutputTextBox.Text) ? FolderOutputTextBox.Text : System.IO.Path.GetDirectoryName(args.eac3toPath);
            args.resultState = ResultState.ExtractCompleted;

            try
            {
                args.args = GenerateArguments();
            }
            catch (ApplicationException ex)
            {
                MessageBox.Show(ex.Message, "Stream Extract", MessageBoxButtons.OK, MessageBoxIcon.Exclamation, MessageBoxDefaultButton.Button1);
                return;
            }

            /*
            InitBackgroundWorker();
            backgroundWorker.ReportProgress(0, "Extracting streams");
            WriteToLog("Extracting streams");
            QueueButton.Enabled = false;
            Cursor = Cursors.WaitCursor;

            backgroundWorker.RunWorkerAsync(args);*/

            // Load to MeGUI job queue
            if (FolderSelection.Checked)
                job = new HDStreamsExJob(dummyInput, this.FolderOutputTextBox.Text+"xxx", args.featureNumber, args.args, inputType);
            else job = new HDStreamsExJob(this.FolderInputTextBox.Text, this.FolderOutputTextBox.Text+"xxx", null, args.args, inputType);

            lastJob = job;
            info.Jobs.addJobsToQueue(job);
            if (this.closeOnQueue.Checked)
                this.Close();
        }
        void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
        {
            eac3toArgs args = (eac3toArgs)e.Argument;

            using (Process process = new Process())
            {
                process.StartInfo.FileName = args.eac3toPath;
                //process.StartInfo.FileName = @"C:\Users\mgriffor\Documents\Visual Studio 2012\Projects\HdBrStreamExtractor\trunk\Tester\bin\Debug\Tester.exe";

                switch (args.resultState)
                {
                case ResultState.FeatureCompleted:
                    process.StartInfo.Arguments = string.Format("\"{0}\"", args.inputPath);
                    //process.StartInfo.Arguments = string.Concat("\"", System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "feature.txt"), "\"");
                    break;

                case ResultState.StreamCompleted:
                    process.StartInfo.Arguments = string.Format("\"{0}\" {1}) {2}", args.inputPath, args.args, "-progressnumbers");
                    //process.StartInfo.Arguments = string.Concat("\"", System.IO.Path.Combine(System.IO.Directory.GetCurrentDirectory(), "stream.txt"), "\"");
                    break;

                case ResultState.ExtractCompleted:
                    if (InputSourceTextBox.Tag.ToString() == "File")
                    {
                        process.StartInfo.Arguments = string.Format("\"{0}\" {1}", args.inputPath, args.args + " -progressnumbers");
                    }
                    else
                    {
                        process.StartInfo.Arguments = string.Format("\"{0}\" {1}) {2}", args.inputPath, args.featureNumber, args.args + " -progressnumbers");
                    }

                    string value = process.StartInfo.Arguments;

                    if (Control.ModifierKeys == Keys.Control)
                    {
                        if (InputBox("Arguments", "Review or modify arguments:", ref value) == DialogResult.OK)
                        {
                            process.StartInfo.Arguments = value;
                        }
                    }
                    break;
                }

                WriteToLog(string.Format("Arguments: {0}", process.StartInfo.Arguments));

                process.StartInfo.WorkingDirectory       = args.workingFolder;
                process.StartInfo.CreateNoWindow         = true;
                process.StartInfo.UseShellExecute        = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError  = true;
                process.StartInfo.ErrorDialog            = false;
                process.EnableRaisingEvents = true;
                process.EnableRaisingEvents = true;
                process.Exited             += new EventHandler(backgroundWorker_Exited);
                process.ErrorDataReceived  += new DataReceivedEventHandler(backgroundWorker_ErrorDataReceived);
                process.OutputDataReceived += new DataReceivedEventHandler(backgroundWorker_OutputDataReceived);

                try
                {
                    process.Start();
                    process.PriorityBoostEnabled = true;
                    process.BeginErrorReadLine();
                    process.BeginOutputReadLine();

                    while (!process.HasExited)
                    {
                        if (backgroundWorker.CancellationPending)
                        {
                            process.Kill();
                        }

                        // Do not monopolize resource, relinquish some time
                        Thread.Sleep(250);
                    }

                    process.WaitForExit();
                }
                catch (Exception ex)
                {
                    //e.Cancel = true;
                    //e.Result = ex.Message;
                    WriteToLog(ex.Message);
                }
                finally
                {
                    process.ErrorDataReceived  -= new DataReceivedEventHandler(backgroundWorker_ErrorDataReceived);
                    process.OutputDataReceived -= new DataReceivedEventHandler(backgroundWorker_OutputDataReceived);
                }
            }

            e.Result = args.resultState;
        }