''
_path    = '';
_classes = new Object();

_setPath = function(path) { _path = path; }

_import = function(cName,cPath) {
	if (!cPath) cPath = '';
	if (typeof _classes[cName] == 'undefined') {
		_getClass(cName,_path + cPath + ( cPath != '' ? '/' : '' ));
		_classes[cName] = [cPath,true,null]
	}
}

_getClass = function(name,path) { document.write('<script type="text\/javascript" src="' + path + name + '.js"><\/script>'); }

d = document;
n = navigator;
v = n.appVersion.toUpperCase();
ua = n.userAgent.toUpperCase();

ns    = (ua.indexOf("GECKO") > -1);
opera = (ua.indexOf("OPERA") > -1);
ie    = (ua.indexOf("MSIE") > -1 && !opera);
ie5   = (ie && v.indexOf("IE 5") > -1);
ie55  = (ie && v.indexOf("IE 5.5") > -1);
ie6   = (ie && v.indexOf("IE 6") > -1);
ie7   = (ie && v.indexOf("IE 7") > -1);
dom   = (d.createElement && d.appendChild) ? true : false;
win   = (ua.indexOf("WIN") > -1);
mac   = (ua.indexOf("MAC") > -1);

xhtml = false;

cookiesEnabled = (typeof n.cookieEnabled != 'undefined') ? n.cookieEnabled : null;

pageIsLoaded = false;

/**
 * Core extensions
 */
function rVal(v,minV)  { return v > minV ? v : minV };
function rMax(v,maxV)  { return v < maxV ? v : maxV };
function rInt(v)       { v = parseInt(v); return isInt(v) ? v : 0 };

function isDefined(v)  { return typeof v != 'undefined'; }
function notDefined(v) { return typeof v == 'undefined'; }

function isNull(v)     { return v == null && isDefined(v)  && v != 0; }
function notNull(v)    { return v != null || notDefined(v) || v == 0; }

function isValid(v)    { return isDefined(v) && notNull(v) && v; }

function isNumber(v)   { return typeof v == 'number'; }
function notNumber(v)  { return typeof v != 'number'; }

function isString(v)   { return typeof v == 'string' ; }
function isBoolean(v)  { return typeof v == 'boolean'; }
function isObject(v)   { return typeof v == 'object' ; }

function isInt(v)      { return isNumber(v) && parseFloat(parseInt(v)) == v; }
function isFloat(v)    { return isNumber(v); }

function stringIsNumbers(str) { return (str.match(/^\d+$/)  == null) ? false : true; }
function stringIsNotHtml(str) { return (str.match(/[<>\^]/) != null) ? false : true; }

function getElement(id) { return document.getElementById ? document.getElementById(id) : null; }
function getParentNode(n) { return (n.parentElement) ? n.parentElement : n.parentNode; }

function getParentByTagName(node, nodeName) {
	if (!node || node == null) return null;
	return (node.parentNode.nodeName == nodeName) ? node.parentNode : getParentByTagName(node.parentNode,nodeName);
}

function getDistance(obj, id) {
	var x = y = 0;
	if (obj.offsetParent) {
		do {
			if (id && obj.id == id) return [x,y];
			x += obj.offsetLeft;
			y += obj.offsetTop;
		} while (obj = obj.offsetParent);
	}
	return [x,y];
}

function getW() { return window.innerWidth ? innerWidth : document.documentElement ? document.documentElement.offsetWidth  : ie ? document.body.clientWidth  : innerWidth  }
function getH() { return window.innerHeight ? innerHeight : document.documentElement ? document.documentElement.offsetHeight : ie ? document.body.clientHeight : innerHeight }
function getS() { return ie ? document.body.scrollTop || document.documentElement.scrollTop : pageYOffset }

function getContentW() { return ie ? document.body.clientWidth  : innerWidth  }
function getContentH() { return ie ? document.body.clientHeight : innerHeight }

_extends = function(_class, extClass) {
	_class.prototype = new extClass(-1);
	if (typeof _classes[_class.className] == 'undefined') {
		_classes[_class.className] = [null,true,extClass];
	} else {
		_classes[_class.className][2] = extClass;
	}
}

if (typeof Function.prototype.bind == 'undefined') {
	Function.prototype.bind = function(object) {
		var _method = this;
		return function () {
			return _method.apply(object, arguments);
		};
	}
}

if (typeof Function.prototype.call == 'undefined') {
	Object.prototype._call  = null;
	Function.prototype.call = function(obj) { obj._call = this; return obj._call(); }
}

Array.prototype.indexOf = function(o) { for(var i = 0; i < this.length; i++) if(this[i]==o) return i; return -1; };

Array.prototype.removeIndex = function(index) {
	for (var i = index; i < this.length-1; i++) this[i] = this[i+1];
	this.length = this.length-1;
}

Array.prototype.contains = function (e) {
	for (var i = 0; i < this.length; i++) {
		if (this[i] == e) {
			return true;
		}
	}
	return false;
}

if (typeof Array.prototype.push == 'undefined') {
	Array.prototype.push = function() { for (var i = 0; i < arguments.length; i++) this[this.length] = arguments[i]; return this.length; }
	Array.prototype.pop  = function() { this.length = this.length-1; }
}

