ValidatorAbstract.VALIDATION_STATE_DEFAULT = 0;
ValidatorAbstract.VALIDATION_STATE_SUCCESS = 1;
ValidatorAbstract.VALIDATION_STATE_FAILED = 2;

ValidatorAbstract.VALIDATION_STATE_TOSHORT = 3;
ValidatorAbstract.VALIDATION_STATE_TOLONG = 4;

ValidatorAbstract.VALIDATION_STATE_NOTANUMBER = 5;
ValidatorAbstract.VALIDATION_STATE_TOLOW = 6;
ValidatorAbstract.VALIDATION_STATE_TOBIG = 7;

ValidatorAbstract.VALIDATION_STATE_OUTOFRANGE = 8;

ValidatorAbstract.VALIDATION_STATE_REGEXP_FAILED = 9;
ValidatorAbstract.VALIDATION_STATE_EMAIL_INVALID = 10;

ValidatorAbstract.VALIDATION_STATE_DATERANGE_INVALID_ORDER = 11;
ValidatorAbstract.VALIDATION_STATE_DATERANGE_DISTANCE = 12;

ValidatorAbstract.VALIDATION_STATE_VALUE_MISMATCH = 13;

function ValidatorAbstract( formEntity ) {
	if ( arguments.length > 0 ) {
		this.init( formEntity );
    }
};
ValidatorAbstract.prototype.init = function( formEntity ) {
	this.formEntity =  formEntity;
	this.validationState = ValidatorAbstract.VALIDATION_STATE_DEFAULT;
	this.validationMessage = "";
};
ValidatorAbstract.prototype.getFormEntity = function() {
    return this.formEntity;
};
ValidatorAbstract.prototype.getValidationState = function() {
    return this.validationState;
};
ValidatorAbstract.prototype.setValidationState = function( state ) {
    this.validationState = state;
};
ValidatorAbstract.prototype.setValidationMessage = function(msg) {
    this.validationMessage = msg;
};
ValidatorAbstract.prototype.getValidationMessage = function() {
    return this.validationMessage;
};
ValidatorAbstract.prototype.validate = function() {
	return true;
};

ValidatorComposite.prototype = new ValidatorAbstract();
ValidatorComposite.prototype.constructor = ValidatorComposite;
ValidatorComposite.superclass = ValidatorAbstract.prototype;

function ValidatorComposite( formObjectsArray, validateAllElements ) {
	if ( arguments.length > 0 ) {
        this.formObjectArray = new Array(0);
        this.validFormObjects = new Array(0);
        this.invalidFormObjects = new Array(0);
        this.init( formObjectsArray, validateAllElements );
	}
};

ValidatorComposite.prototype.init = function( formObjectsArray, validateAllElements ) {

	ValidatorComposite.superclass.init.call( this, null );

    this.formObjectArray = new Array(0);
    this.validFormObjects = new Array(0);
    this.invalidFormObjects = new Array(0);

	this.validateAllElements = validateAllElements;

    for( var n = 0; formObjectsArray != null && n < formObjectsArray.length; n++ ) {
        var nextFormObject = formObjectsArray[n];
        this.addFormObject( nextFormObject );
    }
};
ValidatorComposite.prototype.getFormObjects = function() {
    if( this.formObjectArray == null ) {
        this.formObjectArray = new Array();
    }
    return this.formObjectArray;
};
ValidatorComposite.prototype.getValidFormObjects = function() {
    return this.validFormObjects;
};
ValidatorComposite.prototype.getInvalidFormObjects = function() {
    return this.invalidFormObjects;
};

