context: using System;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Linq;
  using System.Text;
  using System.Web;
  using System.Web.Mvc;
  using System.Web.Routing;
  using System.Xml;
  using System.Xml.Linq;
  using Newtonsoft.Json;
  using SmartStore.Collections;
  using SmartStore.Core.Caching;
  using SmartStore.Core.Data;
  using SmartStore.Core.Domain.Catalog;
  using SmartStore.Services.Localization;
  
  namespace SmartStore.Services.Catalog
  {
      /// <summary>
      /// Product attribute parser
      /// </summary>
      public partial class ProductAttributeParser : IProductAttributeParser
      {
  		// 0 = ProductId, 1 = AttributeXml Hash
  		private const string ATTRIBUTECOMBINATION_BY_ID_HASH = "SmartStore.parsedattributecombination.id-{0}-{1}";
  
  		private readonly IProductAttributeService _productAttributeService;
  		private readonly IRepository<ProductVariantAttributeCombination> _pvacRepository;
  		private readonly ICacheManager _cacheManager;
  
  		public ProductAttributeParser(
  			IProductAttributeService productAttributeService,
  			IRepository<ProductVariantAttributeCombination> pvacRepository,
  			ICacheManager cacheManager)
          {
              _productAttributeService = productAttributeService;
  			_pvacRepository = pvacRepository;
  			_cacheManager = cacheManager;
          }
  
  		#region Product attributes
  
  		/// <summary>
          /// Gets selected product variant attribute identifiers
          /// </summary>
          /// <param name="attributesXml">Attributes</param>
          /// <returns>Selected product variant attribute identifiers</returns>
          private IEnumerable<int> ParseProductVariantAttributeIds(string attributesXml)
          {
              var ids = new List<int>();
              if (String.IsNullOrEmpty(attributesXml))
                  yield break;
  
              try
              {
                  var xmlDoc = new XmlDocument();
                  xmlDoc.LoadXml(attributesXml);
  
                  var nodeList = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute");
                  foreach (var node in nodeList.Cast<XmlElement>())
                  {
                      string sid = node.GetAttribute("ID").Trim();
                      if (sid.HasValue())
                      {
                          int id = 0;
                          if (int.TryParse(sid, out id))
                          {
                              yield return id;
                          }
                      }
                  }
              }
              finally { }
          }
  
  		//public virtual Multimap<int, string> DeserializeProductVariantAttributes(string attributesXml)
  		//{
  		//    var attrs = new Multimap<int, string>();
  		//    if (String.IsNullOrEmpty(attributesXml))
  		//        return attrs;
  
  		//    try
  		//    {
  		//        var xmlDoc = new XmlDocument();
  		//        xmlDoc.LoadXml(attributesXml);
  
  		//        var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute");
  		//        foreach (var node1 in nodeList1.Cast<XmlElement>())
  		//        {
  		//            string sid = node1.GetAttribute("ID").Trim();
  		//            if (sid.HasValue())
  		//            {
  		//                int id = 0;
  		//                if (int.TryParse(sid, out id))
  		//                {
  
  		//                    var nodeList2 = node1.SelectNodes(@"ProductVariantAttributeValue/Value").Cast<XmlElement>();
  		//                    foreach (var node2 in nodeList2)
  		//                    {
  		//                        string value = node2.InnerText.Trim();
  		//                        attrs.Add(id, value);
  		//                    }
  		//                }
  		//            }
  		//        }
  		//    }
  		//    catch (Exception exc)
  		//    {
  		//        Debug.Write(exc.ToString());
  		//    }
  
  		//    return attrs;
  		//}
  
  		public virtual Multimap<int, string> DeserializeProductVariantAttributes(string attributesXml)
  		{
  			var attrs = new Multimap<int, string>();
  			if (String.IsNullOrEmpty(attributesXml))
  				return attrs;
  
  			try
  			{
  				var doc = XDocument.Parse(attributesXml);
  
  				// Attributes/ProductVariantAttribute
  				foreach (var node1 in doc.Descendants("ProductVariantAttribute"))
  				{
  					string sid = node1.Attribute("ID").Value;
  					if (sid.HasValue())
  					{
  						int id = 0;
  						if (int.TryParse(sid, out id))
  						{
  							// ProductVariantAttributeValue/Value
  							foreach (var node2 in node1.Descendants("Value"))
  							{
  								attrs.Add(id, node2.Value);
  							}
  						}
  					}
  				}
  			}
  			catch (Exception exc)
  			{
  				Debug.Write(exc.ToString());
  			}
  
  			return attrs;
  		}
  
  		/// <summary>
  		/// Gets selected product variant attributes
  		/// </summary>
  		/// <param name="attributesXml">Attributes</param>
  		/// <returns>Selected product variant attributes</returns>
  		public virtual IList<ProductVariantAttribute> ParseProductVariantAttributes(string attributesXml)
  		{
  			var ids = ParseProductVariantAttributeIds(attributesXml);
  
  			return _productAttributeService.GetProductVariantAttributesByIds(ids.ToList());
  		}
  
          public virtual IEnumerable<ProductVariantAttributeValue> ParseProductVariantAttributeValues(string attributeXml)
          {
              //var pvaValues = Enumerable.Empty<ProductVariantAttributeValue>();
  
  			var allIds = new List<int>();
              var attrs = DeserializeProductVariantAttributes(attributeXml);
  			var pvaCollection = _productAttributeService.GetProductVariantAttributesByIds(attrs.Keys);
  
              foreach (var pva in pvaCollection)
              {
                  if (!pva.ShouldHaveValues())
                      continue;
  
                  var pvaValuesStr = attrs[pva.Id];
  
                  var ids =
  					from id in pvaValuesStr
  					where id.HasValue()
  					select id.ToInt();
  
  				allIds.AddRange(ids);
  
                  //var values = _productAttributeService.GetProductVariantAttributeValuesByIds(ids.ToArray());
                  //pvaValues = pvaValues.Concat(values);
              }
  
  			int[] allDistinctIds = allIds.Distinct().ToArray();
  
  			var values = _productAttributeService.GetProductVariantAttributeValuesByIds(allDistinctIds);
  
              return values;
          }
  
  		public IList<string> ParseProductVariantAttributeValues(string attributesXml, IEnumerable<ProductVariantAttribute> attributes, int languageId = 0)
  		{
  			var values = new List<string>();
  
  			if (attributesXml.IsEmpty())
  				return values;
  
  			var allValueIds = new List<int>();
  			var combinedAttributes = DeserializeProductVariantAttributes(attributesXml);
  
  			foreach (var pva in attributes.Where(x => x.ShouldHaveValues()).OrderBy(x => x.DisplayOrder))
  			{
  				if (combinedAttributes.ContainsKey(pva.Id))
  				{
  					var pvaValuesStr = combinedAttributes[pva.Id];
  					var ids = pvaValuesStr.Where(x => x.HasValue()).Select(x => x.ToInt());
  
  					allValueIds.AddRange(ids);
  				}
  			}
  
  			foreach (int id in allValueIds.Distinct())
  			{
  				foreach (var attribute in attributes)
  				{
  					var attributeValue = attribute.ProductVariantAttributeValues.FirstOrDefault(x => x.Id == id);
  					if (attributeValue != null)
  					{
  						var value = attributeValue.GetLocalized(x => x.Name, languageId, true, false);
  
  						if (!values.Any(x => x.IsCaseInsensitiveEqual(value)))
  							values.Add(value);
  						break;
  					}
  				}
  			}
  
  			return values;
  		}
  
  
          /// <summary>
          /// Gets selected product variant attribute value
          /// </summary>
          /// <param name="attributesXml">Attributes</param>
          /// <param name="productVariantAttributeId">Product variant attribute identifier</param>
          /// <returns>Product variant attribute value</returns>
          public virtual IList<string> ParseValues(string attributesXml, int productVariantAttributeId)
          {
              var selectedProductVariantAttributeValues = new List<string>();
              try
              {
                  var xmlDoc = new XmlDocument();
                  xmlDoc.LoadXml(attributesXml);
  
                  var nodeList1 = xmlDoc.SelectNodes(@"//Attributes/ProductVariantAttribute");
                  foreach (XmlNode node1 in nodeList1)
                  {
                      if (node1.Attributes != null && node1.Attributes["ID"] != null)
                      {
                          string str1 = node1.Attributes["ID"].InnerText.Trim();
                          int id = 0;
                          if (int.TryParse(str1, out id))
                          {
                              if (id == productVariantAttributeId)
                              {
                                  var nodeList2 = node1.SelectNodes(@"ProductVariantAttributeValue/Value");
                                  foreach (XmlNode node2 in nodeList2)
                                  {
                                      string value = node2.InnerText.Trim();
                                      selectedProductVariantAttributeValues.Add(value);
                                  }
                              }
                          }
                      }
                  }
              }
              catch (Exception exc)
              {
                  Debug.Write(exc.ToString());
              }
  
              return selectedProductVariantAttributeValues;
          }
  
          /// <summary>
          /// Adds an attribute
          /// </summary>
          /// <param name="attributesXml">Attributes</param>
          /// <param name="pva">Product variant attribute</param>
          /// <param name="value">Value</param>
          /// <returns>Attributes</returns>
          public virtual string AddProductAttribute(string attributesXml, ProductVariantAttribute pva, string value)
          {
  
gt: 			return pva.AddProductAttribute(attributesXml, value);