/**
 * @author Eric Bartels
 * @version $Id: catalog.js 1501 2010-09-02 03:43:13Z ericbartels $
 */

/**
 * The catalog-class
 * @constructor
 */
EKS.Catalog = function () {
    // Controls
    this.dialogProperties       = null;
    this.panelHelpWithProduct   = null;
    this.tabsProperties         = null;

    /// Parameters of the current selection
    this.manufacturerID     = null;
    this.articleID          = null;
    this.ID                 = null;
    this.genericArticleID   = null;

    this.tabMap = new Array ();
    this.tabMap[0] = 'catalog/productCompleteProperties';
    this.tabMap[4] = 'catalog/manufacturerInfo';
    this.tabMap[1] = 'catalog/productAlternateNumbers';
    this.tabMap[2] = 'catalog/productAlternateVehicles';
    this.tabMap[3] = 'catalog/productReplacement';

    /// Catalog-Tree
    this.currentOpenedRootNode = null;
    this.lastSelectedNode = null;
    this.lastSelectedGroup = null;
    this.lastSelectedManufacturer = null;
  this.treePath = new Array();
};

/**
 * Initialize the module
 */
EKS.Catalog.prototype.init = function () {
  var me = this;

  // Create the product-question-dialog
  jQuery("#dlgHelpWithProduct").dialog({
    modal: true,
    autoOpen: false,
    closeOnEscape: true,
    resizable: false,
    draggable: false,
    width: "auto"
  });

  // Create the cart-dialog
  jQuery("#dlgCartOperation").dialog({
    modal: true,
    autoOpen: false,
    closeOnEscape: false,
    resizable: false,
    draggable: false,
    width: "auto"
  });
  jQuery("#dlgCartGotoCart").button();
  jQuery("#dlgCartProceedShopping").button();
  jQuery("#dlgCartProceedShopping").click(function(e) {
    e.preventDefault();
   jQuery("#dlgCartOperation").dialog("close");
  });
  
  // Listen for certain events
  jQuery("#articles div.pagination a").live("click", function(e) {
    e.preventDefault();
    var t = jQuery(e.target);
    if(!t.attr("href"))
    {
      t = t.parent("a");
    }
    me.getProductsWithoutSupplier(null, null, t.attr("href"));
  });

  jQuery("#submitCriteriaFilter").live("click", function(e) {
    e.preventDefault();
    me.onSubmitCriteriaFilter();
  });

  // Catalog tree related listeners
  jQuery("#catalogTree a.catalog-node").click(function(e) {
    if(!window.location.href.match(/catalog/))
    {
      return;
    }
    e.preventDefault();
    me.processTreeNode(e.target, false);
    me.updateUri(e.target);
  });

  // Catalog tree related listeners
  jQuery("#catalogTree a.generic-article-node").click(function(e) {
    if(!window.location.href.match(/catalog/))
    {
      return;
    }
    e.preventDefault();
    me.processGenericArticleNode(e.target);
    me.updateUri(e.target);
  });

  // Listen for shortcuts
  if(jQuery("#catalogShortcuts").length != 0)
  {
    jQuery("#catalogShortcuts a.shortcut-link").click(function(e) {
      e.preventDefault();
      me.processShortcutLink(e.target);
    });
  }
};

/**
 * Add the given product to the shopping cart
 *
 * @param {Object} articleID
 * @param {Object} supplierID
 * @param {Object} idOfElement
 */
