
// twister.js, 2006-12-13-1536 


// (FILE: /detail-page-features/twister-event-manager/n2-event-manager.js) 

function N2EventManager()
{
  this.aEvents = {};

  // 1) Register a widget to be notified when any event in the
  // given list is published.
  // ARGS: oWidget a ref to a widget
  //       aMessages a ref to an array of events to subscribe to
  this.subscribe = function(oWidget, aEvents) {
    var i;
    for (i = 0; i< aEvents.length; i++) {
      var sEvent = aEvents[i];
      var aWidgets = this.aEvents[sEvent];
      if (!aWidgets) {
        aWidgets = this.aEvents[sEvent] = [];
      }
      // Push widget onto array
      aWidgets.push(oWidget);
    }
  };

  // 2) When an event comes in notify all the widgets that have 
  // subscribed to the event
  this.publish = function(oSrcWidget, sEvent, oData) {
    var aWidgets = this.aEvents[sEvent];
    if (aWidgets) {
      var i;
      for (i = 0; i < aWidgets.length; i++) {
        var oWidget = aWidgets[i];
        oWidget.onEvent(oSrcWidget, sEvent, oData);
      }
    }    
  };
}

// (FILE: /utility/twister-utilities.js) 

// XHR Factory object
TwisterXHRFactory = function() {
	var oXHR=false;
    // Native XMLHttpRequest object (Firefox, Safari, IE 7, etc.)
	if (!oXHR && typeof XMLHttpRequest!='undefined') {
		try {
			oXHR = new XMLHttpRequest();
		} catch (e) {
		}
    // IE/Windows ActiveX version (IE 5.5, 6)
    } else if(window.ActiveXObject) {
       	try {
        	oXHR = new ActiveXObject("Msxml2.XMLHTTP");
      	} catch(e) {
        	try {
          		oXHR = new ActiveXObject("Microsoft.XMLHTTP");
        	} catch(e) {
          		oXHR = false;
        	}
		}
  }
	return oXHR
}

TwisterAjaxFactory = function(server, sessionId, requestId) {
  var server = server;
  var sessionId = sessionId;
  var requestId = requestId;

  this.getAjaxObject = function() {
    var ajaxObj = new TwisterXHRFactory();
    return new TwisterAjaxObject(ajaxObj, server, sessionId, requestId);
  }
}


TwisterAjaxObject = function(oXHR, server, sessionId, requestId) {
  var oXHR = oXHR;
  var server = server;
  var sessionId = sessionId;
  var requestId = requestId;

  var myURL = '';

  this.setURL = function(url) {
    myURL = server + url + '/' + sessionId;
  }

  this.request = function(oArgs) {
    try
    {
      var thisUrl = myURL + '?' + 'sid=' + sessionId + '&rid=' + requestId + '&';
      for (var i in oArgs) {
        thisUrl += i + '=' + oArgs[i] + '&';
      }
      oXHR.abort();
      oXHR.onreadystatechange = this.TwisterEvalResults;
      oXHR.open('GET', thisUrl, true);
      oXHR.send(null);
    }
    catch (e){}
  }

  this.TwisterEvalResults = function() {
    if (oXHR.readyState == 4) {
      if (oXHR.status == 200) {
        eval(oXHR.responseText);
      } 
    } 
  }
}

// (FILE: /detail-page-features/twister-manager/twister-manager.js) 

