/**********************************************************************
 * cheslers.js - Javascript utilities for cheslershoes.com 
 *
 * Copyright (c) 2009, White Horse Technology Consulting Inc.
 * Copyright (c) 2009, Cheslers Shoes Inc.
 **********************************************************************/ 

// DEBUG FLAG - THIS MUST BE OFF IN PRODUCTION
var debugMessages = false;
//var debugMessages = true;

// 3D Cart defines a $ function in checkout, so we need to re-define jQuery's 
// shortcut to avoid a conflict
var $jq = jQuery.noConflict();

// Global variables
var gCurrentBannerIndex = 0;
var gCurrentPage = new PageContext();

// Utility functions
function trim(stringToTrim) {
  return stringToTrim.replace(/^\s+|\s+$/g,"");
  }

function ltrim(stringToTrim) {
  return stringToTrim.replace(/^\s+/,"");
  }

function rtrim(stringToTrim) {
  return stringToTrim.replace(/\s+$/,"");
  }

/************************************************************************/
/*
 * Email Defuscator - jQuery plugin 1.0 alpha
 *
 * Copyright (c) 2007 Joakim Stai
 *
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 *
 * Revision: $Id$
 *
 */

/**
 * Converts obfuscated email addresses into normal, working email addresses.
 *
 * @name defuscate
 * @param Boolean link If true, all defuscated email addresses will be turned into links, defaults to true (optional)
 * @descr Converts obfuscated email addresses into normal email addresses
 */

  /* Link to embed: <span class="emailAddress">customerservice(put AT sign here)cheslershoes.com</span> */

jQuery.fn.defuscate = function( settings ) {
    settings = jQuery.extend({
        link: true
    }, settings);
    var regex = /\b([A-Z0-9._%-]+)\([^)]+\)((?:[A-Z0-9-]+\.)+[A-Z]{2,6})\b/gi;
    return this.each(function() {
        if ( jQuery(this).is('a[@href]') ) {
            // If it's an <a> element, defuscate the href attribute
            jQuery(this).attr('href', jQuery(this).attr('href').replace(regex, '$1@$2'));
            // Make sure that the element's contents is not made into a link
            var is_link = true;
            //alert($(this).attr('href'));
        }
        // Defuscate the element's contents
        jQuery(this).html(jQuery(this).html().replace(regex, (settings.link && !is_link ? '<a href="mailto:$1@$2">$1@$2</a>' : '$1@$2')));
  });
}
/************************************************************************/

/**********************************************************************
 highlightEntryFields - Highlight terxt field on focus
**********************************************************************/file:///home/hugh/Projects/Cheslers/web_store/assets/templates/cheslers/js/cheslers.js
function highlightEntryFields () {
  try {
    $jq(":text").blur(function() {
      $jq(this).toggleClass('txtBoxStyleFocus');
      });
    $jq(":text").focus(function() {
      $jq(this).toggleClass('txtBoxStyleFocus');
      });

    $jq(":password").blur(function() {
      $jq(this).toggleClass('txtBoxStyleFocus');
      });
    $jq(":password").focus(function() {
      $jq(this).toggleClass('txtBoxStyleFocus');
      });
    }

  catch (err) {
    if (debugMessages == true) {
      alert("highlightEntryFields: " + err.message);
      }
    }
  } //END: highlightEntryFields

/**********************************************************************
 changeBanner - Changes the banner image using an effect
  
 Changing the banner requires a number of steps:
   1. Hide am IMG that we will use to hold our new banner image.
   2. Change src of this IMG to our new image.
   3. This images is within a containing div whose background 
      image is our current banner
   4. The new banner is faded in on top of the old banner
   3. The new banner is set into the background image of the containing 
      div, in preparation for our next change.
     
  Arguments:
    bannerDirectory - Directory where banners are kept. Must end with /
                      and needs to be relative to where CSS will 
                      look for images (e.g. "../images/banners/")
       
    bannerFile - New banner to display; file name only
        
    fadeDuration - The number of milliseconds the fade should take. A
                   larger number means a slower transition.
**********************************************************************/
function changeBanner(bannerDirectory, bannerFile, fadeDuration) {
  var newBannerImage = bannerDirectory + bannerFile;
  
  try {
    $jq("#newBanner").css("display", "none");
    $jq("#newBanner").css("background-image", "url("+newBannerImage+")");
    $jq("#newBanner").fadeIn(fadeDuration, 
                        function(){changeBannerDone(newBannerImage);});
    }
  catch (err) {
    if (debugMessages == true) {
      alert("changeBanner: " + err.message);
      }
    }
  } //END: changeBanner

