/**
* functions.js
* 
* @author
* BLIM
* KKIM
* May 12, 2010
*
* @internal
* this file contains misc functions that are used throughout all js
*
*
*/

if( typeof array_keys !== 'function' )
{
	function array_keys (input, search_value, argStrict)
	{
		var tmp_arr = {}, strict = !!argStrict, include = true, cnt = 0;
		var key = '';
		
		for (key in input) {
		    include = true;
		    if (search_value != undefined) {
		        if (strict && input[key] !== search_value){
		            include = false;
		        } else if (input[key] != search_value){
		            include = false;
		        }
		    }
		    
		    if (include) {
		        tmp_arr[cnt] = key;
		        cnt++;
		    }
		}

		return tmp_arr;
	}
} // end array_keys.


if( typeof array_values !== 'function' )
{
	function array_values (input)
	{
		var tmp_arr = [], cnt = 0;
		var key = '';

		for ( key in input ){
		    tmp_arr[cnt] = input[key];
		    cnt++;
		}

		return tmp_arr;
	}
} // end array_values.


if( typeof checkParams !== 'function' )
{
	function checkParams( params, defaults )
	{
		var retVal = { };

		/*************************************************************
		* Checks to see if params is undefined or not
		* if it is, set the return value as default param
		* else if check if indiviual keys, value pair is undefined or null,
		*	if it is return value equals to the default value
		* else set the return value as the param key, value pair
		*************************************************************/
		for( var key in defaults ) 
		{
			if( params === undefined || params === null ){ retVal = defaults; break; }

			else if( params[ key ] === undefined || params[ key ] === null ){ retVal[ key ] = defaults[ key ]; }

			else{ retVal[ key ] = params[ key ]; }
		} // end for

		return retVal;
	} 
}// end checkParams


if( typeof empty !== 'function' )
{
	function empty (mixed_var) 
	{
		var key;
		
		if (mixed_var === "" ||
		    mixed_var === 0 ||
		    mixed_var === "0" ||
		    mixed_var === null ||
		    mixed_var === false ||
		    typeof mixed_var === 'undefined'
		){
		    return true;
		}

		if (typeof mixed_var == 'object') {
		    for (key in mixed_var) {
		        return false;
		    }
		    return true;
		}

		return false;
	}
} // end empty.


if( typeof get_defined_functions !== 'function' )
{
	function get_defined_functions( )
	{
		var i = '', arr = [], already = {};

		for (i in this.window) {
		    try {
		        if (typeof this.window[i] === 'function') {
		            if (!already[i]) {
		                already[i] = 1;
		                arr.push(i);
		            }
		        }
		        else if (typeof this.window[i] === 'object') {
		            for (var j in this.window[i]) {
		                if (typeof this.window[j] === 'function' && this.window[j] && !already[j]) {
		                    already[j] = 1;
		                    arr.push(j);
		                }
		            }
		        }
		    }
		    catch (e) {
		        // Some objects in Firefox throw exceptions when their properties are accessed (e.g., sessionStorage)
		    }
		}

		return arr;
	}
} // end get_defined_functions.


