//-  All functions and variables are placed within a single object
//-  RiPHPLib. This minimises namespace pollution.
//-
var	RiPHPLib		= new Object () ;


//-  Validation constants. These must be the same as in the
//-  RiPHPLib::Constants package.
//-
RiPHPLib.unchecked	= 0 ;
RiPHPLib.advisory	= 1 ;
RiPHPLib.enforced	= 2 ;

RiPHPLib.integer	= 0 ;
RiPHPLib.posint		= 1 ;
RiPHPLib.percent	= 2 ;
RiPHPLib.float		= 3 ;
RiPHPLib.posfloat	= 4 ;

//-  Regular expressions used for type validation
//-
RiPHPLib.p_integer	= new RegExp ('^ *([+-]|)[0-9][0-9]* *$') ;
RiPHPLib.p_float		= new RegExp ('^ *([+-]|)[0-9][0-9]*(\.[0-9]*|) *$') ;
RiPHPLib.p_posint	= new RegExp ('^ *[0-9][0-9]* *$') ;
RiPHPLib.p_posfloat	= new RegExp ('^ *[0-9][0-9]*(\.[0-9]*|) *$') ;
RiPHPLib.p_percent	= new RegExp ('^ *[0-9][0-9]*(\.[0-9]*|) *$') ;

//-  ControlList and ControlDict accumulates all the control objects.
//-
RiPHPLib.controlList	= new Array  () ;
RiPHPLib.controlDict	= new Object () ;


//-  Functions to check values for type, optionally allowing null.
//-
RiPHPLib.is_integer = function (value, nullok)
{
	return ((value == '') && nullok) || value.match (RiPHPLib.p_integer ) ;
}

RiPHPLib.is_float = function   (value, nullok)
{
	return ((value == '') && nullok) || value.match (RiPHPLib.p_float   ) ;
}

RiPHPLib.is_posint = function  (value, nullok)
{
	return ((value == '') && nullok) || value.match (RiPHPLib.p_posint  ) ;
}

RiPHPLib.is_posfloat = function(value, nullok)
{
	return ((value == '') && nullok) || value.match (RiPHPLib.p_posfloat) ;
}

RiPHPLib.is_percent = function (value, nullok)
{
	return ((value == '') && nullok) || value.match (RiPHPLib.p_percent ) ;
}

RiPHPLib.is_date = function (value, nullok)
{
	return (((value == '') && nullok) || (RiPHPLib.checkDate(value) != null)) ;
}


RiPHPLib.decodeDateTime = function (value, wrap)
{
	if (! RiPHPLib.datePatterns)
	{
		RiPHPLib.datePatterns = new Object () ;
		RiPHPLib.datePatterns.datetime1	= new RegExp ('^ *([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+).([0-9]+)') ;
		RiPHPLib.datePatterns.datetime2	= new RegExp ('^ *([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+):([0-9]+)') ;
		RiPHPLib.datePatterns.datetime3	= new RegExp ('^ *([0-9]+)-([0-9]+)-([0-9]+) ([0-9]+):([0-9]+)') ;
		RiPHPLib.datePatterns.date1	= new RegExp ('^ *([0-9]+)-([0-9]+)-([0-9]+)') ;
		RiPHPLib.datePatterns.date2	= new RegExp ('^ *([0-9]+)-([A-Za-z]+)-([0-9]+)') ;
		RiPHPLib.datePatterns.date3	= new RegExp ('^ *([0-9]+)\/([0-9]+)\/([0-9]+)') ;
		RiPHPLib.datePatterns.time1	= new RegExp ('^ *([0-9]+):([0-9]+):([0-9]+)') ;
		RiPHPLib.datePatterns.time2	= new RegExp ('^ *([0-9]+):([0-9]+)') ;
		RiPHPLib.datePatterns.dim	= [ 0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ] ;
	}

	if (!wrap) wrap = 50 ;

	var m ;

	m = RiPHPLib.datePatterns.datetime1.exec (value) ;
	if (m)
		return	[ m[1], m[2], m[3], m[4], m[5], m[6] ] ;
	m = RiPHPLib.datePatterns.datetime1.exec (value) ;
	if (m)
		return	[ m[1], m[2], m[3], m[4], m[5], m[6] ] ;
	m = RiPHPLib.datePatterns.datetime3.exec (value) ;
	if (m)
		return	[ m[1], m[2], m[3], m[4], m[5], 0    ] ;
	m = RiPHPLib.datePatterns.date1.exec (value) ;
	if (m)
		return	[ m[1], m[2], m[3], 0, 0, 0 ] ;

	m = RiPHPLib.datePatterns.date3.exec (value) ;
	if (m)
	{	if      (m[3] <= wrap) m[3] = m[3] * 1 + 2000 ;
		else if (m[3] <=   99) m[3] = m[3] * 1 + 1900 ;
		return	[ m[3], m[2], m[1], 0, 0,  ] ;
	}

	m = RiPHPLib.datePatterns.time1.exec (value) ;
	if (m)
		return	[ 0, 0, 0, m[1], m[2], m[3] ] ;
	m = RiPHPLib.datePatterns.time2.exec (value) ;
	if (m)
		return	[ 0, 0, 0, m[1], m[2], 0    ] ;

	return	null ;
}

