/**
 * Used in dynamic pricing. Testing phase, at the moment.
 *
 * Adam Backstrom, 2/10/2006
 */

// Thanks, <http://monsterzz.info/?p=8>.
if (!Array.prototype.indexOf) {
	Array.prototype.indexOf = function(idx)
	{
		for( var i = 0; i < this.length; i++ )
		{
			if( this[i] == idx )
			{
				return i;
			}
		}

		return -1;
	};
}

// http://developer.mozilla.org/en/docs/DOM:window.open#Best_practices
SWCSpecSheetWindow = null;
function dospecsheet( $pf_id )
{
	if( SWCSpecSheetWindow == null || SWCSpecSheetWindow.closed )
	{
		url = 'specsheet.asp?pf_id=' + $pf_id;
		SWCSpecSheetWindow = window.open(url,"swcspecsheet","menubar=no,width=580,height=400,toolbar=no,status=yes,resizable=yes,scrollbars=yes");
	}
	else
	{
		SWCSpecSheetWindow.focus();
	};
}

var skus = function(){
	var skuData = [];
	var skuAttributes = [];
	var skuBase = {};

	var length = 0;

	var ATTR1_MASK = 0xF;
	var ATTR2_MASK = ATTR1_MASK << 4;
	var ATTR3_MASK = ATTR2_MASK << 4;
	var ATTR4_MASK = ATTR3_MASK << 4;
	var ATTR5_MASK = ATTR4_MASK << 4;

	function setBase(length_uom, length_plural, price_foot, base_price, weight, weight_foot, product_discount, shopper_discount, inhouse_note, special_order, rohs_compliant)
	{
		this.skuBase = {
			length_uom:length_uom,
			length_plural:length_plural,
			price_foot:price_foot,
			base_price:base_price,
			weight:weight,
			weight_foot:weight_foot,
			product_discount:product_discount,
			shopper_discount:shopper_discount,
			inhouse_note:inhouse_note,
			special_order:special_order,
			rohs_compliant:rohs_compliant
		};

		if( skuBase.shopper_discount == 0 )
		{
			skuBase.shopper_discount += 1;
		}
	};

	function addSku(sku, attr1, attr2, attr3, attr4, attr5, price, price_foot, weight, weight_foot, disc, rohs)
	{
		var hash = attr1 | (attr2 << 4) | (attr3 << 8) | (attr4 << 12) | (attr5 << 16);

		skuData[hash] = {
			sku:sku, price:price, price_foot:price_foot, weight:weight,
			weight_foot:weight_foot, discount:disc, rohs:rohs
		};

		length += 1;
	};

	function getSku()
	{
		var hash = 0;
		var index;

		for( var i = 0; i < getSku.arguments.length; i++)
		{
			index = getAttributeIndex(i, getSku.arguments[i]);
			hash += (index+1) << (4*i);
		}

		var thisSku = skuData[hash];

		if( thisSku == undefined )
		{
			return false;
		}

		// make sure all sku properties have a value
		if( thisSku.price == 0 ) thisSku.price = this.skuBase.base_price;
		if( thisSku.price_foot == 0 ) thisSku.price_foot = this.skuBase.price_foot;
		if( thisSku.weight == 0 ) thisSku.weight = this.skuBase.weight;
		if( thisSku.weight_foot == 0 ) thisSku.weight_foot = this.skuBase.weight_foot;
		if( thisSku.discount == "" ) thisSku.discount = this.skuBase.product_discount;
		if( thisSku.rohs == "" ) thisSku.rohs = this.skuBase.rohs;

		return skuData[hash];
	};

	function addAttributes(position)
	{
		skuAttributes[position-1] = [];

		for( var i = 1; i < addAttributes.arguments.length; i++)
		{
			skuAttributes[position-1].push(addAttributes.arguments[i]);
		}
	};

	function getAttributeIndex(position, value)
	{
		if( ! skuAttributes[position] )
		{
			return -1;
		}

		for( var i = 0; i < skuAttributes[position].length; i++)
		{
			if( skuAttributes[position][i] == value )
			{
				return i;
			}
		}
	};

	return {
		addSku:addSku,
		getSku:getSku,
		addAttributes:addAttributes,
		length:length,
		setBase:setBase,
		skuBase:skuBase,
		skuData:skuData
	};
}();

