/**
 * @fileoverview
 * Provides classes and functions to be shared amongst all ODAT sites
 * Includes:
 *     Fuel Gauges
 *     People on Site Graphs
 *     Dynamic updating
 *     Promos
 *     Carousel
 *     People on Site Statistics
 */

if (typeof(BCNTRY) == 'undefined') {BCNTRY = {};}
if (typeof BCNTRY.odat == 'undefined') {BCNTRY.odat = {};}
if (typeof(BCNTRY.odat.homepage) == 'undefined') { BCNTRY.odat.homepage = {}; }

BCNTRY.odat.refreshInterval = 20000;

/** 
 * A class for storing information about, and rendering fuel gauges on the page
 * @constructor
 * @param {String} element_id ID for the element containing the fuel gauge
 */
BCNTRY.FuelGauge = function (element_id, liquid_element) {
    
    // Default values
    this.percentage = 0;
    this.margin = 10;
    this.transitions = [0.27,0.28,0.29,0.30,0.31,0.32,0.33,0.34,1];
    this.usePercentTransitions = true;

    if ($(element_id)) {
        this.element = $(element_id);
        this.liquid_element = liquid_element;
        if (!this.liquid_element) {
        //this.element is not guaranteed to exist in the DOM yet
            var element = new YAHOO.util.Element(this.element);
            this.liquid_element = element.getElementsByClassName('liquid','span');
        }
        if (this.liquid_element) {
            this.liquid_element = this.liquid_element[0];
            this.width = this.liquid_element.clientWidth || this.liquid_element.offsetWidth;
            this.height = this.liquid_element.clientHeight || this.liquid_element.offsetHeight;
        }
    }
};
    
/**
 * Sets the data for the FuelGauge
 * @param {Integer} current Current value for the gauge
 * @param {Integer} total Total value for the gauge
 
 */
BCNTRY.FuelGauge.prototype.set_data = function (current, total) {

    if (typeof current == "undefined") {
        return;
    }
    if (current > total) {
        current = total;
    }
    if (current < 0) {
        current = 0;
    }
    if (total < 0) {
        total = 0;
    }
    this.current = current;

    if (typeof total != 'undefined') {
        this.total = total;
    }
    if (this.total !== 0) {
        this.percentage = this.current/this.total;
    }
    else {
        this.percentage = 0;
    }
};
    
/**
 * Get an index into the image that corresponds to the current percentage full
 * to show a transition
 * @returns The index
 */
BCNTRY.FuelGauge.prototype.get_background_index = function () {
        
    // Loop through transitions array until percentage is smaller than the value
    for (var i = 0; i < this.transitions.length; i++) {
        if (this.transitions.hasOwnProperty(i)) {
            if (this.usePercentTransitions) {
                if (this.percentage <= this.transitions[i]) {
                    return i;
                }
            }
            else {
                 if (this.current <= this.transitions[i]) {
                     return i;
                 }
            }
        }
    }
    return i;
};

/** 
 * A class for storing information about, and rendering timer fuel gauges on 
 * the page
 * @constructor
 * @param {String} element_id ID for the element containing the fuel gauge
 */
BCNTRY.TimerFuelGauge = function (element_id) {

    // closure to get around setTimeout scope issues
    var that = this;
    
    this._decrement_time = function () {
        that.set_data(that.current - 1);
        that.draw();
        // Handle events on current time
        if (BCNTRY.on_tick) {
            BCNTRY.on_tick(that.current);
        }
        that.update_timer();
    };
    
    /**
     * Sets the timeout to update the timer.  It is called in this way
     * to get around issues with setTimeout scope
    */
    this.update_timer = function () {
        setTimeout(this._decrement_time,1000);
    };
    
    return BCNTRY.FuelGauge.call(this, element_id);
};

BCNTRY.TimerFuelGauge.prototype = new BCNTRY.FuelGauge();

/**
 * Overrides superclass method to show in time format
 * @returns {String} a time-formatted string
 */
BCNTRY.TimerFuelGauge.prototype.format_current_mark = function () {
    var mins = this.current%60;
    if (mins < 10) { mins = '0'+mins;}
    return Math.floor(this.current / 60)+':'+mins;
};

/**
 * Sets up a timer bar in the 'time_remaining_bar' element
 * @param {Integer} time_remaining the number of seconds remaining
 * @param {Integer} duration the total duration in seconds
 */
BCNTRY.setupTimerBar = function(time_remaining,duration) {
    if ($('time_remaining_bar')) {
        BCNTRY.time_remaining_bar = new BCNTRY.TimerFuelGauge('time_remaining_bar');
        BCNTRY.time_remaining_bar.margin = 0;
        BCNTRY.time_remaining_bar.show_current_mark = true;
        BCNTRY.time_remaining_bar.set_data(time_remaining,duration);
        BCNTRY.time_remaining_bar.draw();
        
        BCNTRY.time_remaining_bar.update_timer();
    }
};

/**
 * For WhiskeyMilitia. Sets up a timer bar in the 'time_remaining_bar' element
 * @param {Integer} time_remaining the number of seconds remaining
 * @param {Integer} duration the total duration in seconds
 */
BCNTRY.setupWMTimerBar = function(time_remaining,duration) {
    if ($('time_remaining_bar')) {
        BCNTRY.time_remaining_bar = new BCNTRY.TimerFuelGauge('time_remaining_bar');
        BCNTRY.time_remaining_bar.margin = 0;
        BCNTRY.time_remaining_bar.current_mark_element = $('time_remaining');
        BCNTRY.time_remaining_bar.show_current_mark = true;
        BCNTRY.time_remaining_bar.set_data(time_remaining,duration);
        BCNTRY.time_remaining_bar.transitions = [0.2];
        BCNTRY.time_remaining_bar.usePercentTransitions = true;
        
        BCNTRY.time_remaining_bar.draw();
        
        BCNTRY.time_remaining_bar.update_timer();
    }
};

/**
 * Adds commas to a number for output at every 1000
 * @returns String with numbers and commas
 */
BCNTRY.addCommas = function (nStr) {
    nStr += '';
    var x = nStr.split('.');
    var x1 = x[0];
    var x2 = x.length > 1 ? '.' + x[1] : '';
    var rgx = /(\d+)(\d{3})/;
    while (rgx.test(x1)) {
        x1 = x1.replace(rgx, '$1' + ',' + '$2');
    }
    return x1 + x2;
};
    
/**
 * Overrideable method to format the display of the current value of the
 * FuelGauge
 * @returns String to display as the current value of the FuelGauge
 */
BCNTRY.FuelGauge.prototype.format_current_mark = function () {
    return BCNTRY.addCommas(this.current);
};
    
/**
 * Shows the current value of the FuelGauge.  If there is no element to hold
 * the value, then creates it.
 */
BCNTRY.FuelGauge.prototype.show_current = function () {
    if (!this.current_mark_element) {
        this.current_mark_element = document.createElement('span');
        this.current_mark_element.setAttribute('class','fg_current_mark');
        this.current_mark_element.className = 'fg_current_mark';
        this.current_mark_element.appendChild(document.createTextNode(this.format_current_mark()));
        if (this.element) {
            this.element.appendChild(this.current_mark_element);
        }
    }
    else {
        this.current_mark_element.innerHTML = this.format_current_mark();
    }
};
    
/**
 * Draws the FuelGauge.
 */
BCNTRY.FuelGauge.prototype.draw = function () {
    if (this.current < 0 ) {
        return;
    }
    var available_width = this.width - (this.margin * 2);

    if (this.liquid_element) {
        this.liquid_element.style.width = available_width * this.percentage+'px';
        this.liquid_element.style.backgroundRepeat = 'repeat-x';
        var possie = '0px -'+(this.get_background_index() * this.height)+'px';
        this.liquid_element.style.backgroundPosition = possie;
        this.liquid_element.style.visibility = 'visible';
    }
    if (this.show_current_mark) {
        this.show_current();
    }
};
    
/* Flip */

/**
 * Sort function for numbers
 */
BCNTRY.sortNumber =  function (a,b)
{
    return a - b;
};

/**
 * Normalises the flip times to take the interval into account.  Also
 * puts them in order.
 * @param {Array} flip_array Array of flip times
 * @param {Integer} interval 
 * @param {Boolean} absolute Set to true if absolute time values are used.
 * @returns Array of flip_times normalised by the interval
 */
BCNTRY.normalise_flip_times = function (flip_array, interval, absolute) {
    if (!interval) {
        return;
    }
    var flips = [];
    for (var i in flip_array) {
           if (flip_array.hasOwnProperty(i)) {
               if (absolute && typeof BCNTRY.page_data.offset_seconds != "undefined") {
                   flips.push(Math.floor(((new Date()).getTime()/1000 - flip_array[i].gcs - BCNTRY.page_data.offset_seconds)/ interval));
               }
               else {
                   flips.push(Math.floor(flip_array[i].gcs / interval));
               }
               flips = flips.sort(BCNTRY.sortNumber);
           }
    }
       
   return flips;
};

/*Visitor Count*/


/**
 * A Class for the times that products flip on the site
 * @constructor
 * @param ctx Canvas context
 */

BCNTRY.Flips = function(ctx) {

    this.ctx = ctx;
    this.right = 0;
    this.top = 0;
    this.width = 100;
    this.height = 100;
    this.flips = [];
    this.interval = 1;
    this.left_color = "#999999";
    this.right_color = "#eeeeee";
};

/**
 * Draws the flip times on the graph
 */
BCNTRY.Flips.prototype.draw = function () {

    if (!this.flips) {
        return;
    }
    for (var flip = 0; flip < this.flips.length; flip++) {
        if (this.flips.hasOwnProperty(flip)) {
            
          // Calculate time in from the end of the graph
          var x = this.right - (this.flips[flip]*this.interval);
          if (x < 0 ) {
              continue;
          }
          this.ctx.beginPath();
          this.ctx.lineWidth = 1;
          this.ctx.moveTo(x, this.top);
          this.ctx.strokeStyle = this.left_color;
          this.ctx.lineTo(x,this.top+this.height);
          this.ctx.stroke();
          
          x++;
          this.ctx.strokeStyle = this.right_color;
          this.ctx.fillRect(x,0,2,this.top+this.height);
        }
    }
};

/**
 * A Class for drawing line graphs
 * @constructor
 */
BCNTRY.LineGraph = function(ctx) {

    this.ctx = ctx;
    this.lineWidth = 1;
    this.strokeStyle = 'black';
    this.left = 0;
    this.top = 0;
    this.width = 100;
    this.height = 100;
    this.normalised_points = [];
    this.interval = 1;
};

/**
 * Set the area of the graph
 * @param {Integer} x Starting x coordinate
 * @param {Integer} y Starting y coordinate
 * @param {Integer} w Width
 * @param {Integer} h Height
 
 */
BCNTRY.LineGraph.prototype.area = function (x,y,w,h) {
    this.left = x;
    this.top = y;
    this.width = w;
    this.height = h;
};

/**
 * Sets a parameter for the canvas context
 * @param {String} element Name of the element to set
 * @param {String} value Value to be set 
 */
BCNTRY.LineGraph.prototype.SetContext = function (element, value) {
    this[element] = value;
    this.ctx[element] = this[element];
};

/**
 * Draws the LineGraph
 */
BCNTRY.LineGraph.prototype.draw = function () {

  var x = this.left;
  this.ctx.beginPath();
  var first_point = true;

  for (var point = 0; point < this.normalised_points.length; point++) {
      if (this.normalised_points.hasOwnProperty(point)) {
         var real_point = this.top + (this.height - (this.height*this.normalised_points[point]));
         if (first_point) {
             this.ctx.moveTo(x,real_point);
             first_point = false;
         }
         this.ctx.lineTo(x,real_point);
         x += this.interval;
         
         // Do not draw off the end
         if (x > this.left+this.width) {
             break;
         }
      }
  }
  this.ctx.stroke();
};

/**
 * A Class for a bar graph
 * @constructor
 * @extends BCNTRY.LineGraph
 * @param ctx Canvas context
 */
BCNTRY.BarGraph = function (ctx) {
    this.ctx = ctx;
};

BCNTRY.BarGraph.prototype = new BCNTRY.LineGraph();
BCNTRY.BarGraph.prototype.fillStyle = null;

/**
 * Draws the BarGraph
 */