RiPHPLib.checkDate = function (value, wrap)
{
	var	date	= RiPHPLib.decodeDateTime (value, wrap) ;
	if (date == null) return null ;

	var	year	= date[0] ;
	var	month	= date[1] ;
	var	day	= date[2] ;
	var	hour	= date[3] ;
	var	minute	= date[4] ;
	var	second	= date[5] ;

	if (year  ==  0) return null ;
	if (month <   1) return null ;
	if (month >  12) return null ;
	if (day   <   1) return null ;
	if (day > RiPHPLib.datePatterns.dim[month]) return null ;

	if (month == 2)
	{
		var	days	= (year % 400 == 0) ? 29 :
				  (year % 100 == 0) ? 28 :
				  (year % 4   == 0) ? 29 : 28 ;
		if (day > days)	return null ;
	}

	var rtn = new Array(5);
	rtn[1] = day;
	rtn[2] = month;
	rtn[3] = year % 100 ;
	rtn[4] = year;
	return rtn;
}


//-  Verification flag images
//-
RiPHPLib.verifyFlags 	   = [ new Image(), new Image() ] ;
RiPHPLib.verifyFlags[0].src = "/images/valid/reqd.gif"	  ;
RiPHPLib.verifyFlags[1].src = "/images/valid/eval.gif"	  ;


//-  RiPHPLib.setupBase
//-  -----------------
//-  Common constructor code for control objects. Sets name and legend plus
//-  common methods.
//-
RiPHPLib.setupBase = function (object, name, legend)
{
	object.m_name	= name		;
	object.m_legend	= legend	;

	object.getError = function (error, text)
		{
			//- If there is an explicit error message then return that,
			//- possibly substiting in the legend.
			//- 
			if (error)
				return	error.replace ('%{legend}', this.m_legend) ;

			//- If there is a legend then combine that with the default
			//- error text.
			//-
			if (this.m_legend)
				return	this.m_legend + ' ' + text ;

			//- Lastly, fall back on the control name, but remove any row
			//- number.
			//
			return	this.m_name.replace (/_[0-9]+$/, '') + ' ' + text ;
		}

	object.setVerifyFlag = function (ctrl, state)
		{
			var flag = document.getElementById(ctrl.id + '_v') ;
			if (flag) flag.src = RiPHPLib.verifyFlags[state].src ;
		}

	object.showError = function (ctrl, submit, prior, error)
		{
			this.setVerifyFlag (ctrl, 1) ;

			if (!prior && !submit)
			{
				var rplError = document.getElementById('rplErrorField') ;
				if (error == null) error = '' ;
				if (rplError)
				{	rplError.firstChild.data = error ;
					return	;
				}
				if (error != '') alert (error) ;
			}
		}

	object.clearError = function (ctrl)
		{
			var rplError = document.getElementById('rplErrorField') ;
			if (rplError) rplError.firstChild.data = '' ;
			this.setVerifyFlag (ctrl, 0) ;
		}

	object.checkOK = function (error)
		{
			return	confirm (error + ": is this correct?") ;
		}

	//-  notNullOpt
	//-  ----------
	//-  Get the not-null option. If there is a control on which this one depends,
	//-  and that control is not set, then return unchecked; otherwise return the
	//-  specified option.
	//-
	object.notNullOpt = function ()
		{
			if (this.m_notnull[2] && !RiPHPLib.controlDict[this.m_notnull[2]].isSet())
				return	RiPHPLib.unchecked ;
			return	this.m_notnull[0] ;
		}

	//-  isSet
	//-  -----
	//-  Returns true if the control has a value set. By default this is a value
	//-  other than the empty string, but we will override for special cases.
	//-
	object.isSet = function ()
		{
			return	document.getElementById(this.m_name).value != '' ;
		}

	object.value = function ()
		{
			return	document.getElementById(this.m_name).value ;
		}

	object.onchange = function ()
		{
			ctrl = document.getElementById(this.m_name) ;
			if (this.f_onchange)
				this.f_onchange (ctrl) ;
			return	this.verify (ctrl, 0, null) == null ;
		}

	object.changed = function ()
		{
			value = document.getElementById(this.m_name).value ;
			if (value == null) value = '' ;
			return	value != this.m_value ;
		}

	object.element = function ()
		{
			return	document.getElementById(this.m_name) ;
		}

	RiPHPLib.controlList[RiPHPLib.controlList.length] = object ;
	RiPHPLib.controlDict[name]			= object ;
}