var discounts = new function(){
	function add(code)
	{
		theDiscounts.push(code);
		index = theDiscounts.indexOf(code);

		theDiscountData[index] = [];
		for( var i = 1; i < 5; i++ )
		{
			theDiscountData[index][i-1] = add.arguments[i];
		}
	}

	function discount(code, level)
	{
		index = theDiscounts.indexOf(code);
		discount = theDiscountData[index][level-1];

		return 1 - (discount * .01)
	}

	var theDiscounts = [];
	var theDiscountData = [];

	return {
		add:add,
		discount:discount
	}
}();

var pricingForm;   // shortcut to "MyFirstForm"
var pfe = {};	  // shortcut to dynamic price form elements
var attrs = [];	// shortcut to attribute boxes

var MAX_ATTRIBUTES = 5;  // maximum attributes for any product
var W3CDOM = document.getElementsByTagName; // see if the browser supports the DOM

var currentSku = false;  // holds the current sku

/**
 * Initialize the global JavaScript variables, creating
 * shortcuts to all the DOM elements we'll need later on.
 */
function pricing_init() {
	if(!W3CDOM) return;

	pricingForm = document.getElementById("MyFirstForm");

	//
	// get all the text boxes
	//

	pfe["length"] = document.getElementById("f_length");
	pfe["quantity"] = document.getElementById("qty");

	pfe["sku"] = document.getElementById("f_sku");
	pfe["list_price"] = document.getElementById("f_listprice");
	pfe["unit_price"] = document.getElementById("f_unitprice");
	pfe["your_price"] = document.getElementById("f_yourprice");
	pfe["total_price"] = document.getElementById("f_totalprice");
	pfe["weight"] = document.getElementById("f_weight");
	pfe["discount"] = document.getElementById("f_discount");
	pfe["sales_list"] = document.getElementById("f_saleslist");
	pfe["sales_stand"] = document.getElementById("f_salesstand");
	pfe["sales_val"] = document.getElementById("f_salesval");
	pfe["sales_pref"] = document.getElementById("f_salespref");

	pfe["your_price_row"] = document.getElementById("t_yourprice");

	if(!pfe["length"]) {
		pfe["length"] = new Object();
		pfe["length"].value = 0;
	}

	//
	// loop through the select boxes, looking for attributes 1 through 5
	//

	for(i = 1; i <= MAX_ATTRIBUTES; i++) {
		theSelect = document.getElementById('attr_value' + i);

		if( ! theSelect ) continue;
		if( theSelect.getAttribute("type") == "hidden" ) continue;

		attrs[i] = theSelect; // add to array of select boxes
	}
}

/**
 * Cleanup a price, replacing any non-numeric and non-decimal character.
 */
function price_clean(s) {
	var re = /[^0-9\.]/;
	return Number(String(s).replace(re,""));
}

/**
 * Format a price to look like a real dollar value.
 */
function format_price(p) {
	p = GaussianRound(p);

	var s = String(p);

	if(s.length > 2) {
		var re = /^(.*)(..)$/;
		return "$"+String(s).replace(re,"$1.$2");
	}

	if(s.length == 2) {
		return "$0."+s;
	}

	// s.length < 2

	return "$0.0"+s;
}

/**
 * Update the subtotal and grand total fields.
 */
