/*******************************************************************************************************************************************************

	Purpose: this file contains all JS for editing/adding rules to records that support them
	
	History:
		File added on 11/23/2005

*******************************************************************************************************************************************************/

var changeRuleDiv;		// global var to contain a reference to the rule that needs to be changed
var dummyName;			// var to store the hidden dummy name span for sizing the name field while typing
var fsetRn = '';		// to keep track of which field set is active. Not sure why, but had to add a blank value to this to keep it defined



/************************************************************************************************
	Called when a menu option is chosen from the Add Rule menu
	
	Parameters:
		ruleRn	(int)	record number of rule to add. If left blank, a blank rule will be added
************************************************************************************************/
var addButtonDiv; // to store a ref. to the div surrounding the "add rule" button
function addRule(ruleRn) {
	// ref. to the Add Rule button
	addButtonDiv = document.getElementById('add_rule_button_'+fsetRn);	// reference to the "add rule" button
	
	// we really only want the inner div
	addButtonDiv = getFirstChildElement(addButtonDiv);
	
	// store current HTML for add rule button
	addButtonDiv.oldInnerHTML = addButtonDiv.innerHTML;
	
	// add a wait indicator
	addButtonDiv.innerHTML = '<div class=valign_middle style=padding:4px><img src=images/cart/indicator.gif /><span> Adding Rule</span></div>';

	// default ruleRn to 0 if not set
	if (ruleRn == undefined) var ruleRn = 0;
	
	// call PHP function to get rule, via AJAX
	x_get_rule(ruleRn,fsetRn,0,0,addRuleCB);
}






/*******************************************************************************
	Function is a callback for AJAX, and adds a rule section as needed
*******************************************************************************/
function addRuleCB(data) {
	var newName;																// variable to hold the name for this new rule
	
	// add new rule row
	addRow('last_rule_row_'+fsetRn,data);

	/********************************************************************
		This is to set an array containing all rule_name_ fields
	********************************************************************/
	// need to grab the master rule fieldset, which should be a parent of
	// the Add Rule button...but might be up a couple of levels
	var ruleFS = addButtonDiv.parentNode;
	while(ruleFS.nodeName != 'FIELDSET') {
		if (ruleFS.parentNode) {
			ruleFS = ruleFS.parentNode;
		} else {
			// ran out of parents, bail
			return;	
		}
	}

	var nameFlds = getElementsByPartialId(ruleFS,'input','rule_name_'+fsetRn);
	
	/***********************************************
		Handle changing the default rule name
	***********************************************/
	if (!nameFlds.length) {
		newName = 'Rule 1';
	} else {
		var nameEnd = nameFlds.length;

		// this loop will keep looping as long as the proposed new name is taken,
		// and will increment nameEnd each time until we have a new unique name
		while(inFieldValues('Rule ' + nameEnd, nameFlds)) {
			nameEnd++;
		}
		
		newName = 'Rule ' + nameEnd;
	}
	
	// set var equal to the name field we just added
	var addedName = nameFlds[nameFlds.length-1];

	// set var equal to the dummyName span, used to resize the name field on the fly
	dummyName = document.getElementById(addedName.id.replace('rule_name_'+fsetRn,'dummy_name_'));
	
	// update the name field
	addedName.value = newName;
	
	// call the onfocus and onkeyup events for the field, so it resizes it's width
	addedName.onkeyup();
	
	// set the formula to combine rules
	setRuleFormula();
	
	// turn the add rule button back on
	addButtonDiv.innerHTML = addButtonDiv.oldInnerHTML;
	
	// set focus on name field
	setFocus(addedName);
}








/******************************************************************************************************
	A rule filter is just a rule used to filter another rule...this adds one.
	
	Parameters:
		btn		(reference)	"add filter" button that was clicked
		ruleRn	(integer)	record number of saved filter rule, if any
******************************************************************************************************/
var addRuleFilterBtn;		// ref. to the button clicked to add the rule filter
var addRuleFilterBtnTD;		// TD surrounding the addRuleFilterBtn
var addFilterRowId;			// ID of the row surrounding the filter btn
var lastRuleRn;				// stores the ruleRn last accessed

function addRuleFilter(btn,ruleRn) {
	// global ref. to the add filter button, so the callback can access it
	addRuleFilterBtn = btn;
	
	// grab parent TD so we can alter it's innerHTML and add a loading msg
	addRuleFilterBtnTD = btn.parentNode;
	
	// store current HTML so we can get it back later
	addRuleFilterBtnTD.oldInnerHTML = addRuleFilterBtnTD.innerHTML;
	
	// add a wait indicator
	addRuleFilterBtnTD.innerHTML = '<div class=valign_middle style=padding:4px><img src=images/cart/indicator.gif /><span> Adding Filter</span></div>';

	// default ruleRn to 0 if not set
	if (ruleRn == undefined) var ruleRn = 0;
	
	lastRuleRn = ruleRn;
	
	// store reference to the row ID that the filter will be added above
	addFilterRowId = addRuleFilterBtn.id.replace('add_filter_button_','add_filter_button_row_');
	
	// grab the unique portion of the rule ID...will be used as the $filter_for param when calling x_get_rule()
	var ruleId = addRuleFilterBtn.id.replace('add_filter_button_','');
	
	// call PHP function to get rule, via AJAX
	x_get_rule(ruleRn,fsetRn,'order_complete',0,0,ruleId,addRuleFilterCB);
}


function addRuleFilterCB(data) {
	// add new rule row
	var ruleRow = addRow(addFilterRowId,data);
	
	// grab unique ID for this new rule
	var ruleId = ruleRow.id.replace('rule_row_','');

	var addCondBtn = document.getElementById('add_condition_button_'+ruleId);

	// if there are no conditions, add one
	if (lastRuleRn < 1) addCondition('order_complete',addCondBtn,'last_condition_row_'+ruleId)

	// put the button back, and hide the button row so it can't be used again
	addRuleFilterBtnTD.innerHTML = addRuleFilterBtnTD.oldInnerHTML;
	
	var addFilterRow = document.getElementById(addFilterRowId);
	addFilterRow.style.display = 'none';
}













