/*
Code by Steffan A. Cline 
Version 1.5 - 9/5/2007
Row color highlighter and automatic price adjustment

usage:

<body onload="init( parameter1, parameter2, parameter3, parameter4 );">
parameter 1 =  the name of the form
parameter 2 =  the type of control to attach a listener to - this can be a single control or an array 
    rather than just radio you could do ..., new Array('radio','checkbox','select-one'), ... 
    or lasso escaped ..., ["['radio','checkbox','select-one']"], ... 
parameter 3 = the target "id" of the price - this can be any thing that contain text 
    for example <span id="price"></span> <div id="price"></div> <td id="price"></td> <input ... id="price">
    all ids must be UNIQUE! multiple can be used. - ..., new Array('price1','price2'),...
parameter 4 =  the BASE price of the item in a raw decimal or integer value. 

changes 9/6/2007 v1.7
1.  documentation update - included alternate to new Array() when initializing the script - [..,..,..] notation
2.  checkType changed to more logical controlTypes name
3.  added support for checkboxes 
4.  added support for selects - single and multiple
5.  more comments
6.  made it smarter so if not existent requested items are not there you do not get errors.
7.  universalized the event bubbling control
8.  monitored items that are not in a row will no longer throw an error.
9.  added &nbsp; to the [ Add.... ] so they wrap appropriately.
10. corrected some logic
11. removed line of code that would place a price for items of the same value.

changes 9/8/2009 v2.0
1. Merged with config portal since all one page
2. Changed options to utilize jQuery for xbrowser compatibility assistance
3. Not a complete rewrite

changes 1/30/2010 v2.1
1. modified the popups behavior
2. fixed issues with totals not updating when removing items.

changes 1/31/2010 v2.2
1. fixed the product table after portal closes.

changes 1/31/2010 v2.3
1. changed the axis scroll to left and right
*/

// begin user configurable
var unselectedColor = "#ffffff";  // color of the rows when not checked/selected
var selectedColor = "#d2ebff";   // color of the rows when selected/checked
var rolloverOnColor = "#eaeaea";  // color of the rows when moused over
var rolloverOffColor = unselectedColor; // color of the rows when moused out
var priceUnChangedClass = "grey12";  // class of a span div td etc where the output text is to be changed
var priceChangedClass =  "red12";  // class of a span div td etc where the output text is to be changed when form changed
var parentToColor = "TR";    // the parent node of a control to have it's background color changed
var selectedItemChangesOnRollover = false; // change to false if a selected item should change color
// end user configurable


// ***** script vars - do not change ******
var calcForm, controlTypes, totalTarget;
var basePrice = 0;
var formWasChanged = false;

$(document).ready(function () {
	$('a.editConfigs').click(function (e) {
		e.preventDefault();
		$("#basicModalContent").modal({	onClose: function (dialog) { dialog.data.fadeOut('slow', function () {
																		dialog.container.slideUp('slow', function () {
																			dialog.overlay.fadeOut('slow', function () {
																				$.modal.close(); // must call this!
																				});
																			});
																		});
																}, //onClose
										persist:true,
										onOpen: function (dialog) { dialog.overlay.fadeIn('slow', function () {
																		dialog.container.slideDown('slow', function () {
																			dialog.data.fadeIn('slow');
																			$("#scroller").scrollTo( $("#" + escID($("#lens").val())), 1, {axis:'x'});
																		});
																	});
																} //onopen
										}); //modal	
		}); //editConfigs

	$('input[value*="||"]').change(function(){	// attach the onChange function to the checkboxes
		var sku = $(this).val().split('||')[2];
		var cbSet = $('input:checkbox[value*="' + sku + '"]');
		$('input:checkbox[value*="' + sku + '"]').not($(this)).attr("checked", false); //set all others to unchecked
		if($('input:checkbox:checked[value*="' + sku + '"]').length) {
			cbSet.parent().parent().children('p').remove(); // remove any <p>s
			cbSet.not($(this)).parent().hide().parent().append('<p align="center" class="warning">Already Selected!</p>'); // add a <p>
			}
		else {
			cbSet.parent().parent().children('p').remove(); // remove the <p>s since nothing is checked.
			cbSet.parent().show(); // show all cbs
			}
	}); // change

	$("#lens").change(function(){
		$("#scroller").scrollTo(("#" + $(this).val()), 1, {axis:'x'});
	});
	
	$("#lens-base").change(function(){
		$("#lens").val(this.value);
		$("a.editConfigs").click();
	});
	
	// attach onclick to the submit "Add to Cart" buttons
	$(".portal-submit").click( function() {
		drawTable(); // draw main window here
		$.modal.close();;
	});	
	
	
});	// ready
		
