 
function assert(value, msg) { 
  if (!value) {

    var m = msg ? "Assertion failed: "+ msg : "Assertion failed";
    //m = assert.caller.toString() + ": " + m;
    if (typeof(debug_Debug) == "undefined") {
      throw new Error(m);
    } else {
      debug_Debug.getInstance().assert(value, m);
    }
  }
}

function libjs_log(msg, /*optional*/ exc) {
  if (typeof(util_Logger) == "undefined") {
    if (exc != undefined) {
      msg += ": " + exc;
    }
  } else {
    util_Logger.log(msg, exc);
  }
  return msg;
}

var __loadParameters = { libraryRootUri: null };

/**
 Load a JavaScript package. If no libraryRootUri is given, assume we
 are in the same library as the previous import.

 This function has been named "load..." and not "import..." to avoid name conflicts with Rhino
 shell properties.

 By convention, each package contains a .js file with the same name as the package.
 The browser is triggered to load this .js file, which in turn will trigger loading the entire package.
 note that all packages are evailable _after_ the script section which called this function.
 This is due to the semantics of the document#write() method, which is used in the implementation 
 of this function.

 Example usage: loadPackage("client_util", "../../libjs") 

 This will trigger the load of "../../libjs/client/util/util.js", which in turn will load all the
 classes in "libjs/client" using loadClass().
*/
function loadPackage(packageName, /*optional*/ libraryRootUri) {

  if (!libraryRootUri) {
    libraryRootUri = __loadParameters.libraryRootUri;
  }
  assert(libraryRootUri, "loadPackage: libraryRootUri not set");

  var unqualified = _unqualify(packageName)
  var packageScript = libraryRootUri + "/" + _name2uri(packageName) + "/" + unqualified.name + '.js';

  enqueueScriptLoad(packageScript, {libraryRootUri: libraryRootUri});
}

/**
 * className must always be qualified.
 */
function loadClass(className, /*optional*/ libraryRootUri) {

  var unqualified = _unqualify(className);
  var isQualifiedClass = unqualified.path.length > 0;
  var packageRootUri = "";

  if (!libraryRootUri) {
    libraryRootUri = __loadParameters.libraryRootUri;
  }
  packageRootUri = libraryRootUri;
  if (isQualifiedClass)
    packageRootUri += "/" + unqualified.path;
  assert(libraryRootUri, "loadPackage: libraryRootUri not set");
  assert(packageRootUri, "loadPackage: packageRootUri not set");

  enqueueScriptLoad(packageRootUri + "/" + unqualified.name + '.js', 
    {libraryRootUri: libraryRootUri}); 
}

// x_y_z or x.y.z -> "x/y/z }
function _name2uri(name) {
  return name.replace(/_|\./g, '/');
}

// x_y_z or x.y.z -> { path: "x/y", name: "z" }
function _unqualify(name) {
  var lastSeparatorPos = Math.max(name.lastIndexOf("_"),name.lastIndexOf("."));
  return (lastSeparatorPos != -1) 
    ? { path: _name2uri(name.substring(0, lastSeparatorPos)),
        name: name.substring(lastSeparatorPos + 1)}
    : { path: "", name: name };
}

/**
 * Post the load of the given file. the file is going to be loaded 
 * after the currently running script and all previously posted
 * file loads and scriplet evaluations have finished.
 * Pass the given 'parameters', if any, 
 * in the variable  __loadParameters to the code within the file.
 */
function enqueueScriptLoad(fileName, /*optional*/ parameters) {

  enqueueScriptletEvaluation('__loadParameters = ' + (parameters ? _unparse(parameters) : "{}") + ';');
  
  _enqueueScriptLoad(fileName);
}

function _inheritsFrom(obj, cls) {
  var potentialSuperProto = cls.prototype;
  var proto = obj.prototype;
  while (proto) {
    if (proto == potentialSuperProto)
      return true;
    proto = proto.prototype;
  }
  return false;
}

function _unparse(o) {
  if (o == null)
    return "null";
  if (!o)
    return "null";
  var result = null;
  switch(typeof(o)) {
  case "undefined":
    result = "undefined";
    break;
  case "string":
    result = '"' + o + '"';
    break;
  case "object":
    result = "{";
    var isFirstProp = true;
    for (var prop in o) {
      if (!isFirstProp)
        result += ", ";
      isFirstProp = false;
      result += prop + ": " + _unparse(o[prop]);
    }
    result += "}";
    break;
  default:
    result = o.toString();
    break;
  }
  return result;
}