/*******************************************************************************
	Function is a callback for AJAX, and replaces the inside content of a rule
	fieldset with that of the type chosen by the "Type" field
*******************************************************************************/
function changeRuleType(data) {

	// grab reference to the content div
	var contentDiv = document.getElementById('content');

	// store the scrollHeight before the row is added
	contentDiv.oldScrollHeight = contentDiv.scrollHeight;
	
	changeRuleDiv.innerHTML = data;
	
	// scroll up as needed, so the new data doesn't affect the scroll position
	var newScrollTop = contentDiv.scrollTop + contentDiv.scrollHeight - contentDiv.oldScrollHeight;
	if (newScrollTop > 0) contentDiv.scrollTop = newScrollTop;
	
	/*******************************************
		add one condition to the rule
	*******************************************/
	// grab ID for the rule type field
	var ruleTypeId 	= changeRuleDiv.id.replace('rule_type_div_','rule_type_');
	
	// ID of row to add condition above
	var condRowId	= changeRuleDiv.id.replace('rule_type_div_','last_condition_row_');
	
	// reference to the "Add Condition" button
	var condButton	= document.getElementById(changeRuleDiv.id.replace('rule_type_div_','add_condition_button_'));
	
	// grab ref. to the rule type field
	var ruleTypeSel	= document.getElementById(ruleTypeId);
	
	// add a single condition to the new rule
	addCondition(ruleTypeSel.value,condButton,condRowId)
	
}




/******************************************************************************
	Purpose of function is to ensure that all named rules on a given
	record are unique. This function is called when the Name field for any
	rule loses focus (onblur)
	
	lastNameFld, if set, should be a reference to the field that just lost focus
******************************************************************************/
function checkRuleNames(lastNameFld,evt) {
	// need to grab the master rule fieldset, by looping up thru parents
	// until we find it
	var ruleFS = document.getElementById('add_rule_button_'+fsetRn).parentNode;
	while(ruleFS.nodeName != 'FIELDSET') {
		if (ruleFS.parentNode) {
			ruleFS = ruleFS.parentNode;
		} else {
			// ran out of parents, bail
			return;	
		}
	}

	var nameFlds = getElementsByPartialId(ruleFS,'input','rule_name_'+fsetRn);

	// if name fields where found
	if (nameFlds) {
		// if there is more than one name field
		if (nameFlds.length > 1) {
			for(x=0;nameFlds[x];x++){
				// if the field we are on is the one we are checking, skip to next one
				if (nameFlds[x] == lastNameFld) continue;

				// check for matching value... if found, bail with error
				if (nameFlds[x].value == lastNameFld.value) {
					// this is here for Firefox...needs this to return focus for some reason
					alert('Rule names must be unique. There already is a rule with the name "' + nameFlds[x].value + '" on this record. Please choose a unique name for this rule.');
					setFocus(lastNameFld);
					return false;
				}
			}
		}
	}

	// set the formula to combine rules
	setRuleFormula();
	
	return true;
}






/*********************************************************************************************
	Function is called when the Add Condition button is clicked
	This handles turning the Add Condition button into a loading indicator,
	and calls the code to add a condition
	
	Parameters:
	ruleType	(string)	type of rule to add
	button		(ref)		optional - reference to the button that was clicked
	condRowId	(string)	optional - ID of row to add the condition before.
							If not set, it will be determined based on the button
*********************************************************************************************/
var condBtnParent; 			// to store global reference ot the container of the Add Condition button
var pendingCondRow = '';	// to store the ID of the "last_condition_row" to add the condition to...used by the addConditionCB function

function addCondition(ruleType,button,condRowId){
	// bail if no rule type sent
	if (!ruleType) return alert('Error: No rule type passed to addCondition() function.');
	
	// grab the unique portion of the id for this rule
	var ruleId = button.id.replace('add_condition_button_','');
	
	// handle changing the Add Condition button to a Loading message, if a button reference was passed
	if (button) {
		condBtnParent = button.parentNode;
	
		// store the current HTML so we can grab it later
		condBtnParent.oldInnerHTML = condBtnParent.innerHTML;
		
		// add a wait indicator
		condBtnParent.innerHTML = '<div class="valign_middle" style="padding: 3px"><img src="images/cart/indicator.gif" /><span> Adding Condition</span></div>';
	}
		
	// set pendingCondRow to the id of the row that the condition will be added above, so the callback function knows where to put the new row
	pendingCondRow = condRowId;
	
	// call exported PHP function via AJAX to grab a blank condition
	x_get_condition(ruleType,ruleId,fsetRn,0,addConditionCB);
}




/*******************************************************************************
	Function is a callback for AJAX, to add a new condition to a rule
*******************************************************************************/
function addConditionCB(data) {
	var i;

	if (!pendingCondRow) return alert('Error: function addConditionCB() cannot determine where to place new condition row.')

	// add row above last one
	addRow(pendingCondRow,data);

	// pull out the rule ID from the pendingCondRow var
	var ruleId = pendingCondRow.replace('last_condition_row_','');

	condNameInputs = getConditionNames(ruleId);
	
	/***********************************************
		Handle changing the default condition name
	***********************************************/
	if (!condNameInputs) {
		newName = 'Condition 1';
	} else {
		var nameEnd = condNameInputs.length;

		// this loop will keep looping as long as the proposed new name is taken,
		// and will increment nameEnd each time until we have a new unique name
		while(inFieldValues('Condition ' + nameEnd, condNameInputs)) {
			nameEnd++;
		}
		
		newName = 'Condition ' + nameEnd;
	}
	
	// set condition name field
	condNameInputs[condNameInputs.length-1].value = newName;

	// set the same name as the condition's legend
	var conditionId 			= condNameInputs[condNameInputs.length-1].id.replace('condition_name_','');
	var conditionLegend 		= document.getElementById('condition_legend_'+conditionId);
	conditionLegend.innerHTML 	= newName;
	
	// change condition formula to account for new condition
	setConditionFormula(ruleId);
	
	// put the add condition button back to normal
	if (condBtnParent) condBtnParent.innerHTML = condBtnParent.oldInnerHTML;

	// to prevent form from submitting, for oddball browsers
	return false;
}







