/**
 * The stylefinder application.
 * 
 * @author Christoph Rust <christoph.rust@vonaffenfels.de>
 * @copyright von Affenfels GmbH (c) 2009 <http://www.vonaffenfels.de>
 * @version 1.0
 */

/*
 * ################
 * ##### Main #####
 * ################
 */

/**
 * Contains common methods for the stylefinder application.
 */
var sf =
{

    /**
     * The current stylefinder version.
     * 
     * @var string
     */
     version : '0.7',

    /**
     * Replaces the given content in the given selector.
     * 
     * @param string
     *            selector a jquery selector e.q. "#div_id"
     * @param string
     *            content the html content to replace
     * @return void
     */
    replaceContent : function(selector, content)
    {
        jQuery(selector).html(content);
    }

};

/*
 * ################
 * ##### Ajax #####
 * ################
 */

/**
 * Contains common ajax functionality for the stylefinder application.
 */
sf.Ajax =
{

    /**
     * Indicates if a current request is running.
     * 
     * @var boolean
     */
    isRunning : false,
    
    /**
     * Returns the html content for the given url.
     * 
     * @param string
     *            url the url
     * @param object|array
     *            data the get parameters
     * @param function
     *            callback the callback function, will be called after the ajax
     *            request has been finished
     * @return void
     */
    getContent : function(url, data, callback)
    {

        if (this.isRunning == true)
        {
            return false;
        }

        // Perform ajax request
        jQuery.post(url, data, function(response)
        {
            callback(response);
        }, 'html');
    
    }

};

// Setup jQuery Ajax
jQuery.ajaxSetup(
{
    cache : false,
    beforeSend : function(request)
    {
        sf.Ajax.isRunning = true;
        
        // Set overlay
        sf.UI.addOverlay(sf.UI.containerId);

        // Set timeout to reset an running request
        window.setTimeout('sf.Ajax.isRunning = false;', 5000);
    
    },
    complete : function(request, status)
    {
        
        sf.Ajax.isRunning = false;
        
        // Remove overlay
        sf.UI.removeOverlay(sf.UI.containerId);
        
    }
});

/*
 * ##############
 * ##### UI #####
 * ##############
 */

/**
 * Contains common ui functionality for the stylefinder application.
 */
sf.UI =
{

    /**
     * The container div id. Contains the application content in the layout.
     * 
     * @var string
     */
    containerId : 'sf_container',

    /**
     * The filter container div id. Contains the application filters in the
     * layout.
     * 
     * @var string
     */
    filterContainerId : 'sf_filter_panel',
    
    /**
     * The filter panel container.
     * Contains all filters.
     * 
     * @var string
     */
    filterPanelContainerId : 'sf_filter_panel_container',

    /**
     * Contains callback to updated the filter panel.
     * 
     * @var object
     */
    filterCallbacks : {},

    /**
     * The css class for an opened widget.
     * 
     * @var string
     */
    widgetClassOpened : 'sf_control_open',

    /**
     * The css class for a closed widget.
     * 
     * @var string
     */
    widgetClassClosed : 'sf_control_close',

    /**
     * Toggles the widget box with the given id. If the widget box is open, it
     * will close it, if closed, it will open.
     * 
     * @param string
     *            controlId the control element id
     * @parma string contentId the content element id
     * @return void
     */
    toogleWidget : function(controlId, contentId)
    {

        var controlElement = jQuery('#' + controlId);
        var contentElement = jQuery('#' + contentId);

        if (controlElement.hasClass(this.widgetClassOpened))
        {
            this.closeWidget(controlId, contentId);
        }
        else
        {
            this.openWidget(controlId, contentId);
        }

    },

    /**
     * Opens the widget box with the given id.
     * 
     * @param string
     *            controlId the control element id
     * @parma string contentId the content element id
     * @return void
     */
    openWidget : function(controlId, contentId)
    {

        var controlElement = jQuery('#' + controlId);
        var contentElement = jQuery('#' + contentId);

        controlElement.removeClass(this.widgetClassClosed);
        controlElement.addClass(this.widgetClassOpened);

        contentElement.show('blind', null, 500);

    },

    /**
     * Closes the widget box with the given id.
     * 
     * @param string
     *            controlId the control element id
     * @parma string contentId the content element id
     * @return void
     */
    closeWidget : function(controlId, contentId)
    {

        var controlElement = jQuery('#' + controlId);
        var contentElement = jQuery('#' + contentId);

        controlElement.removeClass(this.widgetClassOpened);
        controlElement.addClass(this.widgetClassClosed);

        contentElement.hide('blind', null, 500);

    },
    
    /**
     * Add a overlay to given element.
     * 
     * @param string id the element id
     * @return void
     */
    addOverlay : function(id) {
        
        // Get element
        var element = jQuery('#' + id);
        
        // Create overlay div
        var overlayDiv = jQuery('<div id="sf_overlay_' + id + '" class="overlay_3"></div>');
        
        // Set width
        overlayDiv.width(element.width());
        
        // Set height
        overlayDiv.height(element.height());
        
        // Get element position
        var elementPosition = element.offset();
        
        // Set left
        overlayDiv.css('left', (parseInt(elementPosition.left)) + 'px');
        
        // Set top
        overlayDiv.css('top', (parseInt(elementPosition.top)) + 'px');
        
        // Add to body
        jQuery('body').append(overlayDiv);
        
    },
    
    /**
     * Removes the overlay from the given element.
     * 
     * @param string id the element id
     * @return void
     */
    removeOverlay : function(id) {
      
        // Get element
        var element = jQuery('#sf_overlay_' + id);
        
        // Remove overlay
        element.remove();
        
    }

};