String.prototype.trim = function() {
	return this.replace(/^\s+|\s+$/, '');
}


/**
 * Observer
 */
Observer = function() {
	this.listeners = [];
}

Observer.className = 'Observer';

Observer.prototype.notify = function() {
	var r = true;
	for (var i = 0; i < this.listeners.length; i++) {
		r = (this.listeners[i]() && r);
	}
	return r;
}

Observer.prototype.invoke = function() { this.notify(); }
Observer.prototype.addListener = function(cMethod,cObj) { this.listeners[this.listeners.length] = cMethod.bind(cObj); }
Observer.prototype.clear = function(c) { this.listeners.length = 0; }


/**
 * Common
 */
Common = {}

Common.click = function(id) {
	var elm = document.getElementById(id);
	if (elm != null) {
		elm.click();
	}
}

Common.cancelEnterSubmit = function(e) {
	if (window.event) e = window.event;
	var key = e.keyCode ? e.keyCode : e.which ? e.which : null;
	if (key != null) {
		// key: enter
		if (key == 13) {
			return false;
		}
	}
	return true;
}

Common.inputEnterButtonActivate = function(e) {
	if (window.event) e = window.event;
	var key = e.keyCode ? e.keyCode : e.which ? e.which : null;
	if (key != null) {
		// key: enter
		if (key == 13) {
			var id = e.target ? e.target.id : e.srcElement.id;
			var elm = null;
			if (id.toLowerCase().indexOf('_input') > -1) {
				elm = document.getElementById( id.substring(0, id.toLowerCase().indexOf('_input')) + '_button' );
			} else if (id.indexOf('LISTBOXINPUT_') == 0 && id.toLowerCase().indexOf('_id') > -1) {
				elm = document.getElementById( id.substring(13, id.toLowerCase().indexOf('_id')) + '_additem' );
			}
			if (elm != null) {
				if (elm.href) {
					_url( elm.href );
				} else if (elm.click) {
					elm.click();
				}
			}
		}
	}
	return false;
}

Common.selector = {};
Common.selector.addOption = function(sel, value, text) {
	sel.options[sel.options.length] = new Option(value, text);
}
Common.selector.removeOption = function(sel, index, defaultText) {
	sel.options[index] = null;
	if( sel.length == 0 && defaultText ) {
		sel.options[0] = new Option( defaultText , '' );
	}
}
Common.selector.removeSelectedOptions = function(sel, defaultText) {
	for( var i = sel.length-1; i >= 0; i-- ) {
		if( sel[i].selected ) {
			sel.options[i] = null;
		}
	}
	if( sel.length == 0 && defaultText ) {
		sel.options[0] = new Option( defaultText , '' );
	}
}
Common.selector.removeAllOptions = function(sel, defaultText) {
	for( var i = sel.options.length-1; i >= 0; i--) {
		sel.options[i] = null;
	}
}
Common.selector.selectAllOptions = function(sel) {
	for( var i = 0; i < sel.length; i++ ) {
		sel[i].selected = true
	}	
}
Common.selector.selectOption = function(sel, value) {
	for( var i = 0; i < sel.length; i++ ) {
		if (sel[i].value == value) {
			sel[i].selected = true;
			continue;
		}
	}
}
Common.selector.getTextByValue = function(sel, value) {
	for( var i = 0; i < sel.length; i++ ) {
		if (sel[i].value == value) {
			return sel[i].text;
		}
	}
}
Common.checkbox = {};
Common.checkbox.selectAll = function(checkbox) {
	if (checkbox && checkbox != null) {
		if (checkbox.length) {
			var b = !Common.checkbox.isAllSelected(checkbox);
			for (var i = 0; i < checkbox.length; i++) {
				checkbox[i].checked = b;
			}
		} else {
			checkbox.checked = !checkbox.checked;
		}
	}
}
Common.checkbox.isAllSelected = function(checkbox) {
	for (var i = 0; i < checkbox.length; i++) {
		if (!checkbox[i].checked) return false;
	}
	return true;
}
Common.checkbox.hasOneSelected = function(checkbox) {
	if (typeof checkbox.length == 'undefined') return checkbox.checked; 
	for (var i = 0; i < checkbox.length; i++) {
		if (checkbox[i].checked) return true;
	}
	return false;
}

Common.radio = {};
Common.radio.getValue = function(radio) {
	if (radio.length) {
		for (var i = 0; i < radio.length; i++) {
			if (radio[i].checked) return radio[i].value; 
		}
	} else {
		return radio.value;
	}
}

Common.insertAtCursor = function(myField, myValue) {
	//IE support
	if (document.selection) {
		myField.focus();
		sel = document.selection.createRange();
		sel.text = myValue;
        sel.select();
	}
	//MOZILLA/NETSCAPE support
	else if (myField.selectionStart || myField.selectionStart == '0') {
		var startPos = myField.selectionStart;
		var endPos = myField.selectionEnd;
		myField.value = myField.value.substring(0, startPos)
			+ myValue
			+ myField.value.substring(endPos, myField.value.length);
		myField.focus()
        myField.setSelectionRange(startPos+1, startPos+1);
	} else {
		myField.value += myValue;
	}
	myField.focus()
}