// Twister manager object
function TwisterManager(
  oEventManager,
  oTwisterVariations,
  oTwisterPriceBlock,
  oTwisterAvailability,
  oTwisterAltImages,
  oTwisterBuyBox,
  oTwisterMoreBuyingChoices,
  oTwisterPrime,
  oTwisterManagerArgs) {

  var oEventManager = oEventManager;
  var oTwisterVariations = oTwisterVariations;
  var oTwisterPriceBlock = oTwisterPriceBlock;
  var oTwisterAvailability = oTwisterAvailability;
  var oTwisterAltImages = oTwisterAltImages;
  var oTwisterBuyBox = oTwisterBuyBox;
  var oTwisterMoreBuyingChoices = oTwisterMoreBuyingChoices;
  var oTwisterPrime = oTwisterPrime;
  var oTwisterManagerArgs = oTwisterManagerArgs;

  var oTMAjaxObj = oTwisterManagerArgs['oTMAjaxObj'];
  var sTwisterManagerName = oTwisterManagerArgs['sTwisterManagerName'];

  // Child ASIN offer data
  var oOfferData = {};
  // Offer data can be in 4 states (null means not needed)
  var oOfferDataState = {};
  var REQUEST_PENDING = 1;
  var REQUEST_SENT = 2;
  var REQUEST_RECEIVED = 3;
  // Ajax queue
  var oAjaxQueue = new Array();
  var oAjaxTimeout = null;

  // State for when offer data is not yet available
  var sLastPreviewASIN = null;
  var sLastSelectASIN = null;
  var oLastSelectData = {};

  // Subscribe to preview and select events
  if (oTwisterVariations) {
    var aEvents = [
      gsTwisterVariationsEventName_PreviewVariations,
      gsTwisterVariationsEventName_SelectVariations,
      ];

    goEventManager.subscribe(this, aEvents);
  }

  this.onEvent = function(oSrcWidget, sEvent, oData) {
    var oTwisterVariationData = oData;
    var aAsinList = oTwisterVariationData.aAsinList;
    var hSelectedVariations = oTwisterVariationData.oSelectedVariations;
    var numOfVariations = oTwisterVariationData.nVariationsSelected; 
    var totalNumOfVariations = oTwisterVariationData.nVariationsTotal;
    var oDisplayableNames = oTwisterVariationData.oVariationTypeDisplayLabels;
    var sBuyableASIN = oTwisterVariationData.sBuyableASIN; 

    if (sEvent == gsTwisterVariationsEventName_PreviewVariations)
    {
      if (sBuyableASIN && !oOfferData[sBuyableASIN]) {
        // Offer data not available for this preview; save for later
        sLastPreviewASIN = sBuyableASIN;
      }

      // Price and availability block
      if (oTwisterPriceBlock && oTwisterAvailability) {
        if (sBuyableASIN && oOfferData[sBuyableASIN]) {
          oTwisterPriceBlock.update(sBuyableASIN, oOfferData[sBuyableASIN]);
          oTwisterAvailability.update(sBuyableASIN, oOfferData[sBuyableASIN]);
        } else {
          oTwisterPriceBlock.update(null, null);
          oTwisterAvailability.update(null, null);
        }
      }

      // Product images
      if (oTwisterAltImages) {
        oTwisterAltImages.previewVariationValues(oTwisterVariationData);
      } 
    }
    else if (sEvent == gsTwisterVariationsEventName_SelectVariations)
    {
      // Preload offer data on select events
      if (numOfVariations >= (totalNumOfVariations - 1)) {
        this.preloadOfferData(oTwisterVariationData);
      }

      if (sBuyableASIN && !oOfferData[sBuyableASIN]) {
        // Offer data not available for this select; save for later
        sLastSelectASIN = sBuyableASIN;

        oLastSelectData.nVariationsSelected = oTwisterVariationData.nVariationsSelected;
        oLastSelectData.nVariationsTotal = oTwisterVariationData.nVariationsTotal;
        oLastSelectData.oSelectedVariations = oTwisterVariationData.oSelectedVariations;
        oLastSelectData.oDisplayableNames = oTwisterVariationData.oVariationTypeDisplayLabels;
      } else {
        sLastSelectASIN = null;
        oLastSelectData = {};
      }

      // Price and availability block
      if (oTwisterPriceBlock && oTwisterAvailability) {
        if (sBuyableASIN && oOfferData[sBuyableASIN]) {
          oTwisterPriceBlock.update(sBuyableASIN, oOfferData[sBuyableASIN]);
          oTwisterAvailability.update(sBuyableASIN, oOfferData[sBuyableASIN]);
        } else {
          oTwisterPriceBlock.update(null, null);
          oTwisterAvailability.update(null, null);
        }
      }

      // Variations
      if (oTwisterVariations) {
        if (sBuyableASIN && oOfferData[sBuyableASIN]) {
          oTwisterVariations.updateSizeChart(oOfferData[sBuyableASIN]);
        } else {
          oTwisterVariations.clearSizeChart();
        }
      }

      // Buy box
      if (oTwisterBuyBox) {
        if (sBuyableASIN) {
          oTwisterBuyBox.update(sBuyableASIN, oOfferData[sBuyableASIN], 
            numOfVariations, totalNumOfVariations, 
            hSelectedVariations, oDisplayableNames);
        } else {
          oTwisterBuyBox.update(null, null, 
            numOfVariations, totalNumOfVariations, 
            hSelectedVariations, oDisplayableNames);
        }
      }

      // Prime bar
      if (oTwisterPrime) {
        if (sBuyableASIN && oOfferData[sBuyableASIN]) {
          oTwisterPrime.setBuyableASIN(sBuyableASIN);
        } else {
          oTwisterPrime.setBuyableASIN("");
        }
      }

      // More Buying Choices box
      if (oTwisterMoreBuyingChoices) {
        if (sBuyableASIN && oOfferData[sBuyableASIN]) {
          oTwisterMoreBuyingChoices.update(sBuyableASIN);
        } else {
          oTwisterMoreBuyingChoices.clear();
        }
      }

      // Product images
      if (oTwisterAltImages) {
        oTwisterAltImages.selectVariationValues(oTwisterVariationData);
      }
    }
  }

  this.onOfferDataUpdate = function() {
    // Update the page with pending selected ASIN
    if (sLastSelectASIN && oOfferData[sLastSelectASIN]) {
      // Price and availability block
      if (oTwisterPriceBlock && oTwisterAvailability) {
        oTwisterPriceBlock.update(sLastSelectASIN, oOfferData[sLastSelectASIN]);
        oTwisterAvailability.update(sLastSelectASIN, oOfferData[sLastSelectASIN]);
      }

      // Variations
      if (oTwisterVariations) {
        oTwisterVariations.updateSizeChart(oOfferData[sLastSelectASIN]);
      }

      // Buy box
      if (oTwisterBuyBox) {
        oTwisterBuyBox.update(sLastSelectASIN, 
          oOfferData[sLastSelectASIN], 
          oLastSelectData.nVariationsSelected, 
          oLastSelectData.nVariationsTotal,
          oLastSelectData.oSelectedVariations, 
          oLastSelectData.oDisplayableNames);
      }

      // Prime bar
      if (oTwisterPrime) {
        oTwisterPrime.setBuyableASIN(sLastSelectASIN);
      }

      // More Buying Choices box
      if (oTwisterMoreBuyingChoices) {
        oTwisterMoreBuyingChoices.update(sLastSelectASIN);
      }

      sLastSelectASIN = null;
      oLastSelectData = {};
    }

    // Update the page with pending preview ASIN
    if (sLastPreviewASIN && oOfferData[sLastPreviewASIN]) {
      // Price and availability block
      if (oTwisterPriceBlock && oTwisterAvailability) {
        oTwisterPriceBlock.update(sLastPreviewASIN, oOfferData[sLastPreviewASIN]);
        oTwisterAvailability.update(sLastPreviewASIN, oOfferData[sLastPreviewASIN]);
      }

      sLastPreviewASIN = null;
    }
  }

  this.onLoad = function() {
    // Buy box must come before variations
    if (oTwisterBuyBox) {
      oTwisterBuyBox.onLoad();
    }
    if (oTwisterVariations) {
      oTwisterVariations.onLoad();
    }
  }

  this.preloadOfferData = function(oTwisterVariationData) {
    var aAsinList = oTwisterVariationData.aAsinList;

    // Add new ASINs in pending state
    var nCount = 0;
    for (var i = 0; i < aAsinList.length; i++) {
      var sASIN = aAsinList[i];
      if (oOfferDataState[sASIN] == null) {
        oOfferDataState[sASIN] = REQUEST_PENDING;
        nCount++;
      }
    }

    // If any new ASINs, generate requests
    this.processAjax();
  }

  this.processAjax = function() {
    // If there's an outstanding request, return
    if (oAjaxTimeout != null) {
      return;
    }

    // Build a request
    var sRequestList = '';
    var nCount = 0;

    // Make sure offer data for selected ASIN loads ASAP
    if (sLastSelectASIN) {
      var nState = oOfferDataState[sLastSelectASIN];
      if ((nState == null) || (nState == REQUEST_PENDING)) {
        oOfferDataState[sLastSelectASIN] = REQUEST_SENT;
        sRequestList += (sLastSelectASIN + ',');
        nCount++;
      }
    }

    // Add up to 20 other pending ASINs
    for (var sASIN in oOfferDataState) {
      if (oOfferDataState[sASIN] == REQUEST_PENDING) {
        oOfferDataState[sASIN] = REQUEST_SENT;
        sRequestList += (sASIN + ',');
        nCount++;
      }

      if (nCount == 20) {
        break;
      }
    }

    // Make the request
    if (nCount) {
      oTMAjaxObj.request({merchantID: oTwisterManagerArgs['merchantID'], asinList: sRequestList});
      oAjaxTimeout = setTimeout(sTwisterManagerName + ".offerDataTimeout();", 5000);
    }
  }

  this.resetPending = function() {
    // Reset any sent ASINs that weren't received to pending
    for (var sASIN in oOfferDataState) {
      if (oOfferDataState[sASIN] != REQUEST_RECEIVED) {
        oOfferDataState[sASIN] = REQUEST_PENDING;
      }
    }
  }

  this.setOfferingData = function(sASIN, oOffering) {
    if (oOffering) {
      oOfferData[sASIN] = oOffering;
      oOfferDataState[sASIN] = REQUEST_RECEIVED;
    }
  }

  this.offerDataReceived = function() {
    // The Ajax request came back, so clear the timeout
    clearTimeout(oAjaxTimeout);
    oAjaxTimeout = null;

    // Reset any sent (but not received) ASINs to pending
    this.resetPending();

    // Process any more Ajax requests we need to make.
    setTimeout(sTwisterManagerName + ".processAjax();", 0);
    // Do any updates based on newly available offer data.
    setTimeout(sTwisterManagerName + ".onOfferDataUpdate();", 0);
  }

  this.offerDataTimeout = function() {
    // The Ajax request timed out
    clearTimeout(oAjaxTimeout);
    oAjaxTimeout = null;

    // Reset any sent (but not received) ASINs to pending
    this.resetPending();

    // Retry a new request
    this.processAjax();
  }
}

// (FILE: /detail-page-features/twister-variations/twister-variations-events.js) 

// Events published by the Twister Variations component
var gsTwisterVariationsEventName_PreviewVariations        = "TWISTER_VARIATIONS_PREVIEW_VARIATIONS";
var gsTwisterVariationsEventName_SelectVariations         = "TWISTER_VARIATIONS_SELECT_VARIATIONS";
/* Performance Testing Code */
var gsTwisterVariationsEventName_StartTimer				  =	"TWISTER_VARIATIONS_START_TIMER";		
var gsTwisterVariationsEventName_EndTimer				  =	"TWISTER_VARIATIONS_END_TIMER";

// (FILE: /detail-page-features/twister-variations/twister-swatches.js) 

