/**!
	HeroDevelopment ©2008
	http://www.herodev.com/

	Developer:	$Author: LCValentine $
	Language:	JS
	Class:		N/A
	Created:	2008-05-24
	Modified:	$Date: 2008-03-08 19:21:13 -0700 (Sat, 08 Mar 2008) $
	Revision:	$Rev: 85 $

	Dependancies: 

	[Description]
	A collection of commonly used methods.
 **/

var chRent = null;
function checkRent( form ){
	var rent = form[ 'Rent' ];
	var rentVal = parseFloat( rent.value );
	if( rentVal < 1500 || rentVal == Number.NaN || rentVal.toString() == 'NaN' ){
		var error = document.getElementById( 'rentCheck' );
		if( error ){
			error.style.display = 'inline';

			if( chRent == null ){
				chRent = window.location.href + '#rentCheck';
			}

			window.location.href = chRent;
			return false;
		}
	}
}

/**
 * Returns the boolean of some value.
 * @param {Object} value
 * @return bool
 */
function bool( val ){
	return !!val;
}

function not( val ){
	return !val;
}

function num( val ){
	return parseFloat( val );
}

function str( val ){
	return val.toString();
}

/**
 * Determines whether an object is an Array. 
 * @param {Object} obj	The object to check
 * @return {Boolean}
 */
function isArray( obj ){
	return isTypeOf( obj, Array );
}

/**
 * Determines whether an object is an Function. 
 * @param {Object} obj	The object to check
 * @return {Boolean}
 */
function isFunction( obj ){
	return typeof obj == 'function';
}

function isNumber( obj ){
	return obj instanceof Number;
}

/**
 * Determines whether a value can be evaluated as purely numeric.
 * @param {Object} val	The value to check
 * @return {Boolean}
 */
function isNumeric( value ){
	return parseFloat( value ) == value;
}

/**
 * Determines whether an object is in fact just an object.
 * @param {Object} obj	The object to check
 * @return {Boolean}
 */
