package com.salesmanager.web.filter;

import com.salesmanager.core.business.catalog.category.model.Category;
import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
import com.salesmanager.core.business.catalog.category.service.CategoryService;
import com.salesmanager.core.business.catalog.product.model.Product;
import com.salesmanager.core.business.catalog.product.service.ProductService;
import com.salesmanager.core.business.content.model.Content;
import com.salesmanager.core.business.content.model.ContentDescription;
import com.salesmanager.core.business.content.model.ContentType;
import com.salesmanager.core.business.content.service.ContentService;
import com.salesmanager.core.business.customer.model.Customer;
import com.salesmanager.core.business.customer.service.CustomerService;
import com.salesmanager.core.business.merchant.model.MerchantStore;
import com.salesmanager.core.business.merchant.service.MerchantStoreService;
import com.salesmanager.core.business.reference.language.model.Language;
import com.salesmanager.core.business.reference.language.service.LanguageService;
import com.salesmanager.core.business.system.model.MerchantConfig;
import com.salesmanager.core.business.system.model.MerchantConfiguration;
import com.salesmanager.core.business.system.model.MerchantConfigurationType;
import com.salesmanager.core.business.system.service.MerchantConfigurationService;
import com.salesmanager.web.constants.Constants;
import com.salesmanager.web.entity.catalog.category.ReadableCategory;
import com.salesmanager.web.entity.customer.Address;
import com.salesmanager.web.entity.customer.AnonymousCustomer;
import com.salesmanager.web.entity.shop.Breadcrumb;
import com.salesmanager.web.entity.shop.BreadcrumbItem;
import com.salesmanager.web.entity.shop.BreadcrumbItemType;
import com.salesmanager.web.entity.shop.PageInformation;
import com.salesmanager.web.populator.catalog.ReadableCategoryPopulator;
import com.salesmanager.web.shop.controller.category.facade.CategoryFacade;
import com.salesmanager.web.utils.GeoLocationUtils;
import com.salesmanager.web.utils.LabelUtils;
import com.salesmanager.web.utils.LanguageUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Servlet Filter implementation class StoreFilter
 */
//TODO Jhonny cache removed
public class StoreFilter extends HandlerInterceptorAdapter {

    private static final Logger LOGGER = LoggerFactory.getLogger(StoreFilter.class);

    private final static String STORE_REQUEST_PARAMETER = "store";


    @Autowired
    private ContentService contentService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private ProductService productService;

    @Autowired
    private MerchantStoreService merchantService;

    @Autowired
    private CustomerService customerService;

    @Autowired
    private MerchantConfigurationService merchantConfigurationService;

    @Autowired
    private LanguageService languageService;

    @Autowired
    private LabelUtils messages;

    @Autowired
    private LanguageUtils languageUtils;

//	@Autowired
//	private CacheUtils cache;

//    @Autowired
//    private WebApplicationCacheUtils webApplicationCache;

    @Autowired
    private CategoryFacade categoryFacade;

    private final static String SERVICES_URL_PATTERN = "/services";
    private final static String REFERENCE_URL_PATTERN = "/reference";


    /**
     * Default constructor.
     */
    public StoreFilter() {

    }