function update_price() {
	// fail if there is no DOM, no pricing form, or no current sku
	if(!W3CDOM || !pricingForm || !currentSku) return;

	// do not update pricing on special orders
	if(skus.skuBase.special_order == "yes") return;

	var price = price_clean(currentSku.price);
	var price_foot = price_clean(currentSku.price_foot);

	var length = pfe["length"].value;
	var quantity = pfe["quantity"].value;

	if(length == "na" || !length) length = 0;

	if(quantity > 0 && (length > 0 || price_foot == 0)) {
		// user entered a quantity and length, give them a price

		var foot_price = Number(price_foot) * Number(length);

		var subtotal = Number(currentSku.price) + foot_price;
		subtotal -= subtotal%1; // remove remainder, rounding down

		pfe["unit_price"].innerHTML = format_price(subtotal);

		// get customer-specific price based on discount code

		var yourprice = 0;

		var this_discount = discounts.discount(currentSku.discount, skus.skuBase.shopper_discount);

		if(this_discount < 1) {
			yourprice = subtotal * this_discount;

			pfe["your_price"].innerHTML = format_price(yourprice);

			// move total price to the "your price" row
			if(total_prev_span() == "f_unitprice") {
				pfe["your_price"].parentNode.appendChild(pfe["total_price"]);
				pfe["your_price_row"].style.display = "";
			}

			var totalprice = GaussianRound(yourprice) * quantity;
		} else {
			// move total price to the unit price row
			if(total_prev_span() == "f_yourprice") {
				pfe["unit_price"].parentNode.appendChild(pfe["total_price"]);
				pfe["your_price_row"].style.display = "none";
			}

			var totalprice = subtotal * quantity;
		}

		pfe["total_price"].innerHTML = "&nbsp;&nbsp;<span class=\"nine\">Total:</span> " + format_price(totalprice);
		
		try
		{
			var sales_list = subtotal * discounts.discount(currentSku.discount, 1);
			var sales_stand = subtotal * discounts.discount(currentSku.discount, 2);
			var sales_val = subtotal * discounts.discount(currentSku.discount, 3);
			var sales_pref = subtotal * discounts.discount(currentSku.discount, 4);

			pfe["sales_list"].innerHTML = format_price(sales_list) + "&nbsp;&nbsp;<span class=\"nine\">Total:</span> " + format_price(sales_list * quantity);
			pfe["sales_stand"].innerHTML = format_price(sales_stand) + "&nbsp;&nbsp;<span class=\"nine\">Total:</span> " + format_price(sales_stand * quantity);
			pfe["sales_val"].innerHTML = format_price(sales_val) + "&nbsp;&nbsp;<span class=\"nine\">Total:</span> " + format_price(sales_val * quantity);
			pfe["sales_pref"].innerHTML = format_price(sales_pref) + "&nbsp;&nbsp;<span class=\"nine\">Total:</span> " + format_price(sales_pref * quantity);
		}
		catch(e) { }

	} else {
		// user did not enter the required fields, complain at them

		if(price_foot > 0)
		{
			pfe["unit_price"].innerHTML = "Please enter length and quantity for pricing.";
		}
		else
		{
			pfe["unit_price"].innerHTML = "Please enter quantity for pricing.";
		}

		try
		{
			pfe["sales_list"].innerHTML = "";
			pfe["sales_stand"].innerHTML = "";
			pfe["sales_val"].innerHTML = "";
			pfe["sales_pref"].innerHTML = "";
		}
		catch(e) { }

		pfe["your_price"].innerHTML = "";
		pfe["total_price"].innerHTML = "";
	}

	// development & staging: update weight and discount code
	if(pfe["weight"] && pfe["discount"]) {
		var weight = (currentSku.weight + currentSku.weight_foot * length) * quantity / 1000;
		
		// account for fiber over 75 meters that will be shipped on a spool
		if(skus.skuBase.inhouse_note == "fiber_spool") {
			if( (skus.skuBase.length_uom == 'Meter ' && length > 76) || (skus.skuBase.length_uom == 'Foot' && length > 250) ) {
				weight += 3;
			}
		}

		pfe["weight"].innerHTML = weight;
		pfe["discount"].innerHTML = currentSku.discount;
	}
}