Common.moveCursorToBeginning = function(elm) {
	if (elm.createTextRange) {
		var r = elm.createTextRange();
		r.collapse(true);
		r.select();
	}
	//MOZILLA/NETSCAPE support
	else if (elm.selectionStart || elm.selectionStart == '0') {
		elm.focus();
        elm.setSelectionRange(0, 0);
	}
	elm.focus();
}

Common.alert = {};
Common.alert.show = function(text, headerText) {
	if (ie6) {
		$J('SELECT').each( function() {
			this.style.visibility = 'hidden';
		});
	}
	$J('#system-inactive-screen').each( function() {
        if (!ie6) this.style.display = 'block';
	});
	$J('#box_validation_error .header-text').each( function() {
        this.innerHTML = headerText ? headerText : _text[ 'error.validation.h1'  ];
	});
	$J('#box_validation_error DIV.text').each( function() {
        this.innerHTML = text;
	});
	$J('#box_validation_error').each( function() {
		this.style.display = 'block';
		this.style.left = ((getW()-this.offsetWidth)/2) + 'px';
		this.style.top = (((getH()-this.offsetHeight)/2) + document.documentElement.scrollTop) + 'px';
		this.style.visibility = 'visible';
	});
	$J('#box_validation_error .button').each( function() {
        //this.focus();
	});
}
Common.alert.hide = function() {
	hideLoader();
	if (ie6) {
		$J('SELECT').each( function() {
			this.style.visibility = 'visible';
		});
	}
	$J('#system-inactive-screen').each( function() {
        this.style.display = 'none';
	});
	$J('#box_validation_error').each( function() {
		this.style.display = 'none';
		this.style.visibility = 'hidden';
	});
}

Common.validators = {};
Common.validators.isMatching = function(r,s) {
	if( s == null ) {
		return false
	}
	if( r.test(s) ) {
		return true
	}
	return false
}
Common.validators.isSoftScanTag = function(s) {
	if( /^msg\.\d{10}\.\d+\.\d+$/.test(s) ) {
		return true;
	}
	return false;
}
Common.validators.dateFormatRegex = {};
Common.validators.dateFormatRegex['MM/dd/yyyy'] = /^([0-9]{1,2})\/([0-9]{1,2})\/([0-9]{4,4})/;
Common.validators.dateFormatRegex['dd-MM-yyyy'] = /^([0-9]{1,2})-([0-9]{1,2})-([0-9]{4,4})/;