    public boolean preHandle(
            HttpServletRequest request,
            HttpServletResponse response,
            Object handler) throws Exception {

        request.setCharacterEncoding("UTF-8");

        /**
         * if url contains /services
         * exit from here !
         */
        //System.out.println("****** " + request.getRequestURL().toString());
        //System.out.println("****** " + request.getRequestURI().toString());
        if (request.getRequestURL().toString().toLowerCase().contains(SERVICES_URL_PATTERN)
                || request.getRequestURL().toString().toLowerCase().contains(REFERENCE_URL_PATTERN)
                ) {
            return true;
        }

        /*****
         * where is my stuff
         */
        //String currentPath = System.getProperty("user.dir");
        //System.out.println("*** user.dir ***" + currentPath);
        //LOGGER.debug("*** user.dir ***" + currentPath);

        try {

            /** merchant store **/
            MerchantStore store = (MerchantStore) request.getSession().getAttribute(Constants.MERCHANT_STORE);

            String storeCode = request.getParameter(STORE_REQUEST_PARAMETER);

            //remove link set from controllers for declaring active - inactive links
            request.removeAttribute(Constants.LINK_CODE);

            if (!StringUtils.isBlank(storeCode)) {
                if (store != null) {
                    if (!store.getCode().equals(storeCode)) {
                        store = setMerchantStoreInSession(request, storeCode);
                    }
                } else { // when url sm-shop/shop is being loaded for first time store is null
                    store = setMerchantStoreInSession(request, storeCode);
                }
            }

            if (store == null) {
                store = setMerchantStoreInSession(request, MerchantStore.DEFAULT_STORE);
            }

            request.setAttribute(Constants.MERCHANT_STORE, store);

            /** customer **/
            Customer customer = (Customer) request.getSession().getAttribute(Constants.CUSTOMER);
            if (customer != null) {
                if (customer.getMerchantStore().getId().intValue() != store.getId().intValue()) {
                    request.getSession().removeAttribute(Constants.CUSTOMER);
                }
                request.setAttribute(Constants.CUSTOMER, customer);
            }

            if (customer == null) {

                Authentication auth = SecurityContextHolder.getContext().getAuthentication();
                if (auth != null &&
                        request.isUserInRole("AUTH_CUSTOMER")) {
                    customer = customerService.getByNick(auth.getName());
                    if (customer != null) {
                        request.setAttribute(Constants.CUSTOMER, customer);
                    }
                }

            }


            AnonymousCustomer anonymousCustomer = (AnonymousCustomer) request.getSession().getAttribute(Constants.ANONYMOUS_CUSTOMER);
            if (anonymousCustomer == null) {

                Address address = null;
                try {

                    String ipAddress = GeoLocationUtils.getClientIpAddress(request);
                    com.salesmanager.core.business.common.model.Address geoAddress = customerService.getCustomerAddress(store, ipAddress);
                    if (geoAddress != null) {
                        address = new Address();
                        address.setCountry(geoAddress.getCountry());
                        address.setCity(geoAddress.getCity());
                        address.setZone(geoAddress.getZone());
                        address.setPostalCode(geoAddress.getPostalCode());
                    }
                } catch (Exception ce) {
                    LOGGER.error("Cannot get geo ip component ", ce);
                }

                if (address == null) {
                    address = new Address();
                    address.setCountry(store.getCountry().getIsoCode());
                    if (store.getZone() != null) {
                        address.setZone(store.getZone().getCode());
                    } else {
                        address.setStateProvince(store.getStorestateprovince());
                    }
                    address.setPostalCode(store.getStorepostalcode());
                }

                anonymousCustomer = new AnonymousCustomer();
                anonymousCustomer.setBilling(address);
                request.getSession().setAttribute(Constants.ANONYMOUS_CUSTOMER, anonymousCustomer);
            } else {
                request.setAttribute(Constants.ANONYMOUS_CUSTOMER, anonymousCustomer);
            }


            /** language & locale **/
            Language language = languageUtils.getRequestLanguage(request, response);
            request.setAttribute(Constants.LANGUAGE, language);


            Locale locale = languageService.toLocale(language);

            //Locale locale = LocaleContextHolder.getLocale();
            LocaleContextHolder.setLocale(locale);

            /** Breadcrumbs **/
            setBreadcrumb(request, locale);


            /**
             * Get global objects
             * Themes are built on a similar way displaying
             * Header, Body and Footer
             * Header and Footer are displayed on each page
             * Some themes also contain side bars which may include
             * similar emements
             *
             * Elements from Header :
             * - CMS links
             * - Customer
             * - Mini shopping cart
             * - Store name / logo
             * - Top categories
             * - Search
             *
             * Elements from Footer :
             * - CMS links
             * - Store address
             * - Global payment information
             * - Global shipping information
             */


            //get from the cache first
            /**
             * The cache for each object contains 2 objects, a Cache and a Missed-Cache
             * Get objects from the cache
             * If not null use those objects
             * If null, get entry from missed-cache
             * If missed-cache not null then nothing exist
             * If missed-cache null, add missed-cache entry and load from the database
             * If objects from database not null store in cache
             */

            /******* CMS Objects ********/
            this.getContentObjects(store, language, request);

            /******* CMS Page names **********/
            this.getContentPageNames(store, language, request);

            /******* Top Categories ********/
            //this.getTopCategories(store, language, request);
            this.setTopCategories(store, language, request);

            /******* Default metatags *******/

            /**
             * Title
             * Description
             * Keywords
             */

            PageInformation pageInformation = new PageInformation();
            pageInformation.setPageTitle(store.getStorename());
            pageInformation.setPageDescription(store.getStorename());
            pageInformation.setPageKeywords(store.getStorename());


            @SuppressWarnings("unchecked")
            Map<String, ContentDescription> contents = (Map<String, ContentDescription>) request.getAttribute(Constants.REQUEST_CONTENT_OBJECTS);

            if (contents != null) {
                //for(String key : contents.keySet()) {
                //List<ContentDescription> contentsList = contents.get(key);
                //for(Content content : contentsList) {
                //if(key.equals(Constants.CONTENT_LANDING_PAGE)) {

                //List<ContentDescription> descriptions = content.getDescriptions();
                ContentDescription contentDescription = contents.get(Constants.CONTENT_LANDING_PAGE);
                if (contentDescription != null) {
                    //for(ContentDescription contentDescription : descriptions) {
                    //if(contentDescription.getLanguage().getCode().equals(language.getCode())) {
                    pageInformation.setPageTitle(contentDescription.getName());
                    pageInformation.setPageDescription(contentDescription.getMetatagDescription());
                    pageInformation.setPageKeywords(contentDescription.getMetatagKeywords());
                    //}
                }
                //}
                //}
                //}
            }

            request.setAttribute(Constants.REQUEST_PAGE_INFORMATION, pageInformation);


            /******* Configuration objects  *******/

            /**
             * SHOP configuration type
             * Should contain
             * - Different configuration flags
             * - Google analytics
             * - Facebook page
             * - Twitter handle
             * - Show customer login
             * - ...
             */

            this.getMerchantConfigurations(store, request);

            /******* Shopping Cart *********/

            String shoppingCarCode = (String) request.getSession().getAttribute(Constants.SHOPPING_CART);
            if (shoppingCarCode != null) {
                request.setAttribute(Constants.REQUEST_SHOPPING_CART, shoppingCarCode);
            }


        } catch (Exception e) {
            LOGGER.error("Error in StoreFilter", e);
        }

        return true;

    }