function TwisterVariations(oEventManager, oVariationLabels, oVariationValues, oSelectedVariationValues, oChildItems, oSwatchVariationKeys, oDropdownVariationKeys, oVariationArgs) {
var oEventManager = oEventManager;
var oVariationLabels = oVariationLabels;
var oVariationValues = oVariationValues;
var oChildItems = oChildItems;
var oVariationArgs = oVariationArgs;

// Selection items array (maps selection to ASIN lists)
var oSelectionItems = new Array();
// Selection/hover state
var nVariationsTotal = 0;
var oSelectedVarValues = oSelectedVariationValues;
var oHoveredVarValues = new Array();
// Variation display types (swatch or dropdown)
var oVariationDisplayTypes = new Array();
// Swatch element and state cache
var oSwatchElements = new Array();
var oSwatchStateCache = new Array();
// Dropdown lookup state
var oDropdownLookupState = new Array();

{
  // Initialize variation value state
  for (var sVarKey in oSelectedVarValues) {
    nVariationsTotal++;
    oHoveredVarValues[sVarKey] = -1;
  }

  // Populate element and state cache from the DOM
  for (var i = 0; i < oSwatchVariationKeys.length; i++) {
    var sVarKey = oSwatchVariationKeys[i];
    oSwatchElements[sVarKey] = new Array();
    oSwatchStateCache[sVarKey] = new Array();
    for (var nVarValue in oVariationValues[sVarKey]) {
      var sDivId = sVarKey + '_' + nVarValue;
      oSwatchElements[sVarKey][nVarValue] = document.getElementById(sDivId);
      oSwatchStateCache[sVarKey][nVarValue] = oSwatchElements[sVarKey][nVarValue].className;
    }
  }

  // Populate variation display types (swatch or dropdown)
  var oVariationDisplayTypes = new Array();
  for (var i in oSwatchVariationKeys) {
    var sVarKey = oSwatchVariationKeys[i];
    if (oSwatchStateCache[sVarKey][0] == 'swatchPreSelect') {
      oVariationDisplayTypes[oSwatchVariationKeys[i]] = 'f'; // fixed swatch
    } else {
      oVariationDisplayTypes[oSwatchVariationKeys[i]] = 's'; // modifiable swatch
    }
  }
  for (var i in oDropdownVariationKeys) {
    oVariationDisplayTypes[oDropdownVariationKeys[i]] = 'd'; // dropdown
  }

  // Compute mapping from selection to buyable ASIN list
  for (var i = 0; i < oChildItems.length; i++) {
    var oChildItem = oChildItems[i];
    var sLookup;
    var oItems;

    // Add single buyable ASIN for N variations selected
    sLookup = '';
    for (var sVarKey in oSelectedVarValues) {
      sLookup += (oChildItem[sVarKey] + " ");
    }
    oItems = oSelectionItems[sLookup];
    if (oItems == undefined) {
      oItems = new Array();
    }
    // Just index 0 (always 1 ASIN)
    oItems[0] = oChildItem['ASIN'];
    oSelectionItems[sLookup] = oItems;

    // Add to list of ASINs for N-1 variations selected
    for (var sIgnoreVarKey in oSelectedVarValues) {
      sLookup = '';
      for (var sVarKey in oSelectedVarValues) {
        if (sVarKey != sIgnoreVarKey) {
          sLookup += (oChildItem[sVarKey] + " ");
        } else {
          sLookup += "-1 ";
        }
      }
      oItems = oSelectionItems[sLookup];
      if (oItems == undefined) {
        oItems = new Array();
      }
      // Index by the remaining selection value
      oItems[oChildItem[sIgnoreVarKey]] = oChildItem['ASIN'];
      oSelectionItems[sLookup] = oItems;
    }
  }
}

this.onLoad = function() {
  // Update the header label
  this.updateLabels();

  // Trigger a selection event on load if necessary
  var nVariationsSelected = 0;
  for (var sVarKey in oSelectedVarValues) {
    if (oSelectedVarValues[sVarKey] != -1) {
      nVariationsSelected++;
    }
  }
  if ((nVariationsSelected > 0) || (nVariationsTotal == 1)) {
    this.triggerEvent('select');
  }
}

this.updateSwatches = function() {
  for (var sVarKey in oSwatchElements) {
    // Ignore fixed swatches
    if (oVariationDisplayTypes[sVarKey] == 'f') {
      continue;
    }

    // If N-1 other variations are selected, limit availability
    var sLookup = '';
    var oItems = null;
    for (var sCurVarKey in oSelectedVarValues) {
      if (sCurVarKey != sVarKey) {
        if (oHoveredVarValues[sCurVarKey] != -1) {
          sLookup += (oHoveredVarValues[sCurVarKey] + " ");
        } else if (oSelectedVarValues[sCurVarKey] != -1) {
          sLookup += (oSelectedVarValues[sCurVarKey] + " ");
        } else {
          sLookup = null;
          break;
        }
      } else {
        sLookup += "-1 ";
      }
    }
    if (sLookup != null) {
      oItems = oSelectionItems[sLookup];
    }

    // Now go through each swatch and apply style
    for (var nVarValue in oSwatchElements[sVarKey]) {
      var sSwatchState = 'swatchAvailable';
      if (oSelectedVarValues[sVarKey] == nVarValue) {
        if (oItems && (oItems[nVarValue] == undefined)) {
          sSwatchState = 'swatchSelectGray';
        } else {
          sSwatchState = 'swatchSelect';
        }
        sSwatchState = 'swatchSelect';
      } else if (oHoveredVarValues[sVarKey] == nVarValue) {
        if (oItems && (oItems[nVarValue] == undefined)) {
          sSwatchState = 'swatchUnavailableHover';
        } else {
          sSwatchState = 'swatchHover';
        }
      } else {
        if (oItems && (oItems[nVarValue] == undefined)) {
          sSwatchState = 'swatchUnavailable';
        } else {
          sSwatchState = 'swatchAvailable';
        }
      }

      // Sync with the DOM
      if (sSwatchState != oSwatchStateCache[sVarKey][nVarValue]) {
        oSwatchElements[sVarKey][nVarValue].className = sSwatchState;
        oSwatchStateCache[sVarKey][nVarValue] = sSwatchState;
      }
    }
  }
}

this.updateDropdowns = function(sChangedVarKey) {
  for (var sVarKey in oSelectedVarValues) {
    if ((oVariationDisplayTypes[sVarKey] != 'd') ||
        (sVarKey == sChangedVarKey)) {
      continue;
    }
    var oDropdown = document.getElementById(sVarKey);

    // Compute lookup to find list of dropdown entries
    var sLookup = '';
    for (var sCurVarKey in oSelectedVarValues) {
      if (sCurVarKey != sVarKey) {
        if (oSelectedVarValues[sCurVarKey] != -1) {
          sLookup += (oSelectedVarValues[sCurVarKey] + " ");
        } else {
          sLookup = '';
          break;
        }
      } else {
        sLookup += "-1 ";
      }
    }
    // If the lookup didn't change, then we don't need to update the dropdown
    if ((oDropdownLookupState[sVarKey] != undefined) &&
        (oDropdownLookupState[sVarKey] == sLookup)) {
        continue;
    }
    oDropdownLookupState[sVarKey] = sLookup;

    // Save the old selected value
    var nVarValueOrig = oSelectedVarValues[sVarKey];

    // Compute the available options for this dropdown
    var aOptions = new Array();
    var count = 0;
    if (sLookup != '') {
      // Lookup ok; use a limited range of values
      var oItems = oSelectionItems[sLookup];
      for (var nVarValue in oItems) {
        aOptions[count] = { nVal: nVarValue, sVal: oVariationValues[sVarKey][nVarValue] };
        count++;
      }
    } else {
      // Use the full range of values
      for (var nVarValue in oVariationValues[sVarKey]) {
        aOptions[count] = { nVal: nVarValue, sVal: oVariationValues[sVarKey][nVarValue] };
        count++;
      }
    }
   
    // Sort the dropdown alphabetically
    function sortDropdown(a, b) {
      return (b.sVal < a.sVal) - (a.sVal < b.sVal);
    }
    aOptions.sort(sortDropdown);

    // Rebuild the dropdown
    oDropdown.options.length = 0;
    oDropdown.options[0] = new Option(goTwisterSwatchStrings['select'], -1, true);

    var index = 0;
    for (var i = 0; i < aOptions.length; i++) {
      if (aOptions[i].nVal == nVarValueOrig) {
        index = i + 1;
      }
      oDropdown.options[i + 1] = new Option(aOptions[i].sVal, aOptions[i].nVal); 
    }

    // Restore the original selection
    if (index > 0) {
      oDropdown.options[index].selected = true;
    }
  }
}

this.updateLabels = function() {
  var headerDiv = document.getElementById("swatchHeader");
  var sHeader = "Select ";
  var bFirst = 1;
  for (var sVarKey in oSelectedVarValues) {
    if (oSelectedVarValues[sVarKey] == -1) {
      if (!bFirst) { sHeader += " and " }
      bFirst = 0;

      sHeader += oVariationLabels[sVarKey];
    }
  }
  if (bFirst) {
    sHeader = "To Buy, Add to Shopping Cart";
  }
  headerDiv.innerHTML = sHeader;

  for (var sVarKey in oSelectedVarValues) {
    var labelDiv = document.getElementById("selected_" + sVarKey);
    var sHTML = '<b class=variationDefault>' + oVariationLabels[sVarKey] + ': </b> ';

    if ((oHoveredVarValues[sVarKey] != -1) && (oHoveredVarValues[sVarKey] != oSelectedVarValues[sVarKey])) {
      sHTML += '<b class=variationLabelHovered>' + oVariationValues[sVarKey][oHoveredVarValues[sVarKey]] + '</b>'; 
    } else if (oSelectedVarValues[sVarKey] != -1) {
      sHTML += '<b class=variationLabel>' + oVariationValues[sVarKey][oSelectedVarValues[sVarKey]] + '</b>';
    } else {
      sHTML += '<b class=variationDefault>' + goTwisterSwatchStrings['unselected'] + '</b>';
    }

    labelDiv.innerHTML = sHTML;
  }
}

this.onHoverOverSwatch = function(sVarKey, nVarValue) {
  oHoveredVarValues[sVarKey] = nVarValue;

  this.updateSwatches();
  this.updateLabels();
  this.triggerEvent('preview');
}

this.onHoverOffSwatch = function() {
  for (var sVarKey in oHoveredVarValues) {
    oHoveredVarValues[sVarKey] = -1;
  }

  this.updateSwatches();
  this.updateLabels();
  this.triggerEvent('preview');
}

this.onClickSwatch = function(sVarKey, nVarValue) {
  if (oVariationDisplayTypes[sVarKey] == 'f') { // Ignore fixed swatches
    return;
  }

  if (oSelectedVarValues[sVarKey] == nVarValue) {
    oSelectedVarValues[sVarKey] = -1;
  } else {
    // When unavailable swatch is toggled on, deselect other variations
    if (oSwatchStateCache[sVarKey][nVarValue] == 'swatchUnavailableHover') {
      for (var sCurVarKey in oSelectedVarValues) {
        if (oVariationDisplayTypes[sCurVarKey] != 'f') { // Ignore fixed swatches
          oSelectedVarValues[sCurVarKey] = -1;
        }
      }
    }
    oSelectedVarValues[sVarKey] = nVarValue;
  }

  this.updateSwatches();
  this.updateDropdowns(sVarKey);
  this.updateLabels();
  this.triggerEvent('select');
  this.triggerEvent('preview'); // needed since mouse is still hovering over swatch
} 

this.onChangeDropdown = function(sVarKey) {
  var oDropdown = document.getElementById(sVarKey);
  var nVarValue = oDropdown.options[oDropdown.selectedIndex].value;

  if (nVarValue == -1) {
    // If user cleared the selected option, deselect other variations (helps user get reoriented)
    for (var sCurVarKey in oSelectedVarValues) {
      if (oVariationDisplayTypes[sCurVarKey] != 'f') { // Ignore fixed swatches
        oSelectedVarValues[sCurVarKey] = -1;
      }
    }
  } else {
    oSelectedVarValues[sVarKey] = nVarValue;
  }

  this.updateSwatches();
  this.updateDropdowns(sVarKey);
  this.updateLabels();
  this.triggerEvent('select');
} 

this.triggerEvent = function(sEventType) {
  // Compute the variation value array
  var oEventVarValues = new Array();
  var nEventVariationsSelected = 0;
  for (var sVarKey in oSelectedVarValues) {
    if ((sEventType == 'preview') && (oHoveredVarValues[sVarKey] != -1)) {
      oEventVarValues[oVariationLabels[sVarKey]] = oVariationValues[sVarKey][oHoveredVarValues[sVarKey]];
      nEventVariationsSelected++;
    } else if (oSelectedVarValues[sVarKey] != -1) {
      oEventVarValues[oVariationLabels[sVarKey]] = oVariationValues[sVarKey][oSelectedVarValues[sVarKey]];
      nEventVariationsSelected++;
    } else {
      oEventVarValues[oVariationLabels[sVarKey]] = null;
    }
  }

  // Compute buyable ASIN if all variations selected
  var sBuyableASIN = null;
  if (nEventVariationsSelected == nVariationsTotal) {
    var sLookup = '';
    for (var sVarKey in oSelectedVarValues) {
      if ((sEventType == 'preview') && (oHoveredVarValues[sVarKey] != -1)) {
        sLookup += (oHoveredVarValues[sVarKey] + " ");
      } else if (oSelectedVarValues[sVarKey] != -1) {
        sLookup += (oSelectedVarValues[sVarKey] + " ");
      } else {
        sLookup = null;
        break;
      }
    }
    if (sLookup != null) {
      var oItems = oSelectionItems[sLookup];
      if (oItems != null) {
        sBuyableASIN = oSelectionItems[sLookup][0];
      }
    }
  }

  // Compute the ASIN list (for select events only); these are all the ASINs
  // that could potentially be selected on the user's next click
  var aAsinList = new Array();
  var count = 0;
  if (sEventType == 'select') {
    for (var sIgnoreVarKey in oSelectedVarValues) {
      var sLookup = '';
      for (var sVarKey in oSelectedVarValues) {
        if (sVarKey != sIgnoreVarKey) {
          if ((sEventType == 'preview') && (oHoveredVarValues[sVarKey] != -1)) {
            sLookup += (oHoveredVarValues[sVarKey] + " ");
          } else if (oSelectedVarValues[sVarKey] != -1) {
            sLookup += (oSelectedVarValues[sVarKey] + " ");
          } else {
            sLookup = null;
            break;
          }
        } else {
          sLookup += "-1 ";
        }
      }
      if (sLookup != null) {
        var oItems = oSelectionItems[sLookup];
        for (var nVarValue in oItems) {
          aAsinList[count] = oItems[nVarValue];
          count++;
        }
      }
    }
  }

  // Create the event object
  var oEventData = new VariationData();
  oEventData.oSelectedVariations = oEventVarValues;
  oEventData.nVariationsTotal = nVariationsTotal;
  oEventData.nVariationsSelected = nEventVariationsSelected;
  oEventData.oVariationTypeDisplayLabels = oVariationLabels;
  oEventData.aAsinList = aAsinList;
  oEventData.sBuyableASIN = sBuyableASIN;

  // Publish the event
  if (sEventType == 'preview') {
    oEventManager.publish(this, gsTwisterVariationsEventName_PreviewVariations, oEventData);
  } else if (sEventType == 'select') {
    oEventManager.publish(this, gsTwisterVariationsEventName_SelectVariations, oEventData);
  }
} 

this.selectChild = function(oChildVariations, sObjName) {
  var time = 0;

  for (var sVarKey in oChildVariations) {
    var sVarValue = oChildVariations[sVarKey];

    var nVarValue = -1;
    for (var nCurVarValue in oVariationValues[sVarKey]) {
      if (sVarValue == oVariationValues[sVarKey][nCurVarValue]) {
        nVarValue = nCurVarValue;
        break;
      }
    }

    if (oSelectedVarValues[sVarKey] == nVarValue) {
      continue; // No change
    }

    if (oVariationDisplayTypes[sVarKey] == 's') {
      setTimeout(sObjName + '.onClickSwatch(\'' + sVarKey + '\', ' + nVarValue + ')', time * 500);
    } else if (oVariationDisplayTypes[sVarKey] == 'd') {
      var ddList = document.getElementById(sVarKey);
      for (var i = 1; ddList.options[i] != null; i++) {
        if (ddList.options[i].value == nVarValue) {
          ddList.options[i].selected = true;
          break;
        }
      }
      setTimeout(sObjName + '.onChangeDropdown(\'' + sVarKey + '\')', time * 500);
    }

    time++; // Delay selection
  }
}

this.updateSizeChart = function(oOfferData) {
  if (!oVariationArgs['merchSizeChartLink'] || !oVariationArgs['merchSizeText'] || !oVariationArgs['divID'] ||
      !oOfferData['ASIN'] || !oOfferData['merchantID']) {
    return;
  }
  var div = document.getElementById(oVariationArgs['divID']);
  if (!div) {
    return;
  }
  var link = oVariationArgs['merchSizeChartLink'] + '?asin=' + oOfferData['ASIN'] + '&seller=' + oOfferData['merchantID'];
  var sHTML = '<a href=\"' + link + '\" target="_blank">' + oVariationArgs['merchSizeText'] + '</a>';
  div.innerHTML = sHTML;
}

this.clearSizeChart = function() {
  if (!oVariationArgs['divID']) {
    return;
  }
  var div = document.getElementById(oVariationArgs['divID']);
  if (!div) {
    return;
  }
  div.innerHTML = oVariationArgs['twisterDefaultSizingChartLink'];
}

}