Common.date = {}
Common.date.minDate = null;
Common.date.maxDate = null;
Common.date.fromDateObj = null;
Common.date.toDateObj = null;
Common.date.validateInterval = function(fromDate, toDate) {
	var fromDateStr = fromDate.value;
	var toDateStr = toDate.value;
	if (Common.date.validateDate(fromDateStr) && Common.date.validateDate(toDateStr)) {
		var minDateObj = Common.date.minDate != null && Common.date.minDate != '' ? Common.date.getDateFromMatch( Common.date.minDate.match(strutsDateRegex)) : null;
		var maxDateObj = Common.date.maxDate != null && Common.date.maxDate != '' ? Common.date.getDateFromMatch( Common.date.maxDate.match(strutsDateRegex)) : null;
		var fromDateObj = Common.date.fromDateObj = Common.date.getDateFromMatch( fromDateStr.match(strutsDateRegex));
		var toDateObj = Common.date.toDateObj = Common.date.getDateFromMatch( toDateStr.match(strutsDateRegex));
		//alert( fromDateObj );
		//alert( toDateObj );
		if (minDateObj != null && fromDateObj.getTime() < minDateObj.getTime()) {
			Common.alert.show( _text[ 'validation.date_interval.fromDate_before_minDate' ] );
		} else if (minDateObj != null && toDateObj.getTime() < minDateObj.getTime()) {
			Common.alert.show( _text[ 'validation.date_interval.toDate_before_minDate' ] );
		} else if (maxDateObj != null && fromDateObj.getTime() > maxDateObj.getTime()) {
			Common.alert.show( _text[ 'validation.date_interval.fromDate_after_maxDate' ] );
		} else if (maxDateObj != null && toDateObj.getTime() > maxDateObj.getTime()) {
			Common.alert.show( _text[ 'validation.date_interval.toDate_after_maxDate' ] );
		} else if ( fromDateObj.getTime() > toDateObj.getTime() ) {
			Common.alert.show( _text[ 'validation.date_interval.toDate_before_fromDate' ] );
		} else {
			fromDate.value = Common.date.getDateStr(Common.date.fromDateObj);
			toDate.value = Common.date.getDateStr(Common.date.toDateObj);
			return true
		}
	} else {
		if (!Common.date.validateDate(fromDateStr)) {
			Common.alert.show( _text[ 'validation.date_interval.fromDate_not_valid' ] );
		} else {
			Common.alert.show( _text[ 'validation.date_interval.toDate_not_valid' ] );
		}
	}
	return false;
}
Common.date.resetDateInterval = function(fromDate, toDate) {
	fromDate.value = Common.date.getDateStr(new Date());
	toDate.value = Common.date.getDateStr(new Date());
}
Common.date.validateDate = function(dateStr) {
	return dateStr.match(strutsDateRegex) != null;
}
Common.date.getDateFromMatch = function(dateMatch) {
	if (strutsDateFormat == 'MM/dd/yyyy') {
		return new Date( parseInt(dateMatch[3], 10), parseInt(dateMatch[1], 10)-1, parseInt(dateMatch[2], 10),0,0,0,0);
	} else if ('dd-MM-yyyy') {
		return new Date( parseInt(dateMatch[3], 10), parseInt(dateMatch[2], 10)-1, parseInt(dateMatch[1], 10),0,0,0,0);
	} else {
		return new Date( parseInt(dateMatch[3], 10), parseInt(dateMatch[1], 10)-1, parseInt(dateMatch[2], 10),0,0,0,0);
	}
}
Common.date.getDateStr = function(dateObj) {
	var month = (dateObj.getMonth()+1);
	if (month < 10) month = '0' + month;
	var dayOfMonth = dateObj.getDate();
	if (dayOfMonth < 10) dayOfMonth = '0' + dayOfMonth;
	if (strutsDateFormat == 'MM/dd/yyyy') {
		return month + '/' + dayOfMonth + '/' + dateObj.getFullYear();
	} else if ('dd-MM-yyyy') {
		return dayOfMonth + '-' + month + '-' + dateObj.getFullYear();
	} else {
		return month + '/' + dayOfMonth + '/' + dateObj.getFullYear();
	}
}
Common.date.selectorShowMe_onchange = function(select) {
	$J('#date_range_group').each( function() {
		if (select.value == '7') {
			this.style.display = 'block';
		} else {
			this.style.display = 'none';
		}
	});
}
Common.date.validateShowMe = function(form) {
	try {
		var fromDate = form.elements['searchForm.fromDate'];
		var toDate = form.elements['searchForm.toDate'];
		if (form['searchForm.showMe'].value == '7' ) {
			var fromDate = form.elements['searchForm.fromDate'];
			var toDate = form.elements['searchForm.toDate'];
			return Common.date.validateInterval(fromDate, toDate);
		} else {
			Common.date.resetDateInterval(fromDate, toDate);
		}
	} catch (e) {
		alert(e.getMessage());
		return false;
	}
	return true;
}
Common.date.bigSearchShowMeValidValues = [ '1' , '8' , '2', '3', '4', '7' ];
Common.date.validateBigSearchInterval = function() {
	var domains = document.search_form['searchForm.domainId'];
	var subject = EmailSearch.getSearchFieldValue('SUBJECT');
	var allDomainsSelected = domains.value == -1;
	var showMe = document.search_form['searchForm.showMe'];
	if( ( subject != null && subject != '' ) || allDomainsSelected ) {
		if (!Common.date.bigSearchShowMeValidValues.contains(showMe.value)) {
			if (allDomainsSelected) {
				Common.alert.show( _text[ 'validation.date_interval.all_domain_date_interval_week' ] );
			} else {
				Common.alert.show( _text[ 'validation.date_interval.subject_date_interval_week' ] );
			}
			return false;
		}
		if (showMe.value == 7) {
			var fromDateObj = Common.date.fromDateObj;
			var toDateObj = Common.date.toDateObj;
			if (toDateObj.getTime()-fromDateObj.getTime() > 60*60*24*7*1000) {
				if (allDomainsSelected) {
					Common.alert.show( _text[ 'validation.date_interval.all_domain_date_interval_week' ] );
				} else {
					Common.alert.show( _text[ 'validation.date_interval.subject_date_interval_week' ] );
				}
				return false;
			}
		}
	}
	return true;
}

Common.ajax = {};
Common.ajax.responseText = null;
Common.ajax.getLoadingHTML = function() {
	return '<div style="padding: 2px 0px 6px 8px" >' + document.getElementById('loading_container').innerHTML + '</div>';
}
Common.ajax.request = function( url, parameters, successMessage ) {
	
	var _parameters = parameters;
	
	Common.loader.showEmphasized();
	
	$J.ajax({
		type: 'GET',
		url: url,
		data: _parameters,
		error: function() {
			Common.alert.show( _text[ 'info.error_occurred' ] );
			Common.loader.hideEmphasized();
		},
		success: function(msg){
			Common.ajax.responseText = msg;
			if (msg.indexOf('SUCCESS') > -1) {
				Common.alert.show( successMessage );
			} else {
				Common.ajax.viewResponse();
				/*
				Common.alert.show(
					_text[ 'info.error_occurred' ] + "<br/><br/>\n\n" + (new Date()) +
					"<br/><br/>\n\n" +
					"<a href=\"javascript:_void( Common.ajax.viewResponse() );\" >View error</a>"
				);
				*/
			}
			Common.loader.hideEmphasized();
		}
	});
}
Common.ajax.viewResponse = function() {
	var p = Popup.open( 'about:blank', '_blank' , 760 , 500 );
	
	var response = Common.ajax.responseText;
	if (ie) {
		response = response.replace(/<script[\s\S]*<\/script>/g,"");
		response = response.replace("<div id=\"view_error_link\" >","<div id=\"view_error_link\" style=\"display: none;\" >");
		response = response.replace("<div id=\"view_error\" style=\"display: none;\" >","<div id=\"view_error\" >");
	}
	
	p.document.open("text/html", "replace");
	p.document.write(response);
	p.document.close();
}

