/*
    COPYRIGHT 2009 by Manuel Schneider <info@efreetsystems.de>
    http://www.efreetsystems.de

    This File is licensed under the LGPL.

    There is absolutely no warranty for anything!
*/

/*
    step #1: Logging

      LoggingPolicy:
        - FATAL: Errors that have impact on the user-experience
        - ERROR: Errors that may have indirect impact on the user-experience
        - WARNING: tipps for the programmer if something could go wrong
        - INFO: some event has occured
        - DEBUG: what do you do in each step
*/


//do i need full logging?
var logging = false;

//activate logging for debugging
if (logging) {
  createLoggingPane();
}

//a function to handle FATAL-Log- and ERROR-Log-Messages
var myFatal = false;
// function (mess) {
//   alert("FATALERROR: "+mess.info.join());
// }

//a function to handle ERROR-Log-Messages
var myError = false;
// function (mess) {
//   alert("ERROR: "+mess.info.join());
// }


var create_logger = function (myError,myFatal) {
  //set up logListeners for ERROR/FATAL
  forEach( [ [ "myFatal", "FATAL", myFatal ], [ "myError", "ERROR", myError ] ],
    function (obj) {
      if (typeof(obj[2]) == "function") {
        MochiKit.Logging.logger.addListener(obj[0],obj[1],obj[2]);
      }
    }
  );
}

function log (msg,myname) {
  MochiKit.Logging.log("["+myname+"] "+msg);
}

function logDebug (msg,myname) {
  MochiKit.Logging.logDebug("["+myname+"] "+msg);
}

function logWarning (msg,myname) {
  MochiKit.Logging.logWarning("["+myname+"] "+msg);
}

function logError (msg,myname) {
  MochiKit.Logging.logError("["+myname+"] "+msg);
}

function logFatal (msg,myname) {
  MochiKit.Logging.logFatal("["+myname+"] "+msg);
}

log("logging established.","es-base");

/*
    step #2: helpful 'classes'

    NOTE: every class needs a 'myname' argument which will be printed in log-messages
*/