EKS.Catalog.prototype.addProductToCart = function (articleID, supplierID, ID, idOfElement, customArticleID) {
  // Get the elements holding the progress and the response
  var progress = $("progress_" + idOfElement);
  var quantity = jQuery("#quantity_" + idOfElement).val();
  var price = null;
  if(jQuery("#price_" + idOfElement).length != 0)
  {
    price = jQuery("#price_" + idOfElement).val();
  }
  if(!quantity.match(/^[0-9]{1,3}$/))
  {
    alert("Bitte geben Sie eine Zahl zwischen 1 und 999 ein.");
    return;
  }

  var dlg = jQuery("#dlgCartOperation");
  // Hide the "close-x" and add a button to the dialog
  dlg.dialog("close");
  dlg.parents(".ui-dialog:first").find(".ui-dialog-titlebar-close").hide();
  dlg.find("#dlgCartOperationStatus").show();
  dlg.find("#dlgCartOperationContent").hide();
  dlg.find("#dlgCartOperationCrossSelling").hide();
  dlg.find("#dlgCartOperations").hide();
  dlg.dialog("open");

  // Add the parameters to the call
  var params = "articleID=" + articleID + "&id=" + ID + "&supplierID=" + supplierID +
    "&quantity=" + quantity + "&t=" + new Date().getTime();
  if(price != null)
  {
    params += "&price=" + price;
  }
  
  // Do we have a custom article?
  if (false != customArticleID)
  {
    params += '&customArticle=' + customArticleID;
  }

  jQuery.get(Base + "cart/add", params, function(data) {
    // Show the "close-x" and add a button to the dialog
    var dlg = jQuery("#dlgCartOperation");
    dlg.parents(".ui-dialog:first").find(".ui-dialog-titlebar-close").show();

    if(!data.Status)
    {
      jQuery("#dlgCartOperationContent .status-text").html(data.StatusText);
      jQuery("#dlgCartOperationContent .status-text").removeClass("ui-state-highlight");
      jQuery("#dlgCartOperationContent .status-text").addClass("ui-state-error");
    }
    else
    {
      jQuery("#dlgCartOperationContent .status-text").html(data.StatusText);
      jQuery("#cartStatusInfo .status-data .count").html(data.TotalCount);
      jQuery("#cartStatusInfo .status-data .total").html(data.Total);
      jQuery("#dlgCartOperationContent .status-text").removeClass("ui-state-error");
      jQuery("#dlgCartOperationContent .status-text").addClass("ui-state-highlight");

      // Update the cart-display
      if (jQuery('#currentCartInfoDetails'))
      {
        jQuery('#currentCartInfoTotalSum').html(data.Total);
        jQuery('#currentCartInfoCount').html(data.TotalCount);
        jQuery('#currentCartInfoDetails').show();
        jQuery('#currentCartInfoEmpty').hide();
      }

      // Cross sellings available?
      if(data.crossSellings && data.crossSellings.length > 0)
      {
        // Find the template
        var list = jQuery("#dlgCartOperationCrossSelling ul");
        var tpl = jQuery("#dlgCartOperationCrossSelling ul li:first").clone();
        jQuery("#dlgCartOperationCrossSelling ul li").remove();

        var nbCrossSelling = data.crossSellings.length;
        for(var i = 0; i < nbCrossSelling; ++i)
        {
          var t = jQuery(tpl).clone();
          jQuery(t).find(".url").attr("href", data.crossSellings[i].url);
          jQuery(t).find(".product-name").html(data.crossSellings[i].name);
          jQuery(t).find(".product-supplier").html(data.crossSellings[i].supplierName);

          var img = jQuery(t).find(".product-image img");
          if( data.crossSellings[i].image.length > 0)
          {
            img.attr("src", data.crossSellings[i].image);
            img.attr("alt", data.crossSellings[i].name);
          }
          else
          {
            img.hide();
          }

          list.append(t);
        }
        jQuery("#dlgCartOperationCrossSelling").show();
      }
    }

    jQuery("#dlgCartOperationStatus").hide();
    jQuery("#dlgCartOperationContent").show();
    jQuery("#dlgCartOperations").show();
    dlg.dialog("close");
    dlg.dialog("open");

    // Trace GA
    EKS.trackPage(data.trackingUrl);
  }, "json");
};

/**
 * Get the article properties
 * @param {Object} articleID
 * @param {Object} ID
 * @param {Object} genericArticleID
 * @param {Boolean} isMapped Use product as mapping
 */