Common.prepareClickable = function() {
	$J('TABLE.DataList TR.clickable').each( function() {
		this.onmouseover = function() { this.className = 'clickable selected'; }
		this.onmouseout = function() { this.className = 'clickable'; }
	});
}

Common.adjustEmailActionContextMenu = function(emailType, scanDate, spamScore) {
	var disableAll = false;
	if (typeof g_quarantineDayLimitMilliSeconds != 'undefined' && scanDate && scanDate != null) {
		if (scanDate < g_quarantineDayLimitMilliSeconds) disableAll = true;
	}
	if (spamScore && spamScore != null) {
		var spamScoreLimit = 17;
		if (spamScore > spamScoreLimit) disableAll = true;
	}
	if (disableAll || emailType != 'SPAM') {
		if (Tree.getElementById('spam_analysis') != null) Tree.getElementById('spam_analysis').disable();
	} else {
		if (Tree.getElementById('spam_analysis') != null) Tree.getElementById('spam_analysis').enable();
	}
	if (disableAll || ( emailType == 'SPAM' && !g_hasAccessPrivilegeReleaseSpam ) ||
			( (emailType == 'VIRUS' || emailType == 'PARANOID') && !g_hasAccessPrivilegeReleaseVirusParanoid )) {
		Tree.getElementById('preview').disable();
		Tree.getElementById('download').disable();
		Tree.getElementById('release').disable();
		if (Tree.getElementById('reply') != null) Tree.getElementById('reply').disable();
		if (Tree.getElementById('delete') != null) Tree.getElementById('delete').disable();
	} else {
		Tree.getElementById('preview').enable();
		Tree.getElementById('download').enable();
		Tree.getElementById('release').enable();
		if (Tree.getElementById('reply') != null) Tree.getElementById('reply').enable();
		if (Tree.getElementById('delete') != null) Tree.getElementById('delete').enable();
	}
	if (!g_hasArchive || !g_hasOutgoing) {
		if (Tree.getElementById('reply') != null) Tree.getElementById('reply').disable();
	}
}

Common.loader = {};
Common.loader.cancelLoader = false;
Common.loader.loaderTimer = null;

Common.loader.showEmphasized = function() {
	$J('#loading_emphasized').each( function() {
		this.style.display = 'block';
		this.style.left = ((getW()-this.offsetWidth)/2) + 'px';
		this.style.top = (((getH()-this.offsetHeight)/2) + document.documentElement.scrollTop) + 'px';
		this.style.visibility = 'visible';
	});
}
Common.loader.hideEmphasized = function() {
	$J('#loading_emphasized').each( function() {
		this.style.display = 'none';
		this.style.visibility = 'hidden';
	});
}

Common.loader.show = function() {
	$J('#loading').each( function() {
		this.style.display = 'block';
	});
}
Common.loader.hide = function() {
	$J('#loading').each( function() {
		this.style.display = 'none';
	});
	pageIsLoaded = true;
}
Common.loader.prevent = function() {
	if (!ie) return;
	$J('TD.DatePicker A').each( function() {
		if (this.href == 'javascript:;') this.href = 'javascript:_void( Common.loader.prevent() );';
	});
}
Common.loader.onload = function() {
	if (!Common.loader.cancelLoader) Common.loader.loaderTimer = window.setTimeout( 'Common.loader.show()' , 50 )
	Common.loader.cancelLoader = false;
}


/**
 * DataGrid
 */
DataGrid = {};
DataGrid.curTR = null;
DataGrid.selectRow = function(tr) {
	if (DataGrid.curTR != null && DataGrid.curTR != tr) {
		DataGrid.deselectCurRow();
	}
	DataGrid.curTR = tr;
	if (DataGrid.curTR.className.indexOf('selected') == -1) {
		tr.className = DataGrid.curTR.className + ' selected';
	}
}
DataGrid.deselectCurRow = function() {
	if (DataGrid.curTR != null) {
		DataGrid.curTR.className = DataGrid.curTR.className.replace(' selected', '');
		DataGrid.curTR = null;
	}
}


/**
 * Checks for whitespace or null character string
 *
 * @param string _v
 * @return bool
 */
function isEmptyOrWhitespace(_v) {
	if( /^\s*$/.test(_v) ) {
		return true
	}
	return false
}

/**
 * Checks for whitespace characters
 *
 * @param string _v
 * @return bool
 */
function hasWhitespace(_v) {
	if( /\s+/.test(_v) ) {
		return true
	}
	return false
}

/* BOOL */ function isUnsignedSmallint(_v) {
	if( isNaN(_v) ) {
		return false
	}
	if( _v < 0 || _v > 65535 ) {
		return false
	}
	if( !/^[1-9]\d*$/.test(_v) ) {
	    return false
	}
	return true
}

/* BOOL */ function isSignedSmallint(_v) {
	if( isNaN(_v) ) {
		return false
	}
	if( _v < -32768 || _v > 32768 ) {
		return false
	}
	if( !/^[-]?[1-9]\d*$/.test(_v) ) {
	    return false
	}
	return true
}

