// Util.js

// Some global static utility functions

function Util() {}

function Util_initialize() {
  // Type checking
  Util.isString = Util_isString;
  Util.isNumber = Util_isNumber;
  Util.isBoolean = Util_isBoolean;
  Util.isArray = Util_isArray;
  Util.isFunction = Util_isFunction;
  Util.isOk = Util_isOk;
  Util.isAny = Util_isOk;
  Util.isOkClean = Util_isOkClean;
  Util.isAnyClean = Util_isOkClean;
  Util.isInInstance = Util_isInInstance;
  Util.isGivenObject = Util_isGivenObject;
  Util.isGivenType = Util_isGivenType;
  Util.isNull = Util_IsNull;
  Util.isObject = Util_IsObject;

  Util.isException = Util_isException;

  Util.addURLParameter = Util_addURLParameter;
  Util.getURLParameters = Util_getURLParameters;

  Util.instanceOf = Util_instanceOf;
  Util.insertProto = Util_insertProto;
  Util.concatProto = Util_concatProto;
  Util.concatParent = Util_concatParent;

  // Misc
  Util.get_if_ok = Util_get_if_ok;
  Util.getIfOk = Util_get_if_ok; // Synonym
  Util.getFunctionName = Util_getFunctionName;
  Util.displayObjectStruct = Util_displayObject;
  Util.arrayToList = Util_arrayToList;

  Util.getInstanceProperties = Util_getInstanceProperties;
  Util.getInstancePropertiesAsHTML = Util_getInstancePropertiesAsHTML;
  Util.arrayToURI = Util_arrayToURI;

  Util.trim = Util_trim;

  Util.objectClone = Util_clone;
  Util.clone = Util_any_clone;
  Util.object_clone = Util_object_clone;
  Util.array_clone = Util_array_clone;

  Util.emptyString = '';
  Util.emptyFunction = function/*emptyFunction*/() {}

  // Check whether constructor.name exists
  if ( Util.isOk( Util.constructor.name ) ) {
    Util.getConstructorName = Util_getConstructorName_JS14;
  } else {
    Util.getConstructorName = Util_getConstructorName_JS13;
  }

  // For JS older than 1.3 we have to implement call and apply
  /*
  if ( !Function.prototype.call ) {
    var ca = {};
    ca.n = 0;
    ca.i = null;
    ca._call = new Closure( Util_CallApply_call, ca );
    ca._apply = new Closure( Util_CallApply_apply, ca );
    Function.prototype.call = Util_CallApply_call;
    Function.prototype.apply = Util_CallApply_apply;
    Util.__callCnt = 0;
  }
*/
}

/**
 * Checks wether the input argument is a valid, defined String.
 * @return  true, if the argument is a String.
 * @return  false, if the argument is undefined, null or any object
 *          other than String.
 */
function Util_isString( cadena ) {
  return Util.isGivenObject( cadena, String );
}

function Util_isNumber( numero ) {
  if ( isNaN( numero ) ) return false;
  return Util.isGivenObject( numero, Number );
}

function Util_isBoolean( bBool ) {
  return Util.isGivenObject( bBool, Boolean );
}

function Util_isArray( a ) {
  return Util.isGivenObject( a, Array );
}

function Util_isFunction( f ) {
  return Util.isGivenType( f, "function" );
}

function Util_isOk( o ) {
  return ( (typeof o != "undefined") && (o != null) );
}

function Util_isOkClean( o, prop )
{
  if ( (o == null) || (typeof o == "undefined") )
    return false;
  if ( (o[prop] != null) && (typeof o[prop] != "undefined") )
    return true;
  else
    {
      delete o[prop];
      return false;
    }
}

/** Like isOkClean, but does not look at the __proto__ chain */
function Util_isInInstance( o, prop )
{
  // Otra implementacion -- tiene problemas con los arrays
  //dirty hack para arrays vacias
  var isEmptyArray = ( ( o.constructor == Array ) && ( o.length == 0 ) );

  if ( (o == null) || (typeof o == "undefined") )
    return false;
  var oProto = o.__proto__;
  o.__proto__ = null;
  var result = this.isOkClean( o, prop );
  o.__proto__ = oProto;

  //dirty hack para arrays vacias
  if ( isEmptyArray )
    o.pop();

  return result;
}

function Util_IsNull( pData )
{
  if ( ( typeof pData == 'undefined' ) || ( pData == null ) )
    return true;
  else
    return false;
}

function Util_IsObject( pData )
{
  if ( typeof pData == 'object' )
    return true;
  else
    return false;
}

function Util_instanceOf( object, constructor )
{
  while ( object != null )
    {
      if ( object == constructor.prototype )
  return true;
      object = object.__proto__;
    }
  return false;
}