    @SuppressWarnings("unchecked")
    private void getMerchantConfigurations(MerchantStore store, HttpServletRequest request) throws Exception {


        StringBuilder configKey = new StringBuilder();
        configKey
                .append(store.getId())
                .append("_")
                .append(Constants.CONFIG_CACHE_KEY);


        StringBuilder configKeyMissed = new StringBuilder();
        configKeyMissed
                .append(configKey.toString())
                .append(Constants.MISSED_CACHE_KEY);

        Map<String, Object> configs = null;

        if (store.isUseCache()) {

            //get from the cache
//				configs = (Map<String, Object>) cache.getFromCache(configKey.toString());
            configs = null;

            if (configs == null) {
                //get from missed cache
                //Boolean missedContent = (Boolean)cache.getFromCache(configKeyMissed.toString());

                //if( missedContent==null) {
                configs = this.getConfigurations(store);
                //put in cache

                if (configs != null) {
//					    	cache.putInCache(configs, configKey.toString());
                } else {
                    //put in missed cache
                    //cache.putInCache(new Boolean(true), configKeyMissed.toString());
                }
                //}
            }

        } else {
            configs = this.getConfigurations(store);
        }


        if (configs != null && configs.size() > 0) {
            request.setAttribute(Constants.REQUEST_CONFIGS, configs);
        }


    }