/*
  encapsulate all kinds of xml_requests

  API:
      xml_requests(myname[,useINIT,[,doc]])
          'doc' is the path to the server that should be used for xml-requests.
          it defaults to the current document.
          'useINIT' is a boolean value which indicates that the FIRST_REQUEST object should
          be used for the first request (if possible). default is 'false'. The FIRST_REQUEST
          object is written when the page is loading, you may use this to save some first
          XML-requests after loading for performance reasons.

      .registerResultcode(code)
          'code' is a string containing a resultcode that could possibly be returned
              in the 'result' property of the evaled json. you don't need to register "good"
              and "error". The "error" code and unknown codes will issue an error/a warning.
              all registered Resultcodes + "good" will call the callback (see below)

      .syncJSONrequest(uri,Callback)
          perform a request with query-string 'uri' and don't use deferreds - wait
          until the request completed
          'Callback' is a function with one argument: the json data. it will be called
          if the resultcode is "good" or one of the registered.

      .performJSONrequest(uri,Callback)
          perform a request with query-string 'uri' using deferreds
          'Callback' is a function with one argument: the json data. it will be called
          if the resultcode is "good" or one of the registered.

          NOTE: register resultcodes before the performing the request ;)

*/
var xml_requests = function (myname,useINIT,doc) {

  if (typeof(useINIT) == "string") {
    doc = useINIT;
    useINIT = false;
  } else if (typeof(doc) != "string") {
    doc = location.href;
  }

  if ((typeof(useINIT) != "boolean" && typeof(useINIT) != "string") || typeof(FIRST_REQUEST) != "object") {
    useINIT = false;
  }

  var failedRequest = function (err) {
    logError("retrieving json failed! Error: '"+err+"'",myname);
  }

  var results = ["error", "good"];

  var used_inits = [];

  var findInitRequest = function (uri) {
    for (var i=0; i<FIRST_REQUEST.length; i++) {
      var reg = new RegExp("[?&]"+FIRST_REQUEST[i].request+"\\=");
//       logDebug("looking for "+reg+" in '"+uri+"': '"+uri.search(reg)+"'",myname);
      if (uri.search(reg) != -1) {
        return i;
      }
    }
    return false;
  }

  var is_used = function (uri) {
    //looking for the uri in FIRST_REQUEST
    if ((i = findInitRequest(uri)) !== false) {
      if (findValue(used_inits,FIRST_REQUEST[i].request) == -1) {
        logDebug("found previously unused initial request '"+uri+"' as index '"+i+"' of 'FIRST_REQUEST'",myname);
        used_inits[used_inits.length] = FIRST_REQUEST[i].request;
        if (used_inits.length == FIRST_REQUEST.length) {
          logDebug("all initial requests done, setting 'useINIT' to false",myname);
          useINIT = false;
        }
        return false;
      } else {
        logDebug("initial request '"+uri+"' already used",myname);
        return true;
      }
    }
    logDebug("initial request '"+uri+"' is not available in 'FIRST_REQUEST'",myname);
    return true;
  }

  var evalCallback = function (Callback,mydata) {

    if (isUndefinedOrNull(mydata)){
      logWarning ("error! mydata is empty or null! This should not happen..",myname);
    } else if (mydata.result == "error") {
      logError ("server side error! server said: '"+repr(mydata.descr)+"'",myname);
    } else if (findValue(results,mydata.result) != -1) {
      logDebug ("found registered value '"+mydata.result+"', calling Callback",myname);
      Callback(mydata);
    } else {
      logWarning ("found unregistered returnCode: '"+mydata.result+"'",myname);
    }

  }

  var do_initJSONrequest = function (uri,goodCallback) {
    log("starting initial fake json request: GET '"+doc+uri+"'",myname);
    evalCallback(goodCallback,FIRST_REQUEST[findInitRequest(uri)].data);
  }

  var do_performJSONrequest = function (uri,goodCallback) {
    log("starting asynchronous json request: GET '"+doc+uri+"'",myname);
    var d = loadJSONDoc(doc+uri);
    d.addCallbacks(partial(evalCallback,goodCallback),failedRequest);
  }

  var do_syncJSONrequest = function (uri,goodCallback) {
    log("starting synchronous json request: GET '"+doc+uri+"'",myname);
    var request = getXMLHttpRequest();
    request.open("GET",doc+uri,false);
    request.send(null);
    if (request.status == 200){
      evalCallback(goodCallback,evalJSONRequest(request));
    } else {
      failedRequest(request.status+": '"+request.statusText+"'");
    }
  }

  this.syncJSONrequest = function (uri, goodCallback) {
    if (useINIT && !is_used(uri)) {
      do_initJSONrequest(uri,goodCallback);
    } else {
      do_syncJSONrequest(uri,goodCallback);
    }
  }

  this.performJSONrequest = function (uri, goodCallback) {
    if (useINIT && !is_used(uri)) {
      do_initJSONrequest(uri,goodCallback);
    } else {
      do_performJSONrequest(uri,goodCallback);
    }
  }

  //default result codes are error - unknown result codes will isue a warning
  this.registerResultcode = function (code) {
    logDebug("registering resultcode with index '"+results.length+"': '"+code+"'",myname);
    results[results.length] = code;
  }

  this.version = "0.1";
  log("new instance of 'xml_requests' with options: useINIT='"+repr(useINIT)+"'; doc='"+doc+"'",myname);

}


/*
  let's simplify signaling a bit :)
  TODO: dynamic arguments
*/
function signal (object,signal,args,args2,args3) {
  MochiKit.Signal.signal(object.ctrl,signal,object,args,args2,args3);
}


priorityDeferredLock = function (myname) {
    this.waiting = [];
    this.locked = false;
    this.myname = myname;

    this.acquire = function (priority) {
        var d = new MochiKit.Async.Deferred();
        if (this.locked) {
            var thisObj = {};
            thisObj.def = d;
            thisObj.prio = priority;
            var newIndex=0;
            while (!isUndefinedOrNull(this.waiting[newIndex])
             && this.waiting[newIndex].prio <= thisObj.prio) {
              newIndex++;
            }
            if (!isUndefinedOrNull(this.waiting[newIndex])) {
              for (var i=this.waiting.length-1;i>=newIndex;i--) {
                this.waiting[i+1] = this.waiting[i];
              }
            }
            this.waiting[newIndex] = thisObj;
        } else {
            this.locked = true;
            d.callback(this);
        }
        return d;
    }

    this.release = function () {
        if (!this.locked) {
            logWarning("Tried to release an unlocked DeferredLock",myname);
        }
        this.locked = false;
        if (this.waiting.length > 0) {
            this.locked = true;
            this.waiting.shift().def.callback(this);
        }
    }

    this.getNextprio = function () {
      if (isUndefinedOrNull(this.waiting[0])) {
        return "nan";
      } else {
        return this.waiting[0].prio;
      }
    }
};