/**********************************************************************
 changeBannerDone - Called when changeBanner is complete
  
 After we fade in our banner, we want to set the backgroudn div to the
 same image as our new banner, so we are all set for our next 
 transition. If we do this in changeBanner, it happens before the fade
 effect is finished. So this function is called by jsQUery when the 
 transition is complete, at which time we can change the background 
 image.

 Arguments:
  bannerImage - The complete path to the new image, ready to be placed 
                into the background image property.
**********************************************************************/
function changeBannerDone(bannerImage) {
  try {
    $jq("#banner").css("background-image", "url("+bannerImage+")");
    }
  catch (err) {
    if (debugMessages == true) {
      alert("changeBannerDone: " + err.message);
      }
    }
  } //END: changeBannerDone


/**********************************************************************
 rotateBanner - Rotates among our standard banners 
  
 This is called by a timer. The interval between calls is defined in
 bannerRotateTime in the configuration file. It simply keeps track of
 how many images are in our array, increments the banner index or 
 rolls it over, and calls changeBanner.
**********************************************************************/
function rotateBanner() {
  try {
    gCurrentBannerIndex++;
    gCurrentBannerIndex = gCurrentBannerIndex % (siteBanners.length -1);
    changeBanner (siteBannersDirectory, siteBanners[gCurrentBannerIndex], bannerFadeTime);
    }
  catch (err) {
    if (debugMessages == true) {
      alert("rotateBanner: " + err.message);
      }
    }
  } //END: rotateBanner  


/**********************************************************************
 rotateBrandBanner - Rotates randomly among our brand banners
  
 This is called by a timer. The interval between calls is defined in
 bannerRotateTime in the configuration file. It simply calls the 
 BrandData function getRandomBanner, then calls changeBanner.
**********************************************************************/
function rotateBrandBanner() {
  try {
    var brandBanner = brandData.randomBanner();
    changeBanner (brandBannersDirectory, brandBanner, bannerFadeTime);
    }
  catch (err) {
    if (debugMessages == true) {
      alert("rotateBrandBanner: " + err.message);
      }
    }
  } //END: rotateBrandBanner  


/**********************************************************************
 escapeJQuerySelector - Escape illegal characters in selectors
 
 3dCart uses ids, particularly in option controls (e.g. Grey:::3) with
 characters that are reserved in CSS. So we need to escape these for 
 jQuery to work. 

  NOTE: There is a problem where Javascript turns a "\" in a variable
        into a "\\" to escape it. But this breaks JQuery, and I 
        haven't found a way to avoid it. So don't use \ in any 
        option names, etc.

 See: http://docs.jquery.com/Selectors for details. Spaces also need
to be escaped; the jQuery docs don't mention these.
**********************************************************************/
function escapeJQuerySelector (selector) {
  if (!arguments.callee.compiledRegEx) {
    var specials = [
        '#', ';', '&', ',', '.', '+', '*', '~', 
        "'", ':', '"', '!', '^', '$', '[', ']', 
        '{', '}', '(', ')', '=', '>', '|', '/', ' '
      ];

    arguments.callee.compiledRegEx = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
    }
  
  return selector.replace(arguments.callee.compiledRegEx, '\\$1');
  } //END: escapeJQuerySelector


/*
 * Menuing Functions - A series of functions to deal with 3D Cart's
 * subnavigation:
 *    a) Move current subcatgergory from under top-level category to 
 *       side nav
 *    b) Fix 3DCart bug where subcategory is only shown on the 1st 
 *       page of results for a category.
*/


/**********************************************************************
 serialiseMenu - Create a breadcrumb/menu storage structure

 We store the subcategories, and the breaadcrumb identifying them,
 in a cookie. To do this we need to stuff (serialise) the two pieces
 of information into a single string. 

 Arguments:
   breadcrumbId - The breadcrumb text identifying the area the 
                  subcategories belong to

   subcategoriesHtml - String with HTML contents of submenu
**********************************************************************/
function serialiseMenu(breadcrumbId, subcategoriesHtml) {
  try {
    var cookieString = "";
    cookieString = trim(breadcrumbId) + "|";
    cookieString += subcategoriesHtml;

    return cookieString;
    }
  catch (err) {
    if (debugMessages == true) {
      alert("serialiseMenu: " + err.message);
      }
    }
  } //END: serialiseMenu


/**********************************************************************
 deserialiseMenu - Break a serialised menu string into its parts

 See serialiseMenu for details

 Arguments:
   cookieString - The cookie contents to pull apart 

 Returns an array
   breadcrumbId - Entry 0
   subcategoriesHtml - Entry 1
**********************************************************************/
function deserialiseMenu(cookieString) {
  try {
    return cookieString.split("|");
    }
  catch (err) {
    if (debugMessages == true) {
      alert("deserialiseMenu: " + err.message);
      }
    }
  } //END: deserialiseMenu