/*********************************************************************************
	Purpose of function is to return an array containing references to condition
	name fields, for the rule specified.
	
	Parameters:
		ruleId	(string)	this should be the unique portion of the rule id
*********************************************************************************/
function getConditionNames(ruleId) {
	if (!ruleId) return;
	
	// grab all condition_name fields nested inside this rule
	var condNameInputs = getElementsByPartialId('rule_row_'+ruleId,'input','condition_name_');

	// because the above code will also grab conditions from filter rules if present, we need to exclude those
	var condNameInputsFixed = new Array();
	for(x=0;condNameInputs[x];x++) {
		if (condNameInputs[x].name.indexOf(ruleId) != -1) condNameInputsFixed[condNameInputsFixed.length] = condNameInputs[x];
	}
	return condNameInputsFixed;
}







/*******************************************************************************
	This function is used to change the options for the operator field,
	based on a custom "operators" property on the option tag of the "Apply When"
	field. Operators are listed in the operators property as numbers,
	with commas separating them, like:
	<option operators="1,7,8">Field:Bill_First_Name</option>
	
	When the Apply When field is changed, this function is called, and the 
	option chosen is passed as "choice".
	
	Parameters:
		choice					(reference)		ref. to <option /> element that is selected
		dontChangeCondValues	(bool)			set to true to prevent the call to changeConditionValues()		
*******************************************************************************/
function changeConditionOperators(choice,dontChangeCondValues) {
	// set some vars
	var i;																// index for looping
	var opsHTML 		= '';											// string to contain all option tags that correspond to choice that was passed
	var ops 			= new Array();									// to contain all available option values
	var allowedOps 		= choice.getAttribute('operators').split(",");	// grab operators property, and convert into an array
	var applyWhenSelect	= choice.parentNode;							// select tag for the option passed as "choice"
	
	// this sets a var to determine whether the field is for a date type rule or not
	var isDateType = false;
	for(i in allowedOps) {
		if (allowedOps[i] == 15) {
			isDateType = true;
			break;
		}
	}

	// bail if choice isn't sent
	if (!choice) return alert('Missing parameter "choice" in call to changeOperators() function.');
	
	// grab the ID property of the operators field and the "is/is not" field, by grabbing the time at the end of the id of the "apply when" select tag
	var opId = applyWhenSelect.id.replace('condition_apply_when','condition_operators');
	var isId = applyWhenSelect.id.replace('condition_apply_when','condition_is');

	// grab reference to the operators select tag
	var opSelect = document.getElementById(opId);
	var isSelect = document.getElementById(isId);

	// wipe out current options
	opSelect.options.length = 0;

	// create an array containing all operator choices
	ops[1] 	= 'equal to';
	ops[2] 	= 'between';
	ops[3] 	= 'less than';
	ops[4] 	= isDateType ? 'on or before' 	: 'less than or equal to';
	ops[5] 	= 'greater than';
	ops[6] 	= isDateType ? 'on or after' 	: 'greater than or equal to';
	ops[7] 	= 'contains';
	ops[8] 	= 'starts with';
	ops[9] 	= 'ends with';
	ops[10]	= 'one of the following';
	ops[11]	= 'all of the following';
	ops[12]	= 'timespan';
	ops[13] = 'in year';
	ops[14] = 'in month';
	ops[15] = 'on day';
	ops[16]	= 'a match to regular expression';
	
	// loop thru allowed options
	for(i in allowedOps){
		// add the option to select field
		opSelect.options[opSelect.options.length] = new Option(ops[allowedOps[i]], allowedOps[i], false, false);
	}
	
	// make fields visible
	opSelect.style.display = 'inline';
	isSelect.style.display = 'inline';
	
	// call the changeConditionValues function so it adds the correct fields for the first operator in the list
	if (!dontChangeCondValues) {
		changeConditionValues(opSelect.options[0],applyWhenSelect.id.replace('condition_apply_when_',''),'','','',1);
	}
}






/************************************************************************************************************
	
	This function is called when an operator field is changed, and controls the content of the content_values
	div, which contains the fields used to specify condition values.
	
	If the Apply When field for this condition has a condition_values property set to "normal", then
	this function takes care of generating the HTML for the condition values. If it is set to "special",
	a call is made via AJAX to get the content, via the get_condition_values() PHP function.
	
	Parameters:
		op		- a reference to the option field that was chosen
		id_time	- string containing the trailing portion of the id used for all fields on this condition
		val1	- value to plug into the Value 1 field (optional)
		val2	- value to plug into the Value 2 field (optional)
		data	- value to plug into the Data field (optional)
		forceValueChange - set to 1 to force the value field(s) to change

************************************************************************************************************/
var conditionValuesDiv; // global var to hold the current condition values div that is being worked on