BCNTRY.BarGraph.prototype.draw = function () {
          
    if (this.fillStyle) {        
        this.ctx.fillRect(this.left,this.top,this.width,this.height);
    }
    this.ctx.beginPath();
    var x = this.left;
    for (var point = 0; point < this.normalised_points.length; point++) {
        if (this.normalised_points.hasOwnProperty(point)) {
            var real_point = this.top + (this.height - (this.height*this.normalised_points[point]));
            this.ctx.moveTo(x,this.top + this.height);
            this.ctx.lineTo(x,real_point);
            x+=this.interval;
            // Do not allow graph to go outside box
            if (x > this.left+this.width) {
             break;
            }
        }
      }
      this.ctx.stroke();        
};

/**
 * A Class for the whole graph, line, bar, flips
 * @constructor
 * @param ctx Canvas context
 */
BCNTRY.VStatsGraph = function(ctx) {
    this.ctx = ctx;
};

/**
 * Initialise the VStatsGraph
 * @param {Hash} opt A Hash of options
 */
BCNTRY.VStatsGraph.prototype.init = function (opt) {
    
    // default values
    this.height = 45;
    this.width = 165;
    this.full_width = 280;
    this.interval = 4;
    this.line_color = "#006439";
    this.new_bar_color = this.line_color;
    this.old_bar_color = "#999999";
    this.old_gradient_top = '#999';
    this.old_gradient_bottom = '#e6e6e6';
    this.new_gradient_top = '#e6e6e6';
    this.new_gradient_bottom = '#fff';
    this.high_water_mark = 100000;
    this.low_water_mark = 0;
    this.current_count = 0;
    
    this.counts = [];
    this.normalised_points = [];
    this.current_normalised_points = [];
    this.old_normalised_points = [];
    this.flip_times = [];

    // Set options
    if (opt) {
        for (var parameter in opt) {
            if (opt.hasOwnProperty(parameter)) {
                this[parameter] = opt[parameter];
            }
        }
    }
    
    this.num_points = Math.floor(this.width / this.interval);
    
};


/**
 * Slices the visitor count data into current and old segments, based
 * on the most recent flip time.
 *
 */
BCNTRY.VStatsGraph.prototype.slice = function () {
   
    if (!this.normalised_points) {
        return;
    }
    var last_flip = 0;
    if (this.flips) {
        last_flip = this.normalised_points.length - this.flips[0];
    }
    this.old_normalised_points = this.normalised_points.slice(0,last_flip);
    this.current_normalised_points = this.normalised_points.slice(last_flip);
   
};

/**
 * Draws the entire graph
 */
BCNTRY.VStatsGraph.prototype.draw = function () {

    this.ctx.clearRect(0,0,this.full_width,this.height);

    // Fill the entire graph with a gradient
    var lingrad = this.ctx.createLinearGradient(0,0,0,this.height);    
    lingrad.addColorStop(0, this.new_gradient_top);
    lingrad.addColorStop(1, this.new_gradient_bottom);
    this.ctx.fillStyle = lingrad;
    this.ctx.fillRect(0,0,this.full_width,this.height);
    
    // Draw the old bars
    var old_bars = new BCNTRY.BarGraph(this.ctx);
    old_bars.normalised_points =  this.old_normalised_points;
    old_bars.SetContext('strokeStyle',this.old_bar_color);
    old_bars.area(0,0,this.old_normalised_points.length*this.interval,this.height);
    old_bars.interval = this.interval;
    lingrad = this.ctx.createLinearGradient(0,0,0,this.height);
    lingrad.addColorStop(0, this.old_gradient_top);
    lingrad.addColorStop(1, this.old_gradient_bottom);
    // assign gradients to fill and stroke styles
    old_bars.SetContext('fillStyle',lingrad);
    old_bars.draw();
    
    // Draw the new bars
    var new_bars = new BCNTRY.BarGraph(this.ctx);
    new_bars.normalised_points =  this.current_normalised_points;
    new_bars.SetContext('strokeStyle',this.new_bar_color);
    new_bars.area(this.old_normalised_points.length*this.interval,0,this.width,this.height);
    new_bars.interval = this.interval;
    lingrad = this.ctx.createLinearGradient(0,0,0,this.height);
    lingrad.addColorStop(0, this.new_gradient_top);
    lingrad.addColorStop(1, this.new_gradient_bottom);
    // assign gradients to fill and stroke styles
    new_bars.SetContext('fillStyle',lingrad);
    new_bars.draw();
    
    // Draw the flip times
    var flipper = new BCNTRY.Flips(this.ctx);
    flipper.flips = this.flips;
    flipper.interval = this.interval;
    flipper.right = this.normalised_points.length*this.interval;
    flipper.draw();
    
    // Draw the line graph
    var line = new BCNTRY.LineGraph(this.ctx);
    line.normalised_points =  this.normalised_points;
    line.SetContext('strokeStyle',this.line_color);
    line.area(0,0,this.width,this.height);
    line.interval = this.interval;
    line.draw();
    
    // Hack
    this.ctx.strokeStyle = 'rgba(0,0,0,0)';
    this.ctx.stroke();

};
  
/**
 * A Class to hold the visitor counts
 * @constructor
 * @param {String} element_id ID of the HTML element to hold the vistor count
 */
BCNTRY.VStats = function (element_id) {
    this.element = $(element_id);
    this.water_mark_interval = 1000;
    this.water_mark_margin = 0.2;
};

/**
 * Initialises the context for the canvas element
 * @returns A Canvas context
 */
BCNTRY.VStats.prototype.init_context = function () {
    
    if (!this.element) {
        return;
    }
    
    if (!(this.canvas && this.canvas.getContext)) {
        var canvases = this.element.getElementsByTagName('canvas');
        if (canvases) {
            this.canvas = canvases[0];
            if (typeof G_vmlCanvasManager != 'undefined') { 
                G_vmlCanvasManager.initElement(this.canvas); 
            }
            if (this.canvas.getContext) {
                this.ctx=this.canvas.getContext('2d');
            }
            else {
            }
        }
    }
    return this.ctx;
};

/**
 * Normalises the data into the range 0-1 and sets the high and low
 * water marks
 */
BCNTRY.VStats.prototype.normalise = function () {
     
    if (!this.counts) {
        return;
    }
    
    var min = 999999999999;
    var max = 0;
    var index;
    
    if (this.graph.num_points < this.counts.length) {
        this.counts = this.counts.slice(this.counts.length - this.graph.num_points);
    }

    for (index = 0; index < this.counts.length; index++) {
        if (this.counts.hasOwnProperty(index)) {
            var vcount = this.counts[index];
            if (vcount > max) { max = vcount;}
            if (vcount < min) { min = vcount;}
        }
    }
    
    // No data
    if (max === 0 && min == 999999999999) {
        this.high_water_mark = null;
        this.low_water_mark = null;
        return;
    }

    this.high_water_mark = Math.ceil(max*(1+this.water_mark_margin) / this.water_mark_interval) * this.water_mark_interval;
    this.low_water_mark =  Math.floor(min*(1-this.water_mark_margin) / this.water_mark_interval) * this.water_mark_interval;
    var range = this.high_water_mark - this.low_water_mark;

    // Do not continue if range is zero for some reason
    if (!range) {
        return;
    }
    
    for (index = 0; index < this.counts.length; index++) {
        if (this.counts.hasOwnProperty(index)) {
            this.normalised_points.push((this.counts[index] - this.low_water_mark )/ range);
        }
    }
};

/**
 * Initialise VStats
 * @param {Hash} opt Options for VStats
 */
BCNTRY.VStats.prototype.init = function (opt) {

    this.normalised_points = [];

    // Set options
    for (var parameter in opt) {
        if (opt.hasOwnProperty(parameter)) {
            this[parameter] = opt[parameter];
        }
    }
    
    this.init_context();
    
    if (this.ctx) {
        this.graph = new BCNTRY.VStatsGraph(this.ctx);
        this.graph.init(this.graph_opts);
    }
    else {
        return;
    }

    if (opt.counts) {
        this.counts = opt.counts;
    }
    if (this.counts) {
        this.current_mark = this.counts[this.counts.length-1];
        this.normalise();
    }
};
  
/**
 * Update the high-water, low-water and current values.  If the elements
 * do not exist, then create them
 */
BCNTRY.VStats.prototype._marks = function () {
    
    if (!this.element) {
        return;
    }
    if (typeof this.current_mark !== 'undefined' && this.current_mark !== null) {
        if (!this.current_mark_element) {
            this.current_mark_element = document.createElement('span');
            this.current_mark_element.setAttribute('class','current_mark');
            this.current_mark_element.className = 'current_mark';
            this.current_mark_element.appendChild(document.createTextNode(BCNTRY.addCommas(this.current_mark)));
            this.element.appendChild(this.current_mark_element);
        }
        else {
            this.current_mark_element.innerHTML = BCNTRY.addCommas(this.current_mark);
        }
    }
    if (typeof this.high_water_mark !== 'undefined' && this.high_water_mark !== null) {
        if (!this.high_water_mark_element) {
            this.high_water_mark_element = document.createElement('span');
            this.high_water_mark_element.setAttribute('class','high_water_mark');
            this.high_water_mark_element.className = 'high_water_mark';
            this.high_water_mark_element.appendChild(document.createTextNode(this.high_water_mark));
            this.element.appendChild(this.high_water_mark_element);
        }
        else {
            this.high_water_mark_element.innerHTML = BCNTRY.addCommas(this.high_water_mark);
        }
    }
    if (typeof this.low_water_mark !== 'undefined' && this.low_water_mark !== null) {
        if(!this.low_water_mark_element) {
            this.low_water_mark_element = document.createElement('span');
            this.low_water_mark_element.setAttribute('class','low_water_mark');
            this.low_water_mark_element.className = 'low_water_mark';
            this.low_water_mark_element.appendChild(document.createTextNode(BCNTRY.addCommas(this.low_water_mark)));
            this.element.appendChild(this.low_water_mark_element);
        }
        else {
            this.low_water_mark_element.innerHTML = BCNTRY.addCommas(this.low_water_mark);
        }
    }
};

/**
 * Render the VStats object
 */
BCNTRY.VStats.prototype.draw = function () {
    
    this._marks();
    if (this.ctx) {
        if (!(this.graph && this.graph.ctx)) {
            this.graph = new BCNTRY.VStatsGraph(this.ctx);
            this.graph.init(this.graph_opts);
        }
        this.graph.flips = this.flip_times;
        this.graph.normalised_points = this.normalised_points;
        this.graph.slice();
        this.graph.draw();

    }
    else {
        this.init_context();
    }
};

/**
 * Refreshes the graph and re-draws
 * @param {Hash} opt Hash of options
 */
BCNTRY.VStats.prototype.refresh = function (opt) {
    this.init(opt);
    this.draw();
};


// function used to swap images 
BCNTRY.changeImage = function(imageName) {
    var parent_image = $('item_image');
    var item_image = YAHOO.util.Dom.getFirstChild(parent_image);
    var actual_image = YAHOO.util.Dom.getAttribute(item_image,'src');
    
    if (imageName != 0 &&  actual_image.indexOf(imageName) < 0) {
        YAHOO.util.Dom.setAttribute(item_image,'src',imageName);
    }
};


function sendEmail(){
    var sUrl = email_friend_path;
      
    var args = 'catalog_id=' + BCNTRY.site.catalog +'&from_name=' + $('your_name').value + 
               '&your_email=' + $('your_email').value +
               '&sku=' + $('email_sku').value +
               '&discount=' + $('email_percent_off').value +
               '&price=' + $('email_price').value +
               '&friend_email=' + $('friend_email').value;
               
    ajax(sUrl, args, function(r) {
        $('email_friend_message').innerHTML = r.responseText;
        if(r.responseText.match(/Email Sent/)) {    
            var sfo = new ScEmailFriendOdat(); // Omniture function to update site catalyst with email a friend data
        }
    },'post');
    
}

BCNTRY.show_promos = function (promo_content_ids) {
    if (promo_content_ids.length) {
        var id_to_show = promo_content_ids[Math.floor(Math.random()*promo_content_ids.length)];
        var parent = document.getElementById(id_to_show).parentNode;
        var children = parent.childNodes;
        for (var child = 0; child < children.length; child++) {
            if (children[child].style) {
                children[child].style.display = 'none';
            }
        }
        document.getElementById(id_to_show).style.display = 'block';
    }
};