    @SuppressWarnings("unchecked")
    private void getContentPageNames(MerchantStore store, Language language, HttpServletRequest request) throws Exception {


        /**
         * CMS links
         * Those links are implemented as pages (Content)
         * ContentDescription will provide attributes name for the
         * label to be displayed and seUrl for the friendly url page
         */

        //build the key
        /**
         * The cache is kept as a Map<String,Object>
         * The key is <MERCHANT_ID>_CONTENTPAGELOCALE
         * The value is a List of Content object
         */

        StringBuilder contentKey = new StringBuilder();
        contentKey
                .append(store.getId())
                .append("_")
                .append(Constants.CONTENT_PAGE_CACHE_KEY)
                .append("-")
                .append(language.getCode());

        StringBuilder contentKeyMissed = new StringBuilder();
        contentKeyMissed
                .append(contentKey.toString())
                .append(Constants.MISSED_CACHE_KEY);

        Map<String, List<ContentDescription>> contents = null;

        if (store.isUseCache()) {

            //get from the cache
//					contents = (Map<String, List<ContentDescription>>) cache.getFromCache(contentKey.toString());
            contents = null;

            if (contents == null) {
                //get from missed cache
                //Boolean missedContent = (Boolean)cache.getFromCache(contentKeyMissed.toString());


                //if(missedContent==null) {

                contents = this.getContentPagesNames(store, language);

                if (contents != null) {
                    //put in cache
//								cache.putInCache(contents, contentKey.toString());

                } else {
                    //put in missed cache
                    //cache.putInCache(new Boolean(true), contentKeyMissed.toString());
                }
                //}
            }
        } else {
            contents = this.getContentPagesNames(store, language);
        }


        if (contents != null && contents.size() > 0) {
            List<ContentDescription> descriptions = contents.get(contentKey.toString());

            if (descriptions != null) {
                request.setAttribute(Constants.REQUEST_CONTENT_PAGE_OBJECTS, descriptions);
            }
        }
    }

    @SuppressWarnings({"unchecked"})
    private void getContentObjects(MerchantStore store, Language language, HttpServletRequest request) throws Exception {


        /**
         * CMS links
         * Those links are implemented as pages (Content)
         * ContentDescription will provide attributes name for the
         * label to be displayed and seUrl for the friendly url page
         */

        //build the key
        /**
         * The cache is kept as a Map<String,Object>
         * The key is CONTENT_<MERCHANT_ID>_<LOCALE>
         * The value is a List of Content object
         */

        StringBuilder contentKey = new StringBuilder();
        contentKey
                .append(store.getId())
                .append("_")
                .append(Constants.CONTENT_CACHE_KEY)
                .append("-")
                .append(language.getCode());

        StringBuilder contentKeyMissed = new StringBuilder();
        contentKeyMissed
                .append(contentKey.toString())
                .append(Constants.MISSED_CACHE_KEY);

        Map<String, List<Content>> contents = null;

        if (store.isUseCache()) {

            //get from the cache
//				contents = (Map<String, List<Content>>) cache.getFromCache(contentKey.toString());
            contents = null;

            if (contents == null) {

                //get from missed cache
                //Boolean missedContent = (Boolean)cache.getFromCache(contentKeyMissed.toString());


                //if(missedContent==null) {

                contents = this.getContent(store, language);
                if (contents != null && contents.size() > 0) {
                    //put in cache
//							cache.putInCache(contents, contentKey.toString());
                } else {
                    //put in missed cache
                    //cache.putInCache(new Boolean(true), contentKeyMissed.toString());
                }
                //}

            }
        } else {

            contents = this.getContent(store, language);

        }


        if (contents != null && contents.size() > 0) {

            //request.setAttribute(Constants.REQUEST_CONTENT_OBJECTS, contents);

            List<Content> contentByStore = contents.get(contentKey.toString());
            if (!CollectionUtils.isEmpty(contentByStore)) {
                Map<String, ContentDescription> contentMap = new HashMap<String, ContentDescription>();
                for (Content content : contentByStore) {
                    if (content.isVisible()) {
                        contentMap.put(content.getCode(), content.getDescription());
                    }
                }
                request.setAttribute(Constants.REQUEST_CONTENT_OBJECTS, contentMap);
            }


        }


    }