function escID(myid)
  { return myid.replace(/:/g,"\\:").replace(/\./g,"\\.");}


function init( _formSeed, _supportedControls, _targets, _price )
{
 calcForm = document.forms[_formSeed];           // set the form to attach the event to
 controlTypes = (typeof(_supportedControls) == 'string' ? new Array(_supportedControls) : _supportedControls); // set the type of element we will check in the form
 totalTarget = (typeof(_targets) == 'string' ? new Array(_targets) : _targets); // insure we are working with an array and set the target(s) for the total
 basePrice = parseFloat(_price);             // set the base price
 
 // init data integrity validation
 if( !calcForm )  alert("init() did not receive a form name to process!");
 if( !controlTypes ) alert("init() did not receive (a) form element type(s)!");
 if( !totalTarget ) alert("init() did not receive (a) target(s) for the total!");
 if( !basePrice )  alert("init() did not receive a base price!");
 
 for( var i = 0; i < calcForm.elements.length; i++ )
  for( var j in controlTypes )
   if( calcForm.elements[i].type == controlTypes[j] )
   {
    if( getValue(calcForm.elements[i]) && calcForm.elements[i].type.indexOf('select') == -1 ) // if radio or checkbox
     getParent(calcForm.elements[i]).cells[1].innerHTML += (" <b>[&nbsp;Add&nbsp;$" + getValue(calcForm.elements[i]) + "&nbsp;]</b>");

    if( calcForm.elements[i].type.indexOf('select') > -1 )     // selects
     for( var j = 0; j < calcForm.elements[i].length; j++ )
      if( getValue(calcForm.elements[i].options[j].value) )
       calcForm.elements[i].options[j].text += ("&nbsp;[&nbsp;Add&nbsp;$" + getValue(calcForm.elements[i].options[j]) + "&nbsp;]") 
     
    
    calcForm.elements[i].onclick = function (e) 
             {  var e = e || event;
              e.cancelBubble = true; // stop this click from bubbling up to the row handler
              formWasChanged = true; // set the form as dirty so it can be processed
              setTotal(); 
             };  // attach the event to all types specified
    
    var row = getParent(calcForm.elements[i]);
    if( row )
    	{
    	row.onmouseover = function () { if( !selectedItemChangesOnRollover && (getControl(this).checked || getControl(this).selectedIndex) ) 
             return; // will control whether or not a row is affected by rollover when selected
            this.style.backgroundColor = rolloverOnColor; // highlight the row 
             }
    	row.onmouseout  = function () { var x = getControl(this); this.style.backgroundColor = ( x && ( x.selectedIndex || x.checked ) ?  selectedColor : rolloverOffColor ); }
    	row.onclick  = function () { var x = getControl(this); 
            if( x ) // if there is a control in this row then process it
            {
			switch( x.type )
			{
				case( "radio" )   : this.style.backgroundColor = selectedColor;
				x.checked = true;
				break;
				case( "checkbox" )  : x.checked = !x.checked;
				this.style.backgroundColor = ( x.checked ? selectedColor : unselectedColor );
				break;
				case( "select" )  : // catch alls for the selects 
				case( "select-multiple" ): 
				case( "select-one" ) : this.style.backgroundColor = ( x.selectedIndex ? selectedColor : unselectedColor );
				break;
			}
			formWasChanged = true;   // set the form as dirty so it can be processed
            setTotal();
            }
		}
	  } 
	}
 setTotal();            // setTotal will color the rows appropriately and then displayTotal()
}