ValidatorComposite.prototype.isFullValidation = function() {
    return this.validateAllElements;
};
ValidatorComposite.prototype.addFormObject = function( formObject ) {
	if( formObject != null ) {
		this.formObjectArray.push( formObject );
	}
};
ValidatorComposite.prototype.validate = function() {

	var verificationState = true;

    var stateCode = ValidatorAbstract.VALIDATION_STATE_DEFAULT;
    var stateMsg = "";

    // reset last validation data
    this.validFormObjects = new Array(0);
    this.invalidFormObjects = new Array(0);

    var invalidDataSet = false;


	for( var n = 0; n < this.getFormObjects().length && (verificationState == true || this.isFullValidation() ); n++ ) {

		var nextFormObject = this.getFormObjects()[n];

		var nextValid = nextFormObject.validate();

		if( nextValid == false ) {
		    verificationState = false;
		    this.invalidFormObjects.push( nextFormObject );

		    // set first validated formObjects state if it was invalid
		    if( invalidDataSet == false ) {
                stateCode = nextFormObject.getValidationState();
                stateMsg = nextFormObject.getValidationMessage();
                this.formEntity = nextFormObject.formEntity;
                invalidDataSet = true;
            }

		} else {
		    this.validFormObjects.push( nextFormObject );
		}

	}


    ValidatorComposite.superclass.setValidationState.call( this, stateCode );
    ValidatorComposite.superclass.setValidationMessage.call( this, stateMsg );

	return verificationState;
};

ValidatorText.prototype = new ValidatorAbstract();
ValidatorText.prototype.constructor = ValidatorText;
ValidatorText.superclass = ValidatorAbstract.prototype;

function ValidatorText( formEntity ) {
	if ( arguments.length > 0 ) {
        this.init( formEntity, 0, 0 );
	}
};

function ValidatorText( formEntity, minLength, maxLength ) {
	if ( arguments.length > 0 ) {
        this.init( formEntity, minLength, maxLength );
	}
};
ValidatorText.prototype.init = function( formEntity, minLength, maxLength ) {
	ValidatorText.superclass.init.call( this, formEntity );
	if( minLength > maxLength ) {
	    this.minimumTextLength = maxLength;
	    this.maximumTextLength = minLength;
	}
	else {
	    this.minimumTextLength = minLength;
	    this.maximumTextLength = maxLength;
	}
};

ValidatorText.prototype.hasMandatoryVerificationLength = function() {
	return this.maximumTextLength > 0 || this.minimumTextLength > 0 ;
};
ValidatorText.prototype.hasMinimumLength = function() {
    return this.minimumTextLength > 0;
};
ValidatorText.prototype.hasMaximumLength = function() {
    return this.maximumTextLength > 0;
};
ValidatorText.prototype.getMaximumTextLength = function() {
    return this.maximumTextLength;
};
ValidatorText.prototype.getMinimumTextLength = function() {
    return this.minimumTextLength;
};


ValidatorText.prototype.validate = function() {
    var verificationState = false;

    var stateCode = ValidatorAbstract.VALIDATION_STATE_DEFAULT;
    var stateMsg = "";

    if( this.hasMandatoryVerificationLength() ) {

        var selectedValue = this.formEntity.getSelectedValue();
        if( selectedValue == null ) {
            selectedValue = "";
        }

        //alert( "name[" + this.formEntity.getName() + "] value[" + selectedValue +" ]");

        if( this.hasMinimumLength() && selectedValue.length < this.getMinimumTextLength() ) {
            stateCode = ValidatorAbstract.VALIDATION_STATE_TOSHORT;
            stateMsg = "text to short";
            verificationState = false;
        }
        else
        if( this.hasMaximumLength() && selectedValue.length > this.getMaximumTextLength() ) {
            stateCode = ValidatorAbstract.VALIDATION_STATE_TOLONG;
            stateMsg = "text to long";
            verificationState = false;
        }
        else
        {
            verificationState = true;
            stateCode = ValidatorAbstract.VALIDATION_STATE_SUCCESS;
            stateMsg = "ok";
        }
    }
    else
    {
        stateCode = ValidatorAbstract.VALIDATION_STATE_SUCCESS;
        stateMsg = "ok";
        verificationState = true;
    }

    ValidatorText.superclass.setValidationState.call( this, stateCode );
    ValidatorText.superclass.setValidationMessage.call( this, stateMsg );

    return verificationState;
};


ValidatorRegExp.prototype = new ValidatorText();
ValidatorRegExp.prototype.constructor = ValidatorRegExp;
ValidatorRegExp.superclass = ValidatorText.prototype;