/**
* Refreshes all the iframes that have a given class
* @param {String} refreshClass  Class name for the iframes to be refreshed
*/
BCNTRY.refreshAds = function (refreshClass) {
    var frames = yd.getElementsByClassName(refreshClass,'iframe');
    for (var i in frames) {
        if (frames.hasOwnProperty(i)) {
            var src = frames[i].src;
            frames[i].src = src;
        }
    }
};

/**
* Refreshes all the iframes that have a given class.  If the supplied interval
* is false, then there will be no refreshing.
* @param {Integer} interval Milliseconds between refreshes
*/
BCNTRY.startRefreshAds = function (interval) {
    if (interval) {
        setInterval(function () {BCNTRY.refreshAds('refreshable');},interval);
    }
};

BCNTRY.showNoneSelected = function () {
    if (typeof BCNTRY.odat.homepage.none_popup == 'undefined') {
        BCNTRY.setupNoneSelected();
    }
    BCNTRY.odat.homepage.none_popup.show();
    if (typeof(ScVariantPop) !== 'undefined') {
        var scv = new ScVariantPop();
    }

    return false;
};

BCNTRY.checkOptions = function() {
    
    if (!$('sizeSelectBox')  || !$('mv_order_quantity')) {
        return false;
    } 
    if($('sizeSelectBox').value === '0' || $('mv_order_quantity').value === '0') {
        return BCNTRY.showNoneSelected();
    }

    return true;
};

BCNTRY.isLoggedIn = function() {
	return document.cookie.match(/username=\d+/) || document.cookie.match(/mv_password=\w+/i);
};

/**
 * Shows the user's display name in the element provided
 * @returns user's display name
 * @type String
 */
BCNTRY.showName = function(El) {
    var displayName = _readCookie('review_display_name');
    if ($(El)) {
        $(El).innerHTML = displayName;
    }
	return displayName;
};
/**
 * Displays logged-in sections if the user is logged-in
 * @returns true if logged-in
 * @type Boolean
 */
BCNTRY.setLogInOut = function() {
    var loggedinElements = YAHOO.util.Dom.getElementsByClassName('logged_in');
    var loggedoutElements = YAHOO.util.Dom.getElementsByClassName('logged_out');
    var i;

    if (BCNTRY.isLoggedIn()) {
		for (i in loggedinElements) {
			if (loggedinElements[i].style) {
				loggedinElements[i].style.display='inline';
			}
		}
			
		for (i in loggedoutElements) {
			if (loggedinElements[i].style) {
				loggedoutElements[i].style.display='none';
			}
		}
		return true;
    }
    else {
		for (i in loggedinElements) {
            if (loggedinElements[i].style) {
                loggedinElements[i].style.display='none';
			}
		}
		
		for (i in loggedoutElements) {
            if (loggedoutElements[i].style) {
                loggedoutElements[i].style.display='inline';
            }
		}
        return false;
    }
};

BCNTRY.setDebugInfo = function() {
    
    if ($('debug_webserver')) {
        $('debug_webserver').innerHTML = _readCookie('ServerID');
    }
    if ($('debug_username')) {
        $('debug_username').innerHTML = _readCookie('username');
    }
    if ($('debug_session')) {
        $('debug_session').innerHTML = _readCookie('MV_SESSION_ID');
    }
};


var _isLoggedInOmni = function() {
    if(BCNTRY.isLoggedIn()) {
        return 'Logged in';
    }
    else {
        return 'Logged out';
    }
};

function _getUrlVariable(v) {
    var uri = document.URL.split('?');

    if (uri.length == 1) {
        return '';
    }    

    var kvPair;
    var Url = {};

    if (uri[1].match(/&/g)) {
        var varSet = uri[1].split('&');

        for (i = 0; i < varSet.length; i++) {
            kvPair = varSet[i].split('=');
            Url[kvPair[0]] = unescape(kvPair[1]);
        }
    }
    else {
        kvPair = uri[1].split('=');
        Url[kvPair[0]] = unescape(kvPair[1]);
    }

    if (v) {
        return Url[v];
    }
    return Url;
}

function getPromoIDS (p) {
    // Arguments: ID of a div that contains a promo.
    // Returns: comma separated list of internal campaign IDS for a given promo spot.
    // Short Comings: will only do one promo spot... In the future,
    //   will need to do all promo spots on a page.
    
    if(!document.getElementById(p)) {
        return;
    }
    var a = document.getElementById(p).getElementsByTagName('a');
    var ids_ary = [];

    var seen = {};

    var params;
    var kvpair = [];
    
    for (i = 0; i < a.length; i++) {
        var qstr = a[i].search.replace(/\?/, '');
        if (!qstr) {
            return;
        }
        params = qstr.split('&');

        for (var j = 0; j < params.length; j++) {
            if (params[j].indexOf('=') != -1) {
                kvpair = params[j].split('=');
            }
        
            if (kvpair.length == 2 && kvpair[0].match(/(?:CMP|INT)_ID/i)) {
                if (!seen[kvpair[1]]) { ids_ary.push(kvpair[1]); }
                seen[kvpair[1]] = 1;
            }
        }
    }

    return ids_ary.join(',');
}

BCNTRY.getAllPromoIDs = function () {
    
    var all_promos = yd.getElementsByClassName('promo');
    var promo_id_str = '';
    for (var promo_index in all_promos) {
        if (all_promos.hasOwnProperty(promo_index)) {
            if (yd.getStyle(all_promos[promo_index],'display') == 'block') {

                var current_promo_str = getPromoIDS($(all_promos[promo_index]).id);
                if (current_promo_str) {
                    if (promo_id_str) {
                        promo_id_str += ',';
                    }
                    promo_id_str += current_promo_str;
                }
            }
        }
    }
    return promo_id_str;
};

BCNTRY.setMaxQ = function (elem,qsel,max_qty_el,other_elem_name, disable_class) {
    max_qty_el = $(max_qty_el);
    
    // return if no variant selector on page i.e. soldout
    if (!elem) {
        return 0;
    }
    if (elem.selectedIndex === 0) {
        if (elem.options.length > 1) {
            qsel.selectedIndex = 0;
            if (other_elem_name) {
                yd.addClass(other_elem_name,disable_class);
            }
            if (max_qty_el) { max_qty_el.value = ''; }
            return;
        } 
    }    
    if (other_elem_name) {
        yd.removeClass(other_elem_name,disable_class);
    }
    var code = elem.options[elem.selectedIndex].value;
    var mq = BCNTRY.variants_mp[code];
    var qty_selected = qsel.value;
    if (qsel.options.length != mq) { qsel.options.length = mq; }

    qsel.options[0].text = qsel.options[0].text.replace(/Max\. \d+/, 'Max. ' + mq);
    for (i = 0; i < qsel.options.length; i++) {
        if (i == (qsel.options.length - 1)) {
            qsel.options[i].text = (i + 1) + " (Max)";
        }
        else {
            qsel.options[i].text = (i + 1);
        }
        qsel.options[i].value = i + 1;
    }
    if (qty_selected > mq) {
        qsel.value = mq;
    }
    if (max_qty_el) { max_qty_el.value = mq; }
};

/**
 * Change image on dropdown change
 */
BCNTRY.select_change = function () {
    var variant = $('sizeSelectBox').value;
    
     if(BCNTRY.images[variant]) {
        BCNTRY.changeImage(BCNTRY.images[variant]);
    }
};


BCNTRY.setupNoneSelected = function(){
    // Setup the 'none selected popup'

    BCNTRY.odat.homepage.none_popup = new YAHOO.widget.Panel("none_selected_popup", {
        visible:false,
        close:true,
        draggable:true,
        modal:true,
        zIndex:500,
        fixedcenter:true
    });

    // There's a bug where this element is 'inherit' in IE, but properly 'hidden' in FF.
    yd.setStyle(BCNTRY.odat.homepage.none_popup.element, 'visibility', 'hidden');

    BCNTRY.odat.homepage.none_popup.updateSubmitPanel = function (variant_id) {
        BCNTRY.odat.homepage.none_popup.hide();
        var form = $('buy_form');

        if (typeof BCNTRY.pete !== 'undefined') {
            var tmpVariant = new BCNTRY.Variant();
            tmpVariant.parent = BCNTRY.pete.selector;
            tmpVariant.updateData(variant_id);
            BCNTRY.pete.selectedVariants.addVariant(tmpVariant);
        }
        else {
            form.mv_sku.value = variant_id;
            var selected_index = form.mv_sku.selectedIndex;
            form.mv_sku.selectedIndex = selected_index;
            BCNTRY.setMaxQ(form.mv_sku,$('mv_order_quantity'),'max_quantity');
        }
        form.submit();
    };

    BCNTRY.odat.homepage.none_popup.hideEvent.subscribe(function() {
        $('none_selected_popup').style.display = 'none';
        BCNTRY.odat.homepage.none_popup.hideMask();
    });

    BCNTRY.odat.homepage.none_popup.subscribe('show', function () {
        var p = BCNTRY.odat.homepage.none_popup;
        $('none_selected_popup').style.display = 'block';
        if (!p.mask) {
            p.buildMask();
            ye.addListener(p.mask, 'click', function() { 
                p.hide(); 
            });
        
        p.showMask();
        p.mask.style.zIndex = '499'; // For some reason js sets this to '1'
        }
    });

    BCNTRY.odat.homepage.none_popup.render();

};

BCNTRY.setupSizeSelect = function() {
    
    YAHOO.util.Event.addListener('sizeSelectBox','change',function() {
            BCNTRY.select_change(); 
            BCNTRY.setMaxQ(this,$('mv_order_quantity'),'max_quantity');
    });
};

BCNTRY.setupTimerTicks = function () {
    if (typeof gTicks_1 !== 'undefined') {
        yc.delayedAsyncRequest(
            'POST',
            '/'+BCNTRY.site.catalog+'/'+BCNTRY.site.controller+'/timer_ticks',
            {
                success: function(r) {
                    gTicks_1 = r.responseText;
                }
            }
        );
    }
};

YAHOO.util.Event.onDOMReady(function() {

	//Init a SC Buffer for omniture tracking
	BCNTRY.odat.initSCBuffer();

    BCNTRY.setDebugInfo();
    //BCNTRY.setupNoneSelected();
    BCNTRY.odat.setupTabs();
    //BCNTRY.odat.setupDefaultTexts();
    //BCNTRY.odat.showElementsOnOff();
    
    //Clear shipping cookie so that can default to combined shipping
    _setCookie('shipping_selection',0, '', '/');
    
    if (BCNTRY.showAffRef) {
      BCNTRY.showAffRef(BCNTRY.affRef);
    }

    // Initialize the tab alert - the tab alert starts only when there is a new item
    // This needs to be executed before fireOmni, since tabalerts depend on odat_has_refreshed cookie to start and fireOmni is the one that sets it off
    BCNTRY.odat.tab.alerts.TabAlertManager.initializeTabAlert();
    
    if (BCNTRY.fireOmni) {
      BCNTRY.fireOmni();
    }
  
    if ( BCNTRY.odat.getStats() ) {
        BCNTRY.posInitialized = 1;
    }
    
    if (typeof ScShareOnFacebook !== 'undefined') {
        ye.addListener('fb_share_link','click',ScShareOnFacebook);
    }
    
    if (typeof ScViewRSS !== 'undefined') {
        ye.addListener('rssLink','click',ScViewRSS);
    }
    
    var last_modified = new Date(document.lastModified);
    
    if (typeof BCNTRY.page_data !== "undefined") {
        BCNTRY.page_data.bit_refresh_last_modified = last_modified.toUTCString();
    }
    
    if (BCNTRY.odat.refreshInterval && BCNTRY.odat.refreshInterval > 10000) {
        setTimeout(BCNTRY.checkForNewItem, BCNTRY.odat.refreshInterval);
		if (BCNTRY.page_data.instant_reviews_enabled) {
			setInterval(
				function() {BCNTRY.odatComm.instantReviewManager.fetchLatest();},
				BCNTRY.odat.refreshInterval);
		}
    }
    else {
        BCNTRY.odat.refreshInterval = 60000;
    }
    if (BCNTRY.notify) {
        BCNTRY.notify();
        setInterval(BCNTRY.notify, 180000);
    }
    
    BCNTRY.setupTimerTicks();
    
    BCNTRY.startRefreshAds(BCNTRY.site.AdRefreshInterval);
});

