/*
Talky - A modulable hub for programming language interpreters in JavaScript.
Copyright (c) 2009 Thomas Peri
MIT License
*/
var Talky={Hub:function(parts){var self=this,error,interpreter,clumpy,modules,options,running,paused,count,callback,construct,update,changed,nothing,the_next,setOptions,getOptions,addModule,getModule,lookup,run,init,stop,pause,next,resume,async;construct=function(){parts=parts||{};error=parts.error||nothing;interpreter=parts.interpreter;Talky.InterpreterIF.verify(interpreter,'interpreter');modules={};clumpy=new Clumpy({between:update});options={clumpyDelay:0,clumpyDuration:25,clumpyManual:false,maxUpdatesPerClump:1,ignoreMaxUpdatesPerClump:true};setOptions(parts.options||{});interpreter.setHub(self);};nothing=function(){};update=function(flag){var mod;for(mod in modules){if(modules.hasOwnProperty(mod)){if(modules[mod].changed()){modules[mod].update();}}}};changed=function(){var mod;for(mod in modules){if(modules.hasOwnProperty(mod)){if(modules[mod].changed()){return true;}}}return false;};setOptions=function(opt){var number,bool;opt=opt||{};number=function(key){if(typeof opt[key]!=='undefined'){options[key]=Math.max(0,parseInt(opt[key],10)||0);}};bool=function(key){if(typeof opt[key]!=='undefined'){options[key]=opt[key]?true:false;}};number('clumpyDelay');number('clumpyDuration');bool('clumpyManual');number('maxUpdatesPerClump');bool('ignoreMaxUpdatesPerClump');clumpy.setNow({delay:options.clumpyDelay,duration:options.clumpyDuration,manual:options.clumpyManual});};getOptions=function(){return{clumpyDelay:options.clumpyDelay,clumpyDuration:options.clumpyDuration,clumpyManual:options.clumpyManual,maxUpdatesPerClump:options.maxUpdatesPerClump,ignoreMaxUpdatesPerClump:options.ignoreMaxUpdatesPerClump};};addModule=function(){var i,mod;for(i=0;i<arguments.length;i+=1){mod=arguments[i];Talky.ModuleIF.verify(mod,'Talky.addModule');if(modules.hasOwnProperty(mod.name)){throw"module "+mod.name+" is already loaded.";}modules[mod.name]=mod;mod.setHub(self);mod.init();}};getModule=function(modName){if(modules.hasOwnProperty(modName)){return modules[modName];}return null;};lookup=function(memName,optModName){var mod,modName;if(optModName){modName=optModName;if(modules.hasOwnProperty(modName)){mod=modules[modName];if(mod.talky.hasOwnProperty(memName)){return mod.talky[memName];}else{return null;}}else{throw'module '+modName+' is not loaded';}}else{for(modName in modules){if(modules.hasOwnProperty(modName)){mod=modules[modName];if(mod.talky.hasOwnProperty(memName)){return mod.talky[memName];}}}return null;}};the_next=function(){var proceed;try{proceed=interpreter.next();}catch(e){error(e);proceed=false;}if(proceed){if(changed()){count+=1;}if(!options.ignoreMaxUpdatesPerClump&&count>=options.maxUpdatesPerClump){count=0;clumpy.interrupt();}}else{stop();}};run=function(code,cb){if(running){return false;}running=true;callback=cb;try{interpreter.parse(code);}catch(e){error(e);}count=0;clumpy.while_loop(function(){return true;},the_next);return true;};init=function(){var m;stop();for(m in modules){if(modules.hasOwnProperty(m)){modules[m].init();}}};pause=function(){if(running&&!paused){paused=true;clumpy.pause();}};resume=function(){if(running&&paused){paused=false;clumpy.resume();}};stop=function(){if(running){update();running=false;paused=false;clumpy.init();callback();}};next=function(){if(running&&paused){the_next();update();}};async=function(fn){clumpy.wait(fn);};this.addModule=addModule;this.getModule=getModule;this.lookup=lookup;this.setOptions=setOptions;this.getOptions=getOptions;this.async=async;this.run=run;this.init=init;this.pause=pause;this.resume=resume;this.stop=stop;this.next=next;construct();},module:function(name,fn){fn=Talky.ModuleIF(name,fn);return function(){var mem,tk,names,i;fn.apply(this,arguments);tk=this.talky;this.name=name;names=[];for(mem in tk){if(tk.hasOwnProperty(mem)){names.push(mem);}}for(i=names.length-1;i>=0;i-=1){tk[names[i]].moduleName=name;tk[names[i]].memberName=names[i];}};},ModuleIF:iFace('Talky.ModuleIF',['talky','init','setHub','changed','update']),InterpreterIF:iFace('Talky.InterpreterIF',['parse','next','setHub'])};