function ValidatorRegExp( formEntity, minLength, maxLength, regExpString ) {
    if ( arguments.length > 0 ) {
        this.init( formEntity, minLength, maxLength, regExpString);
    }
};
function ValidatorRegExp( formEntity, regExpString ) {
    if ( arguments.length > 0 ) {
        this.init( formEntity, 0, 0, regExpString);
    }
};

ValidatorRegExp.prototype.init = function( formEntity, minLength, maxLength, regExpString ) {
	ValidatorRegExp.superclass.init.call( this, formEntity, minLength, maxLength );

	// asume its really a string
	if( regExpString != null && regExpString.length > 0 ) {
        this.regExp = new RegExp( regExpString );
	} else {
	    this.regExp = null;//new RegExp( "" );
	}
};

ValidatorRegExp.prototype.getRegularExpression = function() {
    return this.regExp;
};

ValidatorRegExp.prototype.validate = function() {
    var verificationState = ValidatorRegExp.superclass.validate.call( this );

    if( verificationState == true && this.regExp != null ) {

        var stateCode = ValidatorAbstract.VALIDATION_STATE_DEFAULT;
        var stateMsg = "";

        var selectedValue = this.formEntity.getSelectedValue();
        if( selectedValue == null ) {
            selectedValue = "";
        }

        if( this.regExp.test( selectedValue ) == false ) {
            stateCode = ValidatorAbstract.VALIDATION_STATE_REGEXP_FAILED;
            stateMessage = "text does not match pattern";
            verificationState = false;
        } else {
            stateCode = ValidatorAbstract.VALIDATION_STATE_SUCCESS;
            stateMsg = "";
            verificationState = true;
        }

        ValidatorRegExp.superclass.setValidationState.call( this, stateCode );
        ValidatorRegExp.superclass.setValidationMessage.call( this, stateMsg );

    }

    return verificationState;
};


ValidatorNumber.prototype = new ValidatorText();
ValidatorNumber.prototype.constructor = ValidatorNumber;
ValidatorNumber.superclass = ValidatorText.prototype;


function ValidatorNumber( formEntity ) {
    if( arguments.length > 0 ) {
        this.init( formEntity, -Infinity, Infinity, 0, 0 );
    }
};
function ValidatorNumber( formEntity, minValue, maxValue, minDigits, maxDigits ) {
	if ( arguments.length > 0 ) {
        this.init( formEntity, minValue, maxValue, minDigits, maxDigits );
	}
};

ValidatorNumber.prototype.init = function( formEntity, minValue, maxValue, minDigits, maxDigits ) {
    ValidatorNumber.superclass.init.call( this, formEntity, minDigits, maxDigits );
    this.minimumValue = minValue;
    this.maximumValue = maxValue;
};

ValidatorNumber.prototype.hasUpperBoundary = function() {
    return this.maximumValue != Infinity;
};
ValidatorNumber.prototype.hasLowerBoundary = function() {
    return this.minimumValue != -Infinity;
};

ValidatorNumber.prototype.isNumber = function( numberValue ) {
    return !isNaN( parseInt( numberValue ) );
};

ValidatorNumber.prototype.validate = function() {
    var verificationState = ValidatorNumber.superclass.validate.call( this );

    if( verificationState == true ) {

        var stateCode = ValidatorAbstract.VALIDATION_STATE_DEFAULT;
        var stateMsg = "";

        var selectedValue = this.formEntity.getSelectedValue();
        if( this.isNumber( selectedValue ) ) {

            var valueAsNumber = parseInt( selectedValue );
            this.formEntity.setSelectedValue( valueAsNumber );
            if( this.hasLowerBoundary() && valueAsNumber < this.minimumValue ) {
                stateCode = ValidatorAbstract.VALIDATION_STATE_TOLOW;
                stateMsg = "number to low";
                verificationState = false;
            }
            else
            if( this.hasUpperBoundary() && valueAsNumber > this.maximumValue ) {
                stateCode = ValidatorAbstract.VALIDATION_STATE_TOBIG;
                stateMsg = "number to big";
                verificationState = false;
            }
            else
            {
                stateCode = ValidatorAbstract.VALIDATION_STATE_SUCCESS;
                stateMsg = "ok";
                verificationState = true;
            }

        } else {
            stateCode = ValidatorAbstract.VALIDATION_STATE_NOTANUMBER;
            stateMsg = "not a number";
            verificationState = false;
        }

        ValidatorNumber.superclass.setValidationState.call( this, stateCode );
        ValidatorNumber.superclass.setValidationMessage.call( this, stateMsg );

    }

    return verificationState;
};