if (typeof(_enqueueScriptLoad) == "undefined") {
  // we defined this function already if we are running in Rhino
  /**
   * Post the load of the given file. the file is going to be loaded 
   * after the currently running script and all previously posted
   * file loads and scriplet evaluations have finished.
   * Pass the given 'parameters', if any, 
   * in the variable __loadParameters to the code within the file.
   */
  function _enqueueScriptLoad(fileName) {
    //libjs_log("enqueue script load: " + fileName);
    document.writeln('<script src="' + fileName + '"></script>');
  }
}

if (typeof(enqueueScriptletEvaluation) == "undefined") {
  // we defined this function already if we are running in Rhino

  /**
   * Post the evaluation of the given JavaScript source string. 
   * The code is going to be evaluated 
   * after the currently running script and all previously posted
   * file loads and scriplet evaluations have finished.
   * Pass the given 'parameters', if any, 
   * in the variable __loadParameters to the code within the file.
   * @bugs src is not quoted in any way
   */
  function enqueueScriptletEvaluation(src) {
    //libjs_log("enqueue scriptlet: " + src);
    document.writeln('<script>' + src + '</script>');
  }
}

/*
function addHandler(obj, property, handler) { 
  var oldHandler = obj[property];
  var newHandler = handler;
  if (oldHandler) {
    newHandler = function() {
      oldHandler.apply(arguments);
      newHandler.apply(arguments);
    }
  }
}
*/


// IE does not conform to w3c DOM here:
// If there is no Node object, define one with the standard properties and IE values
if (typeof(window) != "undefined" && !window.Node) {
  var Node = {
    ELEMENT_NODE: 1,
    ATTRIBUTE_NODE: 2,
    TEXT_NODE: 3,
    COMMENT_NODE: 8,
    DOCUMENT_NODE: 9,
    DOCUMENT_FRAGMENT_NODE: 11    
  }
}

/*###how to add behaviour to DOM elements in IE? [HTMLHtml]Element is not defined...
if (!document.addEventListener) {
  document.addEventListener = HTMLHtmlElement.addEventListener = function(eventtype, handler, capture) {
    if (capture) throw new Error("Event capturing not supported in Internet Explorer");
    this.attachEvent("on" + eventtype, handler);
  }
}
*/

if (typeof(window) != "undefined" 
  /* the mozilla importNode method is buggy (images are not correctly imported, 
  they are not recognized as HTML IMG elements: && !window.document.importNode*/) {

 window.document.importNode = function(node /*:Node*/,  deep /*:boolean*/) /*:Node*/  {

  //debug(node.nodeName + " type: " + node.nodeType);

  var result;

  switch(node.nodeType) {
  case Node.ELEMENT_NODE:
    result = this.createElement(node.nodeName);
    var attributes = node.attributes;
    for (var i = 0; i < attributes.length; i++) {
      var attribute = attributes.item(i);
      if (attribute.specified)
	result.setAttribute(attribute.nodeName, node.getAttribute(attribute.nodeName));
    }
    if (deep) {
      var child = node.firstChild;
      while (child) {
	result.appendChild(this.importNode(child, true));
	child = child.nextSibling;
      }
    }
    break;
  case Node.TEXT_NODE: 
    result = this.createTextNode(node.nodeValue);
    break;
  case Node.COMMENT_NODE: 
    result = this.createComment(node.nodeValue);
    break;
  default:
    throw new Error("Unknown or unexpected node type in importNode(): " + node.nodeType);
  }
  return result;
 }
}

function _jsc_assert(value, msg) {
  if (!value) {
    m = "Assertion failed: " + msg;
    alert(m);
    throw new Error(m);
  }
}

function _jsc_package(qualifiedName) {
  //print("_jsc_package(" + _unparse(qualifiedName) + ")");
  var n = qualifiedName.length;
  var currentPackage = typeof(window) == "undefined" ? null : window;
  for(var i = 0; i < n; i++) {
    var name = qualifiedName[i];
    if (!currentPackage) {
      _jsc_assert(i == 0, "i == 0");
      try {
        currentPackage = eval(name);
      } catch (e) {
        //print(name+"=new Object();");
        eval(name+"=new Object();");
        currentPackage = eval(name);
      }
    } else if (!currentPackage[name])
      currentPackage = currentPackage[name] = new Object();
    else
      currentPackage = currentPackage[name];
    _jsc_assert(currentPackage && (typeof(currentPackage) == "object" || typeof(currentPackage) == "function" ) , "packages must have object or function type");
  }
}