    @SuppressWarnings("unchecked")
    private void setTopCategories(MerchantStore store, Language language, HttpServletRequest request) throws Exception {

        StringBuilder categoriesKey = new StringBuilder();
        categoriesKey
                .append(store.getId())
                .append("_")
                .append(Constants.CATEGORIES_CACHE_KEY)
                .append("-")
                .append(language.getCode());

        StringBuilder categoriesKeyMissed = new StringBuilder();
        categoriesKeyMissed
                .append(categoriesKey.toString())
                .append(Constants.MISSED_CACHE_KEY);


        //language code - List of category
        Map<String, List<ReadableCategory>> objects = null;
        List<ReadableCategory> loadedCategories = null;

        if (store.isUseCache()) {
//            objects = (Map<String, List<ReadableCategory>>) webApplicationCache.getFromCache(categoriesKey.toString());
            objects = null;
            if (objects == null) {
                //load categories
                loadedCategories = categoryFacade.getCategoryHierarchy(store, 3, language);
                objects = new ConcurrentHashMap<String, List<ReadableCategory>>();
                objects.put(language.getCode(), loadedCategories);
//                webApplicationCache.putInCache(categoriesKey.toString(), objects);

            } else {
                loadedCategories = objects.get(language.getCode());
            }

        } else {
            loadedCategories = categoryFacade.getCategoryHierarchy(store, 3, language);
        }

        if (loadedCategories != null) {
            request.setAttribute(Constants.REQUEST_TOP_CATEGORIES, loadedCategories);
        }

    }

	/*@SuppressWarnings("unchecked")
    private void getTopCategories(MerchantStore store, Language language, HttpServletRequest request) throws Exception {
		   

			*//**
     * Top categories
     * Top categories are implemented as Category entity
     * CategoryDescription will provide attributes name for the
     * label to be displayed and seUrl for the friendly url page
     *//*

			//build the key
			*/