ValidatorEMail.MINIMUM_LENGTH = 5;
ValidatorEMail.MAXIMUM_LENGTH = 64;
ValidatorEMail.MAIL_REGEXP = "^[_a-zA-Z0-9-]+(\\.[_a-zA-Z0-9-]+)*@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*\\.(([0-9]{1,3})|([a-zA-Z]{2,3})|(aero|coop|info|museum|name))$";
ValidatorEMail.prototype = new ValidatorRegExp();
ValidatorEMail.prototype.constructor = ValidatorEMail;
ValidatorEMail.superclass = ValidatorRegExp.prototype;

function ValidatorEMail( formEntity ) {
    if ( arguments.length > 0 ) {
        this.init( formEntity );
    }
};

ValidatorEMail.prototype.init = function( formEntity ) {
	ValidatorEMail.superclass.init.call( this, formEntity, ValidatorEMail.MINIMUM_LENGTH, ValidatorEMail.MAXIMUM_LENGTH, ValidatorEMail.MAIL_REGEXP  );
};


ValidatorEMail.prototype.validate = function() {
    var verificationState = ValidatorEMail.superclass.validate.call( this );

    if( verificationState == true ) {
        // the current used regexp does not properly check for '@'
        var selectedValue = this.formEntity.getSelectedValue();
        if( selectedValue.indexOf( "@" ) == -1 ) {
            verificationState = false;
        }
    }

    if( verificationState == false ) {
        ValidatorEMail.superclass.setValidationState.call( this, ValidatorAbstract.VALIDATION_STATE_EMAIL_INVALID );
        ValidatorEMail.superclass.setValidationMessage.call( this, "invalid email" );
    }
    return verificationState;
};

ValidatorEqualNodeValue.prototype = new ValidatorAbstract();
ValidatorEqualNodeValue.prototype.constructor = ValidatorEqualNodeValue;
ValidatorEqualNodeValue.superclass = ValidatorAbstract.prototype;

function ValidatorEqualNodeValue( formEntity ) {
	if ( arguments.length > 0 ) {
        this.init( formEntity, formEntity );
	}
};

function ValidatorEqualNodeValue( formEntity, formEntityComparable ) {
	if ( arguments.length > 0 ) {
        this.init( formEntity, formEntityComparable );
	}
};
ValidatorEqualNodeValue.prototype.init = function( formEntity, formEntityComparable ) {
	ValidatorEqualNodeValue.superclass.init.call( this, formEntity );
    this.formEntityComparable = formEntityComparable;
};

ValidatorEqualNodeValue.prototype.getFormEntitiyToCompareTo = function() {
	return this.formEntityComparable;
};


ValidatorEqualNodeValue.prototype.validate = function() {
    var verificationState = false;

    var stateCode = ValidatorAbstract.VALIDATION_STATE_DEFAULT;
    var stateMsg = "";

    if( this.formEntityComparable != null ) {

        var selectedValue = this.formEntity.getSelectedValue();
        if( selectedValue == null ) {
            selectedValue = "";
        }
        var comparableSelectedValue = this.formEntityComparable.getSelectedValue();

        if( selectedValue == comparableSelectedValue ) {
            stateCode = ValidatorAbstract.VALIDATION_STATE_SUCCESS;
            stateMsg = "ok";
            verificationState = true;
        } else {
            stateCode = ValidatorAbstract.VALIDATION_STATE_VALUE_MISMATCH;
            stateMsg = "value mismatch";
            verificationState = false;
        }
    }
    else
    {
        stateCode = ValidatorAbstract.VALIDATION_STATE_SUCCESS;
        stateMsg = "ok";
        verificationState = true;
    }

    ValidatorEqualNodeValue.superclass.setValidationState.call( this, stateCode );
    ValidatorEqualNodeValue.superclass.setValidationMessage.call( this, stateMsg );

    return verificationState;
};