//set up popup cookie
function set_popup_cookie() {
    var seen_popup = 'seen_exit_popup';
    var cookie_set = _readCookie(seen_popup);
    if (cookie_set === '') {
        _setCookie(seen_popup, 1, 3660, null);
    }
}

set_popup_cookie();

//Detail images

// Main image navigation
BCNTRY.odat.PDPImage = function (img_src,description, main_image_url, large_image_url, sku_part, is_overview, fmtItem, item_class) {
    /* 
    Class: BCNTRY.odat.PDPImage
    Container to hold individual item information for images
    Constructor parameters:
        img_src: URL for the thumbnail image
        description: description of the image
        main_image_url: URL for the main image
        large_image_url: URL for the large image
        sku_part: Associated SKU part for the image
        is_overview: True if an overview detail image
        fmtItem: Function to provide the HTML for the item in the scrolly
        item_class: Class to be added to the <li> for the item in the scrolly
        */
    return {
        image_src:  img_src,
        description: description,
        main_image_url: main_image_url,
        large_image_url: large_image_url,
        sku_part: sku_part || null,
        is_overview: is_overview,
        fmtItem: fmtItem,
        item_class: item_class
    };
};


/* Carousel/Scrollies stuff*/

//Constant for the width of each item in a scrolly
BCNTRY.slider_item_width = 75;

//Constructor for BCNTRY.Slider class
BCNTRY.Slider = function (carousel_id, item_array, carousel_list_id, left_arrow, right_arrow, left_arrow_off, right_arrow_off, image_id_base) {
/*
Class: BCNTRY.Slider
Class for the swatch and detail image slider/reel/carousel/scrolly
Constructor parameters:
    carousel_id: HTML id of the carousel
    item_array: array of PDPImages holding the information for each item
    carousel_list_id: HTML id of the carousel list
    left_arrow, right_arrow, left_arrow_off, right_arrow_off: HTML ids for each arrow
    image_id_base: Prefix of HTML id for the images within the items

*/
   var show_arrows = 1;
   
   // Hardcoded width of the other parts of the scrolly, which aren't in 
   // the carousel.  More stable across browsers than dynamic methods of 
   // calculating the width
   var extra_width =25 + 45*2 +20;
   
   // Calculate the size of the carousel
   var set_size = function (num_items) {
             num_items = item_array.length;
             
             var enclosing_element = $('product') || $('item_information');
             
             
             // To be cross-browser - have to add in a fudge-factor
             var width = enclosing_element.clientWidth ? enclosing_element.clientWidth : enclosing_element.offsetWidth;
             var right_width = 0;
             var right_ad = $('ad_space') || $('promo_right_middle_1');
             if (right_ad) {
                 right_width = 195;
             }
             var available_width = width - extra_width  - right_width;
             
             num_items_to_show = Math.round((available_width / BCNTRY.slider_item_width) - 0.5);
                          
             // Show navigation arrows depending on how many items and how many 
             // are showing
             if (num_items_to_show >= num_items) {
                 show_arrows = 0;
                 yd.setStyle(left_arrow,'display','none');
                 yd.setStyle(right_arrow,'display','none');
                 yd.setStyle(left_arrow_off,'display','none');
                 yd.setStyle(right_arrow_off,'display','none');
             }
             else {
                 show_arrows = 1;
                 yd.setStyle(left_arrow,'display','none');
                 yd.setStyle(right_arrow,'display','block');
                 yd.setStyle(left_arrow_off,'display','block');
                 yd.setStyle(right_arrow_off,'display','none');
             }
    };
    
    // Initialize the size of the carousel
    set_size(item_array.length);
    
    // Data structure of the object
    var slider = {
        item_array: item_array,
        left_arrow: left_arrow,
        right_arrow: right_arrow,
        left_arrow_off: left_arrow_off,
        right_arrow_off: right_arrow_off,
        num_items_to_show: num_items_to_show,
        width: function () { 
            return num_items_to_show * BCNTRY.slider_item_width + extra_width+'px';
        },
       
        carousel: new YAHOO.widget.Carousel(carousel_id, 
            {
                numItems:        Math.min(item_array.length,num_items_to_show),
                numVisible:        Math.min(item_array.length,num_items_to_show),
                animation:    {speed: 0.7, effect: YAHOO.util.Easing.easeNone},
                scrollIncrement:         2
            }
        ), //end carousel
        carouselNavigation: null,
            // Load the new items
        load: function(start, last, ia) {
            var items;
            if (typeof(slider) !== 'undefined') {
                items = slider.item_array;
            }
            else {
                items = item_array || ia;
            }
            BCNTRY.odat.tooltips = [];
            for(var i=start; i<=last; i++) {
                i = parseInt(i,10);
                this.carousel.addItem(items[i-1].fmtItem(i-1));
                BCNTRY.odat.tooltips[image_id_base+(i-1)] = new YAHOO.widget.Tooltip('tooltip_'+image_id_base+'_'+(i-1),
                    { context:image_id_base+"_"+(i-1), text: items[i-1].description});
            }
        },
        showInitial: function () {
                this.load(1,item_array.length);
                this.carousel.render();
                this.carousel.show();
        },
        clickHandler: function (e) { 
            var elTarget = YAHOO.util.Event.getTarget(e);
            if (typeof elTarget != "undefined") {
                while (elTarget.id != carousel_list_id) { 
                    if(elTarget.nodeName.toUpperCase() == "LI") { 
                        BCNTRY.changeImage(item_array[this.carousel.getItemPositionById(elTarget.id)].large_image_url);
                       break; 
                    } else { 
                     elTarget = elTarget.parentNode; 
                    } 
                }
            }
            return false;
        }, 
        resize: function () {
            set_size();
            this.carousel.set('numVisible', Math.min(item_array.length,num_items_to_show));
            this.carouselNavigation.init();
        },
        range_visible: function (first, last) {
            if (first > last) {
                return false;
            }
            if (first < this.carousel.get('firstVisible')) {
               return false; 
            }
            if (last > (this.carousel.get('firstVisible') + this.carousel.get('numVisible') - 1)) {
               return false; 
            }
            return true;
        },
        // Move the carousel so the first-last images are potentially visible
        move_to_view: function (first,last) {
            this.carousel.scrollTo(first,true);
        }
    };
    
    slider.carouselNavigation = new BCNTRY.ArrowNavigation(slider.carousel,left_arrow,left_arrow_off,right_arrow,right_arrow_off);

    return slider;
};



// Listen to the window resize event and redraw the carousel
ye.addListener(window,"resize", function () {

    if (BCNTRY.detail_images) {
        BCNTRY.detail_images.resize();
        $('more_views').style.width = BCNTRY.detail_images.width();
    }
});
/*End carousel/ slider stuff*/

/* ODAT Stat stuff */
BCNTRY.odat.checkUnique = function (useOmni) {
    var unqCookie;
    if (useOmni) {
        unqCookie = _readCookie('s_vi');
        return unqCookie;
    }
    else {
        unqCookie = _readCookie('bcusrid');
        if (unqCookie !== '') { return unqCookie; }

        var unqString = BCNTRY.odat.genString(32);
        _setCookie('bcusrid', unqString, '3600', '/');
        return unqString;
    }
};

BCNTRY.odat.genString = function (L) {
    var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
    var rstring = '';
    for (var i=0; i<L; i++) {
        var rnum = Math.floor(Math.random() * chars.length);
        rstring += chars.substring(rnum,rnum+1);
    }
    return rstring;
};

BCNTRY.odat.rSuccess = function(o) {
    if ( typeof o.vcount !== 'undefined' && o.vcount.match(/[0-9,]+/) && o.vcount !== "0" ) {
        BCNTRY.posStatus = 'success';
    }
    else {
        BCNTRY.posStatus = 'failure';
    }
    BCNTRY.page_data.pos_value = o.vcount;
    if (BCNTRY.posInitialized) { BCNTRY.setPOSValue(BCNTRY.posStatus); }
};

BCNTRY.setPOSValue = function(pos_status) {
    var e = YAHOO.util.Dom.getElementsByClassName('people_on_site'); 
    if (pos_status == 'failure') {
        for (var i in e) {
            if (e.hasOwnProperty(i)) {
                e[i].style.display = 'none';
            }
        }
    } 
    else if (pos_status == 'success') {
        for (var j in e) {
            if (e.hasOwnProperty(j) && e[j].style.display == 'none') {
                e[j].style.display = 'block';
            }
        }
    }
    $('pplos_value').innerHTML = BCNTRY.page_data.pos_value;
    return 1;
};

BCNTRY.odat.getStats = function() {
    if (typeof BCNTRY.page_data === 'undefined') {
        return 0;
    }
    else if (typeof BCNTRY.page_data.vstats_url === 'undefined') {
        return 0;
    }

    if ($('vstats_script') !== null) {
        BCNTRY.rmDynamicScript('vstats_script', 'vstats');
    }

    BCNTRY.dynamicScript(BCNTRY.page_data.vstats_url+'?rnd='+BCNTRY.odat.genString(32),'vstats_script','vstats');
    return 1;
};

BCNTRY.dynamicScript = function(url, id, placement_id) {
    var script = document.createElement('script');
    script.setAttribute('type', 'text/javascript');
    script.setAttribute('src', url);
    script.setAttribute('id', id);
   
    if ( typeof $(placement_id) !== 'undefined' )  {
        $(placement_id).appendChild(script);
    }
    else {
        return 0;
    }
    return 1;
};

BCNTRY.rmDynamicScript = function(id, parent_id) {
    if ($(id) !== null) {
        if ($(id).parentNode.id === parent_id) {
            $(parent_id).removeChild($(id));
            return 1;
        }
    }
};

/* End ODAT stats stuff */






/* Refresh */

/**
 * Called every second. Checks for a new item if we are getting close to 
 * the end of time.
 * @param {Integer} seconds The number of seconds remaining 
 */
BCNTRY.on_tick = function (seconds) {
    if (seconds === 5 || seconds === 0 || seconds === -5) {
        if (typeof BCNTRY.checked_time == "undefined") {
            BCNTRY.checked_time = [];
        }
        if (!BCNTRY.checked_time[seconds]) {
            BCNTRY.sendCheckRequest();
            BCNTRY.checked_time[seconds] = true;
        }
    }
};

BCNTRY.pingRefresh = function(success_callback) {
  
  try {
     yc.asyncRequest(
            'HEAD',
            window.location,
            {
                success: function (o) {
                    if ( o.status === 0 || (o.status >= 200 && o.status < 300)) {
                        success_callback();
                        window.location.href = window.location.href; 
                    }
                }
            }
     );
     }
     catch (err) {
         return 0;
     }
};

BCNTRY.preRefreshProcessing = function() {
    // Set cookie for omniture
    _setCookie('odat_has_refreshed', '1', '1', '/');
};

BCNTRY.newItemHandler = function (r) {
    
    if (typeof r.getResponseHeader['Last-Modified'] !== 'undefined') {
        // Need to clear newline off end of the variable for Chrome and Safari
        BCNTRY.page_data.bit_refresh_last_modified = r.getResponseHeader['Last-Modified'].replace(/\W*$/,'');
    }
    
    try {
        BCNTRY.jsonData = YAHOO.lang.JSON.parse(r.responseText);
    }
    catch (err) {
        return 0;
    }

     if (typeof BCNTRY.jsonData !== 'undefined') {
         if (BCNTRY.jsonData.refreshInterval) {
             BCNTRY.odat.refreshInterval = BCNTRY.jsonData.refreshInterval;
         } 
         if (BCNTRY.jsonData.errorMsg) { 
             return 0;
         }
         if (YAHOO.lang.isNumber(parseInt(BCNTRY.jsonData.currentItem.odatId,10))) {
             if (parseInt(BCNTRY.jsonData.currentItem.odatId,10) != parseInt(BCNTRY.page_data.odat_id,10)) {
                 BCNTRY.pingRefresh(BCNTRY.preRefreshProcessing);
                 return 1;
             }
             else {
                 BCNTRY.updateVariantData();
                 BCNTRY.updateStats();
             }
         }
     }
     return 0;
};