// VariationData object passed to the twister manager 
function VariationData() { 
  this.aAsinList = new Array();
  this.oSelectedVariations = new Array();
  this.nVariationsSelected = 0;
  this.nVariationsTotal = 0;
  this.sBuyableASIN = null;
  this.oVariationTypeDisplayLabels = new Array();
}

// Event helper functions
window.isChildElement = function(oParent, oChild) {
  var isChild = false;
  for (var i = 0; i < 4; i++) { // Going up 4 levels is all that's necessary!
    if (oChild == null) break;
    if (oChild == oParent) { isChild = true; break; }
    oChild = oChild.parentNode;
  }
  return isChild;
}

window.isMouseOver = function(oElement, e) {
  if (!e) var e = window.event;
  var tg = (window.event) ? e.srcElement : e.target;
  var reltg = (e.relatedTarget) ? e.relatedTarget : e.fromElement;

  if (isChildElement(oElement, tg) && !isChildElement(oElement, reltg)) {
    if (oElement.getAttribute("mouseOver") != "1") {
      oElement.setAttribute("mouseOver", "1");
      return 1;
    }
  }
  return 0;
}

window.isMouseOut = function(oElement, e) {
  if (!e) var e = window.event;
  var tg = (window.event) ? e.srcElement : e.target;
  var reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;

  if (isChildElement(oElement, tg) && !isChildElement(oElement, reltg)) {
    if (oElement.getAttribute("mouseOver") == "1") {
      oElement.setAttribute("mouseOver", "0");
      return 1;
    }
  }
  return 0;
}