/**
 * Validates if a value is a non negative (unsigned) 10 bit integer
 *
 * @param integer _v - the value to be checked
 * @return boolean
 */
function isUnsignedInteger(_v) {
	if( isNaN(_v) ) {
		return false
	}
	if( _v < 0 || _v > 4294967295 ) {
		return false
	}
	if( !/^[1-9]\d*$/.test(_v) ) {
	    return false
	}
	return true
}

/* BOOL */ function isSignedInteger(_v) {
	if( isNaN(_v) ) {
		return false
	}
	if( _v < -2147483648 || _v > 2147483648 ) {
		return false
	}
	if( !/^[-]?[1-9]\d*$/.test(_v) ) {
	    return false
	}
	return true
}

/* BOOL */ function isNumericRange(_v, _lower_limit, _upper_limit) {
	if( isNaN(_v) ) {
		return false
	}
	if( _v < _lower_limit || _v > _upper_limit ) {
		return false
	}
	return true
}

/* BOOL */ function isPositiveInteger(_v) {
	if( isNaN(_v) ) {
		return false
	}
	if( _v <= 0 ) {
		return false
	}
	if( !/^[1-9]\d*$/.test(_v) ) {
	    return false
	}
	return true
}

/**
 *
 * Validates if a given number is decimal
 *
 * @param decimal _v     string to be validated
 * @param string  _sign	 optional sign check ('+' and '-' allowed)
 * @return boolean
 */
function isDecimal(_v, _sign) {
    if( isNaN(_v) ) {
		return false
	}
	if( _sign == '+' && _v < 0 ) {
	    return false
	} else if( _sign == '-' && _v > 0 ) {
	    return false
	}
	if( !/^\-?\d+\.\d+$/.test(_v) ) {
        return false
	}
	return true
}

/**
 *
 * Validates HEX strings, also length if _length is non-zero
 *
 * @param string _v			string to be validated
 * @param integer _length	optional length check
 */
function isHex(_v, _length) {
	if( !/^[a-fA-F0-9]+$/.test(_v) ) {
		return false
	}
	if( _length > 0 && _v.length != _length ) {
		return false
	}
	return true
}