EKS.Catalog.prototype.getArticleProperties = function (articleID, ID, genericArticleID, supplierCode, isMapped) {
  var queryParams = "manufacturerID=" + supplierCode + "&articleID=" + articleID +
    "&genArtID=" + genericArticleID + "&ID=" + ID;

  // Hide certain tabs when the product is mapped
  var tabInst   = jQuery("#propertiesTab");
  var tabLen    = tabInst.tabs("length");
  for(var i = 0; i < tabLen; ++i)
  {
    if(i == 1 || i == 3 || i == 4)
    {
      if(isMapped)
      {
        tabInst.tabs("disable", i);
      }
      else
      {
        tabInst.tabs("enable", i);
      }
    }

    // Update uri and set the content empty
    var newUri = Base + this.tabMap[i] + "?" + queryParams;
    tabInst.tabs("url", i, newUri);

    var contentAreaId = "#" + tabInst.tabs("option", "idPrefix") + (i + 1);
    jQuery(contentAreaId).html("");
  }

  jQuery("#dialogProperties").dialog("open");
  jQuery("#propertiesTab").tabs("select", 0);
  jQuery("#propertiesTab").tabs("load", 0);
};

/**
 * Hide the opened properties dialog
 */
EKS.Catalog.prototype.hidePropertyDialog = function() {
  jQuery("#dialogProperties").dialog("close");
};

/**
 * Handle the selection-display of nodes
 * @param {int} nodeID
 */
EKS.Catalog.prototype._handleSelection = function (nodeID) {
    if (null != this.lastSelectedNode) {
        $('caller_' + this.lastSelectedNode).className = null;
    }

  if(null == nodeID && null == this.lastSelectedNode)
  {
    return;
  }

  // Mark selection
  this.lastSelectedNode = nodeID;
  jQuery('#caller_' + this.lastSelectedNode).addClass("selected");
  jQuery('#caller_' + nodeID).blur();
};

/**
 * Get the generic-articles (groups) of the given node
 * @param {Object} nodeID
 */
EKS.Catalog.prototype.getProductGroups = function (nodeID) {
    var url = Base + 'catalog/retrieveGenericArticles';
    var params = 'node=' + nodeID;

    /// Handle selection-display
    this._handleSelection (nodeID);

    // scroll to top
    window.scrollTo (0, 0);

    var req = new Ajax.Updater (
        'genericArticles',
        url,
        {
            parameters: params,
						evalScripts: true,
            asynchronous: true,
            onLoading: function (req, json) {
                $('productGroupsProgress').style.display = 'block';
                $('genericArticles').style.display = 'none';
                $('articles').style.display = 'none';
                $('manufacturers').style.display = 'none';
            },
            onComplete: function (req, json) {
                $('productGroupsProgress').style.display = 'none';
                $('genericArticles').style.display = 'block';

                // Check if only one result is given and find the element
                // which is the first. Then fire its onclick-event
                if (json.Status && json.Total == 1 && 0 != json.First) {
                    elem = $('productGroup_' + json.First);
                    elem.onclick (elem);
                }
            }
        }
    );
};

/**
 * Get available suppliers of the current node and group (generic-article)
 * @param {int} genArtID
 * @param {int} nodeID
 */
EKS.Catalog.prototype.getSuppliers = function(genArtID, nodeID) {
    var url = Base + 'catalog/retrieveSuppliers';
    var params = 'genart=' + genArtID + '&nodeID=' + nodeID;
    var me = this;

    /// Handle current sticky
    if (null != this.lastSelectedGroup &&
        $('productGroup_' + this.lastSelectedGroup)) {
        $('productGroup_' + this.lastSelectedGroup).className = '';
    }

    var caller = $('productGroup_' + genArtID);
    if (caller) {
        caller.blur();
        caller.className = 'selected';
    }
    this.lastSelectedGroup = genArtID;

    var req = new Ajax.Updater(
        'manufacturers',
        url,
        {
            parameters: params,
            evalScripts: true,
            asynchronous: true,
            onLoading: function(req, json) {
                $('manufacturersProgress').style.display = 'block';
                $('manufacturers').style.display = 'none';
                $('articles').style.display = 'none';
            },
            onComplete: function(req, json) {
                $('manufacturersProgress').style.display = 'none';
                $('manufacturers').style.display = 'block';

                // Check if only one result is given and find the element
                // which is the first. Then fire its onclick-event
                if (json.Status && (json.Total == 1 || 0 != json.First))
                {
                  elem = $('manufacturer_' + json.First);
                  elem.onclick(elem);
                }
                else
                {
                  // Show the proposal
                  me.getProductsWithoutSupplier(genArtID, nodeID, null);
                }
            }
        }
    );
};

