private void HandleResult(CompressionResult result, int count)
        {
            string name = Path.GetFileName(result.OriginalFileName);

            if (result.Saving > 0 && File.Exists(result.ResultFileName))
            {
                if (_dte.SourceControl.IsItemUnderSCC(result.OriginalFileName) && !_dte.SourceControl.IsItemCheckedOut(result.OriginalFileName))
                {
                    _dte.SourceControl.CheckOutItem(result.OriginalFileName);
                }

                File.Copy(result.ResultFileName, result.OriginalFileName, true);

                string text = "Compressed " + name + " by " + result.Saving + " bytes / " + result.Percent + "%";
                _dte.StatusBar.Progress(true, text, AmountCompleted: count, Total: _selectedPaths.Count);
            }
            else
            {
                _dte.StatusBar.Progress(true, name + " is already optimized", AmountCompleted: count, Total: _selectedPaths.Count);
            }

            if (result.Saving > 0)
            {
                Logger.Log(result.ToString());
            }
        }
        void HandleResult(CompressionResult result, int count)
        {
            string name = Path.GetFileName(result.OriginalFileName);

            if (result.Saving > 0 && File.Exists(result.ResultFileName))
            {
                if (_dte.SourceControl.IsItemUnderSCC(result.OriginalFileName) && !_dte.SourceControl.IsItemCheckedOut(result.OriginalFileName))
                {
                    _dte.SourceControl.CheckOutItem(result.OriginalFileName);
                }

                File.Copy(result.ResultFileName, result.OriginalFileName, true);
                File.Delete(result.ResultFileName);

                string text = "Compressed " + name + " by " + result.Saving + " bytes / " + result.Percent + "%";
                _dte.StatusBar.Progress(true, text, count, _selectedPaths.Count + 1);

                Logger.Log(result.ToString());
                string ext     = Path.GetExtension(result.OriginalFileName).ToLowerInvariant().Replace(".jpeg", ".jpg");
                var    metrics = new Dictionary <string, double> {
                    { "saving", result.Saving }
                };
                Telemetry.TrackEvent(ext, metrics: metrics);
            }
            else
            {
                _dte.StatusBar.Progress(true, name + " is already optimized", AmountCompleted: count, Total: _selectedPaths.Count + 1);
                Logger.Log(name + " is already optimized");

                if (result.Processed)
                {
                    Telemetry.TrackEvent("Already optimized");
                }
            }
        }
        void OptimizeImage(bool lossy)
        {
            _isProcessing = true;
            CompressionResult[] list = new CompressionResult[_selectedPaths.Count];
            var stopwatch            = Stopwatch.StartNew();

            try
            {
                string text = _selectedPaths.Count == 1 ? " image" : " images";
                _dte.StatusBar.Progress(true, "Optimizing " + _selectedPaths.Count + text + "...", AmountCompleted: 1, Total: _selectedPaths.Count + 1);

                Compressor compressor = new Compressor();
                Cache      cache      = new Cache(_dte.Solution, lossy);
                int        nCompleted = 0;
                var        options    = new ParallelOptions {
                    MaxDegreeOfParallelism = Environment.ProcessorCount
                };

                Parallel.For(0, _selectedPaths.Count, options, i =>
                {
                    string file = _selectedPaths[i];

                    // Don't process if file has been fully optimized already
                    if (cache.IsFullyOptimized(file))
                    {
                        var bogus = new CompressionResult(file, file, TimeSpan.Zero)
                        {
                            Processed = false
                        };
                        HandleResult(bogus, nCompleted + 1);
                    }
                    else
                    {
                        var result = compressor.CompressFileAsync(file, lossy);
                        HandleResult(result, nCompleted + 1);

                        if (result.Saving > 0 && !string.IsNullOrEmpty(result.ResultFileName))
                        {
                            list[i] = result;
                        }
                        else
                        {
                            cache.AddToCache(file);
                        }
                    }

                    Interlocked.Increment(ref nCompleted);
                });
            }
            finally
            {
                _dte.StatusBar.Progress(false);
                stopwatch.Stop();
                DisplayEndResult(list, stopwatch.Elapsed);
                _isProcessing = false;
            }
        }
        void HandleResult(CompressionResult result, int count)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            string name = Path.GetFileName(result.OriginalFileName);

            if (result.Saving > 0 && result.ResultFileSize > 0 && File.Exists(result.ResultFileName))
            {
                if (_dte.SourceControl.IsItemUnderSCC(result.OriginalFileName) && !_dte.SourceControl.IsItemCheckedOut(result.OriginalFileName))
                {
                    _dte.SourceControl.CheckOutItem(result.OriginalFileName);
                }

                File.Copy(result.ResultFileName, result.OriginalFileName, true);
                File.Delete(result.ResultFileName);

                string text = "Compressed " + name + " by " + result.Saving + " bytes / " + result.Percent + "%";
                _dte.StatusBar.Progress(true, text, count, count + 1);
            }
            else
            {
                _dte.StatusBar.Progress(true, name + " is already optimized", AmountCompleted: count, Total: count + 1);
            }
        }
        private void HandleResult(CompressionResult result, int count)
        {
            string name = Path.GetFileName(result.OriginalFileName);

            if (result.Saving > 0 && File.Exists(result.ResultFileName))
            {
                if (_dte.SourceControl.IsItemUnderSCC(result.OriginalFileName) && !_dte.SourceControl.IsItemCheckedOut(result.OriginalFileName))
                    _dte.SourceControl.CheckOutItem(result.OriginalFileName);

                File.Copy(result.ResultFileName, result.OriginalFileName, true);

                string text = "Compressed " + name + " by " + result.Saving + " bytes / " + result.Percent + "%";
                _dte.StatusBar.Progress(true, text, AmountCompleted: count, Total: _selectedPaths.Count);
            }
            else
            {
                _dte.StatusBar.Progress(true, name + " is already optimized", AmountCompleted: count, Total: _selectedPaths.Count);
            }

            if (result.Saving > 0)
                Logger.Log(result.ToString());
        }
        private async Task OptimizeImageAsync(bool lossy, EventArgs e)
        {
            _isProcessing = true;

            IEnumerable <string> files = null;

            // Check command parameters first
            if (e is OleMenuCmdEventArgs cmdArgs && cmdArgs.InValue is string arg)
            {
                string filePath = arg.Trim('"', '\'');

                if (Compressor.IsFileSupported(filePath) && File.Exists(filePath))
                {
                    files = new[] { filePath };
                }
            }

            // Then check selected items
            if (files == null)
            {
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                files = ProjectHelpers.GetSelectedFilePaths(_dte).Where(f => Compressor.IsFileSupported(f)).ToArray();
            }

            if (!files.Any())
            {
                _isProcessing = false;

                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();

                _dte.StatusBar.Text = "No images found to optimize";
                return;
            }

            var list      = new CompressionResult[files.Count()];
            var stopwatch = Stopwatch.StartNew();
            int count     = files.Count();

            await Task.Run(async() =>
            {
                try
                {
                    string text = count == 1 ? " image" : " images";
                    _dte.StatusBar.Progress(true, "Optimizing " + count + text + "...", AmountCompleted: 1, Total: count + 1);

                    var compressor = new Compressor();
                    var cache      = new Cache(_dte.Solution.FullName, lossy);
                    int nCompleted = 0;
                    var options    = new ParallelOptions {
                        MaxDegreeOfParallelism = Environment.ProcessorCount
                    };

                    Parallel.For(0, count, options, i =>
                    {
                        string file = files.ElementAt(i);

                        // Don't process if file has been fully optimized already
                        if (cache.IsFullyOptimized(file))
                        {
                            var bogus = new CompressionResult(file, file, TimeSpan.Zero)
                            {
                                Processed = false
                            };
                            HandleResult(bogus, nCompleted + 1);
                        }
                        else
                        {
                            CompressionResult result = compressor.CompressFile(file, lossy);
                            HandleResult(result, nCompleted + 1);

                            if (result.Saving > 0 && result.ResultFileSize > 0 && !string.IsNullOrEmpty(result.ResultFileName))
                            {
                                list[i] = result;
                            }
                            else
                            {
                                cache.AddToCache(file);
                            }
                        }

                        Interlocked.Increment(ref nCompleted);
                    });
                }
                finally
                {
                    _dte.StatusBar.Progress(false);
                    stopwatch.Stop();
                    await DisplayEndResultAsync(list, stopwatch.Elapsed);
                    _isProcessing = false;
                }
            });
        }
        private async void OptimizeImageAsync(bool lossy)
        {
            _isProcessing = true;

            IEnumerable <string> files = ProjectHelpers.GetSelectedFilePaths(_dte).Where(f => Compressor.IsFileSupported(f));

            if (!files.Any())
            {
                _dte.StatusBar.Text = "No images found to optimize";
                _isProcessing       = false;
                return;
            }

            var list      = new CompressionResult[files.Count()];
            var stopwatch = Stopwatch.StartNew();
            int count     = files.Count();

            await Task.Run(async() =>
            {
                try
                {
                    string text = count == 1 ? " image" : " images";
                    _dte.StatusBar.Progress(true, "Optimizing " + count + text + "...", AmountCompleted: 1, Total: count + 1);

                    var compressor = new Compressor();
                    var cache      = new Cache(_dte.Solution, lossy);
                    int nCompleted = 0;
                    var options    = new ParallelOptions {
                        MaxDegreeOfParallelism = Environment.ProcessorCount
                    };

                    Parallel.For(0, count, options, i =>
                    {
                        string file = files.ElementAt(i);

                        // Don't process if file has been fully optimized already
                        if (cache.IsFullyOptimized(file))
                        {
                            var bogus = new CompressionResult(file, file, TimeSpan.Zero)
                            {
                                Processed = false
                            };
                            HandleResult(bogus, nCompleted + 1);
                        }
                        else
                        {
                            CompressionResult result = compressor.CompressFileAsync(file, lossy);
                            HandleResult(result, nCompleted + 1);

                            if (result.Saving > 0 && result.ResultFileSize > 0 && !string.IsNullOrEmpty(result.ResultFileName))
                            {
                                list[i] = result;
                            }
                            else
                            {
                                cache.AddToCache(file);
                            }
                        }

                        Interlocked.Increment(ref nCompleted);
                    });
                }
                finally
                {
                    _dte.StatusBar.Progress(false);
                    stopwatch.Stop();
                    await DisplayEndResultAsync(list, stopwatch.Elapsed);
                    _isProcessing = false;
                }
            });
        }