/*
 * ####################
 * ##### Products #####
 * ####################
 */

/**
 * Contains methods for the stylefinder products.
 */
sf.Products =
{
        
    /**
     * Indicates an similar search.
     * 
     * @var boolean
     */
     isSimilarSearch : false,
     
     /**
      * Indicates an opened detail page.
      * 
      * @var boolean
      */
     isDetailPage : false,

    /**
     * The product panel div id.
     * 
     * @var string
     */
    productPanelId : 'sf_product_panel',

    /**
     * The ajax product search url.
     * 
     * @var string
     */
    ajaxProductSearchUrl : '/product/search',
    
    /**
     * The ajax similar product search url.
     * 
     * @var string
     */
    ajaxProductSimilarSearchUrl : '/product/searchsimilar',

    /**
     * The ajax similar product view url.
     * Returns the related product widget content.
     * 
     * @var string
     */
    ajaxProductSimilarWidgetContentUrl : '/product/similarview',
    
    /**
     * The ajax product detail url.
     * 
     * @var string
     */
    ajaxProductDetailUrl : '/product/show',

    /**
     * The ajax product detail page url.
     * 
     * @var string
     */
    ajaxProductDetailPageUrl : '/product/detail',

    /**
     * The latest product details dialog.
     * 
     * @var string
     */
    productDetailsDialog : null,

    /**
     * Shows the products. Used to get back from the product detail page.
     * 
     * @return boolean false to prevent link action
     */
    showProducts : function()
    {

        // Get container div id
        var containerId = sf.UI.containerId;
    
        // Get critierias
        var criterias = sf.Products.Filters.getAppliedFiltersForAjax();
    
        // Check page critieria
        if (typeof criterias.page == 'undefined')
        {
            criterias.page = 1;
        }
    
        // Add content specification
        criterias.showOnlyProducts = true;
    
        var ajaxUrl = this.ajaxProductSearchUrl;
        
        if (this.isSimilarSearch === true) {
            ajaxUrl = this.ajaxProductSimilarSearchUrl;
        }
        
        // Perform ajax request
        sf.Ajax.getContent(ajaxUrl, criterias, function(response)
        {
            
            // Replace page content
            sf.replaceContent('#' + sf.Products.productPanelId, response);
            
            // Show filter panel container
            jQuery('#' + sf.UI.filterPanelContainerId).show();
            
            // Add css class "sf_items_container"
            jQuery('#' + sf.Products.productPanelId).addClass('sf_items_container');
    
            // Execute filter callbacks
            for ( var type in sf.UI.filterCallbacks)
            {
    
                // Get callback
                var callback = sf.UI.filterCallbacks[type];
    
                if (typeof callback != 'undefined')
                {
                    callback();
                }
    
            }
    
        });
    
        return false;
    
    },
    
    /**
     * Shows the similar products.
     * 
     * @param string itemNumber the edelight item number id
     * @return boolean false to prevent a links action
     */
    showSimilarProducts : function(itemNumber, itemName) {
        
        // Set is similar search
        this.isSimilarSearch = true;
        
        // Add item number to criterias
        sf.Products.Filters.updateAppliedFilter('itemNumber', itemNumber, itemName, true, null, null, null, false);
        
        // Get container div id
        var containerId = sf.UI.containerId;
    
        // Get critierias
        var criterias = sf.Products.Filters.getAppliedFiltersForAjax();
        
        // Check page critieria
        if (typeof criterias.page == 'undefined')
        {
            criterias.page = 1;
        }
    
        // Add content specification
        criterias.showOnlyProducts = true;
        
        // Update related product widget
        this.updateRelatedProduct(function()
        {
            
            // Perform ajax request
            sf.Ajax.getContent(sf.Products.ajaxProductSimilarSearchUrl, criterias, function(response)
            {
                
                // Replace page content
                sf.replaceContent('#' + sf.Products.productPanelId, response);
                
                // Show filter panel container
                jQuery('#' + sf.UI.filterPanelContainerId).show();
                
                // Add css class "sf_items_container"
                jQuery('#' + sf.Products.productPanelId).addClass('sf_items_container');
        
                // Execute filter callbacks
                for ( var type in sf.UI.filterCallbacks)
                {
        
                    // Get callback
                    var callback = sf.UI.filterCallbacks[type];
        
                    if (typeof callback != 'undefined')
                    {
                        callback();
                    }
        
                }

                // Update brands
                window.setTimeout('sf.Brands.updateBrands(1);',1);
        
            });
            
        });
    
        return false;
        
    },
    
    /**
     * Closes the similar product view and forward to the usual product view.
     * 
     * @return boolean false to prevent link action
     */
    closeSimilarProducts : function(updateProducts) {

        if( typeof updateProducts === 'undefined' ) {
            updateProducts = true;
        }

        // Set is similar search
        this.isSimilarSearch = false;
        
        // Remove item number filter
        sf.Products.Filters.removeAppliedFilter('itemNumber', null, updateProducts);
        
        // Hide related product widget
        this.hideRelatedProduct();
        
        return false;
        
    },
    
    /**
     * Updates the related product widget content.
     * 
     * @param function callback a callback function which will be executed after the related product has been updated
     * @return boolean false to prevent a link action
     */
    updateRelatedProduct : function(callback) {
      
        if (this.isSimilarSearch) {
            
            // Perform ajax request
            sf.Ajax.getContent(this.ajaxProductSimilarWidgetContentUrl, { itemNumber : sf.Products.Filters.getAppliedFilter('itemNumber') }, function(response)
            {
            
                // Replace widget content
                sf.replaceContent('#sf_widget_related', response);
                
                // Set widget visible
                jQuery('#sf_widget_related').show();
                
                // Set ajax completed
                sf.Ajax.isRunning = false;
                
                if (typeof callback === 'function') {
                    callback();
                }
                
            });
            
        }
        
    },
    
    /**
     * Hides the related product filter widget.
     * 
     * @return boolean false to prevent link action
     */
    hideRelatedProduct : function() {
      
        // Set widget invisible
        jQuery('#sf_widget_related').hide();
        
        return false;
        
    },

    /**
     * Updates the product container content.
     * 
     * @return boolean false to prevent a link action
     */
    updateProducts : function()
    {
        
        // Close detail page if open
        if (this.isDetailPage === true) {
            return this.showProducts();
        }

        // Get product panel id staticly to prevent scope issues
        var productPanelId = this.productPanelId;

        // Get critierias
        var criterias = sf.Products.Filters.getAppliedFiltersForAjax();

        // Check page critieria
        if (typeof criterias.page == 'undefined')
        {
            criterias.page = 1;
        }

        // Add content specification
        criterias.showOnlyProducts = true;

        var ajaxUrl = this.ajaxProductSearchUrl;
        
        if (this.isSimilarSearch === true) {
            ajaxUrl = this.ajaxProductSimilarSearchUrl;
        }
        
        // Perform ajax request
        sf.Ajax.getContent(ajaxUrl, criterias, function(response)
        {
            
            // Replace content
            sf.replaceContent('#' + productPanelId, response);
            
            // Update brands
            window.setTimeout('sf.Brands.updateBrands(1);',1);
            
        });

        return false;

    },

    /**
     * Shows a lightbox with the details of the given product.
     * 
     * @param string
     *            id the edelight item number
     * @param object
     *            element the triggered element, used to display the lightbox
     * @return boolean false to prevent a link action
     */
    showDetails : function(id, element)
    {

        if (id.lenght == 0)
        {
            return false;
        }

        // Get dialog panel id staticly to prevent scope issues
        var dialogPanelId = sf.dialogPanelId;

        // Perform ajax request
        sf.Ajax.getContent(this.ajaxProductDetailUrl,
        {
            itemNumber : id
        }, function(response)
        {

            // Open dialog
            sf.Products.dialog = jQuery(response).dialog(
            {
                width : 400,
                height : 450,
                modal : true,
                zIndex : 100098,
                position : 'center',
                resizeable : false
            });

        });

        return false;

    },

    /**
     * Closes the lightbox with the details of the last product.
     * 
     * @return boolean false to prevnet a link action
     */
    closeDetails : function()
    {
        sf.Products.dialog.dialog('close');
    },

    /**
     * Shows the detail page for the given product.
     * 
     * @param string
     *            id the edelight item number
     * @return boolean false to prevent a link action
     */
    showDetailPage : function(id)
    {
        
        // Set is detail page
        this.isDetailPage = true;

        // Get container div id
        var containerId = sf.UI.containerId;

        // Perform ajax request
        sf.Ajax.getContent(this.ajaxProductDetailPageUrl,
        {
            itemNumber : id
        }, function(response)
        {

            // Hide filter panel container
            jQuery('#' + sf.UI.filterPanelContainerId).hide();
            
            // Remove css class "sf_items_container"
            jQuery('#' + sf.Products.productPanelId).removeClass('sf_items_container');
            
            // Replace layout content with detail page
            sf.replaceContent('#' + sf.Products.productPanelId, response);

            // Close preview dialog
            sf.Products.closeDetails();

        });

        return false;

    }

};