ValidatorDateAbstract.prototype = new ValidatorAbstract();
ValidatorDateAbstract.prototype.constructor = ValidatorDateAbstract;
ValidatorDateAbstract.superclass = ValidatorAbstract.prototype;

function ValidatorDateAbstract( formEntity, fromDate, toDate, monthCorrection ) {
    if ( arguments.length > 0 ) {
        this.init( formEntity, fromDate, toDate, monthCorrection );
    }
};

ValidatorDateAbstract.prototype.init = function( formEntity, fromDate, toDate, monthCorrection) {
    ValidatorDateAbstract.superclass.init.call( this, formEntity );
    if( fromDate != null ) {
	fromDate.setHours( 0 ); fromDate.setMinutes( 0 ); fromDate.setSeconds( 0 ); fromDate.setMilliseconds( 0 );
    }
    if( toDate != null ) {
	tDate.setHours( 23 ); to.setMinutes( 59 ); toDate.setSeconds( 59 ); toDate.setMilliseconds( 999 );
    }
    this.dateBoundary = new DateRange( fromDate, toDate );
    this.actualDate = new Date();
    this.monthCorrection = monthCorrection;
};


ValidatorDateAbstract.prototype.getDay = function() {
    return this.actualDate.getDate();
};
ValidatorDateAbstract.prototype.setDay = function( day ) {
    this.actualDate.setDate( day );
};
ValidatorDateAbstract.prototype.getMonth = function() {
    return this.actualDate.getMonth(); // - this.monthCorrection ;
};
ValidatorDateAbstract.prototype.setMonth = function( month ) {
    this.actualDate.setMonth( month ); //parseInt( month ) )+ this.monthCorrection );
};
ValidatorDateAbstract.prototype.getYear = function() {
    return this.actualDate.getFullYear();
};
ValidatorDateAbstract.prototype.setYear = function( year ) {
    this.actualDate.setFullYear( year );
};
ValidatorDateAbstract.prototype.getActualDate = function() {
    return this.actualDate;
};

ValidatorDateAbstract.prototype.getActualDate = function() {
    return this.actualDate;
}



ValidatorDateAbstract.prototype.validate = function() {
    var verificationState = false;

    var stateCode = ValidatorAbstract.VALIDATION_STATE_DEFAULT;
    var stateMsg = "";

    if( this.dateBoundary.isInRange( this.getActualDate() ) == false ) {

        stateCode = ValidatorAbstract.VALIDATION_STATE_OUTOFRANGE;
        stateMsg = "date out of range";
        verificationState = false;

    } else {
        stateCode = ValidatorAbstract.VALIDATION_STATE_SUCCESS;
        stateMsg = "ok";
        verificationState = true;
    }

    ValidatorDateAbstract.superclass.setValidationState.call( this, stateCode );
    ValidatorDateAbstract.superclass.setValidationMessage.call( this, stateMsg );

    return verificationState;
};


ValidatorDateMulti.prototype = new ValidatorDateAbstract();
ValidatorDateMulti.prototype.constructor = ValidatorDateMulti;
ValidatorDateMulti.superclass = ValidatorDateAbstract.prototype;

function ValidatorDateMulti( dayEntity, monthEntity, yearEntity, fromDate, toDate, monthCorrection ) {
    if ( arguments.length > 0 ) {
        this.init( dayEntity, monthEntity, yearEntity, fromDate, toDate, monthCorrection );
    }
};

ValidatorDateMulti.prototype.init = function( dayEntity, monthEntity, yearEntity, fromDate, toDate, monthCorrection) {
    ValidatorDateMulti.superclass.init.call( this, null, fromDate, toDate, monthCorrection );
    this.dayEntity = dayEntity;
    this.monthEntity = monthEntity;
    this.yearEntity = yearEntity;
    this.datePropertiesValidator = new ValidatorComposite( new Array( this.yearEntity, this.monthEntity, this.yearEntity ), true ) ;
};