/* BOOL */ function isStrictFQDN(_v) {
	if( !isNaN(_v) ) {
		return false
	}
	if( !/^[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+$/.test(_v) ) { // RFC 1123
		return false
	}
	return true
}

/* BOOL */ function isStrictFQDNPort(_v) {
	if( !isNaN(_v) ) {
		return false
	}
	if( /:/.test(_v) ) {
		if( !isUnsignedSmallint(_v.split(':')[1]) ) {
			return false
		}
		_v = _v.split(':')[0]
	}

	if( !/^[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+$/.test(_v) ) { // RFC 1123
		return false
	}
	return true
}

/* BOOL */ function isFQDN(_v) {
	if( !isNaN(_v) ) {
		return false
	}
	if( !/^[A-Za-z0-9\-]+(\.[A-Za-z0-9\-]+)+(\:\d{1,5})?$/.test(_v) ) {
		return false
	}
	return true
}

/* bool */ function isStrictValidEmail(_v) { // RFC 2821/2822
	if( !isNaN(_v) ) {
		return false
	}
	// First, we check that there's one @ symbol, and that the lengths are right
	if( !/^[^@]{1,64}@[^@]{1,255}$/.test(_v) ) {
	  // Email invalid because wrong number of characters in one section, or wrong number of @ symbols.
	  return false
	}
	// Split it into sections to make life easier
	var email_array = _v.split('@')
	var local_array = email_array[0].split('.')

	// LOCAL PART
	for( var i = 0; i < local_array.length; i++ ) {
		if( !/^(([A-Za-z0-9!#$%&'*+\/=?^_`{|}~-][A-Za-z0-9!#$%&'*+\/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$/.test(local_array[i]) ) {
			return false
		}
		//
	}
	// DOMAIN PART
	if( !/^\[?[0-9]{1,2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5](\.[0-9]{1,2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5]){3}\]?$/.test(email_array[1]) ) { // Check if domain is IP. If not, it should be valid domain name
	  var domain_array = email_array[1].split(".")
	  if( domain_array.length < 2 ) {
	      return false // Not enough parts to domain
	  }
	  for( var i = 0; i < domain_array.length; i++ ) {
	    if( !/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$/.test(domain_array[i]) ) {
	      return false
	    }
	  }
	}
	return true
}

/**
 * Validates the local part of an email adress (i.e. the stuff before the @). Validates according to RFC 2821/2822.
 *
 * @param string _v - string to be tested
 * @return boolean
 */
function isValidLocalEmailPart(_v) { 
    if( !isNaN(_v) ) {
		return false
	}
	
    var local_array = _v.split('.')

	// LOCAL PART
	for( var i = 0; i < local_array.length; i++ ) {
		if( !/^(([A-Za-z0-9!#$%&'*+\/=?^_`{|}~-][A-Za-z0-9!#$%&'*+\/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$/.test(local_array[i]) ) {
			return false
        }
    }
	return true
}

/* BOOL */ function isValidEmail(_v, disallowStar) { // RFC 2821/2822, BUT WITHOUT QUOTED LOCAL PART!
	if( !isNaN(_v) ) {
		return false
	}
	// First, we check that there's one @ symbol, and that the lengths are right
	if( !/^[^@]{1,64}@[^@]{1,255}$/.test(_v) ) {
	  // Email invalid because wrong number of characters in one section, or wrong number of @ symbols.
	  return false
	}
	// Split it into sections to make life easier
	var email_array = _v.split('@')
	var local_array = email_array[0].split('.')
	
	var localPartRegex = disallowStar ? /^[A-Za-z0-9!#$%&'+\/=?^_`{|}~-][A-Za-z0-9!#$%&'+\/=?^_`{|}~\.-]{0,63}$/ : /^[A-Za-z0-9!#$%&'*+\/=?^_`{|}~-][A-Za-z0-9!#$%&'*+\/=?^_`{|}~\.-]{0,63}$/ ;

	// LOCAL PART
	for (var i = 0; i < local_array.length; i++) {
	   if( !localPartRegex.test(local_array[i]) ) {
	    return false;
	  }
	}
	// DOMAIN PART
	if( !isIP(email_array[1]) ) { // Check if domain is IP. If not, it should be valid domain name
	  var domain_array = email_array[1].split(".")
	  if( domain_array.length < 2 ) {
	      return false // Not enough parts to domain
	  }
	  for( var i = 0; i < domain_array.length; i++ ) {
	    if( !/^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$/.test(domain_array[i]) ) {
	      return false;
	    }
	  }
	}
	return true
}

function isValidEmailList(_v) { //Checks a CSV list of emails
    _v = _v.replace(/ /g, '');
    var emails_array = _v.split(/[,]/g)
    for (var i = 0; i < emails_array.length; i++) {
    	if (!isValidEmail(emails_array[i])) {
           return false; 
        }
   }
   return true;
}

/* VALIDATES ARGUMENT AS A QUALIFIED DOMAIN NAME */
function isValidDomain(domain) {
	var domainArray = domain.split(".");
	var filter = /^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$/;
	if (domainArray.length < 2) {
		return false; // Not enough parts to domain
	}
	for (var i = 0; i < domainArray.length; i++) {
		if (!filter.test(domainArray[i])) {
			return false;
		}
	}
	return true;
}

/* VALIDATES ARGUMENT AS A QUALIFIED DOMAIN NAME */
function isFullyQualifiedHostname(hostname) {
	var hostnameArray = hostname.split(".");
	var filter = /^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$/;
	var filterEnd = /^([A-Za-z]{0,10})$/;
	if (hostnameArray.length < 3) {
		return false; // Not enough parts to domain
	}
	for (var i = 0; i < hostnameArray.length; i++) {
		if (i < hostnameArray.length-1) {
			if (!filter.test(hostnameArray[i])) {
				alert(1);
				return false;
			}
		} else if (!filterEnd.test(hostnameArray[i])) {
			return false;
		}
	}
	return true;
}


/**
 * Validates a top level domain
 *
 * @param string
 * @return boolean
 *
**/
function isValidTLD(_v) {
	if(_v == '') {
		return false;
	}
	if( !isNaN(_v) ) {
		return false;
	}

	// DOMAIN PART
	if( /^\*\.[A-Za-z]{2,64}$/.test(_v) ) {
		return true
	}
	return false
}

/**
 * Determines if a string is a valid IP number (v4 or v6)
 *
 * @param string _v - string to be tested
 * @return boolean
 */
function isIP(_v) {
    if( isIPv4(_v) || isIPv6(_v) ) {
        return true
    }
    return false
}

/* BOOL */ function isIPv4Port(_v) {
	if( !isNaN(_v) ) {
		return false
	}
	if( /:/.test(_v) ) {
		if( !isUnsignedSmallint(_v.split(':')[1]) ) {
			return false
		}
		_v = _v.split(':')[0]
	}

	if( isIPv4(_v) ) {
		return true
	}
	return false
}

/* BOOL */ function isIPv6(_v) {
	if( !isNaN(_v) ) {
		return false
	}
	if( /^([0-9]{1,2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5](\.[0-9]{1,2}|[0-1][0-9]{2}|2[0-4][0-9]|25[0-5]){5})$/.test(_v) ) {
		return true
	}
	return false
}

/**
 * Validates human name
 * Allowed are: letters a-z (upper and lower case), 
 *             the chars - ' . plus the ISO-8859-1 chars from octal 300 to 377.
 *
 * @param string _v	- string to be validated
 * @return boolean
 */
function isValidHumanNameString(_v) {
	if( !isNaN(_v) ) {
		return false
	}
	if( !/^[a-zA-Z\300-\377\-\.' ]+$/.test(_v) ) {
		return false
	}
	return true
}

/*
 * @param _o - FORM checkbox element object reference
 * @return bool
 */ 
function isChecked(_o) {
	if( _o.checked ) {
		return 1
	}
	return 0
}

/*
 * @param _o - FORM input element object reference (e.g. checkbox)
 * @return bool
 */ 
function isDisabled(_o) {
	if( _o.disabled ) {
		return 1
	}
	return 0
}


/**
 *
 * Events on page controller
 *
 */
function PageEventsClass() {
	/**
	 * Add onload event
	 *
	 * @param _fn - function to be executed on window.onload event
	 */
	this.addOnloadEvent = function(_fn) {
 		addEvent('load', _fn)
	}

	/**
	 * Add onresize event
	 *
	 * @param _fn - function to be executed on window.onresize event
	 */
	this.addOnResizeEvent = function(_fn) {
		addEvent('resize', _fn)
	}

	/**
	 * Add onmousemove event
	 *
	 * @param _fn - function to be executed on window.onmousemove event
	 */
	this.addOnMouseMoveEvent = function(_fn) {
		addEvent('mousemove', _fn)
	}

	/**
	 * Adds event to window event listeners
	 *
	 * @param string _type - type of event
	 * @param function _fn - function to be executed
	 */
	function addEvent(_type, _fn) {
		if( window.addEventListener ) {
   			window.addEventListener(_type, _fn, false)
   			return true
 		} else if( window.attachEvent ) {
   			var r = window.attachEvent('on'+_type, _fn)
   			return r
 		} else {
   			return false
 		}
	}
}

if( PageEvents == undefined ) {
	var PageEvents = new PageEventsClass()
}

/**
 * Decimal rounding
 *
 * @param integer n		round to this number of decimals
 * @return decimal
 */
function _fix(_n) {
	var v = this.valueOf()
	var factor = Math.pow(10, _n)

	return Math.round(v*factor)/factor
}
Number.prototype.roundTo = _fix

/**
 * ProtoType
 */
var Position = {
  cumulativeOffset: function(element) {
    var valueT = 0, valueL = 0;
    do {
      valueT += element.offsetTop  || 0;
      valueL += element.offsetLeft || 0;
      element = element.offsetParent;
    } while (element);
    return [valueL, valueT];
  }
}

/**
 * Conversion
 */
function htmlentities( s ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // *     example 1: htmlentities('Kevin & van Zonneveld');
    // *     returns 1: 'Kevin &amp; van Zonneveld'
 
    var div = document.createElement('div');
    var text = document.createTextNode(s);
    div.appendChild(text);
    return div.innerHTML;
}

function urlencode( str ) {
    // http://kevin.vanzonneveld.net
    // +   original by: Philip Peterson
    // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
    // *     example 1: urlencode('Kevin van Zonneveld!');
    // *     returns 1: 'Kevin+van+Zonneveld%21'
                                     
    var ret = str;
    
    ret = ret.toString();
    ret = encodeURIComponent(ret);
    ret = ret.replace(/%20/g, '+');
 
    return ret;
}

/**
 * PageUp and PageDown handling
 */
PageUpAndDownHandling = {}; 
 
PageUpAndDownHandling.handlePageUpAndPageDown = function(e) {
	if (!e) e = window.event
	try {
		if (e.keyCode && ( e.keyCode == 33 || e.keyCode == 34 )) {
			if (e.type == 'keydown') {
				var bodyH = getH()-170; 
				window.scrollBy( 0 , e.keyCode == 34 ? bodyH : -1*bodyH);
			}
			return PageUpAndDownHandling.turnDefaultOff(e);
		}
	} catch (e) {
		/* ignore */
	}
}

PageUpAndDownHandling.turnDefaultOff = function(e){
	if(window.event){
		window.event.returnValue = false;
		return false;
	}else if (e && e.preventDefault){
		e.stopPropagation();
		e.preventDefault();
	}
}

PageUpAndDownHandling.scrollYPos = 0;
PageUpAndDownHandling.scrollYCount = 0;

PageUpAndDownHandling.handleOnscroll = function(e) {
	if (!e) e = window.event;
	var scrollYOffset = getS()-PageUpAndDownHandling.scrollYPos;
	if (ie) {
		window.setTimeout('PageUpAndDownHandling.scrollCountReset()' , 100);
		PageUpAndDownHandling.scrollYCount += scrollYOffset;
	} else {
		PageUpAndDownHandling.scrollYCount = scrollYOffset
	}
	var scrollYDirMod = PageUpAndDownHandling.scrollYCount < 0 ? -1 : 1;
	PageUpAndDownHandling.scrollYCount = PageUpAndDownHandling.scrollYCount * scrollYDirMod;
	if (PageUpAndDownHandling.isPageUpOrDown()) {
		scrollBy(0, PageUpAndDownHandling.getScrollY() * scrollYDirMod * -1);
		if (ie) PageUpAndDownHandling.scrollCountReset()
	}
	PageUpAndDownHandling.scrollYPos = getS();
}

PageUpAndDownHandling.isPageUpOrDown = function() {
	var scrollYSlack = getH()-PageUpAndDownHandling.scrollYCount; 
	if (ie) {
		var scrollYSlackPercentage = scrollYSlack * 100 / PageUpAndDownHandling.scrollYCount;
		return 14 < scrollYSlackPercentage && scrollYSlackPercentage < 15; 
	} else {
		return 15 < scrollYSlack && scrollYSlack < 25;
	}
}

PageUpAndDownHandling.getScrollY = function() {
	var scrollYSlack = getH()-PageUpAndDownHandling.scrollYCount;
	return 170-scrollYSlack;
}

PageUpAndDownHandling.scrollCountReset = function() {
	PageUpAndDownHandling.scrollYCount = 0;
}