    /**
     * The categories is kept as a Map<String,Object>
     * The key is <MERCHANT_ID>_CATEGORYLOCALE
     * The value is a List of Category object
     *//*

			StringBuilder categoriesKey = new StringBuilder();
			categoriesKey
			.append(store.getId())
			.append("_")
			.append(Constants.CATEGORIES_CACHE_KEY)
			.append("-")
			.append(language.getCode());
			
			StringBuilder categoriesKeyMissed = new StringBuilder();
			categoriesKeyMissed
			.append(categoriesKey.toString())
			.append(Constants.MISSED_CACHE_KEY);
			
			//Map<String, List<Category>> objects = null;
			Map<String, List<ReadableCategory>> objects = null;
			
			if(store.isUseCache()) {
			
				//get from the cache
				//objects = (Map<String, List<Category>>) cache.getFromCache(categoriesKey.toString());
				objects = (Map<String, List<ReadableCategory>>) cache.getFromCache(categoriesKey.toString());
			

				if(objects==null) {
					//Boolean missedContent = (Boolean)cache.getFromCache(categoriesKeyMissed.toString());

					//if(missedContent==null) {
	
						//Get top categories from the database
						objects = this.getCategories(store, language);
	
						if(objects!=null) {
							//put in cache
							cache.putInCache(objects, categoriesKey.toString());
						} else {
							//put in missed cache
							//cache.putInCache(new Boolean(true), categoriesKeyMissed.toString());
						}
						
					//} 
				}
				
			} else {
				objects = this.getCategories(store, language);
			}
			
			if(objects!=null && objects.size()>0) {

				
				//List<Category> categories = objects.get(categoriesKey.toString());
				List<ReadableCategory> categories = objects.get(categoriesKey.toString());
				
				if(categories!=null) {
					request.setAttribute(Constants.REQUEST_TOP_CATEGORIES, categories);
				}
				
				
			}
		   
	   }
*/
    private Map<String, List<ContentDescription>> getContentPagesNames(MerchantStore store, Language language) throws Exception {


        Map<String, List<ContentDescription>> contents = new ConcurrentHashMap<String, List<ContentDescription>>();

        //Get boxes and sections from the database
        List<ContentType> contentTypes = new ArrayList<ContentType>();
        contentTypes.add(ContentType.PAGE);


        List<ContentDescription> contentPages = contentService.listNameByType(contentTypes, store, language);

        if (contentPages != null && contentPages.size() > 0) {

            //create a Map<String,List<Content>
            for (ContentDescription content : contentPages) {


                Language lang = language;
                String key = new StringBuilder()
                        .append(store.getId())
                        .append("_")
                        .append(Constants.CONTENT_PAGE_CACHE_KEY)
                        .append("-")
                        .append(lang.getCode()).toString();
                List<ContentDescription> contentList = null;
                if (contents == null || contents.size() == 0) {
                    contents = new HashMap<String, List<ContentDescription>>();
                }
                if (!contents.containsKey(key)) {
                    contentList = new ArrayList<ContentDescription>();

                    contents.put(key, contentList);
                } else {//get from key
                    contentList = contents.get(key);
                    if (contentList == null) {
                        LOGGER.error("Cannot find content key in cache " + key);
                        continue;
                    }
                }
                contentList.add(content);
            }
        }
        return contents;
    }

    private Map<String, List<Content>> getContent(MerchantStore store, Language language) throws Exception {


        Map<String, List<Content>> contents = new ConcurrentHashMap<String, List<Content>>();

        //Get boxes and sections from the database
        List<ContentType> contentTypes = new ArrayList<ContentType>();
        contentTypes.add(ContentType.BOX);
        contentTypes.add(ContentType.SECTION);

        List<Content> contentPages = contentService.listByType(contentTypes, store, language);

        if (contentPages != null && contentPages.size() > 0) {

            //create a Map<String,List<Content>
            for (Content content : contentPages) {
                if (content.isVisible()) {
                    List<ContentDescription> descriptions = content.getDescriptions();
                    for (ContentDescription contentDescription : descriptions) {
                        Language lang = contentDescription.getLanguage();
                        String key = new StringBuilder()
                                .append(store.getId())
                                .append("_")
                                .append(Constants.CONTENT_CACHE_KEY)
                                .append("-")
                                .append(lang.getCode()).toString();
                        List<Content> contentList = null;
                        if (contents == null || contents.size() == 0) {
                            contents = new HashMap<String, List<Content>>();
                        }
                        if (!contents.containsKey(key)) {
                            contentList = new ArrayList<Content>();

                            contents.put(key, contentList);
                        } else {//get from key
                            contentList = contents.get(key);
                            if (contentList == null) {
                                LOGGER.error("Cannot find content key in cache " + key);
                                continue;
                            }
                        }
                        contentList.add(content);
                    }
                }
            }
        }
        return contents;
    }

