/*=======================================================
 * This is a set of functions that:
 *    beautify fields with a certain format and also can
 *    set or remove the corresponding error messages
 * unfortunatelly, this has to be in an ISML cause the .js files
 * are not beeing procxessed by the server sided software.
 =======================================================*/
 	/**
 	 * this is an abstract class defining all attributes expected by the
 	 * validation framework
 	 */
 	function Beautifier( fieldName )
 	{
		Beautifier.prototype.errorTexts;
		
		if ( typeof Beautifier.prototype.__bf_initialized == "undefined" )
		{
			Beautifier.prototype.ERROR_NO_ERROR =  0;
			// Beautifier.prototype.errorTexts     = new Array();
			// Beautifier.prototype.errorTexts[this.ERROR_NO_ERROR] = "";
	
			Beautifier.prototype.lastError = this.ERROR_NO_ERROR;

			Beautifier.prototype.fieldName = fieldName;
			
			/**
			 *  This function is required by the initiating framework.
			 *  Better might be a function "getField()"  or may be  
			 *  returning fieldName plus formName...
			 */
			Beautifier.prototype.getFieldName = function()
			{
				return this.args.fieldName;
			}
			
			// this method needs to be overwritten!
			// return new Array( beautitied Text, error number, args to format error msg );
			// example for Dates:
			// return new Array( "1/1/2008", DATE_FORMAT_DATE_TOO_BIG, new Array( "1/1/1980" ) );
			// This will result in an errormessage like:  "The date needs to be before 1/1/1980"
			Beautifier.prototype.formatText = function( rawData )
			{
				alert( "this function is not implemented yet!!!" );
			}
			
			/*
			 * The implementation of this is optional.  I intend to 
			 * call this method from the <form onsubmit>
			 */
			Beautifier.prototype.isSubmitable = function()
			{
				return this.lastError == this.ERROR_NO_ERROR;
			}
			
			Beautifier.prototype.__bf_initialized = true;
		}
 	}
	/**
	 * Ths function/class hold all required methods and attributes
	 * for ensuring the proper formatting of a date field.
	 * Some additional functions like trim() or parseInt() are myParseInt are required!
	 *  
	 * @param args      : structure like the following
	 * 			fieldName : mandatory: String : name of the field we are dealing with here
	 *          formatStr : mandatory: String : String representing the date format.  Currently only half fearted US supported
	 *          required  : optional : Boolean: makes the field required only if set to TRUE
	 *          min       : optional : Date   : earliest valid date; dates before than this will be marked errornous 
	 *          max       : optional : Date   : latest valid date; dates past this will be marked errornous 
	 */
	function DateFormatter( args )
	{
		Beautifier.call( this, args.fieldName );
		this.args = args;
		
		this.formatStr = args.formatStr;
		if ( typeof DateFormatter.prototype.__df_initialized == "undefined" )
		{
			DateFormatter.prototype.DATE_FORMAT_INVALID_FORMATTER =  1;
			DateFormatter.prototype.DATE_FORMAT_EXTRA_CHAR        =  2;
			DateFormatter.prototype.DATE_FORMAT_TOO_SHORT         =  3;
			DateFormatter.prototype.DATE_FORMAT_INVALID_DAY       =  4;
			DateFormatter.prototype.DATE_FORMAT_INVALID_MONTH     =  5;
			DateFormatter.prototype.DATE_FORMAT_INVALID_YEAR      =  6;
			DateFormatter.prototype.DATE_FORMAT_DATE_IN_PAST      =  7;
			DateFormatter.prototype.DATE_FORMAT_DATE_IN_FUTURE    =  8;
			DateFormatter.prototype.DATE_FORMAT_DATE_TOO_BIG      =  9;
			DateFormatter.prototype.DATE_FORMAT_DATE_TOO_SMALL    = 10;
			DateFormatter.prototype.DATE_FORMAT_MISSING_VALUE     = 11;
			
			//  This is the array witth error texts that is required buy the initiating
			//  framework.  The numbers must match the number returned by the formatText 
			//  function.
			DateFormatter.prototype.errorTexts     = new Array();
			this.errorTexts[this.DATE_FORMAT_INVALID_FORMATTER] = BeautifierErrorText["forms.profile.parseDateInvalidFormatString"];
			this.errorTexts[this.DATE_FORMAT_EXTRA_CHAR     ] = BeautifierErrorText["forms.profile.parseDateUseNumbersOnly"];
			this.errorTexts[this.DATE_FORMAT_TOO_SHORT      ] = BeautifierErrorText["forms.profile.forms.profile.parseDateTooShort"];
			this.errorTexts[this.DATE_FORMAT_INVALID_DAY    ] = BeautifierErrorText["forms.profile.forms.profile.parseDateInvalidDay"];
			this.errorTexts[this.DATE_FORMAT_INVALID_MONTH  ] = BeautifierErrorText["forms.profile.forms.profile.parseDateInvalidMonth"];
			this.errorTexts[this.DATE_FORMAT_INVALID_YEAR   ] = BeautifierErrorText["forms.profile.forms.profile.parseDateInvalidYear"];
			this.errorTexts[this.DATE_FORMAT_DATE_IN_PAST   ] = BeautifierErrorText["forms.profile.forms.profile.parseDateInPast"];
			this.errorTexts[this.DATE_FORMAT_DATE_IN_FUTURE ] = BeautifierErrorText["forms.profile.forms.profile.parseDateInFuture"];
			this.errorTexts[this.DATE_FORMAT_DATE_TOO_BIG   ] = BeautifierErrorText["forms.profile.forms.profile.parseDatePast"];
			this.errorTexts[this.DATE_FORMAT_DATE_TOO_SMALL ] = BeautifierErrorText["forms.profile.forms.profile.parseDateBefore"];
			this.errorTexts[this.DATE_FORMAT_MISSING_VALUE  ] = BeautifierErrorText["forms.profile.forms.profile.missingValue"];
			
			/**
			 * internal function, formats a date object basically to american format
			 */
			DateFormatter.prototype.__formatIt = function( dateObj, fmtArr )
			{
				var ret = "";
				for ( i = 0; i < fmtArr.length; i++ )
				{
					// there might be someone else making a difference between
					// uppdercase/ lowercase, but I'll ignore it here.
					switch ( fmtArr[i].charAt( 0 ) )
					{
						case 'D' :
						case 'd' :
							if ( fmtArr[i].length == 2 && dateObj.getDate() < 10 )
							{
								ret += "0" + dateObj.getDate();
							}
							else
							{
								ret += dateObj.getDate();
							}
							break;
						case 'M' :
						case 'm' :
							if ( fmtArr[i].length == 2 && dateObj.getMonth() < 9 )
							{
								ret += "0" + (1 + dateObj.getMonth());
							}
							else
							{
								ret += (1 + dateObj.getMonth());
							}
							break;
						case 'Y' :
						case 'y' :
							if ( fmtArr[i].length == 2 )
							{
								ret += new String( dateObj.getFullYear() ).substring( 2 );
							}
							else
							{
								ret += dateObj.getFullYear();
							}
					}
					ret += '/';
				}
				return ret.substring( 0, ret.length - 1 );
			}
			
			/**
			 * the missing value is captured from the backend
			 */
			DateFormatter.prototype.isSubmitable = function()
			{
				return this.lastError == this.ERROR_NO_ERROR || this.lastError == this.DATE_FORMAT_MISSING_VALUE;
			}

			/**
			 * This beautify function is required by the initiating framework.
			 * It takes a String and formats it and returns the beautified string.
			 * 
			 * The return value is actually an array {beautified value, error no, array of format message arguments}
			 *  the error no must have a corresponding entry in the error texts
			 */
			DateFormatter.prototype.formatText = function( rawData )
			{
				var retArr;
				this.lastError = this.ERROR_NO_ERROR;
				
				if ( (rawData = trim( rawData )).length > 0 )
				{ 
					/*
					var format = args.formatStr;
					if ( format == null )
					{
						if ( (format=args[0]) == null )
						{
							return new Array ( rawData, this.lastError = this.DATE_FORMAT_INVALID_FORMATTER );
						}
					}
					*/
					format = this.formatStr;
					/*
					// This is a very simple arser working only on date and not time!
					// expecting only mdyM
					
					for ( i = 0; i < format.length; i++ )
					{
						
						if ( 
					}
					*/
					
					// this is even simplier:  just US format
					var startFormat = 0;
					var startVal = 0;
					var day;
					var month;
					var year;
					var fmtSplits = [];
					while ( startFormat >= 0 )
					{
						var indexFormat = format.indexOf( "/", startFormat );
						// this only works for the simplification
						if ( indexFormat == -1 )
						{
							var tokenFormat = format.substring( startFormat );
						}
						else
						{
							var tokenFormat = format.substring( startFormat, indexFormat );
						}
						
						if ( indexFormat == -1 )
						{
							// if the format does not have any more delimeter take here also all the rest 
							var tokenVal = rawData.substring( startVal );
						}
						else
						{
							var indexVal = rawData.indexOf( "/", startVal );
							if ( indexVal == -1 )
							{
								return new Array( rawData, this.lastError = this.DATE_FORMAT_TOO_SHORT );
							}
							var tokenVal = rawData.substring( startVal, indexVal );
						}
						
						if ( (tokenVal = trim( tokenVal ) ).length == 0 )
						{
							return new Array ( rawData, this.lastError = this.DATE_FORMAT_TOO_SHORT ); 
						}
						
						// now try to convert the string into a number and assign it to the variables
						var val;
						try
						{
							// this parseInt is not the gratest!
							val = myParseInt( tokenVal );
							switch ( tokenFormat.charAt( 0 ) )
							{
								case 'D' :
								case 'd' :
									day = val;
									fmtSplits[fmtSplits.length] = tokenFormat;
									break;
								case 'M' :
								case 'm' :
									month = val;
									fmtSplits[fmtSplits.length] = tokenFormat;
									break;
								case 'Y' :
								case 'y' :
									year = val;
									fmtSplits[fmtSplits.length] = tokenFormat;
									break;
								default:
									// alert( "tokenizing the format string showed: " + tokenFormat.charAt( 0 ) );
									return new Array( rawData, this.lastError = this.DATE_FORMAT_INVALID_FORMATTER );
							}
						}
						catch (ex )
						{
							switch ( tokenFormat.charAt( 0 ) )
							{
								case 'D' :
								case 'd' :
									return new Array( rawData, this.lastError = this.DATE_FORMAT_EXTRA_CHAR );
								case 'M' :
								case 'm' :
									return new Array( rawData, this.lastError = this.DATE_FORMAT_EXTRA_CHAR );
								case 'Y' :
								case 'y' :
									return new Array( rawData, this.lastError = this.DATE_FORMAT_EXTRA_CHAR );
								default:
									// alert( "what happened" + tokenFormat.charAt( 0 ) );
									return new Array( rawData, this.lastError = 99 );
							}
						}
						startFormat = indexFormat + (indexFormat == -1 ? 0 : 1);
						startVal = indexVal + 1;
					}
					// so now here we should have technical correct three digits!
					if ( month < 1 || month > 12 )
					{
						return new Array( rawData, this.lastError = this.DATE_FORMAT_INVALID_MONTH ); 
					}
					// now find out how many days there are in this month/year
					// get a date object that points to the 1st of next month at midnight
					var date = new Date( year, month, 1, 0, 0, 0 );
					date.setTime( date.getTime() - (1000 * 60 * 60 ) );
					if ( day < 0 || day > date.getDate() )
					{
						return new Array( rawData, this.lastError = this.DATE_FORMAT_INVALID_DAY, new Array( new String( date.getDate() ) ) ); 
					}
					
					var wasLess100 = false;
					if ( year < 100 )
					{
						wasLess100 = true;
						// when the user specifies only as two digits year, lets
						// assume it is either up to five years in the furture 
						// or it is 95 in the past.  
						year += 1900;
						if ( year + 95 < new Date().getFullYear() )
						{
							year += 100;
						}
					}
					else
					{
						// no one will specify never ever a date before this!!!!
						if ( year < 1900 )
						{
							return new Array( rawData, this.lastError = this.DATE_FORMAT_INVALID_YEAR );
						}
					}
					
					// alright, looke like we have a vaild date.  Now see if it it in the range
					// if we have a range error we keep going.  We have a proper Date,
					// it just doesn't match the min/max date
					if ( 'min' in this.args && new Date( year, month, day, 24, 0, 0 ).getTime() < this.args.min.getTime() )
					{
						this.lastError = this.DATE_FORMAT_DATE_TOO_SMALL;
						retArr = [this.__formatIt( this.args.min, fmtSplits )];
					}
	
					date = new Date( year, month - 1, day, 0, 0, 0 );
					if ( (this.lastError == this.ERROR_NO_ERROR) && ('max' in this.args) )
					{
						if ( date.getTime() > this.args.max.getTime() )
						{
							if ( wasLess100 )
							{
								date.setYear( date.getFullYear() - 100 );
							}
							if ( date.getTime() > this.args.max.getTime() )
							{
								this.lastError = this.DATE_FORMAT_DATE_TOO_BIG;
								retArr = [this.__formatIt( this.args.max, fmtSplits )];
							}
						}
					}
					// I can't think of anything else to nag about, let's format it nicely
					rawData = this.__formatIt( date, fmtSplits );
				}
				if ( rawData == "" && this.args.required )
				{
					this.lastError = this.DATE_FORMAT_MISSING_VALUE;
				}
				return new Array( rawData, this.lastError, retArr );
			}

			DateFormatter.prototype.__df_initialized = null;
		}
	}
	
	DateFormatter.prototype = new Beautifier();
	
	
	
