/*
 *+------------------------------------------------------------------------+
 *| Licensed Materials - Property of IBM
 *| BI and PM: prmt
 *| (C) Copyright IBM Corp. 2002, 2011
 *|
 *| US Government Users Restricted Rights - Use, duplication or
 *| disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
 *|
 *+------------------------------------------------------------------------+
*/
/*
	CRange.js
	This script is used to provide interactivity for the
	range versions of each of the prompt controls.
*/
//Constructor to create a CRange component
// oRadioFrom: 'from' range radio button
// oFrom: 'from' control javascript object
// oRadioFromAll: not implemented
// oRadioTo: 'to' range radio button
// oTo: 'to' control javascript object
// oRadioToAll: not implemented
// sDataType: the type of data to validate (e.g. number)
// bRequired: a flag to determine whether input is required
// sSubmitType: 'default' will submit as a standard form
//				'XML' will convert the submission to XML and submit
// iInitialState: controls whether to check radio buttons
//				RANGE_NO_VALUE will select lowest to highest
//				RANGE_START_VALUE will select from a particular value to highest
//				RANGE_END_VALUE will select from lowest to a particular value
//				RANGE_BOUND_VALUE will select a range
//				RANGE_EQUAL_VALUE will select a single value
function CRange(oSubmit, oRadioFrom, oFrom, oRadioFromAll, oRadioTo, oTo, oRadioToAll, sDataType, bRequired, sSubmitType, iInitialState, sCVId)
{
	this.setCVId(sCVId);
	this.m_oSubmit = oSubmit;
	this.m_oRadioTo = oRadioTo;
	this.m_oTo = oTo;
	this.m_oRadioToAll = oRadioToAll;
	this.m_oRadioFrom = oRadioFrom;
	this.m_oFrom = oFrom;
	this.m_oRadioFromAll = oRadioFromAll;
	//the range data type
	this.m_sDataType = sDataType;
	//is this control required?
	this.m_bRequired = bRequired;
	this.m_bValid = false;
	this.m_sSubmitType = sSubmitType;
	if (iInitialState)
	{
		this.m_iInitialSate = iInitialState;
	}
	else
	{
		this.m_iInitialSate = null;
	}
	//set the radio button states
	this.initControls();
}
CRange.prototype = new CPromptControl();
//the 'to' control has received focus
//handle this event
function CRange_toGotFocus()
{
	if (this.m_oRadioTo)
	{
		this.m_oRadioTo.checked = true;
		this.rangeNotify();
	}
}
//the 'from' control has received focus
//handle this event
function CRange_fromGotFocus()
{
	if (this.m_oRadioFrom)
	{
		this.m_oRadioFrom.checked = true;
		this.rangeNotify();
	}
}
//update the range control radio buttons
function CRange_initControls()
{
	if (this.m_iInitialSate)
	{
		// RANGE_BOUND_VALUE will select a range or single value
		if ((this.m_iInitialSate == RANGE_BOUND_VALUE) || (this.m_iInitialSate == RANGE_EQUAL_VALUE))
		{
			this.toGotFocus();
			this.fromGotFocus();
		}
		// RANGE_START_VALUE will select from a particular value to highest
		else if (this.m_iInitialSate == RANGE_START_VALUE)
		{
			this.fromGotFocus();
		}
		// RANGE_END_VALUE will select from lowest to a particular value
		else if (this.m_iInitialSate == RANGE_END_VALUE)
		{
			this.toGotFocus();
		}
	}
	else
	{
		if (this.toGetValue() != K_PRMT_sEMPTY)
		{
			this.toGotFocus();
		}
		if (this.fromGetValue() != K_PRMT_sEMPTY)
		{
			this.fromGotFocus();
		}
	}
}
function CRange_toGetValue()
{
	var sValue = K_PRMT_sEMPTY;
	if (this.isRangeReversed()) {
		sValue = new String(this.m_oFrom.sGetValue());
	}
	else {
		sValue = this.m_oTo.sGetValue();
	}
	if ( this.getDataType() == 'date' && typeof this.m_oTo == K_PRMT_sOBJECT && this.m_oTo.m_iDateTimeType === 0 )
	{
		// We are using a date control for a datetime value.
		// Make sure the value ends with T23:59:59.999
		sValue = sValue.replace( /T\d\d:\d\d:\d\d\.\d\d\d\s*$/, "T23:59:59.999" );
	}
	return sValue;
}
function CRange_fromGetValue()
{
	var sValue = K_PRMT_sEMPTY;
	if (this.isRangeReversed()) {
		sValue = this.m_oTo.sGetValue();
	}
	else {
		sValue = new String(this.m_oFrom.sGetValue());
	}
	if ( this.getDataType() == 'date' && typeof this.m_oTo == K_PRMT_sOBJECT && this.m_oTo.m_iDateTimeType === 0 )
	{
		// We are using a date control for a datetime value.
		// make sure the value ends with T00:00:00.000
		sValue = sValue.replace( /T\d\d:\d\d:\d\d\.\d\d\d\s*$/, "T00:00:00.000" );
	}
	return sValue;
}
function CRange_toGetFormatValue()
{
	if (this.isRangeReversed()) {
		return this.m_oFrom.sGetFormatValue();
	}
	else {
		return this.m_oTo.sGetFormatValue();
	}
}
function CRange_fromGetFormatValue()
{
	if (this.isRangeReversed()) {
		return this.m_oTo.sGetFormatValue();
	}
	else {
		return this.m_oFrom.sGetFormatValue();
	}
}
//Return a localized string that can be used for the display value
// this uses the following function to do the substitutions:
// sReplaceToken(sMessage, sTokenValue, sNewValue)
function CRange_sGetFormatValue()
{
	var s = K_PRMT_sEMPTY;
	var sFromValue = (this.fromGetValue().toString() == 'false') ? K_PRMT_sEMPTY : this.fromGetValue();
	var sToValue = (this.toGetValue().toString() == 'false') ? K_PRMT_sEMPTY : this.toGetValue();
	var sFromFormatValue = this.fromGetFormatValue();
	var sToFormatValue = this.toGetFormatValue();
	var sEqualTo = 'equal to ^1';
	var sGreaterThanOrEqualTo = 'greater than or equal to ^1';
	var sLessThanOrEqualTo = 'less than or equal to ^1';
	var sBetweenTo = 'between ^1 and ^2';
	if (typeof PMT_RNG_FILTER_LESS_THAN_EQUAL_TO_STRING == K_PRMT_sSTRING) {
		sLessThanOrEqualTo = PMT_RNG_FILTER_LESS_THAN_EQUAL_TO_STRING;
	}
	if (typeof PMT_RNG_FILTER_EQUAL_STRING == K_PRMT_sSTRING) {
		sEqualTo = PMT_RNG_FILTER_EQUAL_STRING;
	}
	if (typeof PMT_RNG_FILTER_BETWEEN_STRING == K_PRMT_sSTRING) {
		sBetweenTo = PMT_RNG_FILTER_BETWEEN_STRING;
	}
	if (typeof PMT_RNG_FILTER_GREATER_THAN_EQUAL_TO_STRING == K_PRMT_sSTRING) {
		sGreaterThanOrEqualTo = PMT_RNG_FILTER_GREATER_THAN_EQUAL_TO_STRING;
	}
	switch (this.getFilterType(sFromValue,sToValue))
	{
		//FILTER_EQUAL_TO
		case 0:
			s = sReplaceToken(sEqualTo, "^1", sFromFormatValue);
			break;
		//FILTER_GREATER_THAN_OR_EQUAL_TO
		case 1:
			s = sReplaceToken(sGreaterThanOrEqualTo, "^1", sFromFormatValue);
			break;
		//FILTER_LESS_THAN_OR_EQUAL_TO
		case 2:
			s = sReplaceToken(sLessThanOrEqualTo, "^1", sToFormatValue);
			break;
		//FILTER_BETWEEN
		case 3:
			s = sReplaceToken(sBetweenTo, "^1", sFromFormatValue);
			s = sReplaceToken(s, "^2", sToFormatValue);
			break;
		default:
			return false;
	}
	return s;
}
//return the range ?p? in the format that the query engine expects expects
//	[x] in_range {1,2,3, 10 : 100, 201}
//	[x] in_range ?p?
//  [x] in_range {'a' : 'z'}
function CRange_sGetValue()
{
	var s = K_PRMT_sEMPTY;
	var sFromValue = (this.fromGetValue().toString() == 'false') ? K_PRMT_sEMPTY : this.fromGetValue();
	var sToValue = (this.toGetValue().toString() == 'false') ? K_PRMT_sEMPTY : this.toGetValue();
	//perform any special formating
	var singleQuote = K_PRMT_sEMPTY;
	//treat as a string if there is no data type
	if (this.m_sDataType == null)
	{
		singleQuote = "'";
	}
	switch (this.getFilterType(sFromValue,sToValue))
	{
		//FILTER_EQUAL_TO
		case 0:
			s = singleQuote + encodeURIComponent(sFromValue) + singleQuote;
			break;
		//FILTER_GREATER_THAN_OR_EQUAL_TO
		case 1:
			s = singleQuote + encodeURIComponent(sFromValue) + singleQuote + K_PRMT_sCOLON;
			break;
		//FILTER_LESS_THAN_OR_EQUAL_TO
		case 2:
			s = K_PRMT_sCOLON + singleQuote + encodeURIComponent(sToValue) + singleQuote;
			break;
		//FILTER_BETWEEN
		case 3:
			s = singleQuote + encodeURIComponent(sFromValue) + singleQuote + " : " + singleQuote + encodeURIComponent(sToValue)+ singleQuote;
			break;
		default:
			return false;
	}
	return s;
}
function CRange_getFilterType(sFromVal, sToVal)
{
	var filtertype = null;
	var bFrom = false;
	var sFromValue = sFromVal;
	var bTo = false;
	var sToValue = sToVal;
	if (this.m_bRequired == true)
	{
		if (sFromValue != K_PRMT_sEMPTY)
		{
			bFrom = true;
		}
		if (sToValue != K_PRMT_sEMPTY)
		{
			bTo = true;
		}
	}
	else
	{
		//check filters
		if ((this.m_oRadioFrom.checked == true) && (sFromValue != K_PRMT_sEMPTY))
		{
			bFrom = true;
		}
		if ((this.m_oRadioTo.checked == true) && (sToValue != K_PRMT_sEMPTY))
		{
			bTo = true;
		}
	}
	//determine type
	if ((bFrom == true) && (bTo == false))
	{
		filtertype = FILTER_GREATER_THAN_OR_EQUAL_TO;
		return filtertype;
	}
	else if ((bFrom == false) && (bTo == true))
	{
		filtertype = FILTER_LESS_THAN_OR_EQUAL_TO;
		return filtertype;
	}
	else if ((bFrom == true) && (bTo == true))
	{
		if (sFromValue == sToValue)
		{
			filtertype = FILTER_EQUAL_TO;
		}
		else
		{
			filtertype = FILTER_BETWEEN;
		}
		return filtertype;
	}
	return false;
}
function CRange_getDataType()
{
	return this.m_sDataType;
}
//perform any special processing for the server.
// convert to the following format
// 
//	 
//		
//		
//	  
//	
//		
//	
//	
//		
//	
//	
// 
function CRange_preProcess()
{
	if (this.m_sSubmitType == K_PRMT_sXML)
	{
		var sURLValues = K_PRMT_sEMPTY;
		var sFromValue = this.fromGetValue();
		var sFromFormatValue = this.fromGetFormatValue();
		var sToValue = this.toGetValue();
		var sToFormatValue = this.toGetFormatValue();
		switch (this.getFilterType(sFromValue,sToValue))
		{
			//equals FILTER_EQUAL_TO
			case 0:
				sURLValues += '';
				break;
			//greater than or equal to FILTER_GREATER_THAN_OR_EQUAL_TO
			case 1:
				sURLValues += '';
				sURLValues += '';
				sURLValues += '';
				break;
			//less than or equal to FILTER_LESS_THAN_OR_EQUAL_TO
			case 2:
				sURLValues += '';
				sURLValues += '';
				sURLValues += '';
				break;
			//between FILTER_BETWEEN
			case 3:
				sURLValues += '';
				sURLValues += '';
				sURLValues += '';
				sURLValues += '';
				break;
			default:
				break;
		}
		addSelectChoices(this.m_oSubmit, sURLValues);
	}
	else
	{
		this.m_oSubmit.value = this.sGetValue();
	}
}
//verify if the control has values
function CRange_checkData()
{
	var bRequired = this.isRequired();
	var bFromValid = true;
	var bToValid = true;
	//determine if to/from controls have valid values
	if ((this.m_oRadioFrom) && (this.m_oRadioTo))
	{
		if (this.m_oRadioFrom.checked == true)
		{
			bFromValid = this.m_oFrom.isValid();
		}
		if (this.m_oRadioTo.checked == true)
		{
			bToValid = this.m_oTo.isValid();
		}
	}
	else
	{
		bFromValid = this.m_oFrom.isValid();
		bToValid = this.m_oTo.isValid();
	}
	//is a value required?
	if ((bRequired == true) && ((bFromValid = false) || (bToValid == false)))
	{
		this.m_bValid = false;
		this.notify(gFAIL, this);
		return false;
	}
	this.m_bValid = true;
	this.notify(gPASS, this);
	return true;
}
//verify if the control has values
//without sending a notification
function CRange_update()
{
	var bRequired = this.isRequired();
	//determine if to/from controls have valid values
	var bFromValid = this.m_oFrom.getValid();
	var bToValid = this.m_oTo.getValid();
	//is a value required?
	if ((bRequired == true) && ((bFromValid = false) || (bToValid == false)))
	{
		this.m_bValid = false;
		return false;
	}
	this.m_bValid = true;
	return true;
}
function CRange_hasValue()
{
	if ((this.m_oRadioFrom) && (this.m_oRadioTo))
	{
		if (   (this.m_oRadioFrom.checked == true) && (this.m_oFrom.hasValue() )   ||  ( this.m_oRadioTo.checked == true) && (this.m_oTo.hasValue() ) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	else
	{
		if ((this.m_oFrom.hasValue() )   &&  (this.m_oTo.hasValue()) )
		{
			return true;
		}
		else
		{
			return false;
		}
	}
}
//provides the ability to notify other controls when
//the state of the range control changes
//typically used for radio button selections
function CRange_rangeNotify()
{
	this.notify(gUPDATE, this);
}
//check the radio button that has been typed in
function CRange_fromCheckRadioState(evt)
{
	//trap the tab key and shift-tab
	evt = (evt) ? evt : ((event) ? event : null);
	if (evt)
	{
		var keyCode = (evt.keyCode) ? evt.keyCode : evt.which;
		//trap the tab key and shift-tab
		if ((keyCode != '0') && (keyCode != '9') && (keyCode != '16'))
		{
			this.fromGotFocus();
		}
	}
}
//catch the backspace key
//some browsers (IE5.5 don't capture this event)
function CRange_fromKeyPress(sKeyCode)
{
	if (typeof event != K_PRMT_sUNDEFINED)
	{
		if ((sKeyCode=='8'))
		{
			//check the data that has been typed in
			this.fromCheckRadioState(event);
		}
	}
	return true;
}
//check the radio button that has been typed in
function CRange_toCheckRadioState(evt)
{
	//trap the tab key and shift-tab
	evt = (evt) ? evt : ((event) ? event : null);
	if (evt)
	{
		var keyCode = (evt.keyCode) ? evt.keyCode : evt.which;
		//trap the tab key and shift-tab
		if ((keyCode != '0') && (keyCode != '9') && (keyCode != '16'))
		{
			this.toGotFocus();
		}
	}
}
//catch the backspace key
//some browsers (IE5.5 don't capture this event)
function CRange_toKeyPress(sKeyCode)
{
	if (typeof event != K_PRMT_sUNDEFINED)
	{
		if ((sKeyCode=='8'))
		{
			//check the data that has been typed in
			this.toCheckRadioState(event);
		}
	}
	return true;
}
function CRange_isRangeReversed(from, to)
{
	if (typeof from == K_PRMT_sUNDEFINED) {
		from = this.m_oFrom.sGetValue();
	}
	if (typeof to == K_PRMT_sUNDEFINED) {
		to = this.m_oTo.sGetValue();
	}
	if (from == null || from == K_PRMT_sEMPTY || to == null || to == K_PRMT_sEMPTY || (this.m_oRadioTo && this.m_oRadioTo.checked == false) || (this.m_oRadioFrom && this.m_oRadioFrom.checked == false)) {
		return false;
	}
	var fromValue;
	var toValue;
	if (this.getDataType() == 'number' || this.getDataType() == 'currency' ||
		this.getDataType() == 'integer' || this.getDataType() == 'natural' ||
		this.getDataType() == 'whole' || this.getDataType() == 'percentage')
	{
		fromValue = (+sParseByDataType(from,this.getDataType(),true));
		toValue = (+sParseByDataType(to,this.getDataType(),true));
	}
	else if (this.getDataType() == 'interval')
	{
		if (from == "000 00:00:00.000" || to == "000 00:00:00.000") {
			return false;
		}
		fromValue = parseInt(from.substring(0, from.indexOf(K_PRMT_sSP)), 10);
		toValue = parseInt(to.substring(0, to.indexOf(K_PRMT_sSP)), 10);
		if (fromValue > toValue) { //days
			return true;
		}
		fromValue = parseInt(from.substring((from.indexOf(K_PRMT_sSP) + 1), from.indexOf(K_PRMT_sCOLON)), 10);
		toValue = parseInt(to.substring((to.indexOf(K_PRMT_sSP) + 1), to.indexOf(K_PRMT_sCOLON)), 10);
		if (fromValue > toValue) { //hours
			return true;
		}
		fromValue = parseInt(from.substring((from.indexOf(K_PRMT_sCOLON) + 1), from.lastIndexOf(K_PRMT_sCOLON)), 10);
		toValue = parseInt(to.substring((to.indexOf(K_PRMT_sCOLON) + 1), to.lastIndexOf(K_PRMT_sCOLON)), 10);
		if (fromValue > toValue) { //minutes
			return true;
		}
		fromValue = parseInt(from.substring((from.lastIndexOf(K_PRMT_sCOLON) + 1), from.indexOf(K_PRMT_sDOT)), 10);
		toValue = parseInt(to.substring((to.lastIndexOf(K_PRMT_sCOLON) + 1), to.indexOf(K_PRMT_sDOT)), 10);
		if (fromValue > toValue) { //seconds
			return true;
		}
		fromValue = parseInt(from.substr((from.indexOf(K_PRMT_sDOT) + 1)), 10);
		toValue = parseInt(to.substr((to.indexOf(K_PRMT_sDOT) + 1)), 10);
		if (fromValue > toValue) { //milliseconds
			return true;
		}
		return false;
	}
	else
	{
		//determine if this is a number or identifier and if so, parse it as a float
		//so that it can be sorted properly
		//otherwise, this is a string
		if ((bNumbersOnly(from) == true) && (bNumbersOnly(to) == true))
		{
			fromValue = parseFloat(from);
			toValue = parseFloat(to);
		}
		else
		{
			fromValue = from;
			toValue = to;
		}
	}
	return (fromValue > toValue);
}
CRange.prototype.toGotFocus = CRange_toGotFocus;
CRange.prototype.fromGotFocus  = CRange_fromGotFocus;
CRange.prototype.toGetValue = CRange_toGetValue;
CRange.prototype.fromGetValue = CRange_fromGetValue;
CRange.prototype.toGetFormatValue = CRange_toGetFormatValue;
CRange.prototype.fromGetFormatValue = CRange_fromGetFormatValue;
CRange.prototype.sGetFormatValue = CRange_sGetFormatValue;
CRange.prototype.sGetValue = CRange_sGetValue;
CRange.prototype.getFilterType = CRange_getFilterType;
CRange.prototype.getDataType = CRange_getDataType;
CRange.prototype.preProcess = CRange_preProcess;
CRange.prototype.checkData = CRange_checkData;
CRange.prototype.update = CRange_update;
CRange.prototype.initControls = CRange_initControls;
CRange.prototype.hasValue = CRange_hasValue;
CRange.prototype.rangeNotify = CRange_rangeNotify;
CRange.prototype.fromCheckRadioState = CRange_fromCheckRadioState;
CRange.prototype.fromKeyPress = CRange_fromKeyPress;
CRange.prototype.toCheckRadioState = CRange_toCheckRadioState;
CRange.prototype.toKeyPress = CRange_toKeyPress;
CRange.prototype.isRangeReversed = CRange_isRangeReversed;
//CONSTANTS
//constants for filters
//note that netscape 4.7x does not support these for use in
//switch statements.  If these variables are modified, the
//switch statements will need to be modified as well
var FILTER_EQUAL_TO = 0;
var FILTER_GREATER_THAN_OR_EQUAL_TO = 1;
var FILTER_LESS_THAN_OR_EQUAL_TO = 2;
var FILTER_BETWEEN = 3;
//constants for range initialization
//these will determine whether to select/deselect radio buttons
var RANGE_UNKNOWN_VALUE = 0;
var RANGE_START_VALUE = 1;
var RANGE_END_VALUE = 2;
var RANGE_BOUND_VALUE = 3;
var RANGE_EQUAL_VALUE = 4;
var RANGE_NO_VALUE = 5;
//this function can be called to notify
//any range controls to check their states
function rangeNotify()
{
	if (typeof checkRanges != K_PRMT_sUNDEFINED)
	{
		checkRanges();
	}
}
//this function will check to see if all controls are
//ready for navigation to the next page
function checkRanges()
{
	if (typeof rangeObserverArray != K_PRMT_sUNDEFINED)
	{
		var kCount = rangeObserverArray.length;
		var k = 0;
		for (k=0; k