BCNTRY.failHandler = function (o) {
        //do nothing
};

BCNTRY.sendCheckRequest = function () {
    if (typeof BCNTRY.page_data == "undefined") {
        return;
    }
    // Set header for conditional get
    yc.initHeader('If-Modified-Since',BCNTRY.page_data.bit_refresh_last_modified || 'Thu, 01 Jan 1970 00:00:00 GMT');
    try {
    yc.asyncRequest(
           'GET',
           '/' + BCNTRY.site.catalog+ '/' + BCNTRY.site.controller + '/jsdata.js',
               {
                   success: BCNTRY.newItemHandler,
                   failure: BCNTRY.failHandler,
                   timeout: 15000
               }
           );
    }
    catch (err) {
    }
};

BCNTRY.checkForNewItem = function () {

    BCNTRY.sendCheckRequest();
    
    if (BCNTRY.odat.refreshInterval && BCNTRY.odat.refreshInterval > 10000) {
       setTimeout(BCNTRY.checkForNewItem, BCNTRY.odat.refreshInterval);
       setTimeout(BCNTRY.odat.getStats, BCNTRY.odat.refreshInterval);
    }
    else {
        BCNTRY.odat.refreshInterval = 60000;
    }
};

BCNTRY.updateVariantData = function () {
    var data = BCNTRY.jsonData;
    BCNTRY.page_data.variants = data.currentItem.variants;
    
    if (BCNTRY.pete) {
        BCNTRY.pete.updatedVariantData();
    }
    
    if (data.currentItem && data.currentItem.variants) {
        for (var variant in data.currentItem.variants) {
            if (data.currentItem.variants.hasOwnProperty(variant)) {

               
                var variantObj = data.currentItem.variants[variant];

                
                if (typeof variantObj !== "undefined") {
                
                    if (BCNTRY.variant_bars && BCNTRY.variant_bars[variant]) {
                        BCNTRY.variant_bars[variant].set_data(variantObj.onHand,variantObj.totalInv);
                        BCNTRY.variant_bars[variant].draw();
                    }
                    
                    if ($(variant+'_qoh') && $(variant+'_left')) {
                        $(variant+'_qoh').innerHTML = variantObj.onHand;
                        $(variant+'_left').innerHTML = variantObj.totalInv;
                    }
                    
                    var dad;
                    
                    if (variantObj.onHand > 0) {
                        if ($('onhand'+variant)) {
                            $('onhand'+variant).innerHTML = variantObj.onHand;
                            $('totalinventory'+variant).innerHTML = variantObj.totalInv;
                            BCNTRY.updateInventoryBars(variant);

                        }
                        else {
                            
                            if (!$(variant+'_sold_out_img')) {
                                continue;
                            }
                            dad = $(variant+'_sold_out_img').parentNode;
        
                            if (BCNTRY.variant_bars) {
                                if ($('status_bar_'+variant)) {
                                    yd.setStyle('status_bar_'+variant,'display','block');
                                }
                                if ($(variant+'_sold_out_img')) {
                                    yd.setStyle(variant+'_sold_out_img','display','none');
                                }
                            }
                            else {
                                var onHandSpan = document.createElement('span'); 
                                onHandSpan.id = 'onhand'+variant;
                                onHandSpan.className = 'onhand';
                                onHandSpan.innerHTML = variantObj.onHand;
            
                                var totalInventorySpan = document.createElement('span'); 
                                totalInventorySpan.id = 'totalinventory'+variant;
                                totalInventorySpan.className = 'totalInventory';
                                totalInventorySpan.innerHTML = variantObj.totalInv;
            
                                if (BCNTRY.site.catalog == 'chainlove' || BCNTRY.site.catalog == 'tramdock') {
                                    dad.removeChild($(variant+'_sold_out_img'));
                                    dad.appendChild(onHandSpan);
                                    dad.appendChild(totalInventorySpan);
                                }
                                else {
                                    var statusBar = document.createElement('div'); 
                                    statusBar.className = 'statusBar';
            
                                    statusBar.appendChild(onHandSpan);
                                    statusBar.appendChild(totalInventorySpan);
                                    dad.replaceChild(statusBar, $(variant+'_sold_out_img'));
                                }
                                
                                BCNTRY.updateInventoryBars(variant);
                            }
                            $(variant+'_container').setAttribute('onClick', 'BCNTRY.changeImage(\''+variantObj.bigImage+'\');');
        
                            if ( $(variant+'_option') === null && $('sizeSelectBox')) {
                                var variantOption = new Option(variantObj.description, variantObj.sku);
                                variantOption.id = variant+'_option';
                                try { $('sizeSelectBox').add(variantOption,null); }
                                catch (err) { $('sizeSelectBox').add(variantOption); }
                            }
        
                        }
                        BCNTRY.variants_mp[variantObj.sku] = variantObj.maxPurchase;
                    }
                    else {
                        // Handle sold out variants.
                        
                        var image = new Image();
                        image.src = data.currentItem.soldOutImage;
                        image.alt = "Sold Out";
                        image.className = 'sold_out';
                        image.id = variant+'_sold_out_img';
                        
                        var grandpa;
                        if ($('onhand'+variant)) {
                            if (BCNTRY.site.catalog == 'chainlove' || BCNTRY.site.catalog == 'tramdock') {
                                dad = $('onhand'+variant).parentNode;
                                dad.removeChild($('totalinventory'+variant));
                                dad.replaceChild(image, $('onhand'+variant));
                            }
                            else {
                                grandpa = $('onhand'+variant).parentNode.parentNode;
                                grandpa.replaceChild(image, $('onhand'+variant).parentNode);
                            }
                            $(variant+'_container').removeAttribute('onClick');
                            if ($('sizeSelectBox').selectedIndex !== $(variant+'_option').index) {
                                $('sizeSelectBox').removeChild( $(variant+'_option') );
                            }
                        }
                        else {
                            if ($('status_bar_'+variant)) {
                                yd.setStyle('status_bar_'+variant,'display','none');
                            }
                            if ($(variant+'_sold_out_img')) {
                                yd.setStyle(variant+'_sold_out_img','display','block');
                            }
                        }
                    }
                }
            }
        }
        BCNTRY.setMaxQ($('sizeSelectBox'),$('mv_order_quantity'));
    }
};

BCNTRY.updateInventoryBars = function (clean_variant) {
    var onHandAmt = parseInt($('onhand'+clean_variant).innerHTML,10);
    var qohSnapshot = onHandAmt;
    var barWidth = 196;
    if (BCNTRY.site.catalog == 'steepcheap') {barWidth = 196; };

    if(parseInt($('totalinventory'+clean_variant).innerHTML,10) !== 0) { 
        qohSnapshot = parseInt($('totalinventory'+clean_variant).innerHTML,10);
    }  
    yd.setStyle('onhand'+clean_variant, 'width', onHandAmt/qohSnapshot * barWidth + 'px');
    yd.setStyle('totalinventory'+clean_variant, 'width', (qohSnapshot-onHandAmt)/qohSnapshot * barWidth + 'px');

    $('onhand'+clean_variant).innerHTML="&nbsp;";
    $('totalinventory'+clean_variant).innerHTML="&nbsp;";
};  

/**
 * Update data on the page that updates with a new bit of JSON data
 */
BCNTRY.updateStats = function () {
    var data = BCNTRY.jsonData;
   if (typeof data.currentItem !== 'undefined') {
       if ($('total_remaining')) {
            $('total_remaining').innerHTML = data.currentItem.totalRemaining;
        }
        if (($('sellout_rate') !== null) && data.currentItem.sellRate) {
            $('sellout_rate').innerHTML = data.currentItem.sellRate;
        }
        if (BCNTRY.total_qty_bar) {
            BCNTRY.total_qty_bar.set_data(data.currentItem.totalRemaining);
            BCNTRY.total_qty_bar.draw();
        }
        if (BCNTRY.time_remaining_bar) {
            if ($('total_time')) {
                $('total_time').innerHTML = Math.floor(data.currentItem.totalTime / 60);
            }
            if (BCNTRY.page_data.utc_load_time && data.absolute_times) {
                BCNTRY.time_remaining_bar.set_data(data.currentItem.end_time  - (parseInt((new Date()).getTime()/1000,10) - BCNTRY.page_data.offset_seconds),data.currentItem.totalTime);
            }
            else {
                BCNTRY.time_remaining_bar.set_data(data.currentItem.timeRemaining,data.currentItem.totalTime);
            }
            BCNTRY.time_remaining_bar.draw();
        }
    }
    if (BCNTRY.people_on_site && data.pplos && data.pplos.history && data.pplos.interval && data.prev_items) {
        BCNTRY.people_on_site.refresh({counts: data.pplos.history, flip_times: BCNTRY.normalise_flip_times(data.prev_items, data.pplos.interval, data.absolute_times)});
    }
};

/* END REFRESH */

/**
 * Class to hold information about a variant in the buy box.
 * @constructor
 */
BCNTRY.Variant = function () {
    
    // HTML classes
    this.soldOutClass = 'soldOut_variant';
    this.unavailableClass = 'unavailable_variant';
    
    // Public members
    this.data = {};
    this.isAvailable = true;
    this.element = null;
    this.elementTemplate = null;
    this.selector = null;
    this.fuelGauge = null;
    this.type = 'unselected';
    this.status = 'available';
    this.parentSku = null;
    this.parentElement = null;
    this.fuelGaugeWidth = 220;
    this.eventWrapperEl = null;

    // Private members
    this._smallImageEl = null;
    this._descriptionEl = null;
    this._onHandEl = null;
    this._invFullEl = null;
    this._smallImageBase = null;
    this._mvMaxQuantityEl = null;
};

/**
 * Handler for the mouseOver event
 */
BCNTRY.Variant.prototype.onHover = function () {
    BCNTRY.changeImage(this.data.bigImage);
};

/**
 * Adds event listeners to the eventWrapper element, which wraps
 * the variant in HTML.
 */
BCNTRY.Variant.prototype.addEvents = function () {
    this.eventWrapperEl = this.element.getElementsByClassName('event_wrapper');
    this.eventWrapperEl = new YAHOO.util.Element(this.eventWrapperEl[0]);
    this.eventWrapperEl.on('click', this.onClick, null, this);
    this.eventWrapperEl.on('mouseover', this.onHover, null, this);
};

/**
 * Initialises and creates all elements for a variant
 * @param {Boolean} refresh If true, refreshes any cached members
 * @returns Success
 * @type Boolean
 */
BCNTRY.Variant.prototype._initElements = function (refresh) {
    
    if (!this.data) {
        return false;
    }
    
    // Create element (if necessary)
    if (!this.element) {
        if (this.elementTemplate) {
            this.element = new YAHOO.util.Element(yd.getFirstChild(this.elementTemplate).cloneNode(true));
            this.addEvents();
            this._mungeElement();
        }
        else {
            return false;
        }
    }

    // Set values in the element
    if (!this._smallImageEl || refresh) {
        var imgs = this.element.getElementsByClassName('small_image','img');
        this._smallImageEl = imgs[0];
        if (!this._smallImageBase) {
            // img has source for the directory (with a tmp file on end)
            var src = this._smallImageEl.src;
            this._smallImageBase = src.match(/^(.*\/)[^\/]+$/)[1];
        }
    }
    
    if (!this._descriptionEl || refresh) {
        var dels = this.element.getElementsByClassName('description');
        this._descriptionEl = dels[0];
    }
    
    if (!this._totalInvEl || refresh) {
        var tels = this.element.getElementsByClassName('totalInv');
        this._totalInvEl = tels[0];
    }
    
    if (!this._onHandEl || refresh) {
        var oels = this.element.getElementsByClassName('onHand');
        this._onHandEl = oels[0];
    }
    
    if (!this._invFullEl || refresh) {
        var iels = this.element.getElementsByClassName('inv_full');
        this._invFullEl = iels[0];
    }
    
    if (!this._deleteVariantEl || refresh) {
        var dvels = this.element.getElementsByClassName('delete_variant');
        this._deleteVariantEl = dvels[0];
        ye.addListener(this._deleteVariantEl,'click',this.deleteVariant,null,this);
    }
    
    if (!this.parentSku || refresh) {
        var sku = this.data.sku.match(/^(\w+)-/);
        if (sku[1]) {
            this.parentSku = sku[1];
        }
        else {
            return false;
        }
    }
    
    if (!this.fuelGauge || refresh) {
        if (this.fuelGauge) {
            delete this.fuelGauge;
        }
        var fuelGaugeEl = this.element.getElementsByClassName('status_bar');
        this.fuelGauge = new BCNTRY.FuelGauge(fuelGaugeEl,this.element.getElementsByClassName('liquid'));
        this.fuelGauge.width = this.fuelGaugeWidth;
        this.fuelGauge.height = 4;
        if (this.data.totalInv > 10) {
            this.fuelGauge.transitions = [0.2];
            this.fuelGauge.usePercentTransitions = true;
        }
        else {
            this.fuelGauge.transitions = [2];
            this.fuelGauge.usePercentTransitions = false;
        }
    }
    
    return true;
};