/*=======================================================
 *  this function ensures that, incase the user name gets changed in 
 *  edit profile that the password is required too.
 *=======================================================*/
	/*****
	 * args.fieldName    : String : mandatory: FieldName where this validator works on
	 * args.originalName : String : mandatory: initial value of the field
	 * args.required     : Boolean: optional:  flag if this field is a must (here mot likely always true)
	 * args.ignoreCase   : Boolean: optional:  flag if the username is to be treated case sensetive or insensetive
	 * args.callBack     : function : optional:  called after the validation completed
	 * args.illegal      : String : optional:   String with not allowed characters.  Default: "*'?+"<>"
	 * args.minLength    : Number : optional:   minimum string length of the value.  Defaukt: 5
	 * args.maxLength    : Number : optional:   maximum string length of the value.  Defaukt: 322
	 */
	function UserNameMonitor( args )
	{
		Beautifier.call( this, args.fieldName );

		this.args = args;
		this.ignoreCase = new Boolean( this.args.ignoreCase );

		this.originalName = (this.ignoreCase ?  this.args.originalName.toLowerCase() : this.args.originalName );

		this.illegal = "*'?+\"<>";
		if ( "illegal" in args )
		{
			this.illeagal = args.illegal;
		}
		
		this.minLength = 5;
		if ( "minLength" in args && typeof args.minLength == "Number" )
		{
			this.minLength = args.minLength;
		}

		this.maxLength = 322;
		if ( "maxLength" in args && typeof args.maxLength == "Number" )
		{
			this.maxLength = args.maxLength;
		}
		
		if ( typeof UserNameMonitor.prototype.__unm_initializer == "undefined" )
		{
			//  This is the array witth error texts that is required buy the initiating
			//  framework.  The numbers must match the number returned by the formatText 
			//  function.
			UserNameMonitor.prototype.ERROR_MISSING_VALUE = 1;
			UserNameMonitor.prototype.ERROR_USER_NAME_CHANGED = 2;
			UserNameMonitor.prototype.ERROR_ILLEGAL_CHAR  = 3;
			UserNameMonitor.prototype.ERROR_TOO_LONG      = 4;
			UserNameMonitor.prototype.ERROR_TOO_SHORT     = 5;
		
			UserNameMonitor.prototype.errorTexts     = new Array();
			this.errorTexts[this.ERROR_MISSING_VALUE    ] = BeautifierErrorText["forms.profile.missUserName"];
			this.errorTexts[this.ERROR_USER_NAME_CHANGED] = BeautifierErrorText["forms.profile.reenterPwd"];
			this.errorTexts[this.ERROR_ILLEGAL_CHAR     ] = BeautifierErrorText["forms.profile.userNameIllegalCharacter"];
			this.errorTexts[this.ERROR_TOO_LONG         ] = BeautifierErrorText["forms.profile.userNameIsTooLong"];
			this.errorTexts[this.ERROR_TOO_SHORT        ] = BeautifierErrorText["forms.profile.userNameIsTooShort"];
			
			/**
			 * length errors will be captured from the backend
			 */
			UserNameMonitor.prototype.isSubmitable = function()
			{
				return this.lastError != this.ERROR_ILLEGAL_CHAR;
				// this.lastError == this.ERROR_NO_ERROR || this.lastError == this.DATE_FORMAT_MISSING_VALUE;
			}

			/**
			 * This beautify function is required by the initiating framework.
			 * It takes a String and formats it and returns the beautified string.
			 * 
			 * The return value is actually an array {beautified value, error no, array of format message arguments}
			 *  the error no must have a corresponding entry in the error texts
			 */
			UserNameMonitor.prototype.formatText = function( rawData )
			{
				var errArgs = null;
				this.lastError = this.ERROR_NO_ERROR;
				
				if ( (rawData = trim( rawData )).length == 0 )
				{
					if ( this.args.required )
					{
						error = this.ERROR_MISSING_VALUE;
					}
				}
				else
				{
					if ( this.ignoreCase )
					{
						rawData = rawData.toLowerCase();
					}
					for ( var i =  0; i < rawData.length; i++ )
					{
						if ( this.illegal.indexOf( rawData.charAt( i ) ) > -1 )
						{
							this.lastError = this.ERROR_ILLEGAL_CHAR;
							errArgs = [rawData.charAt( i )];
							break;
						}
					}
					if ( this.lastError == this.ERROR_NO_ERROR && rawData.length < this.minLength )
					{
						errArgs = [this.minLength];
						this.lastError = this.ERROR_TOO_SHORT;
					}
					if ( this.lastError == this.ERROR_NO_ERROR && rawData.length > this.maxLength )
					{
						errArgs = [this.maxLength];
						this.lastError = this.ERROR_TOO_LONG;
					}
					if ( this.lastError == this.ERROR_NO_ERROR && this.originalName != rawData )
					{
						this.lastError = this.ERROR_USER_NAME_CHANGED;
					}
				}
				
				if ( 'callBack' in this.args )
				{
					this.args.callBack( rawData, this.lastError, this );
				}
				return new Array( rawData, this.lastError, errArgs );
			}
			
			UserNameMonitor.prototype.__unm_initializer = true;
		}
	}

	UserNameMonitor.prototype = new Beautifier();