/**********************************************************************
 storeSubMenu - Store a submenu in a coookie

 Deals with all the serialisation and cookie details to store a 
 submenu in a cookie.

 Arguments:
   breadcrumbId - breadcrumb text to be stored 

   subcategoriesHtml - JQuery object with subcategories to be stored
**********************************************************************/
function storeSubMenu(breadcrumbId, subcategoriesHtml) {
  try {
    cookieContents = serialiseMenu(breadcrumbId, subcategoriesHtml);
    //Set_Cookie("subMenu", cookieContents, "", "/", "127.0.0.1", "");
    Set_Cookie("subMenu", cookieContents, "", "/", "cheslershoes.com", "");
    }
  catch (err) {
    if (debugMessages == true) {
      alert("storeSubMenu: " + err.message);
      }
    }
  } //END: storeSubMenu


/**********************************************************************
 getSubMenu - Retrieve a submenu from a coookie

 Deals with all the serialisation and cookie details to store a 
 submenu in a cookie.

 Returns an array
   breadcrumbId - Entry 0
   subcategoriesHtml - Entry 1

   Null if cookie not found
**********************************************************************/
function getSubMenu() {
  try {
    cookieContents = Get_Cookie("subMenu");
    if (cookieContents) {
      return deserialiseMenu(cookieContents);
      }
    else {
      return null;
      }
    }
  catch (err) {
    if (debugMessages == true) {
      alert("getSubMenu: " + err.message);
      }

    return null;
    }
  } //END: getSubMenu



/**********************************************************************
 buildLeftNav - Builds our left nav out of sub-categories or sub-pages

 Because 3dCart's template engine generates categrories and 
 subcategories in the same code block, this causes havoc for Cheslers, 
 who have a split menuing system (categories in the top menu, 
 subcategories in the left nav). 

 buildLeftNav is called in pageInit, and builds a left hand nav
 menu out of sub pages for "extrapages" and subcategories for 
 everything else. What it does:
   * Move the contents of the hidden subcategories or subpages 
     containers
   * Set the heading text, based on the menu structure

 It depends on 3D Cart being set to generate subcategories for only
 the currently selected category, and on particular elements 
 (subcategoriesContainer, subpagesContainer, submenuPlaceholder,
 submenuHeading being defined in the HTML. The container items are 
 where 3D Cart places the information, the placeholder and heading 
 are where we display it.

 buildLeftNav also deal with a 3D Cart issue where subcategories are 
 provided only on the first page of a set of results, and lost on 
 subsequent pages. Our solution is to store and retrieve them from
 a cookie, using the breadcrumbs to determine if we have the right 
 set of menus.
**********************************************************************/
function buildLeftNav(pageType) {
  var menuDepth = gCurrentPage.menuDepth();
  var storedMenuLine = "";
  var subcategoriesHtml = "";
  
  // Home page, checkout, etc.
  if (menuDepth < 2) {
    return;
    }

  try {
    var menuLine = gCurrentPage.menuLine(menuDepth);
    var subcategories = $jq("#subcategoriesContainer div")

    // This is a little convoluted, but there's no easier way - trust me
    if (subcategories.length > 0) {
      $jq(subcategories).appendTo("#submenuPlaceholder");
      storeSubMenu(menuLine, $jq("#submenuPlaceholder").html());
      }
    else {
      cookieData = getSubMenu();
      if ((cookieData) && (cookieData [0] == menuLine)) {
        $jq("#submenuPlaceholder").html(cookieData[1]);
        }
      }

    if ($jq("#submenuPlaceholder div").length > 0) {
      // Set up our heading
      var submenuHeading = $jq("#submenuHeading > a");
      submenuHeading.text(gCurrentPage.menuName(menuDepth - 1));
      submenuHeading.attr("href", gCurrentPage.menuLink(menuDepth - 1));
  
      document.getElementById("submenuHeading").style.display = "block";
      document.getElementById("submenuPlaceholder").style.display = "block";
      if (pageType == "brandMaster") {
        $jq("div.subcategoryMenuItem").css("display", "block");
        }
      }
    }
  catch (err) {
    if (debugMessages == true) {
      alert("buildLeftNav - Categories: " + err.message);
      }
    }
  } //END: buildLeftNav