function total_prev_span() {
	theSpan = pfe["total_price"].previousSibling;

	for(i = 0; i < 5; i++) {
		if(theSpan.tagName == 'SPAN') return theSpan.id;

		theSpan = theSpan.previousSibling;
	}

	return '';
}

/**
 * Determine if a character input is valid for the current field.
 * Kill the event if invalid.
 */
function d_validate_keypress(field,evt,decimal) {
	var code;

	// allow decimal values unless otherwise stated
	if(arguments.length < 3) decimal = true;
	else decimal = false;

	if(evt.charCode) code = evt.charCode; // gecko
	else code = evt.keyCode; // ie6

	var allow = true; // allow the keypress by default

	// only allow a single period
	if(decimal && code == 46) {
		if(field.value.indexOf(".") > -1)
			allow = false;

	// disallow non-numeric values
	} else if(code < 47 || code > 57)
		allow = false;

	// checks finished, do the actual allow/disallow action
	if(!allow)
	{
		if(evt.charCode)
		{
			evt.preventDefault(); // gecko
		}
		else
		{
			evt.returnValue = false; // ie6
		}
	}
}

/**
 * Return the current value of a numbered attribute.
 */
function attr_value(num) {
	var theObj = attrs[num];
	if( !theObj ) return "";
	return theObj[theObj.selectedIndex].text;
}

/**
 * Called when an attribute changes. Find the SKU in our list and
 * update the pricing.
 */
function attribute_changed() {
	// bail if the DOM is not supported
	if(!W3CDOM) return;

	// do not update pricing on special orders
	if(skus.skuBase.special_order == "yes") return;

	sku = skus.getSku(attr_value(1), attr_value(2), attr_value(3), attr_value(4), attr_value(5));

	if( sku != false )
	{
		set_pricing(sku);
		return;
	}

	// there was no sku for the selected attributes. possibly
	// a default "choose p2" case.

	currentSku = false;

	pfe["list_price"].innerHTML = "";
	pfe["unit_price"].innerHTML = "";
	pfe["total_price"].innerHTML = "";
	pfe["your_price"].innerHTML = "";

	if(pfe["weight"] && pfe["discount"]) {
		pfe["weight"].innerHTML = "";
		pfe["discount"].innerHTML = "";
	}

	pfe["sku"].innerHTML = "<br><span style=\"color:red;\">Please choose cable options above to display SKU and pricing.</span>";
}

/**
 * Set the pricing to match the selected SKU and update the dollar
 * values on the form.
 */
function set_pricing(sku) {
	// bail if the dom is not supported
	if(!W3CDOM) return;

	// do not update pricing on special orders
	if(skus.skuBase.special_order == "yes") return;

	currentSku = sku;

	pfe["list_price"].innerHTML = format_price(currentSku.price)
	
	if(currentSku.price_foot > 0)
	{
		pfe["list_price"].innerHTML += " + " + format_price(currentSku.price_foot) + " per " + skus.skuBase.length_uom;
	}

	pfe["sku"].innerHTML = currentSku.sku;

	update_price();
}

/**
 * Gaussian rounding (aka Banker's rounding) is a method of statistically
 * unbiased rounding. It ensures against bias when rounding at x.5 by
 * rounding x.5 towards the nearest even number. Regular rounding has a
 * built-in upwards bias.
 *
 * Keith Gaughan http://talideon.com/
 * http://www.bigbold.com/snippets/posts/show/1305
 */
function GaussianRound(x) {
	var absolute = Math.abs(x);
	var sign	 = x == 0 ? 0 : (x < 0 ? -1 : 1);
	var floored  = Math.floor(absolute);
	if (absolute - floored != 0.5) {
		return Math.round(absolute) * sign;
	}
	if (absolute % 2 > 1) {
		// Closest even is up.
		return Math.ceil(absolute) * sign;
	}
	// Closest even is down.
	return floored * sign;
}

