context: using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Linq.Expressions;
  using System.Reflection;
  using SmartStore.Core;
  using SmartStore.Core.Caching;
  using SmartStore.Core.Data;
  using SmartStore.Core.Domain.Localization;
  
  namespace SmartStore.Services.Localization
  {
      /// <summary>
      /// Provides information about localizable entities
      /// </summary>
      public partial class LocalizedEntityService : ILocalizedEntityService
      {
          #region Constants
  
          private const string LOCALIZEDPROPERTY_KEY = "SmartStore.localizedproperty.value-{0}-{1}-{2}-{3}";
          private const string LOCALIZEDPROPERTY_ENTITYID_KEY = "SmartStore.localizedproperty.entityid-{0}-{1}-{2}";
          private const string LOCALIZEDPROPERTY_PATTERN_KEY = "SmartStore.localizedproperty.";
  
          #endregion
  
          #region Fields
  
          private readonly IRepository<LocalizedProperty> _localizedPropertyRepository;
          private readonly ICacheManager _cacheManager;
  
          #endregion
  
          #region Ctor
  
          /// <summary>
          /// Ctor
          /// </summary>
          /// <param name="cacheManager">Cache manager</param>
          /// <param name="localizedPropertyRepository">Localized property repository</param>
          public LocalizedEntityService(ICacheManager cacheManager,
              IRepository<LocalizedProperty> localizedPropertyRepository)
          {
              this._cacheManager = cacheManager;
              this._localizedPropertyRepository = localizedPropertyRepository;
          }
  
          #endregion
  
          #region Methods
  
          /// <summary>
          /// Deletes a localized property
          /// </summary>
          /// <param name="localizedProperty">Localized property</param>
          public virtual void DeleteLocalizedProperty(LocalizedProperty localizedProperty)
          {
              if (localizedProperty == null)
                  throw new ArgumentNullException("localizedProperty");
  
              _localizedPropertyRepository.Delete(localizedProperty);
  
              //cache
              _cacheManager.RemoveByPattern(LOCALIZEDPROPERTY_PATTERN_KEY);
          }
  
          /// <summary>
          /// Gets a localized property
          /// </summary>
          /// <param name="localizedPropertyId">Localized property identifier</param>
          /// <returns>Localized property</returns>
          public virtual LocalizedProperty GetLocalizedPropertyById(int localizedPropertyId)
          {
              if (localizedPropertyId == 0)
                  return null;
  
              var localizedProperty = _localizedPropertyRepository.GetById(localizedPropertyId);
              return localizedProperty;
          }
  
          /// <summary>
          /// Find localized value
          /// </summary>
          /// <param name="languageId">Language identifier</param>
          /// <param name="entityId">Entity identifier</param>
          /// <param name="localeKeyGroup">Locale key group</param>
          /// <param name="localeKey">Locale key</param>
          /// <returns>Found localized value</returns>
          public virtual string GetLocalizedValue(int languageId, int entityId, string localeKeyGroup, string localeKey)
          {
              string key = string.Format(LOCALIZEDPROPERTY_KEY, languageId, entityId, localeKeyGroup, localeKey);
              return _cacheManager.Get(key, () =>
              {
                  var query = from lp in _localizedPropertyRepository.Table
                              where lp.LanguageId == languageId &&
                              lp.EntityId == entityId &&
                              lp.LocaleKeyGroup == localeKeyGroup &&
                              lp.LocaleKey == localeKey
                              select lp.LocaleValue;
                  var localeValue = query.FirstOrDefault();
                  //little hack here. nulls aren't cacheable so set it to ""
                  if (localeValue == null)
                      localeValue = "";
                  return localeValue;
              });
          }
  
          /// <summary>
          /// Find localized values
          /// </summary>
          /// <param name="localeKeyGroup">Locale key group</param>
          /// <param name="localeKey">Locale key</param>
          /// <param name="localeValue">Locale key</param>
          /// <returns>Found localized values</returns>
          public virtual int GetEntityIdByLocalizedValue(string localeKeyGroup, string localeKey, string localeValue)
          {
              string key = string.Format(LOCALIZEDPROPERTY_ENTITYID_KEY, localeKeyGroup, localeKey, localeValue);
              return _cacheManager.Get(key, () =>
              {
                  var query = from lp in _localizedPropertyRepository.Table
                              where lp.LocaleKeyGroup == localeKeyGroup &&
                              lp.LocaleKey == localeKey &&
                              lp.LocaleValue == localeValue
                              select lp.EntityId;
                  var result = query.FirstOrDefault();
                  return result;
              });
          }
  
          /// <summary>
          /// Gets localized properties
          /// </summary>
          /// <param name="entityId">Entity identifier</param>
          /// <param name="localeKeyGroup">Locale key group</param>
          /// <returns>Localized properties</returns>
          public virtual IList<LocalizedProperty> GetLocalizedProperties(int entityId, string localeKeyGroup)
          {
              if (string.IsNullOrEmpty(localeKeyGroup))
                  return new List<LocalizedProperty>();
  
              var query = from lp in _localizedPropertyRepository.Table
                          orderby lp.Id
                          where lp.EntityId == entityId &&
                                lp.LocaleKeyGroup == localeKeyGroup
                          select lp;
              var props = query.ToList();
              return props;
          }
  
          /// <summary>
          /// Inserts a localized property
          /// </summary>
          /// <param name="localizedProperty">Localized property</param>
          public virtual void InsertLocalizedProperty(LocalizedProperty localizedProperty)
          {
              if (localizedProperty == null)
                  throw new ArgumentNullException("localizedProperty");
  
              _localizedPropertyRepository.Insert(localizedProperty);
  
              //cache
              _cacheManager.RemoveByPattern(LOCALIZEDPROPERTY_PATTERN_KEY);
          }
  
          /// <summary>
          /// Updates the localized property
          /// </summary>
          /// <param name="localizedProperty">Localized property</param>
          public virtual void UpdateLocalizedProperty(LocalizedProperty localizedProperty)
          {
              if (localizedProperty == null)
                  throw new ArgumentNullException("localizedProperty");
  
              _localizedPropertyRepository.Update(localizedProperty);
  
              //cache
              _cacheManager.RemoveByPattern(LOCALIZEDPROPERTY_PATTERN_KEY);
          }
  
          /// <summary>
          /// Save localized value
          /// </summary>
          /// <typeparam name="T">Type</typeparam>
          /// <param name="entity">Entity</param>
          /// <param name="keySelector">Key selector</param>
          /// <param name="localeValue">Locale value</param>
          /// <param name="languageId">Language ID</param>
          public virtual void SaveLocalizedValue<T>(T entity,
              Expression<Func<T, string>> keySelector,
              string localeValue,
              int languageId) where T : BaseEntity, ILocalizedEntity
          {
              SaveLocalizedValue<T, string>(entity, keySelector, localeValue, languageId);
          }
  
          public virtual void SaveLocalizedValue<T, TPropType>(T entity,
              Expression<Func<T, TPropType>> keySelector,
              TPropType localeValue,
              int languageId) where T : BaseEntity, ILocalizedEntity
          {
              if (entity == null)
                  throw new ArgumentNullException("entity");
  
              if (languageId == 0)
                  throw new ArgumentOutOfRangeException("languageId", "Language ID should not be 0");
  
              var member = keySelector.Body as MemberExpression;
              if (member == null)
              {
                  throw new ArgumentException(string.Format(
                      "Expression '{0}' refers to a method, not a property.",
                      keySelector));
              }
  
              var propInfo = member.Member as PropertyInfo;
  
gt:             if (propInfo == null)