var ressourcedElements = [];
var doubleElements = [];

var ressource = function (myname,depends,conflicts) {

  //define some attributes
  if (isUndefinedOrNull(conflicts)) {
    logWarning("i have no conflicts",myname);
    conflicts = [];
  } else if (findValue(conflicts,myname) != -1) {
    logWarning("wtf? i am conflicting with myself!",myname);
  }

  if (isUndefinedOrNull(depends)) {
    logWarning("i have no depends",myname);
    depends = [];
  } else if (findValue(depends,myname) != -1) {
    logWarning("wtf? i am depending on myself! fix this!",myname);
  }

  this.conflicts = conflicts;
  this.depends = depends;
  this.myname = myname;
  this.version = "0.1";

  logDebug("depending on "+repr(this.depends),myname);
  logDebug("conflicting with "+repr(this.conflicts),myname);

  this.registerConflict = function (object) {
    logDebug("now conflicting with '"+object.myname+"'",myname);
    this.conflicts[this.conflicts.length] = object;
  }

  this.registerDependant = function (object) {
    logDebug("now depending on '"+object.myname+"'",myname);
    this.depends[this.depends.length] = object;
  }


  //manage html-elements (ressource members)
  this.myelements = [];

  var addElement = function (me,element,id) {
    if (findValue(me.myelements,id) != -1) {
      logWarning("refusing to register element with id '"+id+"': already in this ressource!",myname);
    } else {
      if (findValue(ressourcedElements,element.id) != -1) {
        logWarning("the element with id '"+id+"' is already member of another ressource!",myname);
        if (isUndefinedOrNull(doubleElements[element.id])) {
          doubleElements[element.id] = 0;
        } else {
          doubleElements[element.id]++;
        }
      } else {
        logDebug("adding new element '"+repr(element.id)+"'",myname);
        ressourcedElements[ressourcedElements.length] = element.id;
      }
      me.myelements[id] = element;
    }
  }

  var addElementRecurse = function (me,element,id,recursion_depth) {
    if (!isUndefinedOrNull(id)) {
      addElement(me,element,id);
      if (recursion_depth > 0 && !isUndefinedOrNull(element.childNodes)) {
        forEach (element.childNodes, function (elem) {
//           logDebug("starting another recursion for '"+repr(element.id)+"'",myname);
          addElementRecurse(me,elem,elem.id,recursion_depth-1);
        });
      }
    } else {
      logDebug("skipping element '"+repr(element)+"', because it has no id",myname);
    }
  }

  this.registerElement = function (element,recursion_depth) {
    if (isUndefinedOrNull(getElement(element))) {
      logWarning("element with id '"+element+"' is not available!",myname);
    } else if (isUndefinedOrNull(recursion_depth) || recursion_depth == 0) {
      addElement(this,getElement(element),getElement(element).id);
    } else {
      addElementRecurse(this,getElement(element),getElement(element).id,recursion_depth);
    }
  }

  this.allElements = function (args,func) {
    if (!isUndefinedOrNull(func) && func) {
      forEach (keys(this.myelements),partial(function (me,elem) {
        args(me.myelements[elem]);
      },this));
    } else {
      if (typeof(args) != "function") {
        forEach (keys(this.myelements),partial(function (me,elem) {
          me.myelements[elem].args;
        },this));
      } else {
        forEach (keys(this.myelements),partial(function (me,elem) {
          me.myelements[elem].args();
        },this));
      }
    }
  }

  //locking mechanism
  var lockedby = {};
  var myMom = {};
  //the main lock for this ressource which tracks its state
  var locked = new priorityDeferredLock();
  var curDepends = [];
  var curConflicts = [];
  var foreignElements = [];
  var privqueue = [];

  this.lockedby = function () {
    return lockedby.myname;
  }

  this.acquire = function (process,initstate,mommy) {

    if (lockedby.myname == process.myname) {
      logDebug("already locked by process '"+process.myname+"'!",myname);
      forEach(concat(curDepends,curConflicts),function(obj){
        logDebug("my child '"+obj.myname+"' is locked by '"+obj.lockedby()+"'",myname);
      });
      return false;
    } else {
      //create a waiting list that will fire if this ressource is complete acquired
      //if the resolve-process is interrupted it'll never fire
      var onAcquire = new MochiKit.Async.DeferredLock();
      onAcquire.acquire();
      //create the deferred for this acquire
      var thisAcquire = locked.acquire(process.priority);
      thisAcquire.addCallbacks(partial(function (mythis) {
        var dependencyCount = 1;
        var toAcquireDepends = [];
        var toAcquireConflicts = [];

        var get_dependencies = function (mode,ressource) {
          if (mode == "depends") {
            toAcquireDepends = concat(toAcquireDepends,[ressource]);
            forEach(ressource.depends,function(me){
              var already_In = false;
              for (var i=0;i<toAcquireDepends.length;i++) {
                if (toAcquireDepends[i].myname == me.myname) {
                  already_In = true;
                }
              }
              if (!already_In) {
                get_dependencies("depends",me);
              }
            });
          } else {
            toAcquireConflicts = concat(toAcquireConflicts,[ressource]);
            forEach(ressource.depends,function(me){
              var already_In = false;
              for (var i=0;i<toAcquireConflicts.length;i++) {
                if (toAcquireConflicts[i].myname == me.myname) {
                  already_In = true;
                }
              }
              if (!already_In) {
                get_dependencies("conflicts",me);
              }
            });
          }
    
          forEach(ressource.conflicts,function(me){
            var already_In = false;
            for (var i=0;i<toAcquireConflicts.length;i++) {
              if (toAcquireConflicts[i].myname == me.myname) {
                already_In = true;
              }
            }
            if (!already_In) {
              get_dependencies("conflicts",me);
            }
          });
        }

        if (isUndefinedOrNull(mommy)) {
          logDebug("process '"+process.myname+"' wants to acquire me",myname);
          mommy = mythis;
          if (isUndefinedOrNull(initstate) || initstate == false) {
            initstate = false;
            //calculate all dependencies
            get_dependencies("depends",mythis);
            //kick ressources from toAcquireConflicts that are already in toAcquireDepends
            for (var i=0; i<toAcquireDepends.length; i++) {
              todel = -1;
              for (var j=0; j<toAcquireConflicts.length; j++) {
                if (toAcquireConflicts[j].myname == toAcquireDepends[i].myname) {
                  todel = j;
                }
              }
              if (todel != -1) {
                toAcquireConflicts.splice(todel,1);
              }
            }
            //kick myself
            toAcquireDepends.splice(0,1);
          } else {
            toAcquireDepends = initstate[myname].depends;
            toAcquireConflicts = initstate[myname].conflicts;
          }
          logDebug("toAcquireDepends:",myname);
          forEach(toAcquireDepends,function (me) { logDebug (repr(me.myname),myname);});
          logDebug("-- toAcquireConflicts: ",myname);
          forEach(toAcquireConflicts,function (me) { logDebug (repr(me.myname),myname);});
          dependencyCount = dependencyCount+toAcquireDepends.length+toAcquireConflicts.length;
        } else {
          logDebug("process '"+process.myname+"' wants to acquire me for ressource '"+mommy.myname+"'",myname);
        }

        //check if all Dependencies are satisfied and if so lock myself
        var acquireChildrenFinished = function (me,process) {
          dependencyCount--;
          if (dependencyCount == 0) {
            logDebug("all dependencies are satisfied => locking myself now...",myname);
            thisAcquire.addCallbacks(function () {
              logDebug("successfully locked myself for process '"+process.myname+"'",myname);
              if (initstate != false) {
                me.myelements = initstate[myname].state;
              }
              onAcquire.release();
            });
          }
        }

        lockedby = process;
        myMom = mommy;
        curDepends = toAcquireDepends;
        curConflicts = toAcquireConflicts;

        //acquire dependencies
        var acquireDepends = partial(function (me,res) {
          logDebug("acquiring dependency '"+res.myname+"'",myname);
          var d = res.acquire(process,initstate,mommy);
          d.addCallbacks(function () {
            //add this ressources elements to mine
            logDebug("adding elements of dependant ressource '"+res.myname+"' to mine",myname);
            forEach(keys(res.myelements), function (id) {
              if (!isUndefinedOrNull(me.myelements[id])) {
                logWarning("element '"+id+"' is in ressource '"+me.myname+"' AND '"+res.myname+"'! fix this!",myname);
              } else {
                me.myelements[id] = res.myelements[id];
                foreignElements[foreignElements.length] = id;
              }
            });
            acquireChildrenFinished(me,process);
          });
        },mythis);

        var acquireConflicts = partial(function (me,res) {
          logDebug("acquiring dependency '"+res.myname+"'",myname);
          var d = res.acquire(process,initstate,mommy);
          d.addCallbacks(function () {
            acquireChildrenFinished(me,process);
          });
        },mythis);

        forEach(toAcquireDepends,acquireDepends);
        forEach(toAcquireConflicts,acquireConflicts);

        acquireChildrenFinished(mythis,process);
      },this));

      //if I am locked by a process with a lower priority
      // => signal it to RELEASE mommy
      if (!isEmpty(lockedby.myname) && locked.getNextprio() != "nan" && lockedby.priority > locked.getNextprio()) {
        logDebug("signaling '"+lockedby.myname+"' to release '"+myMom.myname+"'",myname);
        signal(lockedby,'release',myMom);
      }

      return onAcquire.acquire();
    }
  }

  this.release = function (process) {
    if (lockedby.myname != process.myname) {
      logWarning("not locked by '"+process.myname+"'! ignoring release request. ('"+lockedby.myname+"')",myname);
      return false;
    } else {
      logDebug("releasing myself as wished by '"+process.myname+"'",myname);
      var initstate = [];
      initstate[myname] = {};
      initstate[myname].state = this.myelements;
      initstate[myname].depends = curDepends;
      initstate[myname].conflicts = curConflicts;

      forEach(foreignElements,partial(function(me,id) {
        logDebug("kicking element with id '"+id+"'",myname);
        delete me.myelements[id];
      },this));
      foreignElements = [];

      forEach(concat(curDepends,curConflicts),partial(function(me,res) {
        initstate[res.myname] = res.release(process);
      },this));

      //reset
      lockedby = {};
      myMom = {};
      curDepends = [];
      curConflicts = [];

      locked.release();
      return initstate;
    }
  }


  log("new instance of 'ressource'",myname);
}