/**
 * Get available products of the selected supplier and the selected generic article
 * @param {int} genArtID
 * @param {int} supplierCode
 * @param {int} nodeID
 * @param {Boolean} useMap
 */
EKS.Catalog.prototype.getProducts = function (genArtID, supplierCode, nodeID, useMap)
{
  var url = Base + 'catalog/retrieveArticles';
  var params = {};
  var callerWasFilter = false;

  // Serialize filter elements
  if (null == genArtID && jQuery("#criteriaFilterForm").length != 0)
  {
    var form = jQuery("#criteriaFilterForm");
    url = form.attr("action");
    params = form.serialize();
    callerWasFilter = true;
  }
  else
  {
    params.genart   = genArtID;
    params.supplier = supplierCode;
    params.nodeID   = nodeID;
    params.useMap   = (useMap ? 1 : 0);
  }

  if(1 == jQuery('#popup').val())
  {
    params.popup=1;
    params.prc= jQuery('#popupResponseContainer').val();
  }

  // Handle current sticky
  var lastId = 'manufacturer_' + this.lastSelectedManufacturer;
  if (!callerWasFilter && null != this.lastSelectedManufacturer && jQuery("#" + lastId).length != 0) {
    jQuery("#" + lastId).attr("class", "");
  }

  var caller = jQuery('#manufacturer_' + supplierCode);
  if (caller.length != 0)
  {
    caller.blur();
    caller.addClass("selected");
    this.lastSelectedManufacturer = supplierCode;
  }

  var me = this;

  // Load the data
  jQuery("#articles").hide("fast");
  jQuery("#articlesProgress").show("fast");
  jQuery.get(url, params, function(data) {
    if(EKS.isCrapBrowser())
    {
      // Do not evaluate scripts
      document.getElementById("articles").innerHTML = data;
    }
    else
    {
      jQuery("#articles").html(data);
    }
    jQuery("#articlesProgress").hide("fast");
    jQuery("#articles").show("fast");
    if(EKS.hasFacebook())
    {
      FB.XFBML.parse(document.getElementById("articles"));
    }

    EKS.initShadowbox(true);
    me.trackPageView();
  });
};

/**
 * Get the products of a part list
 * @param {string} listID
 * @param {int} supplierCode
 * @param {string} receiverElement The container receiving new content
 * @param {string} progressElement The container displaying the progess
 */
EKS.Catalog.prototype.getPartListProducts = function (listID, supplierCode, receiverElement, progressElement) {
    var url = Base + 'catalog/getPartProducts';
    var params = 'articleID=' + listID + '&supplierCode=' + supplierCode;

    var req = new Ajax.Updater (
        receiverElement,
        url,
        {
            parameters: params,
            asynchronous: true,
            onLoading: function (req, json) {
                $(progressElement).style.display = 'block';
                $(receiverElement).style.display = 'none';
            },
            onComplete: function (req, json) {
                $(receiverElement).style.display = 'block';
                $(progressElement).style.display = 'none';

                EKS.initShadowbox(true);
            }
        }
    );
};

/**
 * Get available products without the selection of a supplier
 * @param {int} genArtID
 * @param {int} nodeID
 * @param {string} url
 */
EKS.Catalog.prototype.getProductsWithoutSupplier = function (genArtID, nodeID, url)
{
  var params = {};
	if (null == url)
  {
  	url = Base + 'catalog/retrieveProductProposal';
  	params.genart = genArtID;
    params.nodeID = nodeID;
  }
  if(1 == $('popup').value)
  {
    params.popup=1;
    params.prc=jQuery('#popupResponseContainer').val();
  }

  // Load the data
  jQuery("#articles").hide("fast");
  jQuery("#articlesProgress").show("fast");
  jQuery.get(url, params, function(data) {
    if(EKS.isCrapBrowser())
    {
      // Do not evaluate scripts
      document.getElementById("articles").innerHTML = data;
    }
    else
    {
      jQuery("#articles").html(data);
    }
    jQuery("#articlesProgress").hide("fast");
    jQuery("#articles").show("fast");
    if(EKS.hasFacebook())
    {
      FB.XFBML.parse(document.getElementById("articles"));
    }

    EKS.initShadowbox(true);
  });
};