function changeConditionValues(op,condition_id,val1,val2,data,forceValuesChange) {
	conditionValuesDiv 		= document.getElementById('condition_values_' + condition_id);			// reference to the div that will receive the condition value fields
	var valueFlds			= '';																// to store HTML for condition value fields
	var applyWhenRef		= document.getElementById('condition_apply_when_' + condition_id);	// reference to the apply when field for this condition
	var val1Id				= 'condition_value_1_'+condition_id;								// id for the value 1 field
	var val2Id				= 'condition_value_2_'+condition_id;								// id for the value 2 field
	var dataId				= 'condition_data_'+condition_id;									// id for the data field
	var conditionRn			= document.getElementById('condition_record_number_'+condition_id).value;
	var operatorFld			= op.parentNode;
	
	// default val1, val2, and 'data' to nothing if not passed into this function
	if (val1 == undefined) var val1 = '';
	if (val2 == undefined) var val2 = '';
	if (data == undefined) var data = '';

	
	// if the value of the operator is changing from one string type operator (1 thru 9) to another, don't change value fields
	if (!forceValuesChange && (op.value > 0 && op.value < 10 && op.value != 2) && (operatorFld.oldValue > 0 && operatorFld.oldValue < 10 && operatorFld.oldValue != 2)) {
		// store choice so when this is called again we know what it was prior to it changing
		operatorFld.oldValue = op.value;
		return; 
	}
	
	// store choice so when this is called again we know what it was prior to it changing
	operatorFld.oldValue = op.value;
	
	
	/********************************************************************
		Purpose of section below is to loop up thru parents
		of conditionValuesDiv until we find the rule_type_div_,
		so we can pull the rule id number from it, and set it as ruleId
	********************************************************************/
	var currentNode = conditionValuesDiv;
	var ruleId;
	while (currentNode.parentNode) {
		currentNode = currentNode.parentNode;
		if (currentNode.id) {
			if (currentNode.id.indexOf('rule_type_div') != -1) {
				ruleId = currentNode.id.replace('rule_type_div_','');
				break;
			}
		}
	}
	
	// prefix to start all field names for this condition
	var fnamePrefix = 'rule_sets['+fsetRn+'][rules]['+ruleId+'][Conditions]['+condition_id+']';
	
	var val1Name = fnamePrefix+'[Value_1]';	// name for value 1 field
	var val2Name = fnamePrefix+'[Value_2]';	// name for value 2 field
	var dataName = fnamePrefix+'[Data]';	// name for Data field

	// grab the selected option for the "Apply When" field
	var applyWhenOpt	= applyWhenRef.options[applyWhenRef.selectedIndex];
	
	// handle normal fields that don't need special value fields
	if (applyWhenOpt.getAttribute('condition_values') == 'normal') {
		if (op.value == 1 || op.value == 3 || op.value == 4 || op.value == 5 || op.value == 6 || op.value == 7 || op.value == 8 || op.value == 9) {
			valueFlds = 'Value: <input type="text" name="'+val1Name+'" id="'+val1Id+'" value="'+val1+'" />';
		} else if(op.value == 2) {
			// 2 is for the "between" operator
			valueFlds = 'Value 1: <input type="text" name="'+val1Name+'" id="'+val1Id+'" value="'+val1+'" /> and Value 2: <input type="text" name="'+val2Name+'" id="'+val2Id+'" value="'+val2+'" />';
		} else if (op.value == 10) {
			valueFlds = 'Values (enter each on a new line): <textarea style="vertical-align: top; width: 200px; height: 100px" name="'+val1Name+'" id="'+val1Id+'">'+val1+'</textarea>';
		} else if (op.value == 16) {
			// 16 is for the "a match to regular expression" operator
			valueFlds = 'Regular Expression: <input type="text" name="'+val1Name+'" id="'+val1Id+'" value="'+val1+'" style="width: 450px" />';
		}
		// add HTML for condition value fields to div
		changeConditionValuesCB(valueFlds);
		
	} else if (applyWhenOpt.getAttribute('condition_values') == 'date') {
		/***********************************
			Handle date value fields
		***********************************/
		// if operator is "between"
		if (op.value == 2) {
			valueFlds = '<span style="vertical-align: middle; margin-right: 2px;">Date 1: <input type="text" name="'+val1Name+'" id="'+val1Id+'" value="'+val1+'" /></span>'+
			'<img date_trigger="1" class="record_button" date_field="'+val1Id+'" show_time="1" id="date_trigger_'+val1Id+'" src="images/cart/calendar.gif" onmouseout="swapClass(event);this.src=\'images/cart/calendar.gif\'" onmouseover="swapClass(event); this.src=\'images/cart/calendar_mo.gif\'" onmousedown="this.style.top = \'1px\'; this.style.left = \'1px\'" onmouseup="this.style.top = \'0px\'; this.style.left = \'0px\'" style="position: relative; vertical-align: middle;" title="Date selector">'+
			'<span style="vertical-align: middle; margin-right: 2px">&nbsp;&nbsp;and Date 2: <input type="text" name="'+val2Name+'" id="'+val2Id+'" value="'+val2+'" /></span>'+
			'<img date_trigger="1" class="record_button" date_field="'+val2Id+'" show_time="1" id="date_trigger_'+val2Id+'" src="images/cart/calendar.gif" onmouseout="swapClass(event);this.src=\'images/cart/calendar.gif\'" onmouseover="swapClass(event); this.src=\'images/cart/calendar_mo.gif\'" onmousedown="this.style.top = \'1px\'; this.style.left = \'1px\'" onmouseup="this.style.top = \'0px\'; this.style.left = \'0px\'" style="position: relative; vertical-align: middle;" title="Date selector">';

			// add HTML for condition value fields to div
			changeConditionValuesCB(valueFlds);

			Calendar.setup({
				inputField     :    val1Id,     // id of the input field
				showsTime : true,
				ifFormat : "%b %e, %Y %l:%M %P",
				button         :    'date_trigger_'+val1Id,  // trigger for the calendar (button ID)
				align          :    "bR",           // alignment (defaults to Br)
				singleClick    :    true,
				weekNumbers    :    false,
				step           :    1,
				timeFormat : 12
			});

			Calendar.setup({
				inputField     :    val2Id,     // id of the input field
				showsTime : true,
				ifFormat : "%b %e, %Y %l:%M %P",
				button         :    'date_trigger_'+val2Id,  // trigger for the calendar (button ID)
				align          :    "bR",           // alignment (defaults to Br)
				singleClick    :    true,
				weekNumbers    :    false,
				step           :    1,
				timeFormat : 12
			});
			
			return;
		} else if (op.value == 12) {
			// if operator is "timespan"
			// set vars to be used to select the appropriate time unit
			var yearsSelected 	= val2 == 'years' 			? 'selected' : '';
			var daysSelected 	= val2 == 'days' || !val2 	? 'selected' : '';
			var hoursSelected 	= val2 == 'hours' 			? 'selected' : '';
			var minutesSelected = val2 == 'minutes' 		? 'selected' : '';
			var secondsSelected = val2 == 'seconds' 		? 'selected' : '';
			
			valueFlds = 'Timespan: <input type="text" name="'+val1Name+'" value="'+val1+'" id="'+val1Id+'" style="width: 40px" />&nbsp;'+
			'<select name="'+val2Name+'" value="'+val2+'" id="'+val2Id+'">'+
			'	<option '+yearsSelected+'	>years</option>'+
			'	<option '+daysSelected+'	>days</option>'+
			'	<option '+hoursSelected+'	>hours</option>'+
			'	<option '+minutesSelected+'	>minutes</option>'+
			'	<option '+secondsSelected+'	>seconds</option>'+
			'</select> from date field specified in "Apply When"';
		} else if (op.value == 13) {
			// if operator is "in year"
			var now = new Date();
			valueFlds = 'Year: <input type="text" name="'+val1Name+'" id="'+val1Id+'" value="'+val1+'" style="width: 35px" /> (format: '+now.getFullYear()+')'
		} else if (op.value == 14) {
			// if operator is "in month"
			var months = new Array('January','February','March','April','May','June','July','August','September','October','November','December');
			var monthSelected;
			valueFlds = 'Month: <select name="'+val1Name+'" id="'+val1Id+'" >';
			for(i=0;months[i];i++) {
				monthSelected = val1 == months[i] ? 'selected' : '';
				valueFlds += '<option '+monthSelected+'>'+months[i]+'</option>';
			}
		} else if (op.value == 15) {
			// if operator is "on day"
			var days = new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday');
			var daySelected;
			valueFlds = 'Day: <select name="'+val1Name+'" id="'+val1Id+'" >';
			for(i=0;days[i];i++) {
				daySelected = val1 == days[i] ? 'selected' : '';
				valueFlds += '<option '+daySelected+'>'+days[i]+'</option>';
			}
		} else {
			valueFlds = '<span style="vertical-align: middle; margin-right: 2px;">Date: <input type="text" name="'+val1Name+'" id="'+val1Id+'" value="'+val1+'"/></span>'+
			'<img date_trigger="1" class="record_button" date_field="'+val1Id+'" show_time="1" id="date_trigger_'+val1Id+'" src="images/cart/calendar.gif" onmouseout="swapClass(event);this.src=\'images/cart/calendar.gif\'" onmouseover="swapClass(event); this.src=\'images/cart/calendar_mo.gif\'" onmousedown="this.style.top = \'1px\'; this.style.left = \'1px\'" onmouseup="this.style.top = \'0px\'; this.style.left = \'0px\'" style="position: relative; vertical-align: middle;" title="Date selector">';

			// add HTML for condition value fields to div
			changeConditionValuesCB(valueFlds);

			Calendar.setup({
				inputField     :    val1Id,     // id of the input field
				showsTime : true,
				ifFormat : "%b %e, %Y %l:%M %P",
				button         :    'date_trigger_'+val1Id,  // trigger for the calendar (button ID)
				align          :    "bR",           // alignment (defaults to Br)
				singleClick    :    true,
				weekNumbers    :    false,
				step           :    1,
				timeFormat : 12
			});
			
			return;
		}

		// add HTML for condition value fields to div
		changeConditionValuesCB(valueFlds);
		
	} else if (applyWhenOpt.getAttribute('condition_values') == 'special'){
		// grab a ref. to the row for this condition
		var condRow = document.getElementById('condition_row_' + condition_id);
		
		// grab the rule type, which is stored in a "rule_type" property on the <tr> we just grabbed above
		var ruleType = condRow.getAttribute('rule_type');
		
		// replace the conditionValuesDiv with a loading msg
		conditionValuesDiv.innerHTML = '<div class="valign_middle"><img src="images/cart/indicator.gif" /><span> Loading Fields</span></div>';

		// call exported PHP function via AJAX :)
		x_get_condition_values(ruleType,'condition_values_' + condition_id,applyWhenRef.value,op.value,val1Name,val2Name,val1Id,val2Id,val1,val2,dataName,dataId,data,conditionRn,changeConditionValuesCB);
	}
}