/*=======================================================
 * This is a the beautification framework:
 =======================================================*/
	/*
	 * This function used by the validation framework to show or hide 
	 * the error text error treatment, detailing the HTML persentation
	 * Setting the label to read and showing error texts
	 */
	function handleIsInputFieldErrors( fieldName, errorNo, errorText )
	{
		field = document.getElementById( "Label_" + fieldName );
		if ( field != null )
		{
			if ( errorNo == 0 )
			{
				field.className = "";
			}
			else
			{
				field.className = "warning";
			}
		}
		field = document.getElementById( "Error_" + fieldName );
		if ( field != null )
		{
			if ( errorNo == 0 )
			{
				field.style.display = "none";
			}
			else
			{
				field.style.display = "";
				field.innerHTML = errorText;
			}
		}
	}
	
	/**
	 * this function does all the initialization for a field with a beautifier...
	 *  The only agument is an object with the following requirement:
	 *    String getFieldName()
	 *    Object[] formatText( String rawText )
	 *        ret[0]:  mandatory: String: beautified text
	 *        ret[1]:  mandatory: Number: error number
	 *        ret[2]:  optional : array of objects used for messages with {n}
	 *   errorTexts:  array of String holding the error texts.  The error # must match the array index. 
	 */
	function beautifyField( beautifier )
	{
		var field;
		
		field = document.getElementsByName( beautifier.getFieldName() );
			
		if ( field != null && field.length == 0 )
		{
			field == null;
		}
		else
		{
			field = field[0];
		}
		/*
		if ( typeof fieldName == 'string' )
		{
			field = document.getElementsByName( fieldName );
				
			if ( field != null && field.length == 0 )
			{
				field == null;
			}
			else
			{
				field = field[0];
			}
		}
		else
		{
			if ( typeof fieldName == 'object' )  // this is in case the user provices the whole field!
			{
				field = fieldName;
			}
		}
		*/
		if ( field != null )
		{
			field.onblur = function( event )
					{
						try
						{
							var ret = beautifier.formatText( field.value );
							field.value = ret[0];
							
							var errTxt = beautifier.errorTexts[ret[1]];
							if ( ret.length > 2 && ret[2] != null )
							{
								errTxt = formatMessage( errTxt, ret[2] );
							}
							handleIsInputFieldErrors( beautifier.getFieldName() , ret[1], errTxt ); 
						}
						catch ( ex )
						{
							handleIsInputFieldErrors( beautifier.getFieldName(), 99, "Error processing the JavaScript validation!" ); 
						}
					};
			field.value = beautifier.formatText( field.value )[0];
		}
	}
	
	function runBeautifier( beautifier )
	{
		var field;
		
		field = document.getElementsByName( beautifier.getFieldName() );
			
		if ( field != null && field.length == 0 )
		{
			field == null;
		}
		else
		{
			field = field[0];
		}
		if ( field != null )
		{
			field.onblur();
		}
	}
	
	
	var __listOfValidator = new Array()
	
	function addValidator( validator )
	{
		if ( __listOfValidator == null )
			__listOfValidator = new Array();
		__listOfValidator[__listOfValidator.length] = validator;
	}
	
	/*
	 *  this function allows submitting only with proper values
	 */
	function isSubmitable( )
	{
		var ret = true;
		if ( __listOfValidator != null )
		{
			for ( var i = 0; i < __listOfValidator.length; i++ )
			{
				// this is just to make sure we executed the validation
				// with error high beautifier once
				runBeautifier( __listOfValidator[i] );
				
				ret = ret && __listOfValidator[i].isSubmitable() ;
				// alert( i + "  " + __listOfValidator[i].lastError + "   " + ret );
			}
		}
		return ret;
	}