var process = function (myname,priority) {

  //some attributes
  if (isUndefinedOrNull(priority)) {
    logWarning("priority is not set! defaulting to 100",myname);
    priority = 100;
  }
  this.myname = myname;
  this.priority = priority;
  this.version = "0.1";


  //manage ressources
  var myRes = [];
  var myResHandles = [];

  var getRes = function (resName) {
    if (!isUndefinedOrNull(myResHandles[resName])) {
      return myResHandles[resName];
    } else {
      return false;
    }
  }

  this.acquire = function (ressource,callback,onForcedRelease) {
    logDebug("acquiring ressource '"+ressource.myname+"'",myname);
    var rh = myRes.length
    myResHandles[ressource.myname] = rh;
    myRes[rh] = {};
    myRes[rh].ressource = ressource;
    myRes[rh].callback = callback;
    myRes[rh].released = true;
    if (isUndefinedOrNull(onForcedRelease)) {
      myRes[rh].onForcedRelease = false;
    } else {
      myRes[rh].onForcedRelease = onForcedRelease;
    }
    var d = ressource.acquire(this);
    if (typeof(d) != "boolean") {
      d.addCallbacks(function () {
        myRes[rh].released = false;
      });
      d.addCallbacks(callback);
    }
  }

  this.release = function (ressource) {
    var rh = getRes(ressource.myname);
    if (typeof(rh) != "number") {
      logWarning("could not release ressource '"+ressource.myname+"': not registered! rh was '"+repr(rh)+"'",myname);
    } else {
      myRes[rh].ressource = ressource;
      logDebug("releasing ressource '"+ressource.myname+"'",myname);
      ressource.release(this);
      delete myRes[rh];
      delete myResHandles[ressource.myname];
    }
  }

  var forcedRelease = function (me,ressource) {
    log("received signal RELEASE for ressource '"+ressource.myname+"'",myname);
    var rh = getRes(ressource.myname);
    myRes[rh].ressource = ressource;
    if (typeof(rh) != "number") {
      logWarning("could not release ressource '"+ressource.myname+"': not registered! rh was '"+repr(rh)+"'",myname);
    } else {
      logDebug("alrite, ressource '"+ressource.myname+"' is registered with handle '"+rh+"'",myname);
      if (myRes[rh].onForcedRelease != false) {
        logDebug("calling onForcedRelease for ressource '"+ressource.myname+"'",myname);
        myRes[rh].onForcedRelease();
      }
      logDebug("releasing ressource '"+ressource.myname+"' forced..",myname)
      var state = myRes[rh].ressource.release(me);
      if (typeof(state) == "object") {
        myRes[rh].released = true;
        logDebug("reAcquiring ressource '"+ressource.myname+"' with previous state",myname);
        var d = myRes[rh].ressource.acquire(me,state);
        if (typeof(d) != "boolean") {
          d.addCallbacks(function () {
            myRes[rh].released = false;
          });
          d.addCallbacks(myRes[rh].callback);
        }
      }
    }
  }


  //daemon stuff
  this.daemonopts = {};
  this.daemon = false;

  var daemonDeferred = function (me) {
    me.daemonopts.callback(me);
    me.daemon = wait(me.daemonopts.wakeupInt);
    me.daemon.addCallback(partial(daemonDeferred,me))
  }

  this.startdaemon = function (wakeupInt,callback,registerOnly) {
    if (typeof(wakeupInt) == "number" && wakeupInt > 0) {

      logDebug("registering deferred daemon with wakeup interval '"+wakeupInt+"'",myname);
      this.daemon = true;
      this.daemonopts = {"wakeupInt": wakeupInt, "callback": callback};
      if (isUndefinedOrNull(registerOnly)) {
        log("starting deferred daemon with wakeup interval '"+wakeupInt+"'",myname);
        daemonDeferred(this);
      }
    } else {
      logWarning ("daemon mode is off (wakeupInt="+repr(wakeupInt)+")",myname);
    }
  }

  var daemonStop = function (me) {
    if (typeof(me.daemon) != "boolean") {
      log("received signal 'stop', trying to stop daemon",me.myname);
      me.daemon.cancel();
      me.daemon = true;
    } else {
      log("received signal 'stop', but there's no daemon running",me.myname);
    }
  }

  var daemonStart = function (me) {
    if (typeof(me.daemon) == "boolean" && me.daemon == false) {
      logWarning("received signal 'start', but there's no daemon defined",me.myname);
    } else if (typeof(me.daemon) == "boolean" && me.daemon == true) {
      log("received signal 'start', trying to fire up daemon",me.mynamae);
      daemonDeferred(me);
    } else {
      log("received signal 'start', but daemon is already running.",me.myname);
    }
  }


  //global signals for this process
  logDebug("registering global signals",myname)
  this.ctrl = {};
  this.ctrlSigs = [];
  this.ctrlSigs[0] = MochiKit.Signal.connect(this.ctrl,'release',forcedRelease);
  this.ctrlSigs[1] = MochiKit.Signal.connect(this.ctrl,'daemonStop',daemonStop);
  this.ctrlSigs[2] = MochiKit.Signal.connect(this.ctrl,'daemonStart',daemonStart);

  this.registerSignal = function (signal,callback) {
    log("registering custom global signal '"+repr(signal)+"'",myname);
    this.ctrlSigs[this.ctrlSigs.length] = MochiKit.Signal.connect(this.ctrl,signal,callback);
  }


  //destructor
  this.destroy = function () {
    log("destroying process now",myname);
    logDebug("stopping daemon",myname);
    daemonStop(this);
    var i=0;
    forEach (this.ctrlSigs, function (signal) {
      logDebug("disconnecting signal #"+i,myname);
      disconnect(signal);
      i++;
    });
    for (i=0;i<acquiredRessources.length; i++) {
      logDebug("releasing ressource #"+i+": '"+acquiredRessources[i].ressource.myname+"'",myname);
      this.releaseRessource(i);
    }
  }

  //finished
  log("new instance of 'process' with priority '"+priority+"'",myname);
}

function proc_factory (myname,extension,priority) {
  if (typeof(extension) != "function") {
    logWarning("extension is not a function, abort factoring",myname);
    return false;
  }
  var tmp = extension;
  tmp.prototype = new process (myname,priority);
  return new tmp();
}

//if the logging-pane is activated, i want the log cleared by spam to work around the scroll problem
if (logging) {
  var clearlog = function () {
    this.startdaemon(3,function (me) {
      logDebug("*ping*",me.myname)
    });
  }
  clearlog = proc_factory ('clearlog',clearlog);

  var stopClearlog = function (waitseconds) {
    var d = wait(waitseconds);
    d.addCallbacks(function () { signal(clearlog,"daemonStop");});
  }
}