/********************************************************************************************************
	Function is an AJAX callback for the get_condition_values PHP function
	It is also called by changeConditionValues() when an AJAX call to get_condition_values is not needed
	
	Purpose of function is to replace the innerHTML of the condition values div (after the operator)
********************************************************************************************************/
function changeConditionValuesCB(html) {
	// grab reference to the content div
	var contentDiv = document.getElementById('content');

	// store the scrollHeight before the row is added
	contentDiv.oldScrollHeight = contentDiv.scrollHeight;
	
	// If this is being called via AJAX, the ID of the target div to receive the fields is the first part of the data,
	// then a separator "^^^", then the actual fields to put inside that div. If not being called by AJAX, then we
	// already know the target div, as it's reference is stored in conditionValuesDiv.
	if (html.indexOf('^^^') != -1) {
		// split the data on the ^^^ separator
		var dataArray = html.split('^^^');
		
		// grab ref. to target div
		conditionValuesDiv = document.getElementById(dataArray[0]);
		
		// set field data as html
		html = dataArray[1];
	}
	
	// add fields
	conditionValuesDiv.innerHTML = html;
	
	// scroll up as needed, so the new row doesn't affect the scroll position
	var newScrollTop = contentDiv.scrollTop + contentDiv.scrollHeight - contentDiv.oldScrollHeight;
	if (newScrollTop > 0) contentDiv.scrollTop = newScrollTop;
	
}