/*
 * ##############################
 * ##### Products :: Filter #####
 * ##############################
 */

sf.Products.Filters =
{

    /**
     * The applied filters counter. Used for the key.
     * 
     * @var integer
     */
    appliedFilterCounter : 0,

    /**
     * The applied filters.
     * 
     * @var object
     */
    appliedFilters : {},

    /**
     * The applied filters container div id.
     * 
     * @var string
     */
    appliedFiltersContainerId : 'sf_filter_applied',

    /**
     * The applied filter category container id prefix.
     * 
     * @var string
     */
    appliedFilterCategoryIdPrefix : 'sf_filter_applied_',

    /**
     * The applied filter id prefix.
     * 
     * @var string
     */
    appliedFilterIdPrefix : 'sf_filter_applied_',
    
    removeAppliedFiltersContainerId : 'sf_filter_remove_all',
    
    noAppliedFiltersContainerId : 'sf_filter_none',

    /**
     * The multiple filter names.
     * 
     * @var Object
     */
    multipleFilterNames :
    {
        'brand' : true
    },

    /*
     * ##### Stack #####
     */

    /**
     * Returns the currently applied filters.
     * 
     * @return Object
     */
    getAppliedFilters : function()
    {
        return this.appliedFilters;
    },

    /**
     * Returns the currently applied filters for an ajax request.
     * 
     * @return Object
     */
    getAppliedFiltersForAjax : function()
    {

        var filters = {};

        for ( var key in this.appliedFilters)
        {

            var appliedFilter = this.appliedFilters[key];

            var filterType = (typeof this.multipleFilterNames[appliedFilter.type] != 'undefined' && this.multipleFilterNames[appliedFilter.type] == true) ? appliedFilter.type + '[]' : appliedFilter.type;
            var filterValue = appliedFilter.value;

            // Add filter to array
            if (typeof filters[filterType] == 'undefined')
            {
                filters[filterType] = new Array();
            }
        
            filters[filterType].push(filterValue);
        
        }
        
        return filters;
        
    },

    /**
     * Checks if the given filter is currently applied in filter stack.
     * 
     * @param string
     *            type the filter type e.q. query, brand, color, ...
     * @param string
     *            value the filter value to search for
     * @return bool
     */
    hasAppliedFilter : function(type, value)
    {

        for ( var key in this.appliedFilters)
        {

            var appliedFilter = this.appliedFilters[key];

            if (appliedFilter.type == type && ((typeof value == 'undefined') || (typeof value != 'undefined' && appliedFilter.value == value)))
            {
                return true;
            }

        }

        return false;

    },

    /**
     * Returns the value of the applied filter with the given type.
     * 
     * @param string
     *            type the applied filter type
     * @return Array|String
     */
    getAppliedFilter : function(type)
    {

        var result = new Array();

        for ( var key in this.appliedFilters)
        {

            var appliedFilter = this.appliedFilters[key];

            if (appliedFilter.type == type)
            {
                result.push(appliedFilter.value);
            }

        }

        return (result.length > 0) ? result : result[0];

    },

    /**
     * Adds the given filter to the applied filter stack and view.
     * 
     * @param string
     *            type the filter type e.q. query, brand, color, ...
     * @param string
     *            value the filter value to add
     * @param string
     *            display the value to display
     * @param boolean
     *            addToView if true, applies the filter to the view as well
     * @param function
     *            callbackAdd the callback function which will be triggered if a
     *            the filter was added to the applied view filters
     * @param function
     *            callbackUpdate the callback function which will be triggered
     *            if the filter was updated in the applied view filters
     * @param function
     *            callbackDelete the callback function which will be triggered
     *            if the filter was deleted from the applied view filters
     * @param boolean
     *            if true, products will be updated
     * @return boolean false to prevent a link action
     */
    addAppliedFilter : function(type, value, display, addToView, callbackAdd, callbackUpdate, callbackRemove, updateProducts)
    {

        if (type != 'page')
        {
            this.updateAppliedFilter('page', 1, null, false, null, null, null, false);
        }

        if (typeof display == 'undefined')
        {
            display = value;
        }

        if (typeof addToView == 'undefined')
        {
            addToView = true;
        }

        if (typeof updateProducts == 'undefined')
        {
            updateProducts = true;
        }

        if (!this.hasAppliedFilter(type, value))
        {

            // Calculate the filter key
            var stackFilterKey = (this.appliedFilterCounter++);

            // Add filter to applied filter stack
            this.appliedFilters[stackFilterKey] =
            {
                type : type,
                value : value,
                display : display,
                callbackAdd : callbackAdd,
                callbackUpdate : callbackUpdate,
                callbackRemove : callbackRemove
            };

            // Add filter to applied filter view
            if (addToView == true)
            {
                this.addAppliedViewFilter(stackFilterKey, display);
            }

        }

        if(type === 'brand' || type === 'category')
        {
            sf.Products.closeSimilarProducts(false);
        }

        // Update products
        if (updateProducts == true)
        {
            sf.Products.updateProducts();
        }
        
        // Update filter status
        this.updateFilterViewStatus();

        return false;

    },

    /**
     * Updates the given filter in the applied filter stack and view.
     * 
     * @param string
     *            type the filter type e.q. query, brand, color, ...
     * @param string
     *            value the filter value
     * @param string
     *            display the the filter value to display
     * @param boolean
     *            addToView if true, applies the filter to the view as well
     * @param function
     *            callbackAdd the callback function which will be triggered if a
     *            the filter was added to the applied view filters
     * @param function
     *            callbackUpdate the callback function which will be triggered
     *            if the filter was updated in the applied view filters
     * @param function
     *            callbackDelete the callback function which will be triggered
     *            if the filter was deleted from the applied view filters
     * @param boolean
     *            if true, products will be updated
     * @return boolean false to prevent a link action
     */
    updateAppliedFilter : function(type, value, display, addToView, callbackAdd, callbackUpdate, callbackRemove, updateProducts)
    {

        if (type != 'page')
        {
            this.updateAppliedFilter('page', 1, null, false, null, null, null, false);
        }

        if (typeof display == 'undefined')
        {
            display = value;
        }

        if (typeof addToView == 'undefined')
        {
            addToView = true;
        }

        if (typeof updateProducts == 'undefined')
        {
            updateProducts = true;
        }

        for ( var key in this.appliedFilters)
        {

            var appliedFilter = this.appliedFilters[key];

            if (appliedFilter.type == type)
            {

                // Set filter values
                this.appliedFilters[key] =
                {
                    type : type,
                    value : value,
                    display : display,
                    callbackAdd : callbackAdd,
                    callbackUpdate : callbackUpdate,
                    callbackRemove : callbackRemove
                };

                if(type === 'brand' || type === 'category')
                {
                    sf.Products.closeSimilarProducts(false);
                }

                // Update applied filter view
                if (addToView == true)
                {
                    this.updateAppliedViewFilter(key, display);
                }

                // Update products
                if (updateProducts == true)
                {
                    sf.Products.updateProducts();
                }

                return false;

            }

        }

        // Add filter to stack if not existing
        this.addAppliedFilter(type, value, display, addToView, callbackAdd, callbackUpdate, callbackRemove, updateProducts);

        return false;

    },

    /**
     * Removes all filters from the applied filter stack and view.
     * 
     * @param boolean
     *            if true, products will be updated
     * @return boolean false to prevent a link action
     */
    removeAppliedFilters : function(updateProducts)
    {

        if (typeof updateProducts == 'undefined')
        {
            updateProducts = true;
        }

        for ( var key in this.appliedFilters)
        {
            this.removeAppliedViewFilter(key, false);
        }

        // Reset applied filter stack
        this.appliedFilters = {};

        // Reset applied filter view
        this.removeAppliedViewFilters();

        // Update products
        if (updateProducts == true)
        {
            if (sf.Products.isSimilarSearch === true) {
                sf.Products.closeSimilarProducts();
            } else {
                sf.Products.updateProducts();
            }
        }
        
        // Update filter status
        this.updateFilterViewStatus();

        return false;

    },

    /**
     * Removes the given filter from the applied filter stack and view.
     * 
     * @param string
     *            type the filter type e.q. query, brand, color, ...
     * @param string
     *            value the filter value
     * @param boolean
     *            if true, products will be updated
     * @return boolean false to prevent a link action
     */
    removeAppliedFilter : function(type, value, updateProducts)
    {
        
        if (type != 'page')
        {
            this.updateAppliedFilter('page', 1, null, false, null, null, null, false);
        }

        if (typeof updateProducts == 'undefined')
        {
            updateProducts = true;
        }

        for ( var key in this.appliedFilters )
        {

            var appliedFilter = this.appliedFilters[key];

            if (appliedFilter.type == type && (typeof value == 'undefined' || value === null || (typeof value != 'undefined' && appliedFilter.value == value)))
            {

                // Remove filter from applied filter view
                this.removeAppliedViewFilter(key);

                // Remove filter from applied filter stack
                delete this.appliedFilters[key];

            }

        }

        // Update products
        if (updateProducts == true)
        {
            sf.Products.updateProducts();
        }
        
        // Update filter status
        this.updateFilterViewStatus();

        return false;

    },

    /**
     * Removes the applied filter from stack and view with the given stack key.
     * 
     * @param integer
     *            key the applied filter stack key
     * @param boolean
     *            if true, products will be updated
     * @return boolean false to prevent a link action
     */
    removeAppliedFilterByKey : function(key, updateProducts)
    {

        this.updateAppliedFilter('page', 1, null, false, null, null, null, false);

        if (typeof updateProducts == 'undefined')
        {
            updateProducts = true;
        }

        if (typeof this.appliedFilters[key] != 'undefined')
        {

            // Remove applied filter from view
            this.removeAppliedViewFilter(key);

            // Close similar product box if needed
            if (this.appliedFilters[key].type == 'itemNumber' )
            {
            	sf.Products.closeSimilarProducts();
            }
            
            // Remove applied filter from stack
            delete this.appliedFilters[key];

        }

        // Update products
        if (updateProducts == true)
        {
            sf.Products.updateProducts();
        }
        
        // Update filter status
        this.updateFilterViewStatus();
        
        return false;

    },

    /*
     * ----------------
     * ----- View -----
     * ----------------
     */
    
    /**
     * Checks if any filters except 'page' filter is set and toggles status indicators
     * 
     * @return void
     */
    updateFilterViewStatus : function ()
    {
    	var hasFilters = false;
    	
    	for( var key in this.appliedFilters )
    	{
            if ( this.appliedFilters[key].type != 'page' )
            {
            	hasFilters = true;
            	break;
            }
    	}
    	
    	if( hasFilters === true )
    	{
    		jQuery('#' + this.removeAppliedFiltersContainerId).css('display', 'inline');
    		jQuery('#' + this.noAppliedFiltersContainerId).css('display', 'none');
    	}
    	else
    	{
    		jQuery('#' + this.removeAppliedFiltersContainerId).css('display', 'none');
    		jQuery('#' + this.noAppliedFiltersContainerId).css('display', 'inline');
    	}
    },

    /**
     * Adds the given filter to the applied filter view. Executes a registered
     * callback.
     * 
     * @param integer
     *            key the applied filter stack key, used to indicate if the
     *            filter is existing
     * @param string
     *            display the display value for the filter
     * @return void
     */
    addAppliedViewFilter : function(key, display)
    {

        // Get filter
        var filter = this.appliedFilters[key];

        if (typeof filter == 'undefined')
        {
            return false;
        }
        
        // Add element to applied view filter category
        jQuery('#' + this.appliedFilterCategoryIdPrefix + filter.type).append('<a id="' + this.appliedFilterIdPrefix + key + '" href="#" onclick="return sf.Products.Filters.removeAppliedFilterByKey(' + key + ');" class="sf_delete"><span>' + display + '</span></a>');

        // Set applied view filter category visible
        jQuery('#' + this.appliedFilterCategoryIdPrefix + filter.type).show();

        // Check callback
        if (typeof this.appliedFilters[key].callbackAdd == 'function')
        {
            this.appliedFilters[key].callbackAdd(this.appliedFilters[key].value);
        }

    },

    /**
     * Updates the given filter in the applied filter view. Executes a
     * registered callback.
     * 
     * @param integer
     *            key the applied filter stack key
     * @param string
     *            display the display value for the filter
     * @return void
     */
    updateAppliedViewFilter : function(key, display)
    {

        // Get element
        var element = jQuery('#' + this.appliedFiltersContainerId + ' a#' + this.appliedFilterIdPrefix + key);

        // Check element existence
        if (element.length != 0)
        {
            element.html('<span>' + display + '</span>');
        }
        else
        {

            // Add applied filter to filter view
            this.addAppliedViewFilter(key, display);

        }

        // Check callback
        if (typeof this.appliedFilters[key].callbackUpdate == 'function')
        {
            this.appliedFilters[key].callbackUpdate(this.appliedFilters[key].value);
        }

    },

    /**
     * Removes all filters from the applied filter view. Be carefull, registered
     * callbacks wont be executed!
     * 
     * @return void
     */
    removeAppliedViewFilters : function()
    {

        // Remove all applied filters from view
        jQuery('#' + this.appliedFiltersContainerId + ' a').remove();
        
        // Hide all category views
        jQuery('#' + this.appliedFiltersContainerId + ' span').hide();

    },

    /**
     * Removes the given filter from the applied filter view. Executes a
     * registered callback.
     * 
     * @param integer
     *            key the applied filter stack key
     * @return void
     */
    removeAppliedViewFilter : function(key)
    {

        // Get filter
        var filter = this.appliedFilters[key];

        if (typeof filter == 'undefined')
        {
            return false;
        }

        // Remove element from applied filters view
        jQuery('#' + this.appliedFiltersContainerId + ' a#' + this.appliedFilterIdPrefix + key).remove();

        // Check containing filters in category view
        if (jQuery('#' + this.appliedFilterCategoryIdPrefix + filter.type + ' a').length == 0) {
            jQuery('#' + this.appliedFilterCategoryIdPrefix + filter.type).hide();
        }

        // Check callback
        if (typeof this.appliedFilters[key].callbackRemove == 'function')
        {
            this.appliedFilters[key].callbackRemove(this.appliedFilters[key].value);
        }

    }

};

/*
 * ##################
 * ##### Brands #####
 * ##################
 */

/**
 * Contains methods for the stylefinder brands.
 */
sf.Brands =
{

    /**
     * The brand container div id.
     * 
     * @var string
     */
    brandContainerId : 'sf_widget_brand',

    /**
     * The ajax product url.
     * 
     * @var string
     */
    ajaxBrandUrl : '/brand/show',

    /**
     * Updates the brand container content.
     * 
     * @param integer
     *            page the page to retrieve
     * @return boolean false to prevent a sumit in the forms
     */
    updateBrands : function(page)
    {

        // Get brand container id staticly to prevent scope issues
        var brandContainerId = this.brandContainerId;

        // Get applied filters
        var appliedFilters = sf.Products.Filters.getAppliedFiltersForAjax();

        // Set criterias
        var criterias = {
            page : page
        }

        if( typeof appliedFilters.category != 'undefined' )
        {
            criterias.category = appliedFilters.category;
        }

        // Perform ajax request
        sf.Ajax.getContent(this.ajaxBrandUrl,
            criterias,
            function(response)
            {
                sf.replaceContent('#' + brandContainerId, response);
            }
        );

        return false;
    
    }

};