//-  RiPHPLib.setupInput
//-  ------------------
//-  Common constructor code for input-derived controls, also used for
//-  text areas.
//-
RiPHPLib.setupInput = function (object, name, legend)
{
	RiPHPLib.setupBase (object, name, legend) ;

	object.notnull_force = function (ctrl, submit, prior)
		{
			if (!this.m_notnull[2] || RiPHPLib.controlDict[this.m_notnull[2]].isSet())
				if ((ctrl.value == '') || (ctrl.value == null))
				{	var error = this.getError  (this.m_notnull[1], "must be set") ;
					this.showError (ctrl, submit, prior, error) ;
					return error ;
				}
			if (!prior) this.clearError (ctrl) ;
			return	null	;
		}

	object.notnull_allow = function (ctrl, submit, prior)
		{
			if (!submit)
				if ((ctrl.value == '') || (ctrl.value == null))
				{	var error = this.m_legend + " is not set" ;
					if (!this.checkOK(error)) return error ;
				}
			if (!prior) this.clearError (ctrl) ;
			return	null	;
		}

	object.regexp_force = function (ctrl, submit, prior)
		{
		        if (!ctrl.value.match(this.m_regExp[1]))
		        {   var error = this.getError  (this.m_regExp[2], "is not valid") ;
		            this.showError (ctrl, submit, prior, error) ;
		            return error ;
		        }
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	object.regexp_allow = function (ctrl, submit, prior)
		{
		        if (!ctrl.value.match(this.m_regExp[1]))
		        {   var error = this.getError  (this.m_regExp[2], "is not valid") ;
		            this.showError (ctrl, submit, prior, error) ;
		            return error ;
		        }
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}
}

//-  RiPHPLib.Input
//-  -------------
//-  Control object for input controls
//-
RiPHPLib.Input = function (name, legend)
{
	RiPHPLib.setupInput (this, name, legend) ;

	this.type_integer = function (ctrl, submit, prior)
		{
		        if (!RiPHPLib.is_integer (ctrl.value, this.m_type[0] != RiPHPLib.enforced))
		        {   var error = this.getError  (this.m_type[2], "is not a whole number") ;
		            this.showError (ctrl, submit, prior, error) ;
		            return error ;
		        }
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.type_posint = function (ctrl, submit, prior)
		{
		        if (!RiPHPLib.is_posint  (ctrl.value, this.m_type[0] != RiPHPLib.enforced))
		        {
		            var error = this.getError  (this.m_type[2], "is not a positive number") ;
		            this.showError (ctrl, submit, prior, error) ;
		            return error ;
		        }
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.type_float = function (ctrl, submit, prior)
		{
		        if (!RiPHPLib.is_float (ctrl.value, this.m_type[0] != RiPHPLib.enforced))
		        {   var error = this.getError  (this.m_type[2], "is not a number") ;
		            this.showError (ctrl, submit, prior, error) ;
		            return error ;
		        }
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.type_posfloat = function (ctrl, submit, prior)
		{
		        if (!RiPHPLib.is_posfloat (ctrl.value, this.m_type[0] != RiPHPLib.enforced))
		        {   var error = this.getError  (this.m_type[2], "is not a positive number") ;
		            this.showError (ctrl, submit, prior, error) ;
		            return error ;
		        }
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.type_percent = function (ctrl, submit, prior)
		{
		        if (!RiPHPLib.is_percent (ctrl.value, this.m_type[0] != RiPHPLib.enforced))
		        {   var error = this.getError  (this.m_type[2], "is not a percentage") ;
		            this.showError (ctrl, submit, prior, error) ;
		            return error ;
		        }
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.verify	= function (ctrl, submit, prior)
		{
			var error ;

			if (this.notNullOpt() == RiPHPLib.advisory)
			    if ((error = this.notnull_allow (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.enforced)
			    if ((error = this.notnull_force (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.unchecked)
				if ((ctrl.value == '') || (ctrl.value == null))
					return	null ;

			if (this.m_type[0] != RiPHPLib.unchecked)
			{
			    if (this.m_type[1] == RiPHPLib.integer)
				if ((error = this.type_integer  (ctrl, submit, prior)) != null)
					return error ;
				else	return null  ;
			    if (this.m_type[1] == RiPHPLib.posint)
				if ((error = this.type_posint   (ctrl, submit, prior)) != null)
					return error ;
				else	return null  ;
			    if (this.m_type[1] == RiPHPLib.percent)
				if ((error = this.type_percent  (ctrl, submit, prior)) != null)
					return error ;
				else	return null  ;
			    if (this.m_type[1] == RiPHPLib.float)
				if ((error = this.type_float    (ctrl, submit, prior)) != null)
					return error ;
				else	return null  ;
			    if (this.m_type[1] == RiPHPLib.posfloat)
				if ((error = this.type_posfloat (ctrl, submit, prior)) != null)
					return error ;
				else	return null  ;
			    return null ;
			}


			if (this.m_regExp[0] == RiPHPLib.advisory)
			    if ((error = this.regexp_allow (ctrl, submit, prior)) != null)
				return error ;
			if (this.m_regExp[0] == RiPHPLib.enforced)
			    if ((error = this.regexp_force (ctrl, submit, prior)) != null)
				return error ;

			return	null ;
		}
}

//-  RiPHPLib.Date
//-  -------------
//-  Control object for date controls
//-
RiPHPLib.Date = function (name, legend)
{
	RiPHPLib.setupInput (this, name, legend) ;

	this.type_date = function (ctrl, submit, prior)
		{
		        if (!RiPHPLib.is_date (ctrl.value, true))
		        {
				var error = this.getError  ("", "is not a date") ;
				this.showError (ctrl, submit, prior, error) ;
				return error ;
		        }

			//- Update the control with the formatted date
			//-
			var res = RiPHPLib.checkDate(ctrl.value, this.m_wrap);  
			if (res != null)
				ctrl.value = res[1] + '/' + res[2] + '/' + res[4] ;

			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}


	this.verify	= function (ctrl, submit, prior)
		{
			var error ;

			if (this.notNullOpt() == RiPHPLib.advisory)
			    if ((error = this.notnull_allow (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.enforced)
			    if ((error = this.notnull_force (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.unchecked)
				if ((ctrl.value == '') || (ctrl.value == null))
					return	null ;

			if ((error = this.type_date  (ctrl, submit, prior)) != null)
				return error ;

			return	null ;
		}
}


//-  RiPHPLib.Choice
//-  --------------
//-  Control object for choice controls
//-
RiPHPLib.Choice = function (name, legend)
{
	RiPHPLib.setupBase (this, name, legend) ;

	this.notnull_force = function (ctrl, submit, prior)
		{
			if (!this.m_notnull[2] || RiPHPLib.controlDict[this.m_notnull[2]].isSet())
			        if (ctrl.selectedIndex == 0)
			        {   var error = this.getError  (this.m_notnull[1], "must be specified") ;
			            this.showError (ctrl, submit, prior, error) ;
		        	    return error ;
		        	}
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.notnull_allow = function (ctrl, submit, prior)
		{
		        if (!submit)
		            if (ctrl.selectedIndex == 0)
		            {   var error = this.getError (this.m_notnull[1], "is not specified") ;
		                if (!this.checkOK(error)) return error ;
			    }
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.verify	= function (ctrl, submit, prior)
		{
			if (this.notNullOpt() == RiPHPLib.advisory)
			    if ((error = this.notnull_allow (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.enforced)
			    if ((error = this.notnull_force (ctrl, submit, prior)) != null)
				return error ;
		
			return	null ;
		}

	this.isSet = function ()
		{
			if (this.m_nullval)
				return	document.getElementById(this.m_name).selectedIndex > 0 ;
			return	true	;
		}
}


//-  RiPHPLib.Check
//-  -------------
//-  Control object for check controls
//-
RiPHPLib.Check = function (name, legend)
{
	RiPHPLib.setupBase (this, name, legend) ;

	this.notnull_force = function (ctrl, submit, prior) { return null ; }
	this.notnull_allow = function (ctrl, submit, prior) { return null ; }
	this.verify	   = function (ctrl, submit, prior) { return null ; }

	this.isChecked = function ()
		{
			return	document.getElementById(this.m_name).checked ;
		}
	this.setChecked = function (set)
		{
			return	document.getElementById(this.m_name).checked = set ;
		}
	this.changed = function ()
		{
			return	this.isChecked() != this.m_value ;
		}

}


//-  RiPHPLib.TextArea
//-  ----------------
//-  Control object for textarea controls
//-
RiPHPLib.TextArea = function (name, legend)
{
	RiPHPLib.setupInput (this, name, legend) ;

	this.verify	= function (ctrl, submit, prior)
		{
			var error ;

			if (this.notNullOpt() == RiPHPLib.advisory)
			    if ((error = this.notnull_allow (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.enforced)
			    if ((error = this.notnull_force (ctrl, submit, prior)) != null)
				return error ;

			if (this.m_regExp[0] == RiPHPLib.advisory)
			    if ((error = this.regexp_allow (ctrl, submit, prior)) != null)
				return error ;
			if (this.m_regExp[0] == RiPHPLib.enforced)
			    if ((error = this.regexp_force (ctrl, submit, prior)) != null)
				return error ;

			return	null ;
		}
}

//-  RiPHPLib.DoubleList
//-  ------------------
//-  Control object for double-list selectors
//-
RiPHPLib.DoubleList = function (name, legend)
{
	RiPHPLib.setupBase (this, name, legend) ;

	this.notnull_force = function (ctrl, submit, prior)
		{
			if (!this.m_notnull[2] || RiPHPLib.controlDict[this.m_notnull[2]].isSet())
				if ((ctrl.value == '') || (ctrl.value == null))
			        {   var error = this.getError  (this.m_notnull[1], "must be specified") ;
			            this.showError (ctrl, submit, prior, error) ;
		        	    return error ;
		        	}
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.notnull_allow = function (ctrl, submit, prior)
		{
		        if (!submit)
				if ((ctrl.value == '') || (ctrl.value == null))
		        	{  	var error = this.getError (this.m_notnull[1], "is not specified") ;
		                	if (!this.checkOK(error)) return error ;
			    	}
			if (!prior) this.clearError (ctrl) ;
			return	null ;
		}

	this.verify	= function (ctrl, submit, prior)
		{
			if (this.notNullOpt() == RiPHPLib.advisory)
			    if ((error = this.notnull_allow (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.enforced)
			    if ((error = this.notnull_force (ctrl, submit, prior)) != null)
				return error ;
		
			return	null ;
		}

	this.isSet = function ()
		{
			return	document.getElementById(this.m_name).selectedIndex > 0 ;
		}

	this.update = function ()
	{
		var vlist   = [] ;
		var ctrl = document.getElementById(this.m_name + '_r') ;
		for (var idx = 0 ; idx < ctrl.options.length ; idx += 1)
			vlist[idx] = ctrl.options[idx].value ;
		document.getElementById(this.m_name).value = vlist.join(this.m_separator) ;
		this.onchange () ;
	}
	this.transfer = function (srce, dest)
	{
		var sidx    = srce.selectedIndex ;
		var sopts   = srce.options ;
		var move    = sopts[sidx]  ;
		dest.options[dest.options.length] = new Option (move.text, move.value) ;
		dest.selectedIndex = dest.options.length - 1 ;
		srce.remove(sidx) ;
		srce.selectedIndex = sidx >= srce.options.length ? srce.options.length - 1 : sidx ;
	}
	this.add = function ()
	{
		if (document.getElementById(this.m_name + '_l').selectedIndex >= 0)
		{	this.transfer (document.getElementById(this.m_name + '_l'), document.getElementById(this.m_name + '_r')) ;
			this.update   () ;
		}
	}
	this.remove = function ()
	{
		if (document.getElementById(this.m_name + '_r').selectedIndex >= 0)
		{	this.transfer (document.getElementById(this.m_name + '_r'), document.getElementById(this.m_name + '_l')) ;
			this.update   () ;
		}
	}
}


//-  RiPHPLib.File
//-  ------------
//-  Control object for file upload controls
//-
RiPHPLib.File = function (name, legend)
{
	RiPHPLib.setupBase (this, name, legend) ;

	this.verify	= function (ctrl, submit, prior)
		{
			var error ;

			if (this.notNullOpt() == RiPHPLib.advisory)
			    if ((error = this.notnull_allow (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.enforced)
			    if ((error = this.notnull_force (ctrl, submit, prior)) != null)
				return error ;
			if (this.notNullOpt() == RiPHPLib.unchecked)
				if ((ctrl.value == '') || (ctrl.value == null))
					return	null ;

			return	null ;
		}
}

//-  RiPHPLib.checkControls
//-  ---------------------
//-  Check controls for validity. Returns a list of errors, which will
//-  be empty if there are none.
//-
RiPHPLib.checkControls = function ()
{
	var	elist	= new Array() ;
	var	prior	= false	;

	for (var idx in RiPHPLib.controlList)
	{
		var ctrl = RiPHPLib.controlList[idx] ;

		if (ctrl.verify == null)
			continue ;

		var err  = ctrl.verify(document.getElementById([ctrl.m_name]), true, prior) ;
		if (err == null)
			continue ;

		elist[elist.length] = err ;
		prior = true ;
	}

	return	elist	;
}

RiPHPLib.changedControls = function ()
{
	var	clist	= new Array() ;

	for (var idx in RiPHPLib.controlList)
	{
		var ctrl  = RiPHPLib.controlList[idx] ;

		if (ctrl.changed == null)
			continue ;

		if (ctrl.changed())
			clist[clist.length] = ctrl ;
	}

	return	clist	;
}


//-  RiPHPLib.onSubmit
//-  ----------------
//-  Standard onSubmit function. Checks control for validity and
//-  displays the errors if any are found. Returns True only if there
//-  are no errors.
//-
RiPHPLib.onSubmit = function ()
{
	RiPHPLib.preSave () ;

	var elist = RiPHPLib.checkControls () ;
	if (elist.length > 0)
	{
		alert	('Some fields are not correct:\n     ' + elist.join('\n     ')) ;
		return	false	;
	}
	return	true	;
}


//-  RiPHPLib.submitError is used to store any form submission error,
//-  which should be set using the RiPHPLib.setSubmitError function.
//-  Any such error is displayed in the RiPHPLib.formOnLoad function.
//-
RiPHPLib.submitError = null

RiPHPLib.setSubmitError = function (error)
{
	RiPHPLib.submitError = error ;
}


//-  RiPHPLib.formOnLoadList is a list of funtions to be executed by
//-  the "onLoad" event. Functions are added using the RiPHPLib.addFormOnLoad
//-  function; the <body> elements "onLoad" event is updated to be the
//-  RiPHPLib.formOnLoad function. This handles common functionality
//-  (including calling any original "onLoad" event, then calls each added
//-  function.
//-
RiPHPLib.formOnLoadList = new Array() ;
RiPHPLib.formOnLoadDef	= null ;

RiPHPLib.addFormOnLoad = function (func)
{
	if (RiPHPLib.formOnLoadList.length == 0)
	{	RiPHPLib.formOnLoadDef = window.onload ;
		window.onload = RiPHPLib.formOnLoad ;
	}
	
	for (var idx in RiPHPLib.formOnLoadList)
		if (RiPHPLib.formOnLoadList[idx] == func)
			return	;

	RiPHPLib.formOnLoadList[RiPHPLib.formOnLoadList.length] = func ;
}

RiPHPLib.formOnLoad = function ()
{
	if ((RiPHPLib.submitError != null) && (RiPHPLib.submitError != ''))
		alert (RiPHPLib.submitError) ;

	if (RiPHPLib.formOnLoadDef)
		RiPHPLib.formOnLoadDef () ;

	for (var idx in RiPHPLib.formOnLoadList)
		RiPHPLib.formOnLoadList[idx]() ;
}


RiPHPLib.formPreSaveList = new Array() ;

RiPHPLib.addFormPreSave = function (func)
{
	for (var idx in RiPHPLib.formPreSaveList)
		if (RiPHPLib.formPreSaveList[idx] == func)
			return	;

	RiPHPLib.formPreSaveList[RiPHPLib.formPreSaveList.length] = func ;
}

RiPHPLib.preSave = function ()
{
	for (var idx in RiPHPLib.formPreSaveList)
		RiPHPLib.formPreSaveList[idx]() ;
}


RiPHPLib.fckedList = [] ;


RiPHPLib.dialogs	= new Object() ;

RiPHPLib.Dialog	= function (name, initx, inity)
{
	this.show = function (message, title, initx, inity)
	{
		var popupDiv  = document.getElementById(this.name + '_popupDiv') ;

		var winWidth  = window.innerWidth  ;
		var winHeight = window.innerHeight ;

		if (message)
			document.getElementById('popup_' + this.name + '_message' ).innerHTML = message ;
		if (title  )
			document.getElementById('popup_' + this.name + '_title'   ).innerHTML = title   ;

		document.getElementById(this.name).style.display = "inline" ;

		if (initx == null) initx = this.initx ;
		if (inity == null) inity = this.inity ;

		if ((winWidth  > 0) && (initx < 0))
			initx	= (winWidth  - popupDiv.offsetWidth ) / 2 ;
		if ((winHeight > 0) && (inity < 0))
			inity	= (winHeight - popupDiv.offsetHeight) / 2 ;

		if (initx > 0) popupDiv.style.left = initx + 'px' ;
		if (inity > 0) popupDiv.style.top  = inity + 'px' ;


		var dx = popupDiv.offsetLeft	;
		var dy = popupDiv.offsetTop	;
		var dw = popupDiv.offsetWidth	;
		var dh = popupDiv.offsetHeight	;

		for (var idx = 0 ; idx < this.parSelect.length ; idx += 1)
		{
			var select = this.parSelect[idx]   ;
			var sx	   = select.offsetLeft     ;
			var sy	   = select.offsetTop      ;
			var sw	   = select.offsetWidth	   ;
			var sh	   = select.offsetHeight   ;

			if (sx >= dx + dw) continue	   ;
			if (sx + sw <  dx) continue	   ;
			if (sy >= dy + dh) continue	   ;
			if (sy + sh <  dy) continue	   ;

			select.style.visibility = 'hidden' ;
		}
	}
	this.hide = function ()
	{
		for (var idx = 0 ; idx < this.parSelect.length ; idx += 1)
			this.parSelect[idx].style.visibility = 'visible' ;

		document.getElementById(this.name).style.display = "none"	;
	}

	this.setState = function (button, state)
	{
		for (var idx = 0 ; idx < 2 ; idx += 1)
		{
			var div = document.getElementById('popup_' + this.name + '_' + button + '_d_' + idx) ;
			if (div) div.style.display = state == idx ? 'block' : 'none' ;
		}
	}

	this.setText = function (button, text)
	{
		document.getElementById('popup_' + this.name + '_' + button + '_t_0').innerHTML = text ;
		document.getElementById('popup_' + this.name + '_' + button + '_t_1').innerHTML = text ;
	}
	this.setTitle = function (title)
	{
		document.getElementById('popup_' + this.name + '_title').innerHTML = title ;
	}

	this.name		= name	;
	this.initx		= initx	;
	this.inity		= inity	;
	RiPHPLib.dialogs[name]	= this	;

	var	allSelect = document.getElementsByTagName('select') ;
	var	popSelect = document.getElementById(this.name).getElementsByTagName('select') ;
	var	parSelect = [] ;

	for (var idxAll = 0 ; idxAll < allSelect.length ; idxAll += 1)
	{	var found = false ;
		for (var idxPop = 0 ; idxPop < popSelect.length ; idxPop += 1)
		{	if (popSelect[idxPop] == allSelect[idxAll])
			{	found = true ;
				break ;
			}
		}
		if (!found) parSelect[parSelect.length] = allSelect[idxAll] ;
	}

	this.parSelect		= parSelect ;

}


//-  sprintf
//-  -------
//-  Basic sprintf-like function. Currently understands only
//-  limited substitution and the %% escape. IE doesn't support []
//-  subscripting in strings. Yuk.
//-
RiPHPLib.sprintf = function (format)
{
	function isdigit (ch)
	{
		var digits = "0123456789" ;
		return	digits.indexOf(ch) >= 0 ? true : false ;
	}

	function f_string (width1, width2, arg)
	{
                arg    = arg + ''   ;
		width1 = width1 * 1 ;
		while (arg.length < width1) arg = ' ' + arg ;
		return	arg	;
	}

	function f_number (width1, width2, arg)
	{
		var	pad	= ' ' ;
		if (width1.charAt(0) == '0') pad = '0' ;
		arg = (arg * 1) + '' ;
		while (arg.length < width1) arg = pad + arg ;
		return	arg	;
	}

	function f_floating (width1, width2, arg)
	{
		var	pad	= ' ' ;
		var	bits	= ('' + arg).split ('.') ;
		var	p0	= bits.length >= 2 ? bits[0] : arg ;
		var	p1	= bits.length >= 2 ? bits[1] : '0' ;

		width1	 = width1 * 1 ;
		width2	 = width2 * 1 ;

		width1	= width1 - width2 - 1 ;
		if (width1 > 0)
			while (p0.length < width1) p0 = pad + p0 ;

		if (width2 > 0)
		{	while (p1.length < width2) p1 = p1 + '0' ;
			p1 = p1.substr(0, width2) ;
		}
		return	p0 + '.' + p1 ;
	}

	var	result	= '' ;
	var	offset	= 1  ;
	var	width1	;
	var	width2	;

	for (var idx = 0 ; idx < format.length ; idx += 1)
		if (format.charAt(idx) == '%')
		{
			idx	+= 1	;
			width1	 = ''	;
			width2	 = ''	;

			while (isdigit (format.charAt(idx)))
			{
				width1	= width1 + format.charAt(idx) ;
				idx    += 1 ;
			}

			if (format.charAt(idx) == '.')
			{
				idx += 1 ;
				while (isdigit (format.charAt(idx)))
				{
					width2	= width2 + format.charAt(idx) ;
					idx    += 1 ;
				}
			}

			switch (format.charAt(idx))
			{
				case '%' :
					result	= result + '%' ;
					break	;

				case 's' :
					// String ....
					result	= result + f_string (width1, width2, arguments[offset]) ;
					offset += 1 ;
					break	;

				case 'd' :
					// Fixed point number ....
					result	= result + f_number (width1, width2, arguments[offset]) ;
					offset += 1 ;
					break	;

				case 'f' :
					// Floating point number .....
					result	= result + f_floating (width1, width2, arguments[offset]) ;
					offset += 1 ;
					break	;

				case 'q' :
					// String, but quoted. Useful when
					// assembing XML elements.
					result	= result + "'" + arguments[offset] + "'" ;
					offset += 1 ;
					break	;

				default	:
					result	= result + format.charAt(idx) ;
					break	;
			}
		}
		else	result	= result + format.charAt(idx) ;

	return	result	;
}

RiPHPLib.isIE = function ()
{
	return	/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent) ;
}