/*********************************************************************************************************
	Function changes the Condition Formula section of a rule. If only one condition is present,
	the section is hidden. If 2 are present, a "Condition 1 AND/OR Condition 2" choice is shown. If 3 or
	more conditions are present, a formula field appears.
	
	Parameters:
		rule_id	(string)	unique portion of id for all rule fields
		formula	(string)	optional - pass to set the formula value
*********************************************************************************************************/
function setConditionFormula(rule_id,formula) {
	var condNameInputs 		= getConditionNames(rule_id);												// Grab all inputs that have a name containing "condition_name_"
	var condFormulaDiv		= document.getElementById('rule_cond_formula_div_'+rule_id);				// Outer div for the condition formula
	var condFormulaInnerDiv	= document.getElementById('rule_cond_formula_inner_div_'+rule_id);			// Inner div for the condition formula
	var condFormulaHTML 	= '';																		// used for the fields that will be inserted
	var xtraDescription		= document.getElementById('rule_cond_formula_xtra_desc_'+rule_id);			// Description <div> for when there are 3 or more conditions
	var fldName 			= 'rule_sets['+fsetRn+'][rules]['+rule_id+'][Condition_Formula]';						// field name (duh)
	var i;																								// increment for loops


	if (condNameInputs.length <= 1) {
		// no formula needed...hide the cond. formula div
		condFormulaDiv.style.display = 'none';
	} else {
		// cond. formula is needed, show outer div
		condFormulaDiv.style.display = 'block';
		
		// if only 2 conditions, we need a select option
		if (condNameInputs.length == 2) {
			// code below sets selected formula option
			var andValue 	= condNameInputs[0].value+' AND '+condNameInputs[1].value;
			var orValue		= condNameInputs[0].value+' OR '+condNameInputs[1].value;
			var andSelected = '', orSelected = '';
			if (formula) {
				if (formula == andValue) 	andSelected = 'selected';
				if (formula == orValue) 	orSelected  = 'selected';
			}
			
			condFormulaHTML = 'Formula: <select name="'+fldName+'"><option '+andSelected+'>'+andValue+'</option><option '+orSelected+'>'+orValue+'</option></select>';

			// turn off the extra description
			xtraDescription.style.display = 'none';

		} else {
			// 3 or more conditions requires a textarea field for the formula
			// if formula value is passed to this function, use it
			if (formula) {
				condFormulaHTML = formula;
			} else {
				// loop thru each condition name
				for(i=0;condNameInputs[i];i++) {
					// add condition name
					condFormulaHTML += condNameInputs[i].value;
					
					// add AND only if we aren't on the last condition
					if (i+1 != condNameInputs.length) {
						condFormulaHTML += ' AND ';
					}
				}
			}
			
			condFormulaHTML = '<span style="vertical-align: top; position: relative; top: 3px">Formula: </span><textarea name="'+fldName+'" style="width: 500px; height: 50px">'+condFormulaHTML+'</textarea>';
			
			// turn on the extra description
			xtraDescription.style.display = 'block';
			
		}
		
		// insert fields into forumla div
		condFormulaInnerDiv.innerHTML = condFormulaHTML;
	}
}






/*********************************************************************************************************
	Function changes the Rule Formula. If only one rule is present,
	the section is hidden. If 2 are present, a "Rule 1 AND/OR Rule 2" choice is shown. If 3 or
	more rules are present, a formula field appears.
	
	Parameters:
			formula		(str)	This should equal the value of the formula field. This is only used for
								page load, for saved records that have rules.
*********************************************************************************************************/
function setRuleFormula(formula) {
	var ruleNameInputs 		= getElementsByPartialId(document,'input','rule_name_'+fsetRn);		// Grab all inputs that have a name containing "rule_name_"
	var ruleFormulaDiv		= document.getElementById('rule_formula_div_'+fsetRn);			// Outer div for the rule formula
	var ruleFormulaInnerDiv	= document.getElementById('rule_formula_inner_div_'+fsetRn);	// Inner div for the rule formula
	var ruleSetDetailsDiv	= document.getElementById('rule_set_details_div_'+fsetRn);		// Div containing the rule set name and other info
	var ruleFormulaHTML 	= '';															// used for the fields that will be inserted
	var xtraDescription		= document.getElementById('rule_formula_xtra_desc_'+fsetRn);	// Description <div> for when there are 3 or more rules
	var ruleFormulaFieldName= 'rule_sets['+fsetRn+'][Rule_Formula]';						// field name for the rule formula field
	var i;																					// increment for loops

	if (ruleNameInputs.length < 1) {
		// hide the rule set details div
		ruleSetDetailsDiv.style.display = 'none';
	} else if(ruleNameInputs.length == 1) {
		// show the rule set details div
		ruleSetDetailsDiv.style.display = 'block';

		// no formula needed...hide the rule. formula div
		ruleFormulaDiv.style.display = 'none';
	} else {
		// rule. formula is needed, show outer div
		ruleFormulaDiv.style.display = 'block';
		
		// show the rule set details div
		ruleSetDetailsDiv.style.display = 'block';

		// if only 2 rules, we need a select option
		if (ruleNameInputs.length == 2) {
			var andValue	= ruleNameInputs[0].value+' AND '+ruleNameInputs[1].value;
			var orValue		= ruleNameInputs[0].value+' OR '+ruleNameInputs[1].value;
			var andSelected,orSelected;
			if (formula) {
				if (formula == andValue) andSelected = 'selected';
				if (formula == orValue) orSelected = 'selected';
			}
			ruleFormulaHTML = 'Formula: <select name="'+ruleFormulaFieldName+'"><option '+andSelected+'>'+andValue+'</option><option '+orSelected+'>'+orValue+'</option></select>';

			// turn off the extra description
			xtraDescription.style.display = 'none';

		} else {
			// 3 or more rules requires a textarea field for the formula
			// if formula was passed to this function, use it
			if (formula) {
				ruleFormulaHTML = formula
			} else {
				// loop thru each rule name
				for(i=0;ruleNameInputs[i];i++) {
					// add rule name
					ruleFormulaHTML += ruleNameInputs[i].value;
					
					// add AND only if we aren't on the last rule
					if (i+1 != ruleNameInputs.length) {
						ruleFormulaHTML += ' AND ';
					}
				}
			}
			ruleFormulaHTML = '<span style="vertical-align: top; position: relative; top: 3px">Formula: </span><textarea name="'+ruleFormulaFieldName+'" style="width: 500px; height: 50px">'+ruleFormulaHTML+'</textarea>';
			
			// turn on the extra description
			xtraDescription.style.display = 'block';
			
		}
		
		// insert fields into forumla div
		ruleFormulaInnerDiv.innerHTML = ruleFormulaHTML;
	}
}