/**********************************************************************
TO BE REMOVED TO BE REMOVED TO BE REMOVED TO BE REMOVED TO BE REMOVED 

OLDbuildLeftNav - Builds our left nav out of sub-categories or sub-pages

 Because 3dCart's template engine generates categrories and 
 subcategories in the same code block, this causes havoc for Cheslers, 
 who have a split menuing system (categories in the top menu, 
 subcategories in the left nav). 

 buildLeftNav is called in pageInit, and builds a left hand nav
 menu out of sub pages for "extrapages" and subcategories for 
 everything else. What it does:
   * Move the contents of the hidden subcategories or subpages 
     containers
   * Set the heading text, based on the menu structure

 It depends on 3D Cart being set to generate subcategories for only
 the currently selected category, and on particular elements 
 (subcategoriesContainer, subpagesContainer, submenuPlaceholder,
 submenuHeading being defined in the HTML. The container items are 
 where 3D Cart places the information, the placeholder and heading 
 are where we display it.
**********************************************************************/
function OLDbuildLeftNav(pageType) {
  menuDepth = gCurrentPage.menuDepth();

  // Home page, checkout, etc.
  if (menuDepth < 2) {
    return;
    }

  try {
    var subcategories = $jq("#subcategoriesContainer div");
    if (subcategories.length > 0) {
      $jq(subcategories).appendTo("#submenuPlaceholder");
    
      // Set up our heading
      var submenuHeading = $jq("#submenuHeading > a");
      submenuHeading.text(gCurrentPage.menuName(menuDepth - 1));
      submenuHeading.attr("href", gCurrentPage.menuLink(menuDepth - 1));

      document.getElementById("submenuHeading").style.display = "block";
      document.getElementById("submenuPlaceholder").style.display = "block";
      if (pageType == "brandMaster") {
        $jq("div.subcategoryMenuItem").css("display", "block");
        }
      }
    }
  catch (err) {
    if (debugMessages == true) {
      alert("buildLeftNav - Categories: " + err.message);
      }
    }
  } //END: OLDbuildLeftNav


/**********************************************************************
 initStorePage - Load map and directions into a store page
  
 If an "extrapage" has a storeMap variable defined we use it to  
 locate the page containing our map and load it into a div.
**********************************************************************/
function initStorePage () {
  try {
    if ((typeof(window["storeMap"]) == "undefined") || (storeMap == trim(""))) {
      return;
      }

    var mapPage = storeMap.toLowerCase() + "_map.html";
    $jq("#storeMapContainer").load(mapPage + " #storeMap"); 
    document.getElementById("storeMapContainer").style.display = "block";
    }
  catch (err) {
    if (debugMessages == true) {
      alert("initStorePage: " + err.message);
      }
    }
  } //END: initStorePage


/**********************************************************************
 pageInit - Called at each page load
  
 Runs all our page start up functions, setting up the rotating banner, 
 fixing up subcategories and links and initialising our page Structure.
**********************************************************************/
function initPage() {

  try {
    gCurrentPage = new PageContext($jq("div#breadcrumbs > a"));
    }
  catch (err) {
    if (debugMessages == true) {
      alert("initPage - PageContext: " + err.message);
      }
    }

  // Frame initialisations
  var currentPageType = gCurrentPage.pageType();
  buildLeftNav(currentPageType);
  $jq(".emailAddress").defuscate();

  //Disable the My Shoebox link when the shoebox is empty
  try {
    if (currentPageType != "checkout") {
      if ($jq("#miniShoeboxContents").length == 0) {
        $jq("a#miniShoeboxView").removeAttr("href");
        }
      }
    }
  catch (err) {
    if (debugMessages == true) {
      alert("initPage - Hide Shoebox: " + err.message);
      }
    }

  highlightEntryFields();

  // Page-specific initialisations
  if (currentPageType == "product") {
    initProductPage();
    } 
  
  if (currentPageType == "checkout") {
    initCheckoutPage();
    }

  if (currentPageType == "faqHome") {
    initFaqPage();
    }

  if (currentPageType == "extraPage") {
    initStorePage();
    }

  if ((currentPageType == "category") ||
      (currentPageType == "brandMaster") ||
      (currentPageType == "brand")) {
        initCategoryPage(currentPageType);
    }

  // Set up our banners
  try {
    if (currentPageType == "brandMaster") {
      // Trigger an immediate banner change
      rotateBrandBanner();
      bannerTimer = setInterval("rotateBrandBanner();", bannerRotateTime * 1000);
      }
    else {
      if (currentPageType == "brand") {
        brandBanner = brandData.banner(gCurrentPage.pageBrand());
        if (brandBanner != "") {
          changeBanner(brandBannersDirectory, brandBanner, 2000);
          }
        }
      else {
        bannerTimer = setInterval("rotateBanner();", bannerRotateTime * 1000);
        }
      }
    }
  catch (err) {
    if (debugMessages == true) {
      alert("initPage - Set up Banners: " + err.message);
      }
    }
  } //END: pageInit