/**
 * Get the child node of the current node
 *
 * @param nodeID
 * @param level
 */
EKS.Catalog.prototype.getTreeNode = function (nodeID, level) {
    var url = Base + 'catalog/retrieveTreeNode';
    var params = 'node=' + nodeID + '&level=' + level;

    /// Build the id's
    var progressID = 'progress_' + nodeID;
    var callerID = 'caller_' + nodeID;
    var receiverID = 'receiver_' + nodeID;

    /// check for special actions
    if (2 == level) {
        if (null != this.currentOpenedRootNode) {
            $('receiver_' + this.currentOpenedRootNode).innerHTML = '';
            $('receiver_' + this.currentOpenedRootNode).style.display = 'none';
            $('caller_' + this.currentOpenedRootNode).className = null;
            this.lastSelectedNode = null;
        }
        this.currentOpenedRootNode = nodeID;
    }

    /// Handle selection-display
    this._handleSelection (nodeID);

    /// Dis-mark current group
    this.lastSelectedGroup = null;

    /// Fire
    var req = new Ajax.Updater (
        receiverID,
        url,
        {
            parameters: params,
						evalScripts: true,
            asynchronous: true,
            onLoading: function (req, json) {
                $(progressID).style.display = 'inline';
            },
            onComplete: function (req, json) {
                $(receiverID).style.display = 'block';
                $(progressID).style.display = 'none';
            }
        }
    );
};

/**
 * Show the "help-with-product" dialog and handle its logic
 * @param {Object} articleID
 * @param {Object} supplierCode
 * @param {Object} genericArticleID
 */
EKS.Catalog.prototype.getHelpWithProduct = function(articleID, supplierCode, genericArticleID, productId) {
  if(jQuery("#dlgHelpWithProduct").length == 0)
  {
    // No dialog available. Feature is disabled
    return;
  }

  var dlgInst = jQuery("#dlgHelpWithProduct");
  dlgInst.find("#dlgHelpWithProductOperationStatus").show();
  dlgInst.find("#helpWithProductContent").hide();
  dlgInst.dialog("open");

  var url = Base + 'catalog/productHelp';
  var params = 'help[articleID]=' + articleID + '&help[supplierCode]=' + supplierCode +
    '&help[genericArticleID]=' + genericArticleID + '&help[productId]=' +
    (typeof productId == "undefined" ? "" : productId);

  // Load data
  jQuery("#helpWithProductContent").load(url, params, function() {
    var dlgInst = jQuery("#dlgHelpWithProduct");
    dlgInst.find("#dlgHelpWithProductOperationStatus").hide();
    dlgInst.find("#helpWithProductContent").show();
    dlgInst.dialog("close");
    dlgInst.dialog("open");

    // Listen to form submission
    dlgInst.find("#helpWithProductForm").die("submit");
    dlgInst.find("#helpWithProductForm").live("submit", function(e) {
      e.preventDefault();
      dlgInst.find("#dlgHelpWithProductOperationStatus").show();
      dlgInst.find("#helpWithProductContent").hide();
      dlgInst.dialog("close");
      dlgInst.dialog("open");

      // Prepare and send data
      var params = jQuery("#helpWithProductForm").serialize();
      jQuery.post(url, params, function(data) {
        var dlg = jQuery("#dlgHelpWithProduct");
        dlg.find("#helpWithProductContent").html(data);
        dlg.find("#dlgHelpWithProductOperationStatus").hide();
        dlg.find("#helpWithProductContent").show();
        dlg.dialog("close");
        dlg.dialog("open");
      });
    });
  });
};

/**
 * Hide the help-panel
 */