/**
 * Gets the status of the variant
 * @returns The status
 * @type String
 */
BCNTRY.Variant.prototype.getStatus = function () {
    if (this.data.onHand <= 0) {
        this.status = 'soldOut';
    }
    else {
        if (this.status == 'unavailable') {
            return this.status;
        }
        else {
            this.status = 'available';
        }
    }
    return this.status;
};

/**
 * Updates the status of all input elements within the variant box.
 * This can be done to stop the variant's data from being passed via CGI
 * to the Cart
 */
BCNTRY.Variant.prototype._updateInputStatuses = function () {
    var inputEls = this.element.getElementsByTagName('input');
    for (var i in inputEls) {
        if (typeof inputEls[i] !== 'undefined') {
            if (this.getStatus() == 'available') {
                inputEls[i].disabled = false;
            }
            else {
                inputEls[i].disabled = true;
            }
        }
    }
};

/**
 * Draws the variant for the first time
 * @param {htmlElement} parentElement Element to add the rendered variant to
 */
BCNTRY.Variant.prototype.draw = function (parentElement, refresh) {
    
    this.parentElement = this.parentElement || parentElement;

    if (!this._initElements(refresh)) {
        return;
    }
    
    // Get base image path from the template
    if (this.data.bigImage) {
        var imagePath = this.data.bigImage.match(/large(.*)$/);
        imagePath = imagePath[1];
        this._smallImageEl.src = this._smallImageBase + imagePath;
    }
    
    this._descriptionEl.innerHTML = this.data.description;
    this._totalInvEl.innerHTML = this.data.totalInv;
    this._onHandEl.innerHTML = this.data.onHand;
    this._invFullEl.innerHTML = this.data.totalInv;
    this.fuelGauge.set_data(this.data.onHand,this.data.totalInv);
    this.fuelGauge.draw();
    
    if (this.getStatus() == 'soldOut') {
        this.element.addClass(this.soldOutClass);
        this.element.addClass(this.unavailableClass);
    }
    if (this.getStatus() == 'unavailable') {
        this.element.removeClass(this.soldOutClass);
        this.element.addClass(this.unavailableClass);
    }
    if (this.getStatus() == 'available') {
        this.element.removeClass(this.soldOutClass);
        this.element.removeClass(this.unavailableClass);
    }
    
    this._updateInputStatuses();
    
    // Add the new element
    if (this.parentElement && (this.htmlElement().parentNode !== this.parentElement)) {
        this.element.appendTo(this.parentElement);
    }
};

/**
 * Redraws the variant box
 */
BCNTRY.Variant.prototype.update = function () {
    this.updateData();
    this.draw();
};

/**
 * Gets the HTML Element containing the variant box
 * @returns The HTML Element or false
 * @type HTMLElement
 */
BCNTRY.Variant.prototype.htmlElement = function () {
    if (!this.element) {
        return false;
    }
    return this.element.get('element');
};

/**
 * Sets the data field for a variant
 */
BCNTRY.Variant.prototype.updateData = function (variantId) {
    if (typeof variantId == 'undefined') {
        variantId = this.data.sku;
    }
    if (typeof variantId == 'undefined') {
        return;
    }
    this.data = this.parent.data[variantId.replace(/-/g,'_')];
};

/**
 * Abstract method.  To be overridden in subclasses
 */
BCNTRY.Variant.prototype.deleteVariant = function () {
    // do nothing, abstract
};

/**
 * Abstract method
 */
BCNTRY.Variant.prototype.onClick = function () {
};

/**
 * Abstract method
 */
BCNTRY.Variant.prototype.deleteVariant = function () {
    //abstract
};

/**
 * Abstract method
 */
BCNTRY.Variant.prototype._mungeElement = function () {
    //abstract
};

/**
 * Class to hold information about a variant that has been selected
 * @constructor
 */
BCNTRY.SelectedVariant = function () {
};

BCNTRY.SelectedVariant.prototype = new BCNTRY.Variant();

/**
 * Abstract method
 */
BCNTRY.SelectedVariant.prototype.onClick = function () {
};

/**
 * Initialises and creates all elements for a variant
 * @param {Boolean} refresh If true, refreshes any cached members
 * @returns Success
 * @type Boolean
 */
BCNTRY.SelectedVariant.prototype._initElements = function (refresh) {
    
    // Call superclass's _initElements
    if (!this.constructor.prototype._initElements.call(this,refresh)) {
        return false;
    }
    
    if (!this._mvSkuEl || refresh) {
        var mels = this.element.getElementsByClassName('mv_sku');
        this._mvSkuEl = mels[0];
        this._mvSkuEl.value = this.parentSku;
    }
    
    if (!this._mvOrderQuantityEl || refresh) {
        var oqels = this.element.getElementsByClassName('mv_order_quantity');
        this._mvOrderQuantityEl = oqels[0];
        this._mvOrderQuantityEl.value = 1;
    }
    
    if (!this._mvMaxQuantityEl || refresh) {
        var maxels = this.element.getElementsByClassName('max_quantity');
        this._mvMaxQuantityEl = maxels[0];
        this._mvMaxQuantityEl.value = this.data.maxPurchase < this.data.totalInv ? this.data.maxPurchase : this.data.totalInv;
    }
    
    if (!this._itemCodeEl || refresh) {
        var icels = this.element.getElementsByClassName('item_code');
        this._itemCodeEl = icels[0];
        this._itemCodeEl.value = this.data.sku;
    }
    return true;
};

/**
 * Deletes itself and children
 * @returns false
 * @type Boolean
 */
BCNTRY.SelectedVariant.prototype.deleteVariant = function () {
    this.parentElement.removeChild(this.htmlElement());
    delete this.element;
    delete this.fuelGauge;
    this.parent.deleteVariant(this);
    return false;
};

/**
 * Class to hold information about an instance of a variant that has not been
 * selected.  This does not mean that another instance of the same variant
 * has been selected already.
 * @constructor
 */
BCNTRY.UnSelectedVariant = function () {
};

BCNTRY.UnSelectedVariant.prototype = new BCNTRY.Variant();

/**
 * Handler for click event.  Tells parent that this variant has been 
 * selected.
 */
BCNTRY.UnSelectedVariant.prototype.onClick = function () {
    if (this.getStatus() == 'available') {
        this.parent.variantSelected(this);
    }
};

/**
 * Removes unwanted HTML elements from the variant box
 */
BCNTRY.UnSelectedVariant.prototype._mungeElement = function () {
    var inputEls = this.element.getElementsByTagName('input');
    for (var i = inputEls.length-1 ; i>=0; i--) {
            inputEls[i].parentNode.removeChild(inputEls[i]);
    }
    var deleteEls = this.element.getElementsByClassName('delete_variant');
    for (var j = deleteEls.length-1; j>=0; j--) {
            deleteEls[j].parentNode.removeChild(deleteEls[j]);
    }
};

/**
 * Class to hold variants that have been selected.
 * @constructor
 */
BCNTRY.SelectedVariants = function () {
    this.variants = [];
    this.maxPurchase = 3;
    this.parent = null;
    this.variantTemplate = null;
    this.parentElement = null;
};

/**
 * Deletes a variant from the selected variants
 * @param {BCNTRY.Variant} variant The variant to be deleted
 */
BCNTRY.SelectedVariants.prototype.deleteVariant = function (variant) {
    for (var i in this.variants) {
        if (this.variants.hasOwnProperty(i)) {
            if (variant === this.variants[i]) {
                delete this.variants[i];
                this.variants.splice(i,1);
                continue;
            }
        }
    }
    
    var numSelected = 0;
    for (var j in this.variants) {
        if (this.variants.hasOwnProperty(j)) {
            if (j == variant.data.sku) {
                numSelected++;
            }
        }
    }
    if (numSelected >= variant.data.totalInv) {
        this.parent.foundUnavailableVariant(variant);
    }
    else {
        this.parent.foundAvailableVariant(variant);
    }
    
    this.parent.updatedVariantData();
    this.parent.deleteVariant(variant);
};

/**
 * Adds a variant from the selected variants
 * @param {BCNTRY.Variant} variant The variant to be added
 */
BCNTRY.SelectedVariants.prototype.addVariant = function (variant) {
    var tmpVariant = new BCNTRY.SelectedVariant();
    tmpVariant.parent = this;
    tmpVariant.elementTemplate = this.variantTemplate;
    tmpVariant.data = variant.data;
    tmpVariant.parentElement = this.parentElement;
    tmpVariant.draw();
    this.variants.push(tmpVariant);
    
    // If too many added, notify parent
    if (this.variants.length >= this.maxPurchase) {
        this.parent.selectedVariantsFull();
    }
};

/**
 * Called when variant data has been updated.  Tallies the number of each
 * variant to see if the quantity selected is too much
 */
BCNTRY.SelectedVariants.prototype.updatedVariantData = function () {
    
    var tally = [];
    
    for (var i in this.variants) {
        if (this.variants.hasOwnProperty(i)) {
            this.variants[i].updateData();
            
            if (typeof tally[this.variants[i].data.sku] == 'undefined') {
                tally[this.variants[i].data.sku] = 0;
            }
            tally[this.variants[i].data.sku]++;
            if (tally[this.variants[i].data.sku] > this.variants[i].data.totalInv) {
                this.variants[i].status = 'unavailable';
            }
            else {
                this.variants[i].status = 'available';
            }
            if (tally[this.variants[i].data.sku] >= this.variants[i].data.totalInv) {
                this.parent.foundUnavailableVariant(this.variants[i]);
            }
            else {
                this.parent.foundAvailableVariant(this.variants[i]);
            }
            this.variants[i].update();
        }
    }
};

/**
 * Returns the number of selected variants
 * @returns The number of selected variants
 * @type Integer
 */
BCNTRY.SelectedVariants.prototype.length = function () {
    return this.variants.length;
};

/**
 * Returns the number of selected variants that are available
 * @returns The number of available selected variants
 * @type Integer
 */
BCNTRY.SelectedVariants.prototype.numAvailable = function () {
    var count = 0;
    for (var i in this.variants) {
        if (this.variants.hasOwnProperty(i)) {
            if (this.variants[i].getStatus() == 'available') {
                count++;
            }
        }
    }
    return count;
};

/**
 * Class for an instance of a selector (graphical dropdown) for variants
 * @constructor
 */
BCNTRY.Selector = function () {
    this.variants = [];
    this.carousel = null;
    this.data = null;
    this.parentElement = null;
    this.variantTemplate = null;
    this.carouselNavigation = null;
    this.wrapperEl = null;
    this.buttonEl = null;
    this.parent = null;
    this.visible = false;
    this.enabled = true;
    this.direction = null;
    this.maxVisible = null;
    this.navigationType = 'arrow';
};

/**
 * Initialises the elements for a selector
 * @returns Success
 * @type Boolean
 */
BCNTRY.Selector.prototype._initElements = function () {
    
    if (!this.data) {
        return false;
    }
    
    var variant;
    
    if (!this.variants || !this.variants.length) {
        this.variants = [];
        for (variant in this.data) {
            if (this.data.hasOwnProperty(variant)) {
                var tmpVariant = new BCNTRY.UnSelectedVariant();
                tmpVariant.parent = this;
                tmpVariant.updateData(variant);
                tmpVariant.elementTemplate = this.variantTemplate;
                tmpVariant.draw();
                this.variants.push(tmpVariant);
            }
        }
    }
    
    function displaySort(a, b)
    {
        return a.data.display_sort - b.data.display_sort;
    }
    
    this.variants = this.variants.sort(displaySort);
    
    if (!this.carousel) {
        this.carousel = new YAHOO.widget.Carousel(this.parentElement);
        
        this.carousel.set("isVertical", true);
        for (variant in this.variants) {
            if (this.variants.hasOwnProperty(variant)) {
                this.carousel.addItem(this.variants[variant].htmlElement());
            }
        }
        if (this.navigationType == 'arrow') {
            this.carouselNavigation = new BCNTRY.ArrowNavigation(this.carousel);
        }
        else {
            this.carouselNavigation = new BCNTRY.SliderNavigation(this.carousel);
        }
    }
    
    return true;
    
};