    /**
     * @param store
     * @param language
     * @return
     * @throws Exception
     */
    //private Map<String, List<Category>> getCategories(MerchantStore store, Language language) throws Exception {
    private Map<String, List<ReadableCategory>> getCategories(MerchantStore store, Language language) throws Exception {

        //Map<String, List<Category>> objects = new ConcurrentHashMap<String, List<Category>>();
        Map<String, List<ReadableCategory>> objects = new ConcurrentHashMap<String, List<ReadableCategory>>();

        /** returns categories with required depth, 0 = root category, 1 = root + 1 layer child ...) **/
        List<Category> categories = categoryService.listByDepth(store, 0, language);

        ReadableCategoryPopulator readableCategoryPopulator = new ReadableCategoryPopulator();


        Map<String, ReadableCategory> subs = new ConcurrentHashMap<String, ReadableCategory>();

        if (categories != null && categories.size() > 0) {

            //create a Map<String,List<Content>
            for (Category category : categories) {
                if (category.isVisible()) {
                    //if(category.getDepth().intValue()==0) {
                    //ReadableCategory readableCategory = new ReadableCategory();
                    //readableCategoryPopulator.populate(category, readableCategory, store, language);

                    List<CategoryDescription> descriptions = category.getDescriptions();
                    for (CategoryDescription description : descriptions) {

                        Language lang = description.getLanguage();

                        ReadableCategory readableCategory = new ReadableCategory();
                        readableCategoryPopulator.populate(category, readableCategory, store, language);

                        String key = new StringBuilder()
                                .append(store.getId())
                                .append("_")
                                .append(Constants.CATEGORIES_CACHE_KEY)
                                .append("-")
                                .append(lang.getCode()).toString();

                        if (category.getDepth().intValue() == 0) {

                            //List<Category> cacheCategories = null;
                            List<ReadableCategory> cacheCategories = null;
                            if (objects == null || objects.size() == 0) {
                                //objects = new HashMap<String, List<Category>>();
                                objects = new HashMap<String, List<ReadableCategory>>();
                            }
                            if (!objects.containsKey(key)) {
                                //cacheCategories = new ArrayList<Category>();
                                cacheCategories = new ArrayList<ReadableCategory>();

                                objects.put(key, cacheCategories);
                            } else {
                                cacheCategories = objects.get(key.toString());
                                if (cacheCategories == null) {
                                    LOGGER.error("Cannot find categories key in cache " + key);
                                    continue;
                                }
                            }
                            //cacheCategories.add(category);
                            cacheCategories.add(readableCategory);

                        } else {
                            subs.put(lang.getCode(), readableCategory);
                        }
                    }
                }
            }


        }
        return objects;
    }

    private Map<String, Object> getConfigurations(MerchantStore store) {

        Map<String, Object> configs = null;
        try {

            List<MerchantConfiguration> configurations = merchantConfigurationService.listByType(MerchantConfigurationType.CONFIG, store);

            if (!CollectionUtils.isEmpty(configurations) && configs == null) {
                configs = new HashMap<String, Object>();
            }


            for (MerchantConfiguration configuration : configurations) {
                configs.put(configuration.getKey(), configuration.getValue());
            }

            //get MerchantConfig
            MerchantConfig merchantConfig = merchantConfigurationService.getMerchantConfig(store);
            if (merchantConfig != null) {
                if (configs == null) {
                    configs = new HashMap<String, Object>();
                }

                ObjectMapper m = new ObjectMapper();
                @SuppressWarnings("unchecked")
                Map<String, Object> props = m.convertValue(merchantConfig, Map.class);

                for (String key : props.keySet()) {
                    configs.put(key, props.get(key));
                }
            }
        } catch (Exception e) {
            LOGGER.error("Exception while getting configurations", e);
        }

        return configs;

    }