// (FILE: /detail-page-features/twister-product-image/twister-product-image.js) 

// Twister Product Image Object
function TwisterProductImage(oStrings) {
  var oStrings = oStrings;

  var registeredImages = new Object();
  var selectedImageID = "none";

  var isPendingPreload = false;

  this.registerImage = function(id, src, imageHTML, captionHTML) {
    if (registeredImages[id] == null) {
      registeredImages[id] = new Object();
      registeredImages[id].imageHTML = imageHTML;
      registeredImages[id].captionHTML = captionHTML;
      registeredImages[id].src = src;
    }
  }

  this.preloadImage = function(id) {
    if (!registeredImages[id].image) {
      registeredImages[id].image = new Image();
      registeredImages[id].image.src = registeredImages[id].src;
    }
  }

  this.displayImage = function(id) {
    this.preloadImage(id);
    this.showImage(id);
    this.hideOverlay();
  }

  this.displayNotBuyable = function(id, oSelectedVariations) {
    this.showImage(id);
    this.showNotBuyableOverlay(oSelectedVariations);
  }

  this.displayImageNotAvail = function(id, sColor) {
    this.showImage(id);
    this.showImageNotAvailOverlay(sColor);
  }

  this.showImage = function(id) {
    if (id != selectedImageID) {
      selectedImageID = id;
      if (id != null) {
        document.getElementById('prodImageCell').innerHTML = registeredImages[id].imageHTML;
        document.getElementById('prodImageCaption').innerHTML = registeredImages[id].captionHTML;
      } else {
        document.getElementById('prodImageCell').innerHTML = "";
        document.getElementById('prodImageCaption').innerHTML = "";
      }
    }
  }

  this.hideOverlay = function() {
    document.getElementById('prodImageOverlay').style.visibility = "hidden";
  }

  this.showOverlay = function(sHTML, sClass) {
    document.getElementById('prodImageOverlayHiddenText').innerHTML = sHTML;
    document.getElementById('prodImageOverlayVisibleText').innerHTML = sHTML;

    document.getElementById('prodImageOverlay').style.visibility = "visible";

    document.getElementById('prodImageOverlayBox').className = sClass;
    document.getElementById('prodImageOverlayVisibleText').className = sClass;
  }

  this.showNotBuyableOverlay = function(oSelectedVariations) {
    var sHTML;
    sHTML = "<b>" + oStrings['prodImageNotBuyableText'] + "<br>";
    var nKeys = 0;
    for (var sKey in oSelectedVariations) {
      if (nKeys) {
        sHTML += "<br>";
      }
      sHTML += (sKey + ": <b class='prodImageNotBuyableOverlayHighlight'>" + oSelectedVariations[sKey] + "</b>");
      nKeys++;
    }
    sHTML += "</b>";

    this.showOverlay(sHTML, "prodImageNotBuyable");
  }

  this.showImageNotAvailOverlay = function(sColor) {
    var sHTML;
    if (sColor != undefined) {
      sHTML = oStrings['prodImageNotAvailTextColorBefore'] + sColor + oStrings['prodImageNotAvailTextColorAfter'];
    } else {
      sHTML = oStrings['prodImageNotAvailTextNoColor'];
    }

    this.showOverlay(sHTML, "prodImageNotAvail");
  }
}

// (FILE: /detail-page-features/twister-alt-images/twister-alt-images.js) 

// Twister Alt Images object
function TwisterAltImages(sInitialColor, nInitialNumThumbs) {
  var oImageDataSets = new Object();
  var nImageDataSets = 0;

  var sDefaultColor = sInitialColor;
  var sCurrentSelectedColor = sInitialColor;
  var sCurrentDisplayedColor = sInitialColor;

  var nMaxThumbs = 7;
  var nThumbs = nInitialNumThumbs;
  var nHighlightThumb = 0;
  var aImageIDs = new Array();


  this.addImage = function(sImageID, sColor, fnRegisterJS, sImageHTML) {
    var oImageData = new Object();
    oImageData.sImageID = sImageID;
    oImageData.fnRegisterJS = fnRegisterJS;
    oImageData.sImageHTML = sImageHTML;

    if (oImageDataSets[sColor] == null) {
      oImageDataSets[sColor] = new Array();
      nImageDataSets++;
    }

    // Store this image in the right image set
    oImageDataSets[sColor][oImageDataSets[sColor].length] = oImageData;

    // Register the image if necessary (causes it to be loaded by the browser)
    if (sColor == sCurrentDisplayedColor) {
      // This is an image for the current color; load all of them
      aImageIDs[aImageIDs.length] = sImageID;
      fnRegisterJS();
    } else if (oImageDataSets[sColor].length == 1) {
      // This is the first image of another color, load it for previews
      fnRegisterJS();
    }
  }

  this.setColor = function(sNewSelectedColor) {
    if (sNewSelectedColor != sCurrentSelectedColor) {
      sCurrentSelectedColor = sNewSelectedColor;

      if (oImageDataSets[sCurrentSelectedColor] != undefined) {
        sCurrentDisplayedColor = sCurrentSelectedColor;
      } else {
        sCurrentDisplayedColor = sDefaultColor;
      }

      var oImageDataSet;
      if (oImageDataSets[sCurrentDisplayedColor] != undefined) {
        oImageDataSet = oImageDataSets[sCurrentDisplayedColor];
      } else {
        oImageDataSet = new Array();
      }

      nThumbs = oImageDataSet.length;

      for (var nThumb = nThumbs; nThumb < nMaxThumbs; nThumb++) {
        document.getElementById("thumb_" + nThumb).style.display = 'none';
      }

      document.getElementById("thumb_strip").style.width = (nThumbs * 36);

      for (var nThumb = 0; nThumb < nThumbs; nThumb++) {
        oImageDataSet[nThumb].fnRegisterJS();
        this.setThumb(nThumb, oImageDataSet[nThumb].sImageID, oImageDataSet[nThumb].sImageHTML);

        document.getElementById("thumb_" + nThumb).style.display = 'inline';
      }

      if (nThumbs > 0) {
        this.viewThumb(0);
      }
    }
  }

  this.setThumb = function(nThumb, sImageID, sImageHTML) {
    var sInnerID = "thumb_" + nThumb + "_inner";
    document.getElementById(sInnerID).innerHTML = sImageHTML;

    aImageIDs[nThumb] = sImageID;
  }

  this.viewThumb = function(nThumb) {
    if ((nImageDataSets > 1) && (sCurrentDisplayedColor != sCurrentSelectedColor)) {
      goTwisterProductImage.displayImageNotAvail(aImageIDs[nThumb], sCurrentSelectedColor);
    } else {
      goTwisterProductImage.displayImage(aImageIDs[nThumb]);
    }

    if (nThumb != nHighlightThumb) {
      var sThumbID;
      sThumbID = "thumb_" + nHighlightThumb;
      document.getElementById(sThumbID).style.border = '1px solid #999999';
      sThumbID = "thumb_" + nThumb;
      document.getElementById(sThumbID).style.border = '1px solid #990000';
      nHighlightThumb = nThumb;
    }
  }

  this.preloadThumbs = function() {
    for (var nThumb = 0; nThumb < nThumbs; nThumb++) {
      goTwisterProductImage.preloadImage(aImageIDs[nThumb]);
    }
  }

  this.onMouseOver = function(nThumb) {
    this.viewThumb(nThumb);
    this.preloadThumbs();
  }

  this.onMouseOut = function(nThumb) {
  }

  this.previewVariationValues = function(oTwisterVariationData) {
    var sSelectedColor = oTwisterVariationData.oSelectedVariations['Color'];

    var sPreviewColor;
    var bImageNotAvail = 0;
    if (nImageDataSets > 0) {
      if (sSelectedColor != undefined) {
        if (oImageDataSets[sSelectedColor] != undefined) {
          sPreviewColor = sSelectedColor;
        } else {
          sPreviewColor = sDefaultColor;
          if (nImageDataSets > 1) {
            bImageNotAvail = 1;
          }
        }
      } else {
        sPreviewColor = sDefaultColor;
      }
    } else {
      sPreviewColor = sDefaultColor;
      sSelectedColor = undefined;
      bImageNotAvail = 1;
    }

    var sPreviewImageID = undefined;
    if (sPreviewColor != "none") {
      if (sPreviewColor == sCurrentDisplayedColor) {
        sPreviewImageID = aImageIDs[nHighlightThumb];
      } else {
        sPreviewImageID = oImageDataSets[sPreviewColor][0].sImageID;
      }
    }

    var bNotBuyable = ((oTwisterVariationData.nVariationsSelected == oTwisterVariationData.nVariationsTotal) && (oTwisterVariationData.sBuyableASIN == undefined))

      if (bNotBuyable) {
        goTwisterProductImage.displayNotBuyable(sPreviewImageID, oTwisterVariationData.oSelectedVariations);
      } else if (bImageNotAvail) {
        goTwisterProductImage.displayImageNotAvail(sPreviewImageID, sSelectedColor);
      } else {
        goTwisterProductImage.displayImage(sPreviewImageID);
      }
  }

  this.selectVariationValues = function(oTwisterVariationData) {
    var oSelectedVariations = oTwisterVariationData.oSelectedVariations;
    var sSelectedColor = oSelectedVariations['Color'];

    if (sSelectedColor != undefined) {
      this.setColor(sSelectedColor);
    } else {
      this.setColor(sDefaultColor);
    }
  }
}