if( typeof gettype !== 'function' )
{
	function gettype (mixed_var) 
	{
		var s = typeof mixed_var, name;
		var getFuncName = function (fn) {
		    var name = (/\W*function\s+([\w\$]+)\s*\(/).exec(fn);
		    if (!name) {
		        return '(Anonymous)';
		    }
		    return name[1];
		};
		if (s === 'object') {
		    if (mixed_var !== null) { // From: http://javascript.crockford.com/remedial.html
		        if (typeof mixed_var.length === 'number' &&
		                !(mixed_var.propertyIsEnumerable('length')) &&
		                typeof mixed_var.splice === 'function') {
		            s = 'array';
		        }
		        else if (mixed_var.constructor && getFuncName(mixed_var.constructor)) {
		            name = getFuncName(mixed_var.constructor);
		            if (name === 'Date') {
		                s = 'date'; // not in PHP
		            }
		            else if (name === 'RegExp') {
		                s = 'regexp'; // not in PHP
		            }
		            else if (name === 'PHPJS_Resource') { // Check against our own resource constructor
		                s = 'resource';
		            }
		        }
		    } else {
		        s = 'null';
		    }
		}
		else if (s === 'number') {
		    s = this.is_float(mixed_var) ? 'double' : 'integer';
		}
		return s;
	}
} // end gettype.


if( typeof htmlentities !== 'function' )
{
	function htmlentities( str )
	{
		var change = 	 [     "'",     '"',      '®',      '©',      'é',     '“',     '”', '\n' ];
		var equivalent = [ '&#39;', '&#34;', '&#174;', '&#169;', '&#233;', '&#34;', '&#34;', ' ' ];
		for( var i in change ){ str = str_replace( change[ i ], equivalent[ i ], str ); }

		return str;
	}
} // end htmlentities.


if( typeof is_array !== 'function' )
{
	function is_array( mixed_var ) 
	{
		var key = '';
		var getFuncName = function (fn) {
		    var name = (/\W*function\s+([\w\$]+)\s*\(/).exec(fn);
		    if (!name) {
		        return '(Anonymous)';
		    }
		    return name[1];
		};

		if (!mixed_var) {
		    return false;
		}

		// BEGIN REDUNDANT
		this.php_js = this.php_js || {};
		this.php_js.ini = this.php_js.ini || {};
		// END REDUNDANT

		if (typeof mixed_var === 'object') {

		    if (this.php_js.ini['phpjs.objectsAsArrays'] &&  // Strict checking for being a JavaScript array (only check this way if call ini_set('phpjs.objectsAsArrays', 0) to disallow objects as arrays)
		        (
		        (this.php_js.ini['phpjs.objectsAsArrays'].local_value.toLowerCase &&
		                this.php_js.ini['phpjs.objectsAsArrays'].local_value.toLowerCase() === 'off') ||
		            parseInt(this.php_js.ini['phpjs.objectsAsArrays'].local_value, 10) === 0)
		        ) {
		        return mixed_var.hasOwnProperty('length') && // Not non-enumerable because of being on parent class
		                        !mixed_var.propertyIsEnumerable('length') && // Since is own property, if not enumerable, it must be a built-in function
		                            getFuncName(mixed_var.constructor) !== 'String'; // exclude String()
		    }

		    if (mixed_var.hasOwnProperty) {
		        for (key in mixed_var) {
		            // Checks whether the object has the specified property
		            // if not, we figure it's not an object in the sense of a php-associative-array.
		            if (false === mixed_var.hasOwnProperty(key)) {
		                return false;
		            }
		        }
		    }

		    // Read discussion at: http://kevin.vanzonneveld.net/techblog/article/javascript_equivalent_for_phps_is_array/
		    return true;
		}

		return false;
	}
} // end is_array.


if( typeof is_email !== 'function' )
{
	function is_email( email )
	{
		var re=/^([0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*@(([0-9a-zA-Z])+([-\w]*[0-9a-zA-Z])*\.)+[a-zA-Z]{2,9})$/i;
		var success=true;
		if( !email.match( re ) ){ success=false; }
		return success;
	}
} // end checkEmail


if( typeof is_object !== 'function' )
{
	function is_object( mixed_var )
	{
		if (mixed_var instanceof Array) {
		    return false;
		} else {
		    return (mixed_var !== null) && (typeof( mixed_var ) == 'object');
		}
	}
} // end is_object.


if( typeof is_string !== 'function' )
{
	function is_string( mixed_var )
	{
		return (typeof( mixed_var ) == 'string');
	}
} // end is_string.


if( typeof pause_function !== 'function' )
{
	function pause_function( timer )
	{
		var date = new Date();
		var curDate = null;

		do { curDate = new Date(); }
		while( ( curDate - date ) < timer );
	} // end
} // end pause_function

if( typeof printr !== 'function' )
{
	function printr( obj )
	{
		if( typeof console == 'undefined' ){ alert( var_export( obj, true ) ); }
		else{ console.log( obj ); }
	} // end.
} // end printr.


if( typeof print_r !== 'function' )
{
	function print_r( array, return_val )
	{   
		var output = "", pad_char = " ", pad_val = 4, d = this.window.document;
		var getFuncName = function (fn) {
		    var name = (/\W*function\s+([\w\$]+)\s*\(/).exec(fn);
		    if (!name) {
		        return '(Anonymous)';
		    }
		    return name[1];
		};

		var repeat_char = function (len, pad_char) {
		    var str = "";
		    for (var i=0; i < len; i++) {
		        str += pad_char;
		    }
		    return str;
		};

		var formatArray = function (obj, cur_depth, pad_val, pad_char) {
		    if (cur_depth > 0) {
		        cur_depth++;
		    }

		    var base_pad = repeat_char(pad_val*cur_depth, pad_char);
		    var thick_pad = repeat_char(pad_val*(cur_depth+1), pad_char);
		    var str = "";

		    if (typeof obj === 'object' && obj !== null && obj.constructor && getFuncName(obj.constructor) !== 'PHPJS_Resource') {
		        str += "Array\n" + base_pad + "(\n";
		        for (var key in obj) {
		            if (obj[key] instanceof Array) {
		                str += thick_pad + "["+key+"] => "+formatArray(obj[key], cur_depth+1, pad_val, pad_char);
		            } else {
		                str += thick_pad + "["+key+"] => " + obj[key] + "\n";
		            }
		        }
		        str += base_pad + ")\n";
		    } else if (obj === null || obj === undefined) {
		        str = '';
		    } else { // for our "resource" class
		        str = obj.toString();
		    }

		    return str;
		};

		output = formatArray(array, 0, pad_val, pad_char);

		if (return_val !== true) {
		    if (d.body) {
		        this.echo(output);
		    }
		    else {
		        try {
		            d = XULDocument; // We're in XUL, so appending as plain text won't work; trigger an error out of XUL
		            this.echo('<pre xmlns="http://www.w3.org/1999/xhtml" style="white-space:pre;">'+output+'</pre>');
		        }
		        catch (e) {
		            this.echo(output); // Outputting as plain text may work in some plain XML
		        }
		    }
		    return true;
		} else {
		    return output;
		}
	}
} // end printr.


if( typeof str_replace !== 'function' )
{
	function str_replace( search, replace, subject, count )
	{
		var i = 0, j = 0, temp = '', repl = '', sl = 0, fl = 0, f = [ ].concat( search ), r = [ ].concat( replace ), s = subject, 
			ra = r instanceof Array, sa = s instanceof Array; s = [ ].concat( s );

		if( count ){ this.window[count] = 0; }
		for( i = 0, sl = s.length; i < sl; i++ ){ if( s[ i ] === '' ){ continue; }
		for( j = 0, fl = f.length; j < fl; j++ )
		{
			temp = s[ i ]+'';
			repl = ra ? ( r[ j ] !== undefined ? r[ j ] : '' ) : r[ 0 ];
			s[ i ] = ( temp ).split( f[ j ] ).join( repl );
			if( count && s[ i ] !== temp ){ this.window[ count ] += ( temp.length - s[ i ].length ) / f[ j ].length; } }
		}

		return sa ? s : s[ 0 ];
	}
} // end str_replace.


if( typeof var_export !== 'function' )
{
	function var_export( mixed_expression, bool_return )
	{
		var retstr = '',
		    iret = '',
		    cnt = 0,
		    x = [],
		    i = 0,
		    funcParts = [],
		    idtLevel = arguments[2] || 2, // We use the last argument (not part of PHP) to pass in our indentation level
		    innerIndent = '', outerIndent = '';

		var getFuncName = function (fn) {
		    var name = (/\W*function\s+([\w\$]+)\s*\(/).exec(fn);
		    if (!name) {
		        return '(Anonymous)';
		    }
		    return name[1];
		};

		var _makeIndent = function (idtLevel) {
		    return (new Array(idtLevel+1)).join(' ');
		};

		var __getType = function (inp) {
		    var i = 0;
		    var match, type = typeof inp;
		    if (type === 'object' && inp.constructor && getFuncName(inp.constructor) === 'PHPJS_Resource') {
		        return 'resource';
		    }
		    if (type === 'function') {
		        return 'function';
		    }
		    if (type === 'object' && !inp) {
		        return 'null'; // Should this be just null?
		    }
		    if (type === "object") {
		        if (!inp.constructor) {
		            return 'object';
		        }
		        var cons = inp.constructor.toString();
		        match = cons.match(/(\w+)\(/);
		        if (match) {
		            cons = match[1].toLowerCase();
		        }
		        var types = ["boolean", "number", "string", "array"];
		        for (i=0; i < types.length; i++) {
		            if (cons === types[i]) {
		                type = types[i];
		                break;
		            }
		        }
		    }
		    return type;
		};
		var type = __getType(mixed_expression);

		if (type === null) {
		    retstr = "NULL";
		} else if (type === 'array' || type === 'object') {
		    outerIndent = _makeIndent(idtLevel-2);
		    innerIndent = _makeIndent(idtLevel);
		    for (i in mixed_expression) {
		        var value = this.var_export(mixed_expression[i], true, idtLevel+2);
		        value = typeof value === 'string' ? value.replace(/</g, '&lt;').replace(/>/g, '&gt;') : value;
		        x[cnt++] = innerIndent+i+' => '+(__getType(mixed_expression[i]) === 'array' ? '\n' : '')+value;
		    }
		    iret = x.join(',\n');
		    retstr = outerIndent+"array (\n"+iret+'\n'+outerIndent+')';
		}
		else if (type === 'function') {
		    funcParts = mixed_expression.toString().match(/function .*?\((.*?)\) \{([\s\S]*)\}/);

		    // For lambda functions, var_export() outputs such as the following:  '\000lambda_1'
		    // Since it will probably not be a common use to expect this (unhelpful) form, we'll use another PHP-exportable
		    // construct, create_function() (though dollar signs must be on the variables in JavaScript); if using instead
		    // in JavaScript and you are using the namespaced version, note that create_function() will not be available
		    // as a global
		    retstr = "create_function ('"+funcParts[1]+"', '"+funcParts[2].replace(new RegExp("'", 'g'), "\\'")+"')";
		}
		else if (type === 'resource') {
		    retstr = 'NULL'; // Resources treated as null for var_export
		} else {
		    retstr = (typeof ( mixed_expression ) !== 'string') ? mixed_expression : "'" + mixed_expression.replace(/(["'])/g, "\\$1").replace(/\0/g, "\\0") + "'";
		}

		if (bool_return !== true) {
		    this.echo(retstr);
		    return null;
		} else {
		    return retstr;
		}
	} // var_export.
} // end var_export.