/**
 * Called when a variant has more selected than in-stock.  Makes that 
 * variant unavailable
 * @param {BCNTRY.Variant} variant The variant to be made unavailable
 */
BCNTRY.Selector.prototype.foundUnavailableVariant = function (variant) {
    for (var i in this.variants) {
        if (this.variants.hasOwnProperty(i)) {
            if (this.variants[i].data.sku == variant.data.sku) {
                this.variants[i].status = 'unavailable';
            }
        }
    }
};

/**
 * Called when a variant should be available
 * @param {BCNTRY.Variant} variant The variant to be made available
 */
BCNTRY.Selector.prototype.foundAvailableVariant = function (variant) {
    for (var i in this.variants) {
        if (this.variants.hasOwnProperty(i)) {
            if (this.variants[i].data.sku == variant.data.sku) {
                this.variants[i].status = 'available';
            }
        }
    }
};

/**
 * The carousel does not copy events to its elements, so need to re-attach them
 */
BCNTRY.Selector.prototype._reattachEvents = function () {
    var i = 0;
    for (var variant in this.variants) {
            if (this.variants.hasOwnProperty(variant)) {
                var variantEl = this.carousel.getElementForItem(i);
                if (variantEl) {
                    this.variants[variant].element = new YAHOO.util.Element(variantEl);
                    this.variants[variant].addEvents();
                    this.variants[variant].draw(null,true);
                }
                i++;
            }
    }
};

/**
 * Draws the selector
 */
BCNTRY.Selector.prototype.draw = function () {
    if (!this._initElements()) {
        return false;
    }
    this.carousel.render();
    this._reattachEvents();
    this.carousel.show();
    
};

/**
 * Called when a variant has been selected
 * @param {BCNTRY.Variant} variant The variant that has been selected
 */
BCNTRY.Selector.prototype.variantSelected = function (variant) {
    if (!variant) {
        return false;
    }
    this.parent.variantSelected(variant);
    this.hide();
};

/**
 * Called when variant data has been updated
 */
BCNTRY.Selector.prototype.updatedVariantData = function () {
    for (var i in this.variants) {
        if (this.variants.hasOwnProperty(i)) {
            this.variants[i].update();
        }
    }
};

/**
 * Show, or open the selector.  At present will open the selector to as large
 * a size as possible, either above, or below the button, depending on where
 * there is more room.
 */
BCNTRY.Selector.prototype.show = function () {
    
    // Get positional data
    var height = yd.getViewportHeight();
    var buttonRegion = yd.getRegion(this.buttonEl);
    var roomBelow = height - buttonRegion.bottom - this.carouselNavigation.totalHeight();
    var roomAbove = buttonRegion.top - this.carouselNavigation.totalHeight();
    var roomForSelector;
    var x = buttonRegion.left;
    var y;
    var type = 'drop';
    var down;
    
    if (this.carousel.get('numItems') > 1000) {
        type='total';
        roomForSelector = height;
    }
    else {
        // Choose above or below
        down = true;
        if (roomBelow > roomAbove || this.direction == 'down') {
            roomForSelector = roomBelow;
            y = buttonRegion.bottom;
        }
        else {
            roomForSelector = roomAbove;
            down = false;
        }
    }
    // Calc number of variants to show
    var fudgeHeight = 71;
    
    var numVisible;
    if (this.maxVisible === null) {
        numVisible= Math.floor(roomForSelector / fudgeHeight);
    }
    else {
        numVisible = this.maxVisible;
    }
    if (numVisible > 0) {
        if (numVisible > this.carousel.get('numItems')) {
            numVisible = this.carousel.get('numItems');
            this.carouselNavigation.visible = false;
        }
        this.carousel.set('numVisible',numVisible);
    }
    
    // Show carousel
    //this.carouselNavigation.init();
    yd.setStyle(this.wrapperEl,'display','block');
    
    if (type == 'drop' && !down) {
        y = buttonRegion.top - (numVisible * fudgeHeight) - this.carouselNavigation.totalHeight();
    }
    
    if (type == 'total') {
        y = parseInt(height/2 - ((numVisible * fudgeHeight) + this.carouselNavigation.totalHeight())/2,10);
    }
    
    // Re-align selector once we know how big it is
    yd.setXY(this.wrapperEl,[x,y]);
    this.carousel.render();
    
    // Another dodgy hack to get around height issues in the carousel code
    var badHeight = yd.getStyle(this.parentElement,'height').match(/\d+/)[0];
    yd.setStyle(this.parentElement,'height',parseInt(badHeight,10)-2+this.carousel.get('numVisible')+'px');
    yd.setStyle(this.carousel._clipEl,'height',parseInt(badHeight,10)-2+this.carousel.get('numVisible')+'px');

    if (type == 'drop' && !down) {
        var wrapperRegion = yd.getRegion(this.wrapperEl);
        y = buttonRegion.top - (wrapperRegion.bottom - wrapperRegion.top);
        yd.setXY(this.wrapperEl,[x,y]);
    }

    this.carouselNavigation.init();
    this.carouselNavigation.setRegion(yd.getRegion(this.parentElement));
    this.visible = true;
};

/**
 * Hides, closes the selector
 */
BCNTRY.Selector.prototype.hide = function () {
    if (this.visible) {
        yd.setStyle(this.wrapperEl,'display','none');
        this.visible = false;
    }
};

/**
 * Called when the selector button is clicked.  Either shows or hides the
 * selector, or does nothing
 */
BCNTRY.Selector.prototype.onClick = function (ev) {
    ye.stopEvent(ev);
    if (this.enabled) {
        if (this.visible) {
            this.hide();
        }
        else {
            this.show();
        }
    }
};

/**
 * Class to hold information the entire Buy Box
 * @constructor
 */
BCNTRY.BuyBox = function () {
    this.mainImage = null;
    this.selectedVariants = null;
    this.selectColorSizeEl = null;
    this.wantAnotherEl = null;
    this.maxPurchase = 3;
    this.selector = null;
    this.activeSelectorEl = null;
    this.selectorEl = null;
    this.formEl = null;
};

/**
 * Notifies the BuyBox that a variant has been selected
 * @param {BCNTRY.Variant} variant The variant that was selected
 */
BCNTRY.BuyBox.prototype.variantSelected = function (variant) {
    if (!variant) {
        return false;
    }

    this.switchActiveButton(this.wantAnotherEl);
    this.selectedVariants.addVariant(variant);
    this.updatedVariantData();
};

/**
 * Enables the button provided.  Can be overridden for different elements
 * @param {HTMLElement} buttonEl The new active button
 */
BCNTRY.BuyBox.prototype.enableButton = function (buttonEl) {
    yd.removeClass(buttonEl,'select_variant_disabled');
    while(ye.removeListener(buttonEl,'click')){}
    ye.addListener(buttonEl,'click',function(ev) {
        this.onClick(ev);
    }, null, this.selector);
    this.selector.enabled = true;
};

/**
 * Disables the button provided.  Can be overridden for different elements
 * @param {HTMLElement} buttonEl The new active button
 */
BCNTRY.BuyBox.prototype.disableButton = function (buttonEl) {
    yd.addClass(buttonEl,'select_variant_disabled');
    while(ye.removeListener(buttonEl,'click',this.selector.onClick)){}
    this.selector.enabled = false;
};

/**
 * Switches to the new active button, and disables the old
 * @param {HTMLElement} newButtonEl The new active button
 */
BCNTRY.BuyBox.prototype.switchActiveButton = function (newButtonEl) {
    if (newButtonEl !== this.activeSelectorEl) {
        var oldButtonEl = this.activeSelectorEl;
        this.activeSelectorEl = newButtonEl;
        this.selector.buttonEl = this.activeSelectorEl;
        if (oldButtonEl) {
            this.disableButton(oldButtonEl);
        }
        this.enableButton(this.activeSelectorEl);

    }
};

/**
 * Called when the BuyBox form is submitted.  Pops up a modal if no variants
 * are selected.
 * @returns whether the form can be selected
 * @type Boolean
 */
BCNTRY.BuyBox.prototype.onSubmit = function () {
    if (this.selectedVariants.numAvailable() === 0) {
        return BCNTRY.showNoneSelected();
    }
    if (this.formEl) {
        this.formEl.submit();
        return true;
    }
    return false;
};

/**
 * Initialises the BuyBox
 */
BCNTRY.BuyBox.prototype.init = function () {
    
    this.selector = new BCNTRY.Selector();
    this.selector.parentElement = this.selector.parentElement || $('car');
    this.selector.variantTemplate = this.selector.variantTemplate || $('variant_template');
    this.selector.data = BCNTRY.page_data.variants;
    this.selector.parent = this;
    this.selector.wrapperEl = this.selectorEl;
    this.selector.direction = 'down';
    //if((navigator.userAgent.match(/iPhone/i)) || (navigator.userAgent.match(/iPod/i))) {
		//this.selector.maxVisible = 5000;
    //}
    //else {
        //this.selector.maxVisible = 5;
    //}
	//temporarily disable scrolling
	this.selector.maxVisible = 5000;
    ye.addListener('index','click',this.selector.hide,null,this.selector);
    
    this.selector.draw();
    
    this.selectedVariants = new BCNTRY.SelectedVariants();
    this.selectedVariants.parentElement = $('selected_variants');
    this.selectedVariants.variantTemplate = $('variant_template');
    this.selectedVariants.parent = this;
    this.selectedVariants.maxPurchase = this.maxPurchase;
    this.selectedVariants.data = BCNTRY.page_data.variants;
    
    this.switchActiveButton(this.selectColorSizeEl);
    
    this.formEl = $('buy_form');
    ye.addListener(this.formEl,'submit',this.onSubmit,null,this);

};

/**
 * Notifies of a deleted variant, and switches active button if there are
 * now none selected
 * @param {BCNTRY.Variant} variant the variant that has just been deleted
 */
BCNTRY.BuyBox.prototype.deleteVariant = function (variant) {
    if (this.selectedVariants.length() === 0) {
        this.switchActiveButton(this.selectColorSizeEl);
    }
    else {
        if (this.selectedVariants.length() < this.maxPurchase) {
            this.enableButton(this.wantAnotherEl);
        }
    }
};

/**
 * Notifies children variant collections that variant data has been updated
 */
BCNTRY.BuyBox.prototype.updatedVariantData = function () {
    delete this.selector.data;
    this.selector.data = BCNTRY.page_data.variants;
    delete this.selectedVariants.data;
    this.selectedVariants.data = BCNTRY.page_data.variants;
    this.selectedVariants.updatedVariantData();
    this.selector.updatedVariantData();
};

/**
 * Notifies the selector that a variant is now unavailable
 * @param {BCNTRY.Variant} variant The variant to be made unavailable
 */
BCNTRY.BuyBox.prototype.foundUnavailableVariant = function (variant) {
    this.selector.foundUnavailableVariant(variant);
};

/**
 * Notifies the selector that a variant is now available
 * @param {BCNTRY.Variant} variant The variant to be made available
 */
BCNTRY.BuyBox.prototype.foundAvailableVariant = function (variant) {
    this.selector.foundAvailableVariant(variant);
};

/**
 * Disables the selector when there are too many variants selected
 */
BCNTRY.BuyBox.prototype.selectedVariantsFull = function () {
    this.disableButton(this.selectColorSizeEl);
    this.disableButton(this.wantAnotherEl);
};

/**
 * Class to control the navigation of the carousel
 * @constructor
 */
BCNTRY.CarouselNavigation = function () {
    this.visible = null;
};

/**
 * Abstract method - to be overridden
 */
BCNTRY.CarouselNavigation.prototype.totalHeight = function () {
    return 0;
};