// (FILE: /detail-page-features/twister-more-buying-choices/twister-more-buying-choices.js) 

function TwisterMoreBuyingChoices(merchID, sDivID, oMBCAjaxObj) {
  var moreOffersInfo = {};
  var sDivID = sDivID;
  var oMBCAjaxObj = oMBCAjaxObj;
  this.clear = function() {
    var div = document.getElementById(sDivID);
    if(div) {
      div.innerHTML = '';
    }
  }

  this.update = function(sASIN) {
    if(merchID) {
      return;
    }
    if(!moreOffersInfo[sASIN]) {
      var oAjaxArgs = {}
      oAjaxArgs['ASIN'] = sASIN; 
      oAjaxArgs['globalObject'] = 'goTwisterMoreBuyingChoices';
	  oAjaxArgs['inTwister'] = 1;
      oMBCAjaxObj.request(oAjaxArgs);
    } else {
      var div = document.getElementById(sDivID);
      if(div) {
        div.innerHTML = moreOffersInfo[sASIN];
      }
    }
  }
  this.setOfferInfo = function(sASIN, sInfo) {
    moreOffersInfo[sASIN] = sInfo;
    var div = document.getElementById(sDivID);
    if(div) {
      div.innerHTML = moreOffersInfo[sASIN];
    }
  }
}

// (FILE: /detail-page-features/twister-buy-box/twister-buy-box.js) 

function TwisterBuybox(headerDivID, mainDivID, oBuyboxStrings) {
  var oStrings = oBuyboxStrings;

  this.onLoad = function() {
    var sHeaderString = this.printBuyboxHeader(null);
    document.getElementById(headerDivID).innerHTML = sHeaderString;

    this.makeButtonsInactive();
  }

  this.update = function(sASIN, oOfferData, numVariations, totalVariations, selectedVariations, displayableNames) {
    var sHeaderString = '';
    var sCurrentString = '<div id="buyboxPriceBlock" style="padding-top: 0px;">'
      + '<table class="product">';

    if (sASIN) {
      sHeaderString = '<strong>' + oStrings['ReadyToBuy'] + '</strong>';

      // Price
      var sPrice;
      if (oOfferData) {
        if (oOfferData['sale_price']) {
          sPrice = oOfferData['sale_price'];
        } else if (oOfferData['our_price']) {
          sPrice = oOfferData['our_price'];
        } else {
          sPrice = oOfferData['list_price'];
        }
      } else {
        sPrice = "loading..."; // Offer data still loading
      }
      sCurrentString += '<tr><td class="productLabel" valign="top">' + oStrings['PriceLabel'] 
        + '</td><td><b class="price">' + sPrice + '</b>';

      // We only show SSS message if Amazon and item is qualified.
      if (oOfferData) {
        if (oOfferData['isEligibleForSuperSaverShipping'] && (oOfferData['merchantID'] == 'ATVPDKIKX0DER')) {
          sCurrentString +='<span class="tiny">&nbsp;' + oStrings['SSSMessage'] + '</span>';
        }
      }

      sCurrentString += '</td></tr>';
      sCurrentString += this.printVariationInfo(selectedVariations);

      if (oOfferData) {
        document.getElementById("twisterBuyboxAvailabilityJS").innerHTML = this.printAvailability(oOfferData);
      } else {
        document.getElementById("twisterBuyboxAvailabilityJS").innerHTML = '';
      }
      
      // Update buybox form with buyable asin and merchant id
      if (oOfferData) {
        document.getElementById("ASIN").value = sASIN;
        document.getElementById("merchantID").value = oOfferData['merchantID'];
        document.getElementById("offerListingID").value = oOfferData['offer_listing_id'];

        this.makeButtonsActive();
      } else {
        this.makeButtonsInactive();
      }
    } else {
      sHeaderString = this.printBuyboxHeader(selectedVariations);

      // Clear the availability when we go from N selected variations to N-x selected variations
      document.getElementById("twisterBuyboxAvailabilityJS").innerHTML = '';
      this.makeButtonsInactive();

      if (numVariations == 0) {
        sCurrentString = '';
        if (totalVariations == 0) {
          sHeaderString = '';
        }
      } else if (numVariations < totalVariations) {
        sCurrentString += this.printVariationInfo(selectedVariations);
      }
    }

    sCurrentString += '</table></div>';

    document.getElementById(headerDivID).innerHTML = sHeaderString;
    document.getElementById(mainDivID).innerHTML = sCurrentString;
  }

  this.printBuyboxHeader = function(selectedVariations) {
    var headerString = '';

    var hasVariationNames = 0;
    for (var x in goVariationLabels) {
      hasVariationNames = 1;
      break;
    }

    if (hasVariationNames) {
      headerString += '<strong>To buy, select ';

      var firstValue = 1;
      if (selectedVariations) {
        for (var y in selectedVariations) {
          if (!selectedVariations[y]) { 
            if (!firstValue) { 
              headerString += ' and '; 
            }
            headerString += y;
            firstValue = 0;
          }
        }
      } else {
        // If selectedVariations is null (eg when page first loads), we have
        // to use the global goVariationLabels to display the proper names.
        for (var x in goVariationLabels) {
          if (!firstValue) { 
            headerString += ' and '; 
          }
          headerString += goVariationLabels[x];
          firstValue = 0;
        }
      }

      headerString += '</strong>' + '<br />(' + oStrings['NoVariationSubheader'] + ')';
    }

    return headerString;
  }

  this.printVariationInfo = function(selectedVariations) {
    var variationString = '';

    for (var x in selectedVariations) {
      if (selectedVariations[x]) { 
        variationString += '<tr><td class="productLabel">' + x + ':</td><td>' 
                           + selectedVariations[x] + '</td></tr>'; 
      } 
    }

    return variationString;
  }

  this.makeButtonsActive = function() {
    addOrig = document.getElementById("twisterAddToCartOrig");
    if (addOrig) { addOrig.style.display = 'none'; }
    addInactive = document.getElementById("twisterAddToCartInactive");
    if (addInactive) { addInactive.style.display = 'none'; }
    addActive = document.getElementById("twisterAddToCartActive");
    if (addActive) { addActive.style.display = 'block'; }
    i = document.getElementById("quantity");
    if (i) { i.disabled = false; }
    w = document.getElementById("twisterOneClickOrig");
    if (w) { w.style.display = 'none'; } 
    x = document.getElementById("twisterOneClickInactive");
    if (x) { x.style.display = 'none'; }
    y = document.getElementById("twisterOneClickActive");
    if (y) { y.style.display = 'block'; }
    z = document.getElementById("twisterShippingDropdown");
    if (z) { z.disabled = false; }
    a = document.getElementById("wishlistAddButtonActive");
    if (a) {a.style.display = 'inline';}
    b = document.getElementById("wishlistAddButtonInactive");
    if (b) {b.style.display = 'none';}
    c = document.getElementById("wishlistDownButtonActive");
    if (c) {c.style.display = 'inline';}
    d = document.getElementById("wishlistDownButtonInactive");
    if (d) {d.style.display = 'none';}
    j = document.getElementById("rslButtonOrig");
    if (j) {j.style.display = 'none';}
    e = document.getElementById("rslButtonJsInactive");
    if (e) {e.style.display = 'none';}
    f = document.getElementById("rslButtonJsActive"); 
    if (f) {f.style.display = 'block';}
    g = document.getElementById("weddingButtonInactive");
    if (g) {g.style.display = 'none';}
    h = document.getElementById("weddingButtonActive");
    if (h) {h.style.display = 'block';}
    u = document.getElementById("babyButtonActive");
    if (u) { u.style.display = 'block'; }
    v = document.getElementById("babyButtonInactive");
    if (v) { v.style.display = 'none'; }
  }

  this.makeButtonsInactive = function() {
    addOrig = document.getElementById("twisterAddToCartOrig");
    if(addOrig){ addOrig.style.display = 'none'; }
    addInactive = document.getElementById("twisterAddToCartInactive");
    if(addInactive){ addInactive.style.display = 'block'; }
    addActive = document.getElementById("twisterAddToCartActive");
    if(addActive){ addActive.style.display = 'none'; }
    i = document.getElementById("quantity");
    if(i) { i.disabled = true; }
    w = document.getElementById("twisterOneClickOrig");
    if(w) { w.style.display = 'none'; }
    x = document.getElementById("twisterOneClickInactive");
    if(x) { x.style.display = 'block'; }
    y = document.getElementById("twisterOneClickActive");
    if(y) { y.style.display = 'none'; }
    z = document.getElementById("twisterShippingDropdown");
    if(z) { z.disabled = true; }
    a = document.getElementById("wishlistAddButtonActive");
    if(a) {a.style.display = 'none';}
    b = document.getElementById("wishlistAddButtonInactive");
    if(b) {b.style.display = 'inline';}
    c = document.getElementById("wishlistDownButtonActive");
    if(c) {c.style.display = 'none';}
    d = document.getElementById("wishlistDownButtonInactive");
    if(d) {d.style.display = 'inline';}
    j = document.getElementById("rslButtonOrig");
    if(j) {j.style.display = 'none';}
    e = document.getElementById("rslButtonJsInactive");
    if(e) {e.style.display = 'block';}
    f = document.getElementById("rslButtonJsActive");
    if(f) {f.style.display = 'none';}
    g = document.getElementById("weddingButtonInactive");
    if(g) {g.style.display = 'block';}
    h = document.getElementById("weddingButtonActive");
    if(h) {h.style.display = 'none';}
    u = document.getElementById("babyButtonActive");
    if(u) { u.style.display = 'none'; }
    v = document.getElementById("babyButtonInactive");
    if(v) { v.style.display = 'block'; }
  }

  this.printAvailability = function(oOfferData) {
    var sAvail = '';
    var sMerchant = oOfferData['merchantName'];
    var sMessage = oOfferData['avail_message'];

    if (!sMessage) {
      return sAvail;
    }
    sAvail += sMessage;

    if (sMerchant) {
      sAvail += ' ' + oStrings['ShipsFrom'] + ' ' + sMerchant;
    }   

    return sAvail;
  }
}