function setTotal() {
	var chosenConfigCost, current_group, current_amount, current_control;
	var total = basePrice;           // set a base point for our total

	if( controlTypes.contains("radio") ) {
	var groups = [];
	var inputControls = calcForm.getElementsByTagName("input").length
								? calcForm.getElementsByTagName("input")
									: new Array(0);     // get all input elements handed off in an array

	for( var i = 0; i < inputControls.length; i++ )    // iterate thru all inputControls - find radio dials and get the groups
	if( inputControls[i].type == "radio" && !groups.find( inputControls[i].name ) ) 
		groups = groups.concat([inputControls[i].name]); // if this is a new group then add it

	for( var i = 0; i < groups.length; i++ ) {      // iterate thru groups
		current_group = calcForm.elements[groups[i]];    // set current group
		chosenConfigCost = 0;         // reset the chosenConfig cost for this iteration

		for( var j = 0; j < current_group.length; j++ )   // iterate thru current group's radio dials (bubble sort)
			if( current_group[j].type == "radio" && current_group[j].checked )
				chosenConfigCost = getValue(current_group[j]); // if this is the higest then set it as the highest

		for( var k = 0; k < current_group.length; k++ ) {  // iterate thru current group
			current_control = current_group[k];     // set the current control
			current_amount = getValue(current_control);   // set the current amount
			current_row = getParent(current_control);   // set the current row

			current_row.cells[1].innerHTML =     // clear out current dollars
			current_row.cells[1].innerHTML.replace(new RegExp("(\\s*<b>\\[.*?\\]</b>\\s*)+?", "gi" ),""); 
			current_row.style.backgroundColor = unselectedColor;

			if( current_amount < chosenConfigCost )    // if current item costs less than the chosen cost then show - subtract
				current_row.cells[1].innerHTML += " <b>[&nbsp;Subtract&nbsp;$" + (chosenConfigCost - current_amount).toFixed(2) + "&nbsp;]</b>";
			if( current_amount > chosenConfigCost )    // if current item costs more than the chosen cost then show - add more
				current_row.cells[1].innerHTML += " <b>[&nbsp;Add&nbsp;$" + (current_amount - chosenConfigCost).toFixed(2) + "&nbsp;More&nbsp;]</b>";
			if( current_control.checked && current_amount )  // if item is the one checked then show - add
				total += chosenConfigCost;
			if( current_control.checked )
				current_row.style.backgroundColor = selectedColor;
			}
		}
	}

	if( controlTypes.contains("select") ) {
		var selects = calcForm.getElementsByTagName('select').length   // catch all for the selects
					? calcForm.getElementsByTagName('select') 
						: calcForm.getElementsByTagName('select-one').length
							? calcForm.getElementsByTagName('select-one')
								: calcForm.getElementsByTagName('select-multiple').length
									? calcForm.getElementsByTagName('select-multiple')
										: new Array(0);

		for( var i = 0; i < selects.length; i++ ) {
			var thisSelectMax = getValue(selects[i].options[selects[i].selectedIndex]);
			for( var j = 0; j < selects[i].length; j++ ) { 
				selects[i].options[j].text = selects[i].options[j].text.replace(new RegExp("(\\s*\\[.*?\\]\\s*)+?", "gi" ),"");
				var thisOption = getValue(selects[i].options[j])
				if(  thisOption < thisSelectMax )
					selects[i].options[j].text += " [ Subtract $" + (thisSelectMax - thisOption).toFixed(2) + " ]";
				if( thisOption > thisSelectMax )
					selects[i].options[j].text += " [ Add $" + (thisOption - thisSelectMax).toFixed(2) + " More ]"
				}
			total += getValue(selects[i].options[selects[i].selectedIndex]);
			}
	}

	if( controlTypes.contains("checkbox") ){
		var inputControls = calcForm.getElementsByTagName("input").length
								? calcForm.getElementsByTagName("input")
									: new Array(0); // get all input elements handed off in an array

		for( var i = 0; i < inputControls.length; i++ )
			if( inputControls[i].type == "checkbox" && inputControls[i].checked ) // if it is a checkbox and is checked
				total += getValue(inputControls[i]); // if so add to total
	} // end if check box

	var x=$(".port-total:first").text().match(/\d+(,\d{3})*(\.\d{1,2})?/g); // get any portal prices
	total += parseFloat((x==null ? 0 : x), 6);

	displayTotal(total);	// display the total in assigned spaces
}

function displayTotal(total) {
	for( var i = 0; i < totalTarget.length; i++ )   // loop thru the list of price locations.
		{
		var target = $("#" + totalTarget[i]); 		// get a handle on the target
		if( target.is("input:text") )        		// determine if this is an input 
			target.val() = total.toFixed(2);      	// output the data in a fixed format
		else {
			target.html(formWasChanged ? ("Updated Price $" + total.toFixed(2) ): " " );
			target.removeClass().addClass( formWasChanged ? priceChangedClass : priceUnChangedClass );
			}
		}
}

function setScroll(x){
	$("#lens-base").val(x);
	$("#lens").val(x);
	$("#scroller").scrollTo( $("#" + x), 1, {axis:'x'});
	$("a.editConfigs").click();
	return false;
}