EKS.Catalog.prototype.hideHelpWithProduct = function()
{
  if(jQuery("#dlgHelpWithProduct").length == 0)
  {
    // No dialog available. Feature is disabled
    return;
  }

  jQuery("#dlgHelpWithProduct").dialog("close");
};

/**
 * Hide the elements of the part list
 * @param {Object} contentContainer
 */
EKS.Catalog.prototype.partListHidePositions = function (contentContainer) {
    if ($(contentContainer)) {
        $(contentContainer).style.display = 'none';
    }
};

/**
 * The user selected smth. from the filter area. Submit this and
 * load all matching products
 */
EKS.Catalog.prototype.onSubmitCriteriaFilter = function()
{
  this.getProducts(null, null, null, 0);
};

EKS.Catalog.prototype.popupChooseProduct = function(articleId, supplierCode, prc)
{
	try {
  	if (window.opener && null != window.opener) {
  		window.opener.handlePopupChoose(articleId, supplierCode, prc);
  		window.close();
  	}
  	else if(parent) {
  		parent.handlePopupChoose(articleId, supplierCode, prc);
  	}
  }
	catch(e){}
};

/**
 * Open the given tree node
 * @param sender The link that caused the click
 * @param openChilds Open all related child nodes, too?
 */
EKS.Catalog.prototype.processTreeNode = function(sender, openChilds)
{
  var senderElem = jQuery(sender);
  senderElem.parent().toggleClass("selected");
  senderElem.parent().removeClass("hidden");

  var hideChilds  = !senderElem.parent().hasClass("selected");
  var targetNode  = senderElem.attr("rel");

  // It can be that a node is display which is somewhere within the hierarchy. So traverse the DOM
  // tree upwards to find the root node and make it visible.
  // so show all possible parent nodes (if any)
  senderElem.parent().parent().parents("li").addClass("selected");

  // Hide all children starting from the current node
  jQuery("#" + targetNode + " li").each(function(index) {
    jQuery(this).removeClass("selected");
  });

  // A default tree node
  this.toggleCatalogResultVisibility(false);
  if(openChilds && !hideChilds)
  {
    jQuery("#" + targetNode + " li").each(function(index) {
      jQuery(this).addClass("selected");
    });
  }
  else
  {
    this.trackPageView();
  }
};

/**
 * Process a click on a generic article node
 * @param sender
 */
EKS.Catalog.prototype.processGenericArticleNode = function(sender)
{
  var senderElem  = jQuery(sender);
  var targetNode  = senderElem.attr("rel");

  var genericArticle = targetNode.replace(/^group_/, "");

  jQuery(document).scrollTop(0);
  this.getSuppliers(genericArticle, null);
  this.toggleCatalogResultVisibility(true, sender);
}

/**
 * Show the main content of the catalog-tree
 * @param enable
 */
EKS.Catalog.prototype.toggleCatalogResultVisibility = function(enable, sender)
{
  if(enable)
  {
    jQuery("#genericArticlesContainer").hide();
    jQuery("#manufacturersContainer").show();
    jQuery("#articlesContainer").show();
    this.toggleCatalogBreadcrumb(true, sender);
  }
  else
  {
    jQuery("#genericArticlesContainer").show();
    jQuery("#manufacturersContainer").hide();
    jQuery("#articlesContainer").hide();
    jQuery("#catalogBreadcrumb").hide();
    this.toggleCatalogBreadcrumb(false, sender);
  }
};

EKS.Catalog.prototype.updateUri = function(sender) {
  // Use the hash as new hash
  window.location.hash = EKS.getHashFromUrlString(jQuery(sender).attr("href"));
};

/**
 * Get the current tracking url for Google analytics
 */
EKS.Catalog.prototype.getCurrentCatalogTrackingUrl = function() {
  var catalogUrl = EKS.Base + "catalog/index/type/" + jQuery("#selectedTypeId").val();

  // Fetch the texts from the selection
  jQuery(".complete-catalog li.selected > a").each(function(index) {
    catalogUrl += "/" + EKS.makeNiceUrl(jQuery(this).text());
  });

  // And eventually the manufacturer
  jQuery("#manufacturersContainer ul.manufacturers:visible li > a.selected").each(function(index) {
    catalogUrl += "/" + jQuery(this).text();
  });

  return catalogUrl.toLowerCase();
};