/***********************************************************************************************
	Purpose: to add a rule set to the current record, along with all it's rules and conditions
	
	Parameters:
		ruleSetRn	(int)	record number of rule_set
***********************************************************************************************/
function addRuleSet(ruleSetRn) {
	var ruleNameInputs 	= getElementsByPartialId(document,'input','rule_name_'+fsetRn);		// Grab all inputs that have a name containing "rule_name_"
	var lastRow			= document.getElementById('last_rule_row_'+fsetRn);
	var ruleSetTbody	= lastRow.parentNode;
	
	// get confirmation IF there are any rules specified
	var confirmed = ruleNameInputs.length >= 1 ? confirm('All rules in this section will be replaced. Are you sure you want to continue?') : true;
	
	if (!confirmed) return;

	/*************************************
		Wipe out all existing rules
	*************************************/
	var rules = getElementsByPartialId(ruleSetTbody,'tr','rule_row_');
	var currentRule;
	for(i=0;rules[i];i++) {
		currentRule = rules[i];
		// remove the rule row IF it's ID isn't "last_rule_row_..."
		if (currentRule.id.indexOf('last_rule_row') == -1) currentRule.parentNode.removeChild(currentRule);
	}
	
	/****************************************************************
		Setup button so it changes to a "Adding Rule..." message
	****************************************************************/
	// grab the add rule button
	addButtonDiv = document.getElementById('add_rule_button_'+fsetRn);	// reference to the "add rule" button
	
	// we really only want the inner div
	addButtonDiv = getFirstChildElement(addButtonDiv);
	
	// store current HTML for add rule button
	addButtonDiv.oldInnerHTML = addButtonDiv.innerHTML;
	
	// add a wait indicator
	addButtonDiv.innerHTML = '<div class=valign_middle style="white-space: nowrap; padding:4px"><img src=images/cart/indicator.gif /><span> Adding Rule Set</span></div>';
	
	x_get_rule_set(ruleSetRn,fsetRn,addRuleSetCB);
}

/*********************************************************************************************
	Purpose: call back function for AJAX call to add rule set
*********************************************************************************************/
function addRuleSetCB(data) {
	// the data sent back is split with a "^^" separator
	// [0] is the record_number of the rule set
	// [1] is the Name
	// [2] is the Description
	// [3] is the Rule_Formula
	// [4] contains the HTML for the rules
	//
	// line below splits the data into an array
	var dataArray = data.split('^^^');

	// add the rules
	addedRuleSet = addRow('last_rule_row_'+fsetRn,dataArray[4]);
	
	// set the rule set name
	document.getElementById('rule_set_name_'+fsetRn).value = dataArray[1];
	
	// set the rule set description
	document.getElementById('rule_set_description_'+fsetRn).value = dataArray[2];
	
	// set the rule set record number
	document.getElementById('rule_set_rn_'+fsetRn).value = dataArray[0];
	
	// set the rule formula
	setRuleFormula(dataArray[3]);
	
	// turn the add rule button back on
	addButtonDiv.innerHTML = addButtonDiv.oldInnerHTML;
	
}






/************************************************************************************************
	
	Purpose: to remove a rule (by removing it's <tr>) from the DOM
	
	Parameters:
		rule_row	id of OR reference to the <tr> containing the rule
	
************************************************************************************************/
function removeRule(ruleRow) {
	// if rule row is an id string, grab reference
	if (typeof(ruleRow) == 'string') ruleRow = document.getElementById(ruleRow);
	
	// grab the parent for this row (tbody)
	var ruleTbody = ruleRow.parentNode;
	
	// grab next row after one being removed
	var nextRow = getNextElement(ruleRow);
	// if next row is a button to add a filter, make it visible
	if (nextRow.id.indexOf('add_filter_button_row_') != -1) nextRow.style.display = '';
	
	removeElement(ruleRow);
	
	setRuleFormula(fsetRn);
	
	// grab all rule rows left for this rule set
	var ruleRows = getElementsByPartialId(ruleTbody,'input','rule_name_');
	
	// if there are no more rules left, we need to wipe out the values for the fields that define the rule set,
	// so it is treated as a brand new rule set
	if (ruleRows.length == 0) {
		document.getElementById('rule_set_rn_'+fsetRn).value 			= '';
		document.getElementById('rule_set_name_'+fsetRn).value 			= '';
		document.getElementById('rule_set_description_'+fsetRn).value 	= '';
	}
}







