public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (_skipControllers.Any(x => filterContext.ActionDescriptor.ControllerDescriptor.ControllerType == x))
            {
                return;
            }
            var context = filterContext.HttpContext;

            // don't 'rewrite' POST requests, child action and ajax requests
            if (context.Request.RequestType != "GET" || filterContext.IsChildAction || context.Request.IsAjaxRequest())
            {
                return;
            }

            if (context.Request.Url != null)
            {
                var baseUri = string.Format(
                    "{0}://{1}{2}",
                    context.Request.Url.Scheme,
                    context.Request.Url.Host,
                    context.Request.Url.Port == 80 ? "" : ":" + context.Request.Url.Port);

                var path = HttpUtility.UrlDecode(string.Concat(baseUri, context.Request.Url.AbsolutePath));

                if (!string.IsNullOrEmpty(path))
                {
                    var query = HttpUtility.UrlDecode(context.Request.Url.Query);
                    var queryString = context.Request.QueryString;
                    var needRedirect = false;

                        //Make sure we allways use same virtual path as Route provides
                        var routePath = filterContext.RouteData.Route.GetVirtualPath(filterContext.RequestContext,
                            filterContext.RouteData.Values);

                        if (routePath != null && !string.IsNullOrEmpty(routePath.VirtualPath))
                        {
                            var absoluteRoutePath = HttpUtility.UrlDecode(string.Concat(baseUri, context.Request.ApplicationPath, context.Request.ApplicationPath != "/" ? "/" : "", routePath.VirtualPath));

                            if (!string.IsNullOrEmpty(absoluteRoutePath) && !absoluteRoutePath.Equals(path, StringComparison.InvariantCultureIgnoreCase))
                            {
                                path = absoluteRoutePath;
                                needRedirect = true;
                            }
                        }

                        //Process query string
                        if (!string.IsNullOrEmpty(query))
                        {
                            //Rebuild querystring from scratch
                            var newQuery = string.Empty;

                            //First goes search filter ordered based on document
                            var helper = new SearchHelper(StoreHelper.StoreClient.GetCurrentStore());
                            var urlHelper = new UrlHelper(context.Request.RequestContext);

                            var parameters = helper.Filters.Where(f => !(f is PriceRangeFilter) || ((PriceRangeFilter)f).Currency.Equals(StoreHelper.CustomerSession.Currency, StringComparison.OrdinalIgnoreCase))
                                .Select(filter => queryString.AllKeys
                                .FirstOrDefault(k => k.Equals(urlHelper.GetFacetKey(filter.Key), StringComparison.InvariantCultureIgnoreCase)))
                                .Where(key => !string.IsNullOrEmpty(key))
                                .ToDictionary<string, string, object>(key => key, key => queryString[key]);

                            if (parameters.Any())
                            {
                                newQuery = urlHelper.SetQueryParameters(newQuery, parameters);
                            }

                            //Order remaining parameters
                            var otherParams = queryString.AllKeys.Where(key => !parameters.ContainsKey(key)).OrderBy(k => k)
                                .ToDictionary<string, string, object>(key => key, key => queryString[key]);

                            if (otherParams.Any())
                            {
                                newQuery = urlHelper.SetQueryParameters(newQuery, otherParams);
                            }

                            if (!string.IsNullOrEmpty(newQuery) && !newQuery.StartsWith("?"))
                            {
                                newQuery = string.Concat("?", newQuery);
                            }

                            newQuery = HttpUtility.UrlDecode(newQuery);

                            if (!string.Equals(query, newQuery, StringComparison.InvariantCultureIgnoreCase))
                            {
                                query = newQuery;
                                needRedirect = true;
                            }
                        }

                      
                        //make language code allways be five symbols
                        if (filterContext.RouteData.Values.ContainsKey(Routing.Constants.Language) &&
                            filterContext.RouteData.Values[Routing.Constants.Language] as string != null)
                        {
                            var lang = filterContext.RouteData.Values[Routing.Constants.Language].ToString();
                            if (lang.Length < 5)
                            {
                                try
                                {
                                    var cult = CultureInfo.CreateSpecificCulture(lang);
                                    if (!path.ToLowerInvariant().Contains(cult.Name.ToLowerInvariant()))
                                    {
                                        path = path.Replace(lang, cult.Name);
                                        needRedirect = true;
                                    }
                                }
                                catch
                                {
                                    //Something wrong with language??
                                }
                            }
                        }

                        //make path segments allways encoded
                        var encodedPath = path;
                        encodedPath = ProcessSegment(filterContext.RouteData.Values, encodedPath, Routing.Constants.Store);
                        encodedPath = ProcessSegment(filterContext.RouteData.Values, encodedPath, Routing.Constants.Category);
                        encodedPath = ProcessSegment(filterContext.RouteData.Values, encodedPath, Routing.Constants.Item);

                        // check for any upper-case letters:
                        if (path != encodedPath.ToLowerInvariant())
                        {
                            path = encodedPath.ToLowerInvariant();
                            needRedirect = true;
                        }

                        // make sure request ends with a "/"
                        if (path.EndsWith("/"))
                        {
                            needRedirect = true;
                        }
                    

                    if (needRedirect)
                    {
                        Redirect(context, path, query);
                        return;
                    }
                }
            }

            base.OnActionExecuting(filterContext);

        }
        /// <summary>
        /// Gets the description from filter.
        /// </summary>
        /// <param name="helper">The helper.</param>
        /// <param name="key">The key.</param>
        /// <returns>
        /// System.String.
        /// </returns>
		private static string GetDescriptionFromFilter(SearchHelper helper, string key)
		{
            var name = helper.CatalogClient.GetPropertyName(key);
			return key.Equals("price", StringComparison.OrdinalIgnoreCase) ? "Price".Localize() : !string.IsNullOrEmpty(name) ? name : key;
		}
        /// <summary>
        /// Gets the description from filter value.
        /// </summary>
        /// <param name="helper">The helper.</param>
        /// <param name="key">The key.</param>
        /// <param name="id">The identifier.</param>
        /// <returns>
        /// System.String.
        /// </returns>
        private static string GetDescriptionFromFilterValue(SearchHelper helper, string key, string id)
		{
			var desc = String.Empty;

            var d = (from f in helper.Filters where f.Key.Equals(key, StringComparison.OrdinalIgnoreCase) && 
                         (f as PriceRangeFilter == null || 
                         ((PriceRangeFilter)f).Currency.Equals(helper.CatalogClient.CustomerSession.Currency, StringComparison.OrdinalIgnoreCase)) 
                     select f).SingleOrDefault();

			if (d != null)
			{
                var val = (from v in helper.GetFilterValues(d) where v.Id.Equals(id, StringComparison.OrdinalIgnoreCase) select v).SingleOrDefault();
				if (val != null)
				{
                    desc = Convert(helper, val).Name;
				}
			}

			return desc;
		}
        /// <summary>
        /// Creates the data model.
        /// </summary>
        /// <param name="criteria">The criteria.</param>
        /// <param name="parameters">The parameters.</param>
        /// <param name="cacheResults">if set to <c>true</c> [cache results].</param>
        /// <returns>CatalogItemSearchModel.</returns>
        private CatalogItemSearchModel CreateDataModel(CatalogItemSearchCriteria criteria, SearchParameters parameters,
                                                       bool cacheResults)
        {
            var session = UserHelper.CustomerSession;

            // Create a model
            var dataSource = new CatalogItemSearchModel();

            // Now fill in filters
            var searchHelper = new SearchHelper(_storeClient.GetCurrentStore());

            var filters = searchHelper.Filters;

            // Add all filters
            foreach (var filter in filters)
            {
                // Check if we already filtering
                if (parameters.Facets.Keys.Any(k => filter.Key.Equals(k, StringComparison.OrdinalIgnoreCase)))
                    continue;

                criteria.Add(filter);
            }

            // Get selected filters
            var facets = parameters.Facets;
            dataSource.SelectedFilters = new List<SelectedFilterModel>();
            if (facets.Count != 0)
            {
                foreach (var key in facets.Keys)
                {
                    var filter = filters.SingleOrDefault(x => x.Key.Equals(key, StringComparison.OrdinalIgnoreCase)
                        && (!(x is PriceRangeFilter) || ((PriceRangeFilter)x).Currency.Equals(StoreHelper.CustomerSession.Currency, StringComparison.OrdinalIgnoreCase)));
                    var val =
                        (from v in searchHelper.GetFilterValues(filter) where v.Id == facets[key] select v)
                            .SingleOrDefault();
                    if (val != null)
                    {
                        criteria.Add(filter, val);
                        dataSource.SelectedFilters.Add(new SelectedFilterModel(searchHelper.Convert(filter),
                                                                               searchHelper.Convert(val)));
                    }
                }
            }

            // Perform search
            var sort = string.IsNullOrEmpty(parameters.Sort) ? "position" : parameters.Sort;
            var sortOrder = parameters.SortOrder;

            bool isDescending = "desc".Equals(sortOrder, StringComparison.OrdinalIgnoreCase);

            SearchSort sortObject = null;

            if (!sort.Equals("position", StringComparison.OrdinalIgnoreCase))
            {
                if (sort.Equals("price", StringComparison.OrdinalIgnoreCase))
                {
                    if (session.Pricelists != null)
                    {
                        sortObject = new SearchSort(session.Pricelists.Select(priceList =>
                            new SearchSortField(
                                String.Format("price_{0}_{1}",
                                    criteria.Currency.ToLower(),
                                    priceList.ToLower()))
                            {
                                IgnoredUnmapped = true,
                                IsDescending = isDescending,
                                DataType = SearchSortField.DOUBLE
                            })
                            .ToArray());
                    }
                }
                else
                {
                    sortObject = new SearchSort(sort.ToLower(), isDescending);
                }
            }

            // Put default sort order if none is set
            if (sortObject == null)
            {
                sortObject = CatalogItemSearchCriteria.DefaultSortOrder;
            }

            criteria.Sort = sortObject;
            CatalogItemSearchResults results;
            // Search using criteria, it will only return IDs of the items
            var items = Search(criteria, cacheResults, out results).ToArray();
            var itemsIdsArray = items.Select(i => i.ItemId).ToArray();

            // Now load items with appropriate 
            var itemModelList = new List<CatalogItemWithPriceModel>();
            if (items.Any())
            {

                // Now convert it to the model

                var prices = _priceListClient.GetLowestPrices(session.Pricelists, itemsIdsArray, 1);
                var availabilities = _catalogClient.GetItemAvailability(itemsIdsArray,
                                                   UserHelper.StoreClient.GetCurrentStore().FulfillmentCenterId);

                foreach (var item in items)
                {
                    PriceModel priceModel = null;
                    ItemAvailabilityModel availabilityModel = null;
                    var catalogIdPath = UserHelper.CustomerSession.CatalogId + "/";
                    var searchTags = results.Items[item.ItemId.ToLower()].ToPropertyDictionary();

                    //Cache outline
                    HttpContext.Items["browsingoutline_" + item.Code.ToLower()] = searchTags[criteria.BrowsingOutlineField].ToString();
                    var currentOutline = searchTags[criteria.OutlineField].ToString().Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
                        .FirstOrDefault(x => x.StartsWith(catalogIdPath, StringComparison.OrdinalIgnoreCase)) ?? string.Empty;

                    if (prices != null && prices.Any())
                    {
                        var lowestPrice =
                            (from p in prices
                             where p.ItemId.Equals(item.ItemId, StringComparison.OrdinalIgnoreCase)
                             select p).SingleOrDefault();
                        if (lowestPrice != null)
                        {
                            var tags = new Hashtable
							{
								{
									"Outline",
									currentOutline
								}
							};
                            priceModel = _marketing.GetItemPriceModel(item, lowestPrice, tags);
                        }
                    }

                    if (availabilities != null && availabilities.Any())
                    {
                        var availability =
                            (from a in availabilities
                             where a.ItemId.Equals(item.ItemId, StringComparison.OrdinalIgnoreCase)
                             select a).SingleOrDefault();

                        availabilityModel = new ItemAvailabilityModel(availability);
                    }

                    var itemModel = new CatalogItemWithPriceModel(CatalogHelper.CreateItemModel(item), priceModel, availabilityModel)
                    {
                        SearchOutline = currentOutline
                    };
                    itemModelList.Add(itemModel);
                }
            }

            dataSource.FilterGroups = searchHelper.Convert(results.FacetGroups);
            dataSource.CatalogItems = itemModelList.ToArray();
            dataSource.Criteria = criteria;

            // Create pager
            var pager = new PagerModel
            {
                TotalCount = results.TotalCount,
                CurrentPage = criteria.StartingRecord / criteria.RecordsToRetrieve + 1,
                RecordsPerPage = criteria.RecordsToRetrieve,
                StartingRecord = criteria.StartingRecord,
                DisplayStartingRecord = criteria.StartingRecord + 1,
                SortValues = new[] { "Position", "Name", "Price" },
                SelectedSort = sort,
                SortOrder = isDescending ? "desc" : "asc"
            };

            var end = criteria.StartingRecord + criteria.RecordsToRetrieve;
            pager.DisplayEndingRecord = end > results.TotalCount ? results.TotalCount : end;

            dataSource.Pager = pager;

            // Query similar words
            /*
            if (count == 0)
                dataSource.Suggestions = GetSuggestions();
             * */
            //}

            return dataSource;
        }