/**
 * Track the current page view
 */
EKS.Catalog.prototype.trackPageView = function() {
  if(typeof pageTracker != "undefined")
  {
    pageTracker._trackPageview(this.getCurrentCatalogTrackingUrl());
  }
};

/**
 * Show a clickable breadcrumb for the catalog tree
 * @param enable The flag for enabling or disabling the breadcrumb
 * @param sender The generic-article-mode element that was clicked
 */
EKS.Catalog.prototype.toggleCatalogBreadcrumb = function(enable, sender)
{
  var senderElem  = jQuery(sender);

  var brd = jQuery("#catalogBreadcrumb");
  if(brd.length == 0)
  {
    return;
  }
  
  if(enable)
  {
    var content = jQuery("#catalogBreadcrumbDynamic").html("");
    var elems = new Array();

    var node = senderElem.parent();
    while(!node.hasClass("level0"))
    {
       node = node.parent();
       if("LI" == node.get(0).tagName)
       {
         elems.push(node.children("a.catalog-node").get(0));
       }

    }
    elems.reverse();
    
    var sepCode = jQuery("#catalogBreadcrumbDynamic").prev(".breadcrumb-separator").text();
    elems.push(sender);

    var len = elems.length;
    
    for(var i = 0; i < len; ++i)
    {
      var a = jQuery(elems[i]);
      var hash = EKS.getHashFromUrlString(a.attr("href"));

      if(i < len - 1)
      {
        content.append("<span class=\"breadcrumb-item\"><a href=\"#" + hash + "\">" + a.text() + "</a></span>\n");
        content.append("<span class=\"breadcrumb-separator\">" + sepCode + "</span>\n");
      }
      else
      {
        content.append("<span class=\"breadcrumb-item\">" + a.text() + "</span>\n");
      }
    }
    brd.show();
  }
  else
  {
    brd.hide();
  }
};

/**
 * Process a shortcut-link
 * @param sender
 */
EKS.Catalog.prototype.processShortcutLink = function(sender) {
  var obj     = jQuery(sender);
  var nodes   = obj.attr("rel").split(",");
  var me      = this;
  var isNew   = (obj.attr("opened") == undefined);
  var opened  = (obj.attr("opened") == "opened");

  // check for empty nodes
  if(0 == nodes.length || nodes[0] == "-")
  {
    // Show the complete tree
    this.showAllNodes();
    this.closeAllOpenedNodes();
    return;
  }

  if(isNew)
  {
    // Remove all possible existing opened flags
    jQuery("a.shortcut-link[opened='opened']").removeAttr("opened");
    jQuery("a.shortcut-link[opened='opened']").removeClass("selected");
    this.showAllNodes();
    this.closeAllOpenedNodes();
  }

  // If the shortcut is opened it will no be closed
  if(opened)
  {
    obj.removeAttr("opened");
    obj.removeClass("selected");
    this.closeAllOpenedNodes();
    this.showAllNodes();
  }
  else
  {
    jQuery(nodes).each(function() {
      var expr = "a.catalog-node[node='" + this + "']";
      me.processTreeNode(jQuery(expr), true);
    });

    this.hideAllUnopenedNodes();
    obj.attr("opened", "opened");
    obj.addClass("selected");
  }
};

/**
 * Close all opened nodes
 */
EKS.Catalog.prototype.closeAllOpenedNodes = function() {
  var me = this;

  jQuery(".complete-catalog li.selected").each(function() {
    jQuery(this).removeClass("selected");
  });
};

/**
 * Hide all unopened nodes
 */
EKS.Catalog.prototype.hideAllUnopenedNodes = function() {
  jQuery(".complete-catalog li").not(".selected").addClass("hidden");
};

/**
 * Show all nodes
 */
EKS.Catalog.prototype.showAllNodes = function() {
  jQuery(".complete-catalog li.hidden").removeClass("hidden");
};

EKS.CatalogInst = new EKS.Catalog ();
jQuery(function() {
  EKS.CatalogInst.init();
});