/******************************************************************************************************

	Purpose: 
		Generate random coupon codes. This function is called when the "generate" button
		next to the coupon code field is clicked. User is then prompted via JS for information on how to
		generate codes. Info is passed to a PHP function via AJAX, and call back function is used to
		store codes in the coupon code field.
	
	Parameters:
		id			(string) 	id of coupon code field to populate
		btn			(reference)	reference to the "generate" button so we can swap it to a "loading" msg
		defPrefix	(string)	default prefix for codes (optional)

******************************************************************************************************/
var couponCodeFieldId,couponCodeGenerateBtn;

function generateCouponCodes(id,btn,defPrefix) {
	couponCodeFieldId 		= id;																			// store id of coupon code field in global var so callback function can access it
	couponCodeGenerateBtn	= btn;																			// store btn reference in global var so callback function can assess it
	var couponCodeField		= document.getElementById(couponCodeFieldId);
	var condId				= couponCodeFieldId.replace('condition_coupon_codes_','');						// grab unique ID for condition
	var condRn				= parseInt(document.getElementById('condition_record_number_'+condId).value)	// grab record number for condition
	var regEx	 			= /\d{1,4}/;
	var codeCount			= '';
	var match 				= false;
	var howManyMsg 			= 'How many coupon codes would you like to generate?';
	var overwriteMsg		= 'If you continue, you will overwrite the coupon codes you have already assigned. Continue?';
	
	// warn on overwrite, give them a chance to cancel
	if (couponCodeField.value) {
		if (!confirm(overwriteMsg)) return;
	}
	
	while (!match) {
		codeCount = prompt(howManyMsg,1);
		
		// if canceled, bail out
		if (codeCount == null) return;
		
		match = codeCount.match(regEx);
		if (!match) howManyMsg = 'You must enter a number!';
	}
	
	// if they entered more than 500,000, generate alert and bail out.
	if (codeCount > 500000) {
		alert('There is a 500,000 limit as to the number of codes you can generate for a single condition.');
		return;
	} else if (codeCount >= 50000) {
		var approxMB = Math.ceil(codeCount * .000110);
		if (!confirm('You are about to generate a large number of coupon codes, which may take a long time (1 minute or more), and will require approximately '+approxMB+' MB of space in your database. Do you wish to continue?')) {
			return;
		}
	}
	
	if (defPrefix == undefined) var defPrefix = '';
	var prefix = prompt('To prefix each code with your own text, enter it here. To skip a prefix, leave this blank and click OK',defPrefix);
	if (prefix == null) return;
	if (!prefix) prefix = '';

	// swap out the button with a wait indicator
	couponCodeGenerateBtn.oldInnerHTML 	= couponCodeGenerateBtn.innerHTML;
	couponCodeGenerateBtn.innerHTML 	= '<img src="images/cart/indicator.gif" />';

	// this var grabs the condRn IF it is greater than 0, else it grabs the id
	var condRnId = condRn > 1 ? condRn : condId;
	
	// call PHP function to generate coupon codes
	x_generate_coupon_codes(codeCount,prefix,condRnId,generateCouponCodesCB);
}




// AJAX callback for the function above. Used to store data returned from PHP in the coupon code field
function generateCouponCodesCB(data) {
	var codeField		= document.getElementById(couponCodeFieldId);
	//var viewBtn			= document.getElementById('VIEW_BUTTON_'+couponCodeFieldId);
	var viewField		= document.getElementById('VIEW_'+couponCodeFieldId);

	// hide the "Loading Codes" indicator IF it is present
	if (codesLoadingDiv) codesLoadingDiv.style.display = 'none';
	
	// hide the textarea field
	codeField.style.display='none';

	// store data in field
	codeField.value = data;

	// put the generate button back
	if (couponCodeGenerateBtn) couponCodeGenerateBtn.innerHTML = couponCodeGenerateBtn.oldInnerHTML;

	// if the data returned is set to "too_many_codes", it means that the codes where temporarily stored in the Coupon_Code table
	if (data == 'too_many_codes') {
		// display the view button, and the field showing the explanation as to why codes are hidden
		//viewBtn.style.display='block';
		viewField.style.display='block';
		
		alert('Coupon Code generation is complete.\n\nDue to the large number of coupon codes generated, they will not be displayed on this form in order to save bandwidth. If you would like to view them, click the "show codes" link.');
	} else {
		// show the textarea field
		codeField.style.display='block';

		// hide the view button, and the field showing the explanation as to why codes are hidden
		//viewBtn.style.display='none';
		viewField.style.display='none';
	}
}





/************************************************************************************************************************
	
	Purpose: to show coupon codes that are not initially loaded because there are over 1000 of them.
	
	Parameters:
		condId	(string)	this needs to be either the record number of the Condition, OR the unique id of the
							condition generated from microtime()

************************************************************************************************************************/
var codesLoadingDiv;
function showCouponCodes(viewLinkId) {
	// grab the condition ID
	var condId 			= viewLinkId.replace('VIEW_condition_coupon_codes_','');
	var loadId 			= viewLinkId.replace('VIEW_','LOADING_');
	codesLoadingDiv		= document.getElementById(loadId);
	couponCodeFieldId	= 'condition_coupon_codes_'+condId;
	//var viewCodesDiv	= document.getElementById(viewLinkId)
	
	// turn on the loading indicator
	codesLoadingDiv.style.display = 'block';
	
	// grab the condition record number
	var condRn = parseInt(document.getElementById('condition_record_number_'+condId).value)
	
	// set var to pass to get_coupon_codes...use the condition rn if available
	var condRnId = condRn > 0 ? condRn : condId;

	x_get_coupon_codes(condRnId,generateCouponCodesCB);
}