function isObject( obj ){
	return obj.constructor.toString().match( /function object\(/i );
}

function isObjective( obj ){
	return obj != null && isTypeOf( obj, Object );
}

/**
 * Determines if the object provided represents a scalar type (string or number).
 * @param {Object} obj	The object to check
 * @return {Boolean}
 */
function isScalar( obj ){
	return obj == null || !isObjective( obj );
}

/**
 * Determines if the object provided represents a string.
 * @param {Object} obj	The object to check
 * @return {Boolean}
 */
function isString( val ){
	return val.toString() === val;
}

function isTypeOf( obj, cls ){
	return obj instanceof cls;
}


function callAsync( cb1, cb2 ){
	var cb = function(){
		var out = cb1();
		if( cb2 ){
			cb2( out );
		}
	}

	setTimeout( cb, 0 );
}

/**
 * Clones the members of one object to another.
 * NOTE:  References will not be dereferenced.
 * @param {Object} obj	The object to clone
 * @return {Object}	The clone
 */
function clone( obj, clone ){
	if( !clone ) clone = {};
    for( var prop in obj ){
		try{
        	var val = obj[ prop ];
			clone[ prop ] = val;
		}catch( prot ){
			continue;
		}
	}
    return clone;
}

/**
 * Gets and if necessary creates a LightBox
 * @return {Node}	The LightBox
 */
function getLightBox(){
	var HDLB = document.getElementById( 'HDLightBox' );

	if( !HDLB ){
		HDLB = document.createElement( 'div' );
		HDLB.id = 'HDLightBox';
		HDLB.hasContent = false;

		HDLB.Hide = function(){
			this.style.display = 'none';
		}

		HDLB.Resize = function(){
			var rects = getWindowRects();
			var isXScrolling = rects.Left || ( rects.fullWidth - rects.Width > 17 );

			this.style.height = '0px';
			this.style.height = '100%';

			this.style.width  = '0px';
			this.style.width  = '100%';

			this.style.left = rects.Left +'px';
			this.style.top = isXScrolling ?
				( rects.Top - 17 ) +'px':
				rects.Top +'px';
		}

		HDLB.SetBackgroundColor = function( color ){
			this.style.backgroundColor = color;
		}

		HDLB.Show = function(){
			this.Resize();
			this.style.display = 'block';
			this.style.zIndex = 10000;
		}

		var body = get( 'BODY' )[0];
			body.insertBefore( HDLB, body.firstChild );

		HD.Extend.Attach( HDLB );

		window.onresize = function(){
			var HDLB = document.getElementById( 'HDLightBox' );
				HDLB.Resize();
		}
		
		window.onscroll = function(){
			var HDLB = document.getElementById( 'HDLightBox' );
				HDLB.Resize();
		}
	}

	return HDLB;
}

function tryGetSafe( obj, prop, val ){
	try{
		val.push( obj[ prop ] );
		return true;
	}catch( e ){
		return false;
	}
}

/**
 * Gets and if necessary creates a SandBox.
 * @return {Node}	The SandBox
 */
function getSandBox(){
	var HDSB = document.getElementById( 'HDSandBox' );

	if( !HDSB ){
		var HDSBC = document.createElement( 'div' );
			HDSBC.id = 'HDSandBoxContainer';
			HDSBC.style.height   = '1px';
			HDSBC.style.left     = '-5px';
			HDSBC.style.overflow = 'hidden';
			HDSBC.style.position = 'absolute';
			HDSBC.style.top      = '-5px';
			HDSBC.style.width    = '1px';
			
		HDSB = document.createElement( 'div' );
		HDSB.id = 'HDSandBox';		

		HDSBC.appendChild( HDSB );

		document.body.insertBefore( HDSBC, document.body.firstChild );
		
		HD.Extend.Attach( HDSB );
	}

	return HDSB;
}

/**
 * Attempts to get the measurements for the window provided or the current window.
 * @param {Window} domWin [Optional]	The window to get the measurements for
 * @return {Object}	The window's measurements
 */
function getWindowRects( domWin ){
	var coords = {};
	if( !domWin ){
		domWin = window;
	}

	var domDoc = domWin.document;

	if( domWin.innerHeight ){
		coords['Height'] = domWin.innerHeight;
		coords['Width']  = domWin.innerWidth;
	}else if( domDoc.documentElement && domDoc.documentElement.clientHeight ){
		coords['Height'] = domDoc.documentElement.clientHeight;
		coords['Width']  = domDoc.documentElement.clientWidth;
	}else if( domDoc.body ){
		coords['Height'] = domDoc.body.clientHeight;
		coords['Width']  = domDoc.body.clientWidth;
	}
	
	if( domWin.pageYOffset ){
		coords['Top']  = domWin.pageYOffset;
		coords['Left'] = domWin.pageXOffset;
	}else if( domDoc.documentElement && domDoc.documentElement.scrollTop ){
		coords['Top']  = domDoc.documentElement.scrollTop;
		coords['Left'] = domDoc.documentElement.scrollLeft;
	}else if( domDoc.body ){
		coords['Top']  = domDoc.body.scrollTop;
		coords['Left'] = domDoc.body.scrollLeft;
	}

	fullHeight1 = domDoc.body.scrollHeight;
	fullHeight2 = domDoc.body.offsetHeight
	if( fullHeight1 > fullHeight2 ){
		coords['fullHeight'] = domDoc.body.scrollHeight;
		coords['fullWidth']  = domDoc.body.scrollWidth;
	}else{
		coords['fullHeight'] = domDoc.body.offsetHeight;
		coords['fullWidth']  = domDoc.body.offsetWidth;
	}

	coords['Right']  = coords['Left'] + coords['Width'];
	coords['Bottom'] = coords['Top']  + coords['Height'];

	return coords;
}

function importScript( library ){
	library = '/'+ library.replace( '.', '/' ) +'.js';
	
	var script = createNode( 'script', { language : 'JavaScript', type : 'text/javascript', src : library } );
	document.getElementsByTagName( 'head' )[0].appendChild( script );
}

/**
 * Reads the GET variables from the URL and returns a keyed list.
 * @return {Object}
 */
function object2Query( object ){
	var query = '';
	if( object ){
		for( var prop in object ){
			var value = [];
			if( tryGetSafe( object, prop, value ) ){
				value = value[0];

				if( isScalar( value ) ){
					query += escape( prop ) +'='+ escape( value.toString() ) +'&';
				}else if( isArray( value ) ){
					for( var i = 0; i < value.length; i++ ){
						query += escape( prop ) +'[]='+ escape( value[ i ].toString() ) +'&';
					}
				}
			}
		}
	}

	return query.trimRight( '&' );
}

function objectiveReference(){
	args = Array.toArray( arguments );
	var method = args.shift();
	var object = args.shift();

	return function(){
		return method.apply( object, arguments || args );
	}
}

/**
 * Reads the GET variables from the URL and returns a keyed list.
 * @param {String} The query string to parse
 * @return {Object}
 */
function parseQuery( query ){
	query = unescape( query );
	var pieces = query.split( /&/g );

	if( !isArray( pieces ) ){
		pieces = [ pieces ];
	}

	var kvPairs = {};
    for( var i = 0; i < pieces.length; i++ ){
		var parts = pieces[ i ].split( '=' );
    	var key = parts.shift();
		var val = parts.shift();

		if( key.indexOf( '[]' ) + 2 == key.length ){
			key = key.substring( 0, key.length - 2 );

			if( !isArray( kvPairs[ key ] ) ){
				kvPairs[ key ] = [];
			}

        	kvPairs[ key ].push( val );
		}else{
			kvPairs[ key ] = val;
		}
    }
    
    return kvPairs;
}

function staticize( fromNamespace, toNamespace ){
	var from = [];
	if( tryGetReference( fromNamespace, window, from ) ){
		from = from[0];
		to = [];
		if( tryGetReference( toNamespace, window, to ) ){
			to = to[0];
			for( var prop in from ){
				if( isFunction( from[ prop ] ) ){
					_staticize( prop, from, to );
				}
			}
		}
	}
}

function _staticize( prop, from, to ){
	to[ prop ] = function(){
		var args = Array.toArray( arguments );
		var node = args.shift();
		return from[ prop ].apply( node, args );
	}
}

function tryGetReference( namespace, ref, result ){
	if( isObjective( namespace ) ){
		result.push( namespace );
		return true;
	}else{
		var parts = namespace.split( '.' );
		if( !isArray( parts ) ) parts = [ parts ];
		ref = ref || window;

		while( parts.length ){
			var call = null;
			var pt = parts.shift();

			if( pt in ref ){
				ref = ref[ pt ];
			}else{
				return false;
			}
		}

		result.push( ref );
		return true;
	}
	
	return false;
}

/**
 * Reads through the first-level properties of an object and returns "key: value" for each.
 * @param {Object} obj	The object to iterate
 * @return {String}	The "key: value" sets separated by "\n"
 */
function dump(obj){
    var tmp = '';
    for( var prop in obj ){
		tmp += prop
        try{
            var val = obj[ prop ];
			tmp += ': '+ val +"\n";
        }catch( inv ){
			tmp += ": (unk)\n";
		}
    }
    return tmp;
}

//[ Array ]
Array.prototype.contains = function( obj ){
	return this.indexOf( obj ) != -1;
}
Array.prototype.filter = function( callback ){
	//clone args & self
	var args = Array.toArray( arguments ); 
	var bools = Array.toArray( this );
	bools.map.apply( bools, args );

	for( var i = bools.length - 1; i >= 0; i-- ){
		if( bools[ i ] === false ){
			this.splice( i, 1 );
		}
	}
	return this;
}
Array.prototype.mapFilter = function( callback ){
	this.map.apply( this, arguments );
	for( var i = this.length - 1; i >= 0; i-- ){
		if( this[ i ] === false ){
			this.splice( i, 1 );
		}
	}
	return this;
}
Array.prototype.indexOf = function( val ){
    for( var i = 0; i < this.length; i++ ){
        if( this[ i ] === val ){
            return i;
		}
    }
	return -1;
}
Array.prototype.map = function( callback ){
	if( arguments.length ){
		//remove the first item (the callback)
		//and insert a place for the value and its index
		var args = Array.toArray( arguments );
			args.splice( 0, 1, null, 0 );

		for( var i = 0; i < this.length; i++ ){
			args[0] = this[ i ];
			args[1] = i;

			this[ i ] = callback.apply( null, args );
		}
	}
	return this;
}
Array.prototype.merge = function(){
	if( isArray( arguments[0] ) ){
		for( var i = 0; i < arguments[0].length; i++ ){
			this.push( arguments[0][i] );
		}		
	}else{
		for( var i = 0; i < arguments.length; i++ ){
			this.push( arguments[i] );
		}
	}
}
Array.prototype.spliceValue = function( value ){
	var idx = this.indexOf( value );
	if( idx > -1 ){
		return this.splice( idx, 1 );
	}
}
Array.prototype.sum = function( value ){
	var sum = 0;
	for( var i = 0; i < this.length; i++ ){
		sum += num( this[ i ] );
	}
	return sum;
}
Array.toArray = function( list ){
	var array = [];
	if( !isString( list ) ){
		for( var i = 0; i < list.length; i++ ){
			array.push( list[ i ] );
		}
	}
	return array;
}
Array.prototype.walk = function( callback ){
	if( arguments.length ){
		//remove the first item (the callback)
		//and insert a place for the value and its index
		var args = Array.toArray( arguments );
			args.splice( 0, 1, null, 0 );

		for( var i = 0; i < this.length; i++ ){
			args[0] = this[ i ];
			args[1] = i;

			callback.apply( null, args );
		}
	}
	return this;
}

String.prototype.contains = function( val ){
	return this.indexOf( val ) != -1;
}
String.prototype.indent = function(){
	return "\t"+ this.replace( /\n/g, "\n\t" );
}
String.prototype.trim = function( charList ){
	return this.trimLeft( charList ).trimRight( charList );
}
String.prototype.trimLeft = function( charList ){
	var rex = charList ?
		new RegExp( '^['+ charList +']+' ) :
		/^\s+/;

	return this.replace( rex, '' );	
}
String.prototype.trimRight = function( charList ){
	var rex = charList ?
		new RegExp( '['+ charList +']+$' ) :
		/\s+$/;

	return this.replace( rex, '' );	
}

//Extend forward
if( !HD ){
	var HD = {};
}

HD.Nodes = {
	Document : 9,
	Element : 1,
	Text : 3
};

HD.State = {
	Dragging : false
};
