context: using System;
  using System.Collections.Generic;
  using System.Drawing;
  using System.IO;
  using System.Linq;
  using System.Threading;
  using ImageResizer;
  using Nop.Core;
  using Nop.Core.Data;
  using Nop.Core.Domain.Catalog;
  using Nop.Core.Domain.Media;
  using Nop.Data;
  using Nop.Services.Configuration;
  using Nop.Services.Events;
  using Nop.Services.Logging;
  using Nop.Services.Seo;
  
  namespace Nop.Services.Media
  {
      /// <summary>
      /// Picture service
      /// </summary>
      public partial class PictureService : IPictureService
      {
          #region Const
  
          private const int MULTIPLE_THUMB_DIRECTORIES_LENGTH = 3;
  
          #endregion
  
          #region Fields
  
          private static readonly object s_lock = new object();
  
          private readonly IRepository<Picture> _pictureRepository;
          private readonly IRepository<ProductPicture> _productPictureRepository;
          private readonly ISettingService _settingService;
          private readonly IWebHelper _webHelper;
          private readonly ILogger _logger;
          private readonly IDbContext _dbContext;
          private readonly IEventPublisher _eventPublisher;
          private readonly MediaSettings _mediaSettings;
          private readonly IDataProvider _dataProvider;
  
          #endregion
  
          #region Ctor
  
          /// <summary>
          /// Ctor
          /// </summary>
          /// <param name="pictureRepository">Picture repository</param>
          /// <param name="productPictureRepository">Product picture repository</param>
          /// <param name="settingService">Setting service</param>
          /// <param name="webHelper">Web helper</param>
          /// <param name="logger">Logger</param>
          /// <param name="dbContext">Database context</param>
          /// <param name="eventPublisher">Event publisher</param>
          /// <param name="mediaSettings">Media settings</param>
          /// <param name="dataProvider">Data provider</param>
          public PictureService(IRepository<Picture> pictureRepository,
              IRepository<ProductPicture> productPictureRepository,
              ISettingService settingService,
              IWebHelper webHelper,
              ILogger logger,
              IDbContext dbContext,
              IEventPublisher eventPublisher,
              MediaSettings mediaSettings,
              IDataProvider dataProvider)
          {
              this._pictureRepository = pictureRepository;
              this._productPictureRepository = productPictureRepository;
              this._settingService = settingService;
              this._webHelper = webHelper;
              this._logger = logger;
              this._dbContext = dbContext;
              this._eventPublisher = eventPublisher;
              this._mediaSettings = mediaSettings;
              this._dataProvider = dataProvider;
          }
  
          #endregion
  
          #region Utilities
  
          /// <summary>
          /// Calculates picture dimensions whilst maintaining aspect
          /// </summary>
          /// <param name="originalSize">The original picture size</param>
          /// <param name="targetSize">The target picture size (longest side)</param>
          /// <param name="resizeType">Resize type</param>
          /// <param name="ensureSizePositive">A value indicatingh whether we should ensure that size values are positive</param>
          /// <returns></returns>
          protected virtual Size CalculateDimensions(Size originalSize, int targetSize,
              ResizeType resizeType = ResizeType.LongestSide, bool ensureSizePositive = true)
          {
              float width, height;
  
              switch (resizeType)
              {
                  case ResizeType.LongestSide:
                      if (originalSize.Height > originalSize.Width)
                      {
                          // portrait
                          width = originalSize.Width * (targetSize / (float)originalSize.Height);
                          height = targetSize;
                      }
                      else
                      {
                          // landscape or square
                          width = targetSize;
                          height = originalSize.Height * (targetSize / (float) originalSize.Width);
                      }
                      break;
                  case ResizeType.Width:
                      width = targetSize;
                      height = originalSize.Height * (targetSize / (float)originalSize.Width);
                      break;
                  case ResizeType.Height:
                      width = originalSize.Width * (targetSize / (float)originalSize.Height);
                      height = targetSize;
                      break;
                  default:
                      throw new Exception("Not supported ResizeType");
              }
  
              if (ensureSizePositive)
              {
                  if (width < 1)
                      width = 1;
                  if (height < 1)
                      height = 1;
              }
  
              //we invoke Math.Round to ensure that no white background is rendered - http://www.nopcommerce.com/boards/t/40616/image-resizing-bug.aspx
              return new Size((int)Math.Round(width), (int)Math.Round(height));
          }
  
          /// <summary>
          /// Returns the file extension from mime type.
          /// </summary>
          /// <param name="mimeType">Mime type</param>
          /// <returns>File extension</returns>
          protected virtual string GetFileExtensionFromMimeType(string mimeType)
          {
              if (mimeType == null)
                  return null;
  
              //also see System.Web.MimeMapping for more mime types
  
              string[] parts = mimeType.Split('/');
              string lastPart = parts[parts.Length - 1];
              switch (lastPart)
              {
                  case "pjpeg":
                      lastPart = "jpg";
                      break;
                  case "x-png":
                      lastPart = "png";
                      break;
                  case "x-icon":
                      lastPart = "ico";
                      break;
              }
              return lastPart;
          }
  
          /// <summary>
          /// Loads a picture from file
          /// </summary>
          /// <param name="pictureId">Picture identifier</param>
          /// <param name="mimeType">MIME type</param>
          /// <returns>Picture binary</returns>
          protected virtual byte[] LoadPictureFromFile(int pictureId, string mimeType)
          {
              string lastPart = GetFileExtensionFromMimeType(mimeType);
              string fileName = string.Format("{0}_0.{1}", pictureId.ToString("0000000"), lastPart);
              var filePath = GetPictureLocalPath(fileName);
              if (!File.Exists(filePath))
                  return new byte[0];
              return File.ReadAllBytes(filePath);
          }
  
          /// <summary>
          /// Save picture on file system
          /// </summary>
          /// <param name="pictureId">Picture identifier</param>
          /// <param name="pictureBinary">Picture binary</param>
          /// <param name="mimeType">MIME type</param>
          protected virtual void SavePictureInFile(int pictureId, byte[] pictureBinary, string mimeType)
          {
              string lastPart = GetFileExtensionFromMimeType(mimeType);
              string fileName = string.Format("{0}_0.{1}", pictureId.ToString("0000000"), lastPart);
              File.WriteAllBytes(GetPictureLocalPath(fileName), pictureBinary);
          }
  
          /// <summary>
          /// Delete a picture on file system
          /// </summary>
          /// <param name="picture">Picture</param>
          protected virtual void DeletePictureOnFileSystem(Picture picture)
          {
              if (picture == null)
                  throw new ArgumentNullException("picture");
  
              string lastPart = GetFileExtensionFromMimeType(picture.MimeType);
              string fileName = string.Format("{0}_0.{1}", picture.Id.ToString("0000000"), lastPart);
              string filePath = GetPictureLocalPath(fileName);
              if (File.Exists(filePath))
              {
                  File.Delete(filePath);
              }
          }
  
          /// <summary>
          /// Delete picture thumbs
          /// </summary>
          /// <param name="picture">Picture</param>
          protected virtual void DeletePictureThumbs(Picture picture)
          {
              string filter = string.Format("{0}*.*", picture.Id.ToString("0000000"));
              var thumbDirectoryPath = CommonHelper.MapPath("~/content/images/thumbs");
              string[] currentFiles = System.IO.Directory.GetFiles(thumbDirectoryPath, filter, SearchOption.AllDirectories);
              foreach (string currentFileName in currentFiles)
              {
                  var thumbFilePath = GetThumbLocalPath(currentFileName);
                  File.Delete(thumbFilePath);
              }
          }
  
          /// <summary>
          /// Get picture (thumb) local path
          /// </summary>
          /// <param name="thumbFileName">Filename</param>
          /// <returns>Local picture thumb path</returns>
          protected virtual string GetThumbLocalPath(string thumbFileName)
          {
              var thumbsDirectoryPath = CommonHelper.MapPath("~/content/images/thumbs");
              if (_mediaSettings.MultipleThumbDirectories)
              {
                  //get the first two letters of the file name
                  var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(thumbFileName);
                  if (fileNameWithoutExtension != null && fileNameWithoutExtension.Length > MULTIPLE_THUMB_DIRECTORIES_LENGTH)
                  {
                      var subDirectoryName = fileNameWithoutExtension.Substring(0, MULTIPLE_THUMB_DIRECTORIES_LENGTH);
                      thumbsDirectoryPath = Path.Combine(thumbsDirectoryPath, subDirectoryName);
                      if (!System.IO.Directory.Exists(thumbsDirectoryPath))
                      {
                          System.IO.Directory.CreateDirectory(thumbsDirectoryPath);
                      }
                  }
              }
              var thumbFilePath = Path.Combine(thumbsDirectoryPath, thumbFileName);
              return thumbFilePath;
          }
  
          /// <summary>
          /// Get picture (thumb) URL 
          /// </summary>
          /// <param name="thumbFileName">Filename</param>
          /// <param name="storeLocation">Store location URL; null to use determine the current store location automatically</param>
          /// <returns>Local picture thumb path</returns>
          protected virtual string GetThumbUrl(string thumbFileName, string storeLocation = null)
          {
  
gt:             storeLocation = !String.IsNullOrEmpty(storeLocation)