// (FILE: /detail-page-features/twister-prime/twister-prime.js) 

function TwisterPrime(sChildASIN, sDivID, sParentDivID, oTPAjaxObj) {
    var sCurrentASIN = sChildASIN;
    var oPrimeDiv = document.getElementById(sDivID);
    var oPrimeAjaxObj = oTPAjaxObj;

    var oHTML = new Object();
    oHTML[sCurrentASIN] = oPrimeDiv.innerHTML;
    if (sCurrentASIN != "") {
        var oParentDiv = document.getElementById(sParentDivID);
        oHTML[""] = oParentDiv.innerHTML;
    }

    this.setBuyableASIN = function(sASIN) {
        if (sASIN != sCurrentASIN) {
            if ((sASIN == "") || oHTML[sASIN]) {
                this.displayASIN(sASIN);
            } else {
                var oArgs = new Object();
                oArgs["ASIN"] = sASIN;
                oArgs["globalObject"] = 'goTwisterPrime';
                oPrimeAjaxObj.request(oArgs);
            }
        }
    }

    this.setChildHTML = function(sASIN, sHTML) {
        oHTML[sASIN] = sHTML;
        this.displayASIN(sASIN);
    }

    this.displayASIN = function(sASIN) {
        oPrimeDiv.innerHTML = oHTML[sASIN];
        sCurrentASIN = sASIN;
    }
}

// (FILE: /detail-page-features/twister-price-block/twister-price-block.js) 