function Util_insertProto( obj, newProto )
{
  if ( obj.__proto__ == newProto ) return;
  var oldProto = obj.__proto__;
  obj.__proto__ = newProto;
  while( newProto.__proto__.constructor != Object )
    newProto = newProto.__proto__;
  newProto.__proto__ = oldProto;
}

function Util_concatProto( obj, newProto )
{
  if ( obj.__proto__ == newProto ) return;
  var pObj = obj;
  while( pObj.__proto__ != null )
    {
      obj = pObj;
      pObj = obj.__proto__;
      if ( pObj == Function.prototype ) {
  obj.__proto__ = newProto;
  //Util.concatProto( newProto, Function );
  return;
      }
      if ( pObj == newProto ) return;
    }
  obj.__proto__ = newProto;
}

function Util_concatParent( obj, newParent )
{
  if ( obj.__parent__ == newParent ) return;
  var pObj = obj;
  while( pObj.__parent__ != null )
    {
      obj = pObj;
      pObj = obj.__parent__;
      if ( pObj == newParent ) return;
    }
  obj.__parent__ = newParent;
}

function Util_isGivenObject( argument, objectConstructor ) {
  if ( (typeof argument == "undefined") ||
       (argument == null) ||
       (argument.constructor != objectConstructor) )
    return false;
  else
    return true;
}

function Util_isGivenType( argument, argType ) {
  if ( argument == null ) return false;
  return ( typeof argument == argType );
}

/**
 * get_if_ok
 * @param v => primary value
 * @param dv => default value
 * @return the primary value if it's ok, the default value otherwise
 */
function Util_get_if_ok(v,dv) {
  if (Util.isOk(v)) {
    return v;
  }
  else
  {
    if (Util.isOk(dv)) {
      return dv;
    }
    else {
      return null;
    }
  }
}

/**
 * Returns the name of the given function, or "" if the argument
 * is not a function.
 * [Won't work with unnamed (anonymous) functions]
 */
function Util_getFunctionName( aFunction ) {
  if (! Util.isFunction(aFunction) ) return "";
  //if (! this.isFunction(aFunction) ) return "";
  /*
    var fn = aFunction.toString().match( /function\s+(\S+)\(/ );
    return fn[1];
    */
  aFunction = '' + aFunction;
  var fn = aFunction.slice( 10, aFunction.indexOf( "(" ) );
  return fn;
}

function Util_getConstructorName_JS14( c )
{
  if ( this.isAny( c ) && this.isAny( c.constructor ) )
    return c.constructor.name;
}

function Util_getConstructorName_JS13( c )
{
  if ( this.isAny( c ) && this.isAny( c.constructor ) )
    {
      if ( typeof c.constructor == 'function' )
  {
    if ( c.constructor.toString )
      {
        var cStr = c.constructor.toString();
        return cStr.slice( 10, cStr.indexOf( "(" ) );
      }
  }
      return '' + c.constructor;
    }
  else
    return '--'
}

function Util_getInstanceProperties( obj )
{
  var proto = obj.__proto__;
  var result = [];
  obj.__proto__ = null;
  for ( var i in obj )
    result[ result.length ] = i;
  obj.__proto__ = proto;
  return result;
}

function Util_getInstancePropertiesAsHTML( obj )
{
  var props = this.getInstanceProperties( obj );
  var result = '';
  for ( var i = 0; i < props.length; i++ )
    result += props[ i] + '<br>\n';
  return result;
}

/**
 * Returns the elements of the object as a list of arguments
 */