ValidatorDateMulti.prototype.validate = function() {
    var verificationState = false;

    /*if( this.datePropertiesValidator.validate() == false ) {

        verificationState = false;
        ValidatorDateMulti.superclass.setValidationState.call( this, datePropertiesValidator.getValidationState() );
        ValidatorDateMulti.superclass.setValidationMessage.call( this, datePropertiesValidator.getValidationMessage() );

    }
    else*/ {
	this.actualDate = new Date( parseInt( this.yearEntity.getSelectedValue() ), parseInt( this.monthEntity.getSelectedValue() ) + this.monthCorrection , parseInt( this.dayEntity.getSelectedValue() ) );
        //this.setYear( this.yearEntity.getSelectedValue() );
        //this.setMonth( this.monthEntity.getSelectedValue() );
        //this.setDay( this.dayEntity.getSelectedValue() );
        verificationState = ValidatorDateMulti.superclass.validate.call( this );
    }

    return verificationState;
};


ValidatorDateRange.prototype = new ValidatorComposite();
ValidatorDateRange.prototype.constructor = ValidatorDateRange;
ValidatorDateRange.superclass = ValidatorComposite.prototype;

function ValidatorDateRange( fromDateValidator, toDateValidator ) {
    if ( arguments.length > 0 ) {
        this.init( fromDateValidator, toDateValidator );
    }
};

ValidatorDateRange.prototype.init = function( fromDateValidator, toDateValidator ) {
    ValidatorDateRange.superclass.init.call( this, new Array( fromDateValidator, toDateValidator ), false );

    this.fromDateValid = fromDateValidator;
    this.toDateValid = toDateValidator;

};

ValidatorDateRange.prototype.getAsDateRange = function() {
    return new DateRange( this.fromDateValid.getActualDate() , this.toDateValid.getActualDate() );
};

ValidatorDateRange.prototype.validate = function() {

    var verificationState = ValidatorDateRange.superclass.validate.call( this );

    if( verificationState == true ) {

        if( this.fromDateValid.actualDate.getTime() > this.toDateValid.actualDate.getTime() ) {

            var stateCode = ValidatorAbstract.VALIDATION_STATE_DATERANGE_INVALID;
            var stateMsg = "invalid daterange composition";

            ValidatorDateRange.superclass.setValidationState.call( this, stateCode );
            ValidatorDateRange.superclass.setValidationMessage.call( this, stateMsg );
            verificationState = false;

        }

    }

    return verificationState;
};

ValidatorDateRangeDuration.prototype = new ValidatorDateRange();
ValidatorDateRangeDuration.prototype.constructor = ValidatorDateRangeDuration;
ValidatorDateRangeDuration.superclass = ValidatorDateRange.prototype;

function ValidatorDateRangeDuration( fromDateValidator, toDateValidator, durationValidator ) {
    if ( arguments.length > 0 ) {
        this.init( fromDateValidator, toDateValidator, durationValidator );
    }
};

ValidatorDateRangeDuration.prototype.init = function( fromDateValidator, toDateValidator, durationValidator ) {
    ValidatorDateRangeDuration.superclass.init.call( this, fromDateValidator, toDateValidator );
    this.durationValid = durationValidator;
    this.addFormObject( this.durationValid );
};

ValidatorDateRangeDuration.prototype.validate = function() {
    var verificationState = ValidatorDateRangeDuration.superclass.validate.call( this );

    if( verificationState == true ) {

        var duration = this.durationValid.formEntity.getSelectedValue();

        var dateRange = this.getAsDateRange();

        if( dateRange.getDurationDays() < duration ) {

            var stateCode = ValidatorAbstract.VALIDATION_STATE_DATERANGE_DISTANCE;
            var stateMsg = "dates are to close";
            verificationState = false;

            ValidatorDateRangeDuration.superclass.setValidationState.call( this, stateCode );
            ValidatorDateRangeDuration.superclass.setValidationMessage.call( this, stateMsg );
        }

    }

    return verificationState;
};