    private void setBreadcrumb(HttpServletRequest request, Locale locale) {


        try {

            //breadcrumb
            Breadcrumb breadCrumb = (Breadcrumb) request.getSession().getAttribute(Constants.BREADCRUMB);
            Language language = (Language) request.getAttribute(Constants.LANGUAGE);
            if (breadCrumb == null) {
                breadCrumb = new Breadcrumb();
                breadCrumb.setLanguage(language);
                BreadcrumbItem item = this.getDefaultBreadcrumbItem(language, locale);
                breadCrumb.getBreadCrumbs().add(item);
            } else {

                //check language
                if (language.getCode().equals(breadCrumb.getLanguage().getCode())) {

                    //rebuild using the appropriate language
                    List<BreadcrumbItem> items = new ArrayList<BreadcrumbItem>();
                    for (BreadcrumbItem item : breadCrumb.getBreadCrumbs()) {

                        if (item.getItemType().name().equals(BreadcrumbItemType.HOME)) {
                            BreadcrumbItem homeItem = this.getDefaultBreadcrumbItem(language, locale);
                            homeItem.setItemType(BreadcrumbItemType.HOME);
                            homeItem.setLabel(messages.getMessage(Constants.HOME_MENU_KEY, locale));
                            homeItem.setUrl(Constants.HOME_URL);
                            items.add(homeItem);
                        } else if (item.getItemType().name().equals(BreadcrumbItemType.PRODUCT)) {
                            Product product = productService.getProductForLocale(item.getId(), language, locale);
                            if (product != null) {
                                BreadcrumbItem productItem = new BreadcrumbItem();
                                productItem.setId(product.getId());
                                productItem.setItemType(BreadcrumbItemType.PRODUCT);
                                productItem.setLabel(product.getProductDescription().getName());
                                productItem.setUrl(product.getProductDescription().getSeUrl());
                                items.add(productItem);
                            }
                        } else if (item.getItemType().name().equals(BreadcrumbItemType.CATEGORY)) {
                            Category category = categoryService.getByLanguage(item.getId(), language);
                            if (category != null) {
                                BreadcrumbItem categoryItem = new BreadcrumbItem();
                                categoryItem.setId(category.getId());
                                categoryItem.setItemType(BreadcrumbItemType.CATEGORY);
                                categoryItem.setLabel(category.getDescription().getName());
                                categoryItem.setUrl(category.getDescription().getSeUrl());
                                items.add(categoryItem);
                            }
                        } else if (item.getItemType().name().equals(BreadcrumbItemType.PAGE)) {
                            Content content = contentService.getByLanguage(item.getId(), language);
                            if (content != null) {
                                BreadcrumbItem contentItem = new BreadcrumbItem();
                                contentItem.setId(content.getId());
                                contentItem.setItemType(BreadcrumbItemType.PAGE);
                                contentItem.setLabel(content.getDescription().getName());
                                contentItem.setUrl(content.getDescription().getSeUrl());
                                items.add(contentItem);
                            }
                        }

                    }

                    breadCrumb = new Breadcrumb();
                    breadCrumb.setLanguage(language);
                    breadCrumb.setBreadCrumbs(items);

                }

            }

            request.getSession().setAttribute(Constants.BREADCRUMB, breadCrumb);
            request.setAttribute(Constants.BREADCRUMB, breadCrumb);

        } catch (Exception e) {
            LOGGER.error("Error while building breadcrumbs", e);
        }

    }

    private BreadcrumbItem getDefaultBreadcrumbItem(Language language, Locale locale) {

        //set home page item
        BreadcrumbItem item = new BreadcrumbItem();
        item.setItemType(BreadcrumbItemType.HOME);
        item.setLabel(messages.getMessage(Constants.HOME_MENU_KEY, locale));
        item.setUrl(Constants.HOME_URL);
        return item;

    }

    /**
     * Sets a MerchantStore with the given storeCode in the session.
     *
     * @param request
     * @param storeCode The storeCode of the Merchant.
     * @return the MerchantStore inserted in the session.
     * @throws Exception
     */
    private MerchantStore setMerchantStoreInSession(HttpServletRequest request, String storeCode) throws Exception {
        if (storeCode == null || request == null)
            return null;
        MerchantStore store = merchantService.getByCode(storeCode);
        if (store != null) {
            request.getSession().setAttribute(Constants.MERCHANT_STORE, store);
        }
        return store;
    }

}
