_js_package("org.cote.js.task");

org.cote.js.task={
	TaskService:null,
	TaskServiceImpl:function(){
		var t=this,_j=org.cote.js,_x=org.cote.js.xml,_m=org.cote.js.message.MessageService;
		org.cote.js._implements(t,"base_object","task_service","0.1a");

		t.object_config={
			pointers:{
				tasks:[],
				taskindex:[],
				tasknames:[]
			},
			status:{
				config_name:0,
				config_loaded:0,
				window_loaded:0
			}
		};
		
		t.sigterm=function(){
			var t=this,c;
			c = t.object_config;
			t.ready_state = 5;
		};

		t._handle_window_destroy=function(s,v){
			var t=this,c;
			c = t.object_config;
			t.sigterm();
			c.pointers.tasks=[];
			c.pointers.taskindex=[];
			c.pointers.tasknames=[];
		};
		
		t.processTasks=function(){
			var a,i,b;
			a = t.object_config.pointers.tasks;
			for(i=0;i<a.length;i++){
				b = a[i];
				if(b.state==4) continue;
				if(!b.state && !b.busy){
					t.handle_task(b,1);
				}
				else if(b.state==3 && !b.depends.length){
					b.state = 4;
					t._update_task_depends(b.name);
					_m.publish("_internal_task_event",{id:b.id,task:b});
				}
			}
		};
		t.addTaskDependency=function(b,i){
			if(typeof i == "object") i = i.id;
			
			b.depends[b.depends.length]=i;

			/*
				fix for window load
			*/
			if(
				t.object_config.status.window_loaded
				&&
				i == "_dom_event_window_load"
			){
				t.returnDependency("_dom_event_window_load",1);
			}
		
		};
		t.getTaskDepends=function(b){
			var h,m,r=[];

			if(!b.depends.length) return r;
			for(h=0;h<b.depends.length;h++)
				r[h]=b.depends[h];
			return r;
		};


		t._update_task_depends=function(s){
			var a,b,i,h,m;
			a = t.object_config.pointers.tasks;

			for(i=0;i<a.length;i++){
				b = a[i];
				if(b.state == 4 || !b.depends.length){
					continue;
				}

				m = 0;
				for(h=0;h<b.depends.length;h++){
					if(b.depends[h] == s){
						b.depends[h] = 0;
					}
					else if(b.depends[h] != 0){
						m = 1;
					}
				}
				if(!m){
					b.depends = [];
				}
			}

			/*
				Start another process cycle.
				The cycle iterates for the number of bootstrap objects
				and their dependencies.
			*/
			t.processTasks();

		};
		t.execTaskLoader=function(n,p,s,h,ht){
			t.object_config.status.config_name = n;
			return t.execTask(n,p,s,h,ht);
		};
		t.execTask=function(n,p,s,h,ht){
			var b=n;
			if(typeof n=="string") b=t.addTask(n,p,s,h,ht);
			if(b.state) return 0;
			t.handle_task(b);

			return b;

		};

		t.addTask=function(n,p,s,h,ht){
			/*
				n = config name of bootstrap
				p = type/protocol
				s = source/action
				h = handler/result
				ht = handler type
				xxx d = dependencies
			*/
			var v,i=_j._get_gunid(),l,c;

			c=t.object_config;

			if(typeof c.pointers.tasknames[n]=="number"){
				alert('bad: duplicate task; this is an event problem');
				return;
			}

			l=c.pointers.tasks.length;
			if(typeof h!="string" && typeof h!="function") h = 0;
			if(!h) ht=0;

			v = _j._forName("task_object",n,p,s,h,ht,i,l);
			c.pointers.tasks[l]=v;
			c.pointers.tasknames[n]=l;
			c.pointers.taskindex[i]=l;
			return v;
		};

		t.getTaskByName=function(s){
			var c=t.object_config.pointers;
			if(typeof c.tasknames[s]=="number") return c.tasks[c.tasknames[s]];
			return 0;
		};

		t.getTaskById=function(i){
			var c=t.object_config.pointers;
			if(typeof c.taskindex[i]=="number") return c.tasks[c.taskindex[i]];
			return 0;
		};
		t.returnDependency=function(s,r){
			if(typeof s=="object") s = s.id;
			
			t._update_task_depends(s);
		};

		t._handle_task_event=function(s,v){
			var c = t.object_config,b,d;

			if(typeof v.id != "string") return 0;


			b = (v.task?v.task:t.getTaskById(v.id));
			d = (b.name == c.status.config_name?b:t.getTaskByName(c.status.config_name));

			if(!b.state){
				return t.handle_task(b);
			}
			else{
				/*
					the .handled property was added to make sure
					bootstraps aren't handled twice.
					
					This is a hack-fix for a bug that arose in IE
					when I switched the XML load mechanism to use XMLHttp.
					For some reason, the loader was being processed twice
					when the message service was set to operate in delayed mode.

					It would be just as easy to directly invoke the handler,
					but then that would eliminate the usability gains of 
					delayed messaging.
				*/
				if(
					b.state==4
					&&
					!b.handled
				){
					b.handled=1;
					if(b.handler && b.handler_type){
						switch(b.handler_type){
							case "function":
								if(typeof b.handler == "function")
									b.handler("ontaskcomplete",b);
								else if(typeof b.handler == "string" && typeof window[b.handler]=="function")
									window[b.handler]("ontaskcomplete",b);
								break;
							case "procedure":
								t.executeProcedure(d,b.handler);
								break;
							case "event":
								_m.publish(b.handler,this);
								break;
							default:
								alert("not handled: " + b.handler_type);
								break;
							
						}
					}
					_m.publish("ontaskcomplete",{name:b.name,id:b.id});

				}
			}
		};
		t.importTask=function(d,p,n,b){
			/*
				d = config object
				p = parent task
				n = task node
				b = execute this task immediately
			*/
			var e=n,z,g,h,f,ht;
			if(typeof n=="object"){
				e = n.getAttribute("rid");
			}
			z = _x.queryNode(d.obj,"tasks","task","id",e);

			if(z!=null){
				g = z.getAttribute("type");
				h = z.getAttribute("handler");
				ht = z.getAttribute("htype");
				f = z.getAttribute("src");
				if(typeof p=="object") p.depends[p.depends.length]=e;
				if(b) t.execTask(e,g,f,h,ht);
				else t.addTask(e,g,f,h,ht);
			}
		};

		t.handle_task=function(b,s){
			var r,z,y,a,n,m,i,d = (b.name == t.object_config.status.config_name?b:t.getTaskByName(t.object_config.status.config_name));

			/*
				b = bootstrap object being handled
				d = bootstrap object referencing the "_bootstrap_driver" id.
				m = xml config node for the bootstrap driver
				a = array of specific child nodes in m
				n = element of array a.
				i = int for iteration
				
				z = reference node from n
				XXX e = id
				XXX g = type
				XXX f = [src]
				XXX h = [handler]
				r = raw data
				
				s = skip_recursive_loop
			*/


			/*if the task is complete, or this task service was given a config definition and the config data is not available, then return*/
			if(typeof s=="undefined") s = 0;


			
			if(!b.executed){
				b.executed=1;
				switch(b.type){
					case "procedure":
						t.executeProcedure(d,b.src);
						break;
					case "function":
						if(typeof t[b.src]=="function"){
							try{
								t[b.src]("onevaluate",b);
							}
							catch(x){
								alert("Evaluate Task Node Error: " + b.name);
							}
						}
/*
						if(b.src=="static" && typeof t[b.handler]=="function"){
							try{
								eval(t[b.handler]());
							}
							catch(x){
								alert("Evaluate Task Node Error: " + x);
							}
						}
*/
						break;
					case "xml":
						/*
							Xml returns here because it is not guaranteed to be synchronous
						*/
						b.busy=1;
						_x.getXml(b.src,t._handle_load_xml,1,b.id);
						return;
						break;
					default:
						break;
				}
			}

			if(
				b.state
				||
				(
					t.object_config.status.config_name
					&&
					(!d || !t.object_config.status.config_loaded)
				)
			) return 0;
/*
			if(!d || b.state || !t.object_config.status.config_loaded) return 0;
*/
			b.state = 1;
			
			if(d && typeof d.obj=="object"){
				m = _x.queryNode(d.obj,"tasks","task","id",b.name);

				if(m!=null){
					/*
						Evaluate tasks that are dynamic.
						
						Don't check to see if this was executed because
						the bit was set above
					*/
					switch(b.type){
						case "function":
							if(b.src=="#cdata" && m.hasChildNodes()){
								r = _x.getCDATAValue(m);
								eval(r);
								b.data = r;
						
							}
							break;
					}


					b.state = 2;

					a = _x.queryNodes(m,"exec-task");
	
					for(i=0;i<a.length;i++){
						t.importTask(d,b,a[i],1);
					}
	
					a = _x.queryNodes(m,"add-task");
					for(i=0;i<a.length;i++){
						t.importTask(d,b,a[i],0);
					}
	
					a = _x.queryNodes(m,"add-depends");
					for(i=0;i<a.length;i++){
						t.addTaskDependency(b,a[i].getAttribute("rid"));
					}
	
					a = _x.queryNodes(m,"execute-procedure");
					for(i=0;i<a.length;i++){
						b.depends[b.depends.length]=a[i].getAttribute("rid");
						t.executeProcedure(d,a[i].getAttribute("rid"));
					}
					
				}
			}
			
			/* if bootstrap has no dependencies, then set it to be complete*/
			b.state=3;
			if(!b.depends.length){
				b.state=4;
				_m.publish("_internal_task_event",{id:b.id,task:b});
				t._update_task_depends(b.name);
			}
			if(!s) t.processTasks();
		};

		t._handle_load_xml=function(n,x){

			var i = x.id,c=t.object_config,b;

				/* if this was a bootstrap event*/

			if(typeof c.pointers.taskindex[i]=="number"){

				b = t.getTaskById(i);
				b.busy=0;

				if(
					typeof x.xdom != "undefined"
				){
					b.obj = x.xdom;
				}
				else{
					_m.sendMessage("Null XML Response","512.5",1);
				}

				if(b.name == c.status.config_name){
					c.status.config_loaded=1;

				}

				_m.publish("_internal_task_event",{xml:x,id:i});
			}
		};

		t.executeProcedure=function(d,i){
			var n;
			n = _x.queryNode(d.obj,"procedures","procedure","id",i);
			if(n!=null) t.evaluateNode(n);
		};
/*		
		t.getCDATAValue=function(n){
			var t=this,c,d="",i=0,e;
			c = n.childNodes;
			for(;i<c.length;i++){
				e=c[i];
				if(e.nodeName=="#cdata-section") d+=e.nodeValue;
			}
			return d;
		};
*/		
		t.evaluateNode=function(n){
			var d = _x.getCDATAValue(n);
			try{
				eval(d);

			}
			catch(x){
				alert("TaskService: Evaluate Node Error: " + (x.description?x.description:x.message) + "\n" + d);
			}

		};

		t._handle_window_load=function(){
			t.object_config.status.window_loaded=1;
			t.returnDependency("_dom_event_window_load",1);
		};

		org.cote.js.dom.event._add_event_buffer(t);

		_m.subscribe(this,"_internal_task_event","_handle_task_event");
		_m.subscribe(this,"dom_event_window_load","_handle_window_load");
		_m.subscribe(t,"destroy","_handle_window_destroy",window);
		org.cote.js._application_scope.add_object(t);
	}

};



org.cote.js.task.TaskService=new org.cote.js.task.TaskServiceImpl();