function Util_arrayToList ( args ) {
  var result = '';

  for (i=0; i < args.length; i++) {
    if (i > 0) result += ', ';
    var a = args[i];
    result += ((typeof a == "string") ? '"' + a.replace(/"/g, '\\"') + '"' : a);
}
return result;
}

function Util_addURLParameter( s, para )
{
  var result = '' + s;
  var pos = result.indexOf( '?' );
  if ( pos != -1 )
  {
    result += "&" + para;
  }
  else
  {
    result += "?" + para;
  }
  return result;
}

/**
 * Returns an array of key value pairs
 * OJO: If no value exists for a key, the keywork 'true' is used.
 * @param   theUrl
 * @param   pBegin   [optional] Default: '?'
 * @param   pSep     [optional] Default: '&'
 * @param   pKV      [optional] Default: '='
 */
function Util_getURLParameters( theUrl, pBegin, pSep, pKV ) {
  // Delimitadores por defecto
  if ( ! Util.isOk( pBegin ) ) pBegin = "?";
  if ( ! Util.isOk( pSep ) ) pSep = "&";
  if ( ! Util.isOk( pKV ) ) pKV = "=";

  var result = [];
  var queryPos = theUrl.lastIndexOf( pBegin );
  if ( queryPos >= 0 ) {
    theUrl = theUrl.substring( queryPos + pBegin.length );
    var params = theUrl.split( pSep );
    for ( var p=0; p<params.length; p++ ) {
      var key, value;
      var keyValue = params[p];
      var equal = keyValue.indexOf( pKV );
      if ( equal > 0 ) {
        key = unescape(keyValue.substring(0, equal));
        value = unescape(keyValue.substring(equal+pKV.length));
      } else {
        key = unescape( keyValue );
        value = 'true';
      }
      result[ key ] = value;
    }
  }
  return result;
}

function Util_trim( s )
{
  //if ( ! Util.isOk( s ) ) return '';
  // [la interrogacion elimina el modo greedy
  // (feature no documentada de JavaScript) ]
  //s = (''+s).replace( /^\s*(.*?)\s*$/, "$1" );
  //return s;
  if ( !s ) return '';
  var ch;
  for ( var i=0; i < s.length; i++) {
      ch = s.charAt(i);
      if ( ch != " " ) break;
  }
  for ( var j = s.length-1; j>0; j--) {
      ch = s.charAt(j);
      if ( ch != " " ) break;
  }
  return s.substring(i, j+1);

}

function Util_isException( o ) {
//debug(342);
var result = false;
  if ( this.isOk( o ) ) {
//  debug(345);
//  debug("ExceptionInterface=" + ExceptionInterface);
    result = OOJS.objectImplements( o, ExceptionInterface );
  }
//  debug("result=" + result);
  return result;
}

/*function Util_isException( o ) {
  Logger.enter( "UTIL.ISEXCEPTION" );
  if ( Util.isOk( o ) ) {
    Logger.log( "UTIL.ISEXCEPTION.o = " + o );
    Logger.log( "UTIL.ISEXCEPTION.o._exception = " + o._exception );
    if ( o._exception == true ) {
//    Logger.log( "OBJECT IS EXCEPION" );
      return true;
    } else {
//    Logger.log( "OBJECT IS NOT EXCEPION" );
      return false;
    }
  } else return false;
}*/
function Util_clone( o ) {
  var o2 = {};
  var proto = o.__proto__;
  o2.__proto__ = proto;
  for ( var p in o ) {
    if ( this.isOkClean( proto, p ) ) continue;
    var pv = o[p];
    if ( pv == proto ) continue;
    o2[ p ] = pv;
  }
 return o2;
}

function Util_arrayToURI ( a ){
  var s="";
  for(var e in a)
    s += e +"="+a[e]+"&";
  return s.slice(0,s.length-1);
}

function Util_displayObject( o, s, ind ) {
  if ( ! ind ) ind = "";
  var result = '';
  if ( s ) result += s + ": " + (typeof o) + " ";
  if ( Util.isAny(o) ) {
    if ( o.__proto__ == Object.prototype ) {
      result += "[" + "Object"+ "]" + "<br>\n";
    } else {
      result += "<br>\n";
      result += ind + "constructor: " + Util.getConstructorName(o) + "<br>\n";
      result += ind + "__proto__ -> " + arguments.callee( o.__proto__, s + '.__proto__', ind + "----" );
      result += ind + "__parent__ -> " + arguments.callee( o.__parent__, s + '.__parent__', ind + "----" );
    }
  } else {
    result += "null" + "<br>\n";
  }
  return result;
}

function Util_CallApply_call( obj )
{
  var sf = '__super__f__' + Util.__callCnt++;
  obj[sf] = this;
  var result, c='';
  for ( var i = 1; i < arguments.length; i++ )
    c += c.length == 0?'arguments['+i+']':', arguments['+i+']';
  c = 'result = obj[sf]('+c+');';
  eval(c);
  delete obj[sf];
  return result;
}

function Util_CallApply_apply( obj, args )
{
  var sf = '__super__f__' + Util.__callCnt++;
  obj[sf] = this;
  var result, c='';
  for ( var i = 0; i < args.length; i++ )
    c += c.length == 0?'args['+i+']':', args['+i+']';
  c = 'result = obj[sf]('+c+');';
  eval(c);
  delete obj[sf];
  return result;
}

// (clone)
// @param o -> any thing
function Util_any_clone( o )
{
   var cloned;
	if ( Util.isObject( o ) ) {
		 return Util_object_clone( o );
	}
	if ( Util.isArray( o ) ) {
		 return Util_array_clone( o );
	}
	if ( Util.isString( o ) ) {
		 return new String( o );
	}
	return o;
}
// (object_clone)
// @param o -> any object
function Util_object_clone( o ) 
{
	 if ( Util.isOk( o.length ) ) {
		  return Util.array_clone( o );
	 }
	 var cloned = {};
	 for( var p in o ) {
		  cloned[p] = Util.clone(o[p]);
	 }
	 return cloned;
}

// (array_clone)
// @param o -> any array
function Util_array_clone( o ) 
{
	 var cloned = [];
	 for(var i=0; i<o.length; i++){
		  cloned[i] = Util.clone(o[i]);
	 }
	 return cloned;
}

Util_initialize();
top.Finder( 'register' )( Util );