function drawTable() {
	$("#portal").empty();
	if($("input:checkbox:checked").length) {		
		var tableOpen = '<table class="ports" cellpadding="0" cellspacing="0">';
		var tableClose = '</table><br />';
		var table = tableOpen;
		var skus = "";
		var price = 0.0;
		
		var product = $("input:checkbox:checked").val().split("||")[0];
		var row = $("input:checkbox:checked").parents("td[id^=row]").attr("id");
		table += '<tr bgcolor="#d2ebff"><td nowrap class="portsoption" style="padding-top: 4px; padding-bottom: 4px; padding-left: 4px;"><b>For ' + product + '</b></td><td class="portsprice" style="padding-right:4px; text-align:right; font-size:12px; vertical-align:middle;"><a href="#" name="' + row + '" class="editConfigs3">Edit</a></td></tr>';
		
		$("input:checkbox:checked").each( function() {
				var data=this.value.split("||");
				price += parseFloat(data[3]);
				if( product != data[0] ) {
					var row = $(this).parents("td[id^=row]").attr("id");
					table += tableClose + tableOpen;
					table += '<tr bgcolor="#d2ebff"><td nowrap class="portsoption" style="padding-top: 4px; padding-bottom: 4px; padding-left: 4px;"><b>For ' + data[0] + '</b></td><td class="portsprice" style="padding-right:4px; text-align:right; font-size:12px; vertical-align:middle;"><a href="#" name="' + row + '" class="editConfigs3">Edit</a></td></tr>';
					}
				table +='<tr><td width="100%" class="portsoption" style="padding-top: 4px; padding-bottom: 4px; padding-left: 4px;">' + data[1] + '</td><td nowrap class="portsprice" style="padding-top: 4px; padding-bottom: 4px; padding-left: 4px; padding-right: 4px;">$' + data[3] + '</td></tr>';
				skus += data[2] + "||";
				product = data[0];
				});
		table += tableClose;
		table += '<input type="hidden" name="PortFinderSelectedSKUs" value="' + skus + '">';
		$(table).appendTo("#portal");					// will append the table to the #portal div
		$("a.editConfigs2").click(function () { $("a.editConfigs").click(); }); //attach a click handler to the button just added.
		$(".port-total").html("<b>Port Finder Total:</b> $" + price.toFixed(2));	// set the text inside the class port-total elements to the $ + price fixed to 2 decimal points
		}
	else
		$(".port-total").html("<b>Port Finder Total:</b> $0");
	formWasChanged = true;
	$(".editConfigs3").click(function(event){ event.preventDefault(); setScroll(this.name); });
	setTotal();	// trigger the function which will total everything in the form.
}

function getParent( obj ) {
	do { // back out of the container node until we hit the 
		obj = obj.parentNode; // targeted node
  		}
  	while( obj.nodeName != "HTML" && obj.nodeName != parentToColor ); // use HTML as the safety node
	
	return( obj.nodeName == "HTML" ? null : obj );
}

function getControl( obj ) {
	if( obj.getElementsByTagName("input").length )     // checkboxes and radio dials <or buttons>
		return( obj.getElementsByTagName("input")[0] );
	if( obj.getElementsByTagName("select").length )     // pop up selects - non standard getter
		return( obj.getElementsByTagName("select")[0] );
	if( obj.getElementsByTagName("select-one").length )    // pop up selects
		return( obj.getElementsByTagName("select-one")[0] );
	if( obj.getElementsByTagName("select-multiple").length )  // list box select
		return( obj.getElementsByTagName("select-multiple")[0] );
	return( null );
}

function getValue(obj)
{
	var delimiter = "||";   // the delimiter in your strings to get to the price for the added feature's price
	var valuePosition = 2;   // the position within the delimited string for the added feature's price
 
	var value = 0.0;     // set a default of 0
	if( typeof(obj) == 'string' ) // if we are passed a string in the event of a select item
		value = parseFloat(obj.split(delimiter)[valuePosition]);
	else if( obj.value )   // else there is a value attribute
 		value = parseFloat(obj.value.split(delimiter)[valuePosition]);
	return( value ? value : 0.0 );
}


/******************************************************************************************************************************/
// overloads and utilities
/******************************************************************************************************************************/

// add a new member to the array class
Array.prototype.find = function ( item )  
{           
 for( var i = 0; i < this.length; i++ ) 
  if( this[i] == item ) 
   return( true );
 return( false );
};

// add a new member to the array class
Array.prototype.contains = function ( item )  
{           
 for( var i = 0; i < this.length; i++ ) 
  if( this[i].indexOf(item) != -1 ) 
   return( true );
 return( false );
};

// the following functions will ensure that the dollars are rounded to the specified number of decimal places.
function Stretch(Q, L, c) 
{ 
 var S = Q;
 if (c.length>0) 
  while (S.length<L) 
   { S = c+S } 
 return( S ); 
} 

function StrU(X, M, N) 
{ 
 // X>=0.0 
 var T, S=new String(Math.round(X*Number("1e"+N))); 
 if (S.search && S.search(/\D/)!=-1) { return ''+X } 
 with (new String(Stretch(S, M+N, '0'))) 
 return( substring(0, T=(length-N)) + '.' + substring(T) ); 
} 

function Sign(X) 
{  
 return( X < 0 ? '-' : '' ); 
} 

function StrS(X, M, N) 
{ 
 return( Sign(X)+StrU(Math.abs(X), M, N) ); 
} 
// add the .toFixed() to the number class.
Number.prototype.toFixed = function(n){ return StrS(this,1,n) }; 