function TwisterPriceBlock(parentPriceBlockDivID, priceBlockDivID, oPriceBlockStrings, hasPromotions) {
  var sParentPriceBlockDivID = parentPriceBlockDivID;
  var sPriceBlockDivID = priceBlockDivID;
  var oStrings = oPriceBlockStrings;
  var bHasPromotions = hasPromotions;

  var oHTMLCache = new Array();
  var sCurrentASIN = '';

  this.update = function(sASIN, oOfferData) {
    if (sASIN == sCurrentASIN) {
      return;
    }
    sCurrentASIN = sASIN;

    if (sASIN == null) {
      this.clear();
      return;
    }

    if (oHTMLCache[sASIN] == null) {
      var sHTML = '<div class="buying" id="priceBlock"><table class="product"><tbody>';
      sHTML += this.printImportListPrice(oOfferData);
      sHTML += this.printListPrice(oOfferData); 
      sHTML += this.printOurPrice(oOfferData);
      sHTML += this.printSalePrice(oOfferData);
      sHTML += this.printYouSaveRow(oOfferData);
      if (bHasPromotions) {
        sHTML += this.printSpecialOffers(oOfferData);
      }
      sHTML += '</tbody></table></div>';

      oHTMLCache[sASIN] = sHTML;
    }

    document.getElementById(sPriceBlockDivID).innerHTML = oHTMLCache[sASIN];
  }

  this.clear = function() {
    document.getElementById(sPriceBlockDivID).innerHTML = document.getElementById(sParentPriceBlockDivID).innerHTML;
  }

  // Get the Import List Price
  this.printImportListPrice = function(oOfferData) {
    importListPriceString = '';
    if (oOfferData['import_list_price_raw']) {
      if (oOfferData['list_price_raw'] && oOfferData['list_price']) {
        if (oOfferData['list_price_raw'] > oOfferData['our_price_raw']) {
          listPriceString += '<tr><td class="productLabel">' + oStrings['ListPriceLabel'] 
            + '</td><td><b class="listprice">' + oOfferData['list_price'] + '</b></td></tr>';
        } else {
          listPriceString += '<tr><td class="productLabel">' + oStrings['ListPriceLabel'] 
            + '</td><td><b class="price">' + oOfferData['list_price'] + '</b></td></tr>';
        }
      }
    }
    return importListPriceString;
  }

  // Gets the List Price
  this.printListPrice = function(oOfferData) {
    listPriceString = '';

    if (!oOfferData['list_price_raw'] ) { return listPriceString; }

    if ((oOfferData['our_price_raw'] && oOfferData['list_price_raw'] <= oOfferData['our_price_raw']) ||  (oOfferData['sale_price_raw'] && oOfferData['list_price_raw'] <= oOfferData['sale_price_raw'])){
      return listPriceString;
    }

    listPriceString += '<tr><td class="productLabel">' + oStrings['ListPriceLabel'] 
      + ':</td><td class="listprice">' + oOfferData['list_price'];

    if (oOfferData['list_price_with_tax']) {
      listPriceString += ' ' + oStrings['TaxIncluded'];
    }
    listPriceString += '</td></tr>';

    return listPriceString;
  }

  this.printOurPrice = function(oOfferData) {
    var ourPriceString = '';
    var sSSSMessage = '';

    // Display the 'was' price string
    if (oOfferData['was_price_raw'] && oOfferData['was_price']) {
      if(oOfferData['was_price_breaks_map_raw']) {
        ourPriceString += '<tr><td class="productLabel">'+ oStrings['WasText'] +'</td><td>'
          + oStrings['BreaksMap'] +'</td></tr>';
      } else {
        ourPriceString += '<tr><td class="productLabel">'+ oStrings['WasText'] +'</td><td>'
          + oOfferData['was_price'] +'</td></tr>';
      }
    }

    // If offer breaks map, return string with message saying 'too low to show'.
    if (oOfferData['price_breaks_map_raw']) {
      ourPriceString += '<tr><td class="productLabel">';
      if ($oOfferData['was_price']) {
        ourPriceString += oStrings['NowText'];
      } else {
        ourPriceString += oStrings['ItemDetailPriceLabel'];
      }
      ourPriceString += '</td><td>'+ oStrings['BreaksMap'] +'</td></tr>';
      return ourPriceString;
    }

    if (!oOfferData['our_price_raw']) { return ourPriceString; }

    if (oOfferData['sale_price_raw'] && oOfferData['sale_price_raw'] >= oOfferData['our_price_raw']) { return ourPriceString; }

    var priceLabelName = oStrings['ItemDetailPriceLabel'];
    if(oOfferData['was_price_raw']) { priceLabelName = oStrings['NowText']; }
    if(oOfferData['list_price_with_tax'] && !oOfferData['surcharge']) { priceLabelName = oStrings['OurPrice']; }
    ourPriceString = '<tr><td class="productLabel">' + priceLabelName + '</td>';

    if(oOfferData['sale_price_raw']) {
      ourPriceString += '<td><span class="listprice">' + oOfferData['our_price'] + '</span>'; 
    } else {
      ourPriceString += '<td><b class="price">' + oOfferData['our_price'] + '</b>'; 
    }
    if(oOfferData['list_price_with_tax']) {
      ourPriceString += ' ' + oStrings['TaxIncluded'];
    }

    if (oOfferData['isEligibleForSuperSaverShipping'] && (oOfferData['merchantID'] == 'ATVPDKIKX0DER')) {
      ourPriceString += '&nbsp;' + oStrings['SSSMessage'];
    }
    ourPriceString += '</td></tr>';
    return ourPriceString;
  }

  this.printYouSaveRow = function(oOfferData) {
    youSaveString = '';
    if(oOfferData['price_breaks_map_raw']) { return youSaveString; }
    if(oOfferData['always_show_list_price'] == 0) {
      if(oOfferData['isListPriceSuppressed']){ 
        return youSaveString; 
      }
    }
    if(oOfferData['you_save_percentage'] && oOfferData['you_save']) {
      youSaveString += '<tr><td class="productLabel">' + oStrings['PriceYouSave'] + '</td>'; 
      youSaveString += '<td><span class=price>' + oOfferData['you_save'] 
        + ' (' + oOfferData['you_save_percentage'] + '%)</span></td></tr>'; 
    }
    return youSaveString;
  }

  this.printSpecialOffers = function(oOfferData) {
    var hiddenString = '';
    if (oOfferData['promotions'] == undefined) {
      hiddenString = ' style="visibility: hidden"';
    }

    var specialOffersString = '';
    specialOffersString += '<tr><td class="productLabel">' 
      + '<span' + hiddenString + '>' + oStrings['SpecialOffersImage'] + '</span>'
      + '</td><td class="tiny">'
      + '<span' + hiddenString + '>' + oStrings['SpecialOffers'] + '</span'
      + '</td></tr>';
    return specialOffersString;
  }

  this.printSalePrice = function(oOfferData) {
    salePriceString = '';
    if (oOfferData['price_breaks_map_raw']) { return salePriceString; }
    if (oOfferData['sale_price_raw'] && oOfferData['sale_price']) {
      salePriceString = '<tr><td class="productLabel"><span class="price"><b>' + oStrings['SalePriceLabel'] 
        + '</b></span></td><td class="price"><b>' + oOfferData['sale_price'] + '</b></td></tr>';
      ourPriceString = '<tr><td class="productLabel"><b>' + oStrings['ItemDetailPriceLabel'] 
        + '</b></td><td class="price"><b>' + oOfferData['sale_price'] + '</b></td></tr>';

      if (oOfferData['our_price_raw'] && oOfferData['our_price_raw'] <= oOfferData['sale_price_raw']) {
        return ourPriceString;
      }
    }
    return salePriceString;
  }
}

// (FILE: /detail-page-features/twister-availability/twister-availability.js) 

function TwisterAvailability(parentAvailabilityDivID, availabilityDivID, moreBuyingChoicesDivID, oAvailabilityStrings, holidayTimeFrame, parentASIN, sessionID) {
  var sParentAvailabilityDivID = parentAvailabilityDivID;
  var sAvailabilityDivID = availabilityDivID;
  var sMoreBuyingChoicesDivID = moreBuyingChoicesDivID;
  var oStrings = oAvailabilityStrings;
  var bHolidayTimeFrame = holidayTimeFrame;
  var sParentASIN = parentASIN;
  var sSessionID = sessionID;

  var oAvailabilityHTMLCache = new Array();
  var oMoreBuyingChoicesHTMLCache = new Array();
  var sCurrentASIN = '';

  this.update = function(sASIN, oOfferData) {
    if (sASIN == sCurrentASIN) {
      return;
    }
    sCurrentASIN = sASIN;

    if (sASIN == null) {
      this.clear();
      return;
    }

    if (oAvailabilityHTMLCache[sASIN] == null) {
      oAvailabilityHTMLCache[sASIN] = this.printAvailability(oOfferData);
    }

    if (oMoreBuyingChoicesHTMLCache[sASIN] == null) {
      oMoreBuyingChoicesHTMLCache[sASIN] = this.printMoreBuyingChoices(oOfferData);
    }

    document.getElementById(sAvailabilityDivID).innerHTML = oAvailabilityHTMLCache[sASIN];
    document.getElementById(sMoreBuyingChoicesDivID).innerHTML = oMoreBuyingChoicesHTMLCache[sASIN];
  }

  this.clear = function() {
    document.getElementById(sAvailabilityDivID).innerHTML = document.getElementById(sParentAvailabilityDivID).innerHTML;
    document.getElementById(sMoreBuyingChoicesDivID).innerHTML = '';
  }

  this.printAvailability = function(oOfferData) {
    availString = '';
    if (!oOfferData['avail_message']) {
      return availString;
    }
    merchantID = oOfferData['merchantID'];
    merchantName = oOfferData['merchantName'];
    availString += '<b>Availability: </b>';
    availString += oOfferData['avail_message'];
    availString += ' See <a href="/gp/product/product-availability/' + sParentASIN + '/ref=dp_availability_1/' + sSessionID + '?%5Fencoding=UTF8&m=' + merchantID +'" onClick="return amz_js_PopWin(\'/gp/product/product-availability/' 
      + sParentASIN + '/ref=dp_availability_1/' + sSessionID + '?%5Fencoding=UTF8&m=' + merchantID 
      + '\',\'AmazonHelp\',\'width=570,height=600,resizable=1,scrollbars=1,toolbar=0,status=1\');" >pricing and availability chart</a> for details.';    
    availString += ' Ships from and sold by <a href="/gp/help/seller/at-a-glance.html/' + sSessionID + '?%5Fencoding=UTF8&seller=' + merchantID + '">' + merchantName + '</a>.';
    if (bHolidayTimeFrame && (merchantName != 'Amazon.com')) {
      availString += ' Want it by Dec. 22? View this seller\'s <a href="/gp/help/seller/shipping.html/' + sSessionID + '?ie=UTF8&seller=' + merchantID + '">shipping details</a>.';
    }
    return availString;
  }

  this.printMoreBuyingChoices = function(oOfferData) {
    var sHTML = '';
    var nAvailCond = oOfferData['availabilityCondition'];
    var nUsedAndNew = oOfferData['usedAndNewCount'];

    if ((nAvailCond && nUsedAndNew <= 1) || 
        (!nAvailCond && nUsedAndNew <= 0)) {
      return sHTML;
    }

    var sPrice = oOfferData['usedAndNewLowestPrice'];
    if (sPrice) {
      sHTML += '<b><a href="/gp/offer-listing/' + oOfferData['ASIN'] + '/' + sSessionID + '">';
      sHTML += (nUsedAndNew-1) + ' ';
      sHTML += (nUsedAndNew >= 3) ? oStrings['more_buying_choices'] : oStrings['more_buying_choice'];
      sHTML += '</a>';
      if (!oOfferData['usedAndNewLowestPriceBreaksMAP']) { 
        sHTML += ' ';
        sHTML += (nUsedAndNew >= 3) ? oStrings['from'] : oStrings['at'];
        sHTML += ' ' + '<span class="price">' + sPrice + '</span>';
      }
      sHTML += '</b>';
    }

    return sHTML;
  }
}