/**
 * Abstract method
 */
BCNTRY.CarouselNavigation.prototype.setRegion = function (region) {
};

/**
 * Class to control the navigation of the carousel with arrows
 * @constructor
 */
BCNTRY.ArrowNavigation = function (carousel,topOnEl,topOffEl,bottomOnEl,bottomOffEl) {
    this.topOnEl = topOnEl || $('scroll_variants_top');
    this.topOffEl = topOffEl || $('scroll_variants_top_off');
    this.bottomOnEl = bottomOnEl || $('scroll_variants_bottom');
    this.bottomOffEl = bottomOffEl || $('scroll_variants_bottom_off');
    this.carousel = carousel;
    
    this.visible = false;
    this.prevTimer = null;
    this.nextTimer = null;
};

BCNTRY.ArrowNavigation.prototype = new BCNTRY.CarouselNavigation();


/**
 * Called when state of the carousel changes.  Sets the activity of the 
 * buttons
 * @param {Hash} args The current positions
 */
BCNTRY.ArrowNavigation.prototype.scrollStateHandler = function (args) {
     if (this.visible) {
        if (!args.first) {
            clearInterval(this.prevTimer); 
            yd.setStyle(this.topOnEl,'display','none');
            yd.setStyle(this.topOffEl,'display','block');
        } 
        else {
            yd.setStyle(this.topOffEl,'display','none');
            yd.setStyle(this.topOnEl,'display','block');
        }
        if (args.last < this.carousel.getVisibleItems().length + args.first ) {
            clearInterval(this.nextTimer); 
            yd.setStyle(this.bottomOnEl,'display','none');
            yd.setStyle(this.bottomOffEl,'display','block');
        } 
        else {
            yd.setStyle(this.bottomOffEl,'display','none');
            yd.setStyle(this.bottomOnEl,'display','block');
        }
    }
};

/**
 * Initialises the buttons
 */
BCNTRY.ArrowNavigation.prototype.init = function () {

    var that = this;

    yd.setStyle(this.topOnEl,'display','none');
    yd.setStyle(this.bottomOffEl,'display','none');

    if (this.carousel.getItems().length > this.carousel.getVisibleItems().length) {
        yd.setStyle(this.topOffEl,'display','block');
        yd.setStyle(this.bottomOnEl,'display','block');
        this.visible = true;
    }
    else {
        yd.setStyle(this.topOffEl,'display','none');
        yd.setStyle(this.bottomOnEl,'display','none');
    }
    
    var _scrollNext = function () {
        that.scrollNext();
    };
    
    var _scrollPrev = function () {
        that.scrollPrev();
    };
    
    // Set events
    ye.on(this.topOnEl, 'mouseover', _scrollPrev);
    ye.on(this.topOnEl, 'mouseout', function () {clearInterval(that.prevTimer);});
    ye.on(this.bottomOnEl, 'mouseover',_scrollNext);
    ye.on(this.bottomOnEl, 'mouseout', function () {clearInterval(that.nextTimer);});
    this.carousel.on("afterScroll", this.scrollStateHandler,null,this);

};

/**
 * Called when the previous button is activated, scrolls back
 */
BCNTRY.ArrowNavigation.prototype.scrollPrev = function () {
    
    var that = this;
    
    var _scrollPrev = function () {
        that.scrollPrev();
    };
    
    clearInterval(this.nextTimer);
    clearInterval(this.prevTimer);
    this.carousel.scrollBackward();
    this.prevTimer = setInterval(_scrollPrev,this.carousel.get('animation').speed+3);
};

/**
 * Called when the next button is activated, scrolls forward
 */
BCNTRY.ArrowNavigation.prototype.scrollNext = function () {
    
    var that = this;
    
    var _scrollNext = function () {
        that.scrollNext();
    };
    
    clearInterval(this.nextTimer);
    clearInterval(this.prevTimer);
    this.carousel.scrollForward();
    this.nextTimer = setInterval(_scrollNext,this.carousel.get('animation').speed+3);
};



/**
 * Returns the screen height of the navigational elements
 * @returns The screen height of the navigational elements
 * @type Integer
 */
BCNTRY.ArrowNavigation.prototype.totalHeight = function () {
    if (this.visible) {
        return this.topOnEl.height * 2;
    }
    else {
        return 0;
    }
};

/**
 * Class to hold the thumb of a slider
 * @constructor
 */
BCNTRY.SliderThumb = function () {
    this.element = null;
    this.topEl = null;
    this.middleEl = null;
    this.bottomEl = null;
};

/**
 * Initialises the slider thumb
 */
BCNTRY.SliderThumb.prototype.init = function (element,topEl,middleEl,bottomEl) {
    this.element = element;
    this.topEl = topEl;
    this.middleEl = middleEl;
    this.bottomEl = bottomEl;
    this.extraHeight = null;
    this.height = null;
};

/**
 * Sets the size of a slider thumb.  Assumes the top and bottom sections
 * are immutable.  Adjusts the middle section
 * @param {Integer} height The desired height of the thumb
 */ 
BCNTRY.SliderThumb.prototype.setSize = function (height) {
    this.height = height;
    if (this.extraHeight === null) {
        this.topHeight = yd.getRegion(this.topEl).height;
        this.bottomHeight = yd.getRegion(this.bottomEl).height;
        this.extraHeight = this.topHeight + this.bottomHeight;
    }
    
    if (this.height > this.extraHeight) {
        yd.setStyle(this.middleEl,'height',this.height - this.extraHeight +'px');
    }
};

/**
 * Class to control a carousel with a YUI Slider
 * @constructor
 */
BCNTRY.SliderNavigation = function (carousel) {
    this.slider = null;
    this.carousel = carousel;
    this.height = 350;
    this.sliderbg = $("sliderbg");
    this.sliderThumb = new BCNTRY.SliderThumb();
    this.sliderThumb.init($('sliderthumb'),$('slidertop'),$('slidermiddle'),$('sliderbottom'));
    
};

BCNTRY.SliderNavigation.prototype = new BCNTRY.CarouselNavigation();

/**
 * Converts a slider pixel value into a real value
 * @param {Integer} value Pixel value from Slider
 */
BCNTRY.SliderNavigation.prototype.getRealValue = function(value) { 
    return Math.round(value * this.scaleFactor); 
};

/**
 * Initialises the slider, thumb, and adds some listeners
 */
BCNTRY.SliderNavigation.prototype.init = function () {
    
    if (this.slider === null) {
        this.slider = YAHOO.widget.Slider.getVertSlider(this.sliderbg,this.sliderThumb.element, 0, this.height);
        this.slider.subscribe('change', function (newOffset) {
            // Dirty, dirty, dirty
            // Hacking to get around hack in carousel.js that takes 1px off height
            if (this.carousel._itemsTable.size && !this.hackedHeight) {
                this.hackedHeight = true;
                this.carousel._itemsTable.size+=1;
            }
            this.carousel.scrollTo(this.getRealValue(newOffset));
        },this,true); 
        
        // Do not close on click, so cancel event
        ye.addListener(this.sliderbg,'click',function(ev) {ye.stopEvent(ev);});
    }
    if (this.visible === null) {
        this.visible = this.carousel.getItems().length > this.carousel.getVisibleItems().length;
    }    
    if (this.visible) {
        yd.setStyle(this.sliderbg,'display','block');
    }
    else {
        yd.setStyle(this.sliderbg,'display','none');        
    }
    

};

/**
 * Sets the sizes of the slider and thumb
 * @param {Region} region The region of the containing element
 */
BCNTRY.SliderNavigation.prototype.setRegion = function (region) {
    this.height = region.height;
    if (this.height > 0) {
        this.scaleFactor =  this.carousel.get("numItems") / this.height;
        yd.setStyle(this.sliderbg,'height',this.height+'px');
        this.sliderThumb.setSize(parseInt(this.carousel.get("numVisible") / this.scaleFactor,10));
        this.slider.thumb.initSlider(0,0,0,this.height - this.sliderThumb.height);
    }
};

/**
 * An object for a wall tab
 * @constructor
 * @param tab_id {HTMLElement}  HTML ID of the tab
 * @param content_id {HTMLElement} HTML ID of the content within the tab
 * @param code_to_execute {Function} Function to call when the tab is clicked
*/
BCNTRY.odat.tab = function (tab_id, content_id, code_to_execute) {
	var members = {
		tab_id: tab_id,
		content_id: content_id,
		execute: code_to_execute || function () {},
		fresh: 0
	};
	return members;
};

BCNTRY.odat.tabs = {
	// Each tab works by turning on/off elements of certain HTML classes
	dealTalk_tab: new BCNTRY.odat.tab('dealTalk_tab','dealTalk_content'),
	features_tab: new BCNTRY.odat.tab('features_tab','features_content'),
	sizing_tab: new BCNTRY.odat.tab('sizing_tab','size_content'),
	reviews_tab: new BCNTRY.odat.tab('reviews_tab','reviews_content')
};

/**
 * Function to be called to switch between tabs (should be in class)
 * @param activetab Name of the tab to be made active
*/
BCNTRY.odat.switchTab = function (activetab) {
    var active_class = 'active';
    
	for (var tab_id in BCNTRY.odat.tabs) {
	  if (BCNTRY.odat.tabs.hasOwnProperty(tab_id)) {
            if (tab_id !== activetab && $(tab_id)) {
                yd.removeClass(tab_id,active_class);
                yd.setStyle(BCNTRY.odat.tabs[tab_id].content_id,'display','none');
            }
	  }
	}
	yd.addClass(activetab,active_class);
	if (typeof(BCNTRY.odat.tabs[activetab].execute)) {
		BCNTRY.odat.tabs[activetab].execute();
	}
	yd.setStyle(BCNTRY.odat.tabs[activetab].content_id,'display','block');

	//omniture tracking
	BCNTRY.odat.scBuffer.trackTabSwitch(activetab);
	return;
};

/**
 * Initializes an instance of BCNTRY.sc.ODATCommBuffer, which will be used for
 * Omniture tracking in sevaral places.
 */
BCNTRY.odat.initSCBuffer = function() {
	BCNTRY.odat.scBuffer = new BCNTRY.sc.ODATCommBuffer( s_gi(sc_account), 'ODAT Community',
		{sendOnUnload:true, ir_form_id:'review_form'});
	//For ODAT community, when InstantReviews form is subitted, scBuffer is serialized to cookie.
	//Check for that cookie and restore if it is present.
	if(_readCookie('sc_buffer')) {
		BCNTRY.odatComm.scBuffer.deserialize(unescape(_readCookie('sc_buffer')));
		BCNTRY.odatComm.scBuffer.cfg.sendOnUnload = true; //re-enable in case the cookie disabled it
		_deleteCookie('sc_buffer');
	}
};

/**
* Adds listeners for the tabs
*/
BCNTRY.odat.setupTabs = function () {
	var tabs_count = 0;
	var tab_width = 0;

	if ($('tabs')) { 
	    var tabs_li = $('tabs').getElementsByTagName("LI");

	    tab_width = ((100 / tabs_li.length)-0.05);	
	    for (i=0; i<tabs_li.length; i++) {
		tabs_li[i].style.width = tab_width + '%';
	    }
	    if ($('tabs_content')) {
		$('tabs_content').style.width = (tab_width*tabs_li.length) + "%";
		// Safari displays the tabs_content container wider than it should	
		if (navigator.userAgent.match(/Safari/i)) { 
		    $('tabs_content').style.width = ((tab_width*tabs_li.length)-0.2) + "%";
		}
	    }
	    yd.addClass(tabs_li[tabs_li.length-1], 'last');
	}
	if (BCNTRY.page_data.instant_reviews_enabled) {
		ye.addListener("dealTalk_tab", "mousedown", function () {BCNTRY.odat.switchTab('dealTalk_tab');});
	}
	ye.addListener("reviews_tab", "mousedown", function () {BCNTRY.odat.switchTab('reviews_tab');});
	ye.addListener("features_tab", "mousedown", function () {BCNTRY.odat.switchTab('features_tab');});
	ye.addListener("sizing_tab", "mousedown", function () {BCNTRY.odat.switchTab('sizing_tab');});

	if (!BCNTRY.page_data.instant_reviews_enabled) {
		BCNTRY.odat.switchTab('features_tab');
	}
};
/* End tabs */

