

//douglas crockford's prototypal inheritance function
//http://javascript.crockford.com/prototypal.html
if (typeof Object.create !== 'function') {
    Object.create = function (o) {
        function F() {}
        F.prototype = o;
        return new F();
    };
}



//todo: make editablewidget just function that returns object?
//bind events to element

//create namespace
sector67 = {};

sector67.loadCSS = function(stylesheet) {
	var oLink = document.createElement('link')
	oLink.href = stylesheet;
	oLink.rel = 'stylesheet';
	oLink.type = 'text/css';
	document.body.appendChild(oLink);
}


google.setOnLoadCallback(function () { sector67.loadCSS("/sec67/widget.css"); });


// *** Ajax calls *************************************

//anonymous function to build sec67 ajax function
(function () {
	function GetXmlHttpObject() {
		var xmlHttp=null;
		try {
			// Firefox, Opera 8.0+, Safari
			xmlHttp=new XMLHttpRequest();
		} catch (e)	{
			// Internet Explorer
			try	{
				xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
			} catch (e)	{
				xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
			}
		}
		return xmlHttp;
	}
	
	function makeAjaxCallback(forXmlHttp, successFunc) {
		return function () {
				if (forXmlHttp.readyState==4 || forXmlHttp.readyState=="complete") { 
					successFunc(forXmlHttp.responseText);
				}
		}
	}
	
	sector67.ajaxGet = function (url, params, callback) {
		var xmlHttp;
		xmlHttp=GetXmlHttpObject();
		if (params!="") url += "?" + params;
		xmlHttp.onreadystatechange = makeAjaxCallback(xmlHttp, callback);
		xmlHttp.open('GET', url, true);
		xmlHttp.send(null);
	}

	sector67.ajaxPost = function(url, params, callback) {
		var xmlHttp;
		xmlHttp=GetXmlHttpObject();
		xmlHttp.onreadystatechange = makeAjaxCallback(xmlHttp, callback);
		xmlHttp.open('POST', url, true);
		xmlHttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
		xmlHttp.send(params);
	}
}) ();



// *** EditableWidget *************************************

sector67.EditableWidget = function () {
	var cachePage;
	obj = {};
	
	obj.type="editable";
	obj.eventsMap = new Object();
	
	//fill that.element and that.refreshableElement based on that.id
	//don't just look off of id... if you're a child, then a parent refresh may have renamed your dom.  look based on wid info to find something with same type and id
	obj.findElement = function() {
		var that=this;
		
		widgetCrawl = function(el) {
			el.children().each(function(index,Element) {
				curEl=$(this);
				if(curEl.hasClass("widget")) {
					widInfo = that.getWidgetInfo(curEl);
					if (widInfo.type==that.type && widInfo.id==that.id) {
						//it's a match!
						that.element = curEl;
						return true;
					}
				} else {
					if (widgetCrawl(curEl)) return true;
				}
			});
			
			return false;
		};
		
		if(!widgetCrawl(that.parent.element)) that.element = $("#" + that.dom_id);
		
		
		that.findRefreshableElement();
	};
	
	obj.findRefreshableElement = function() {
		var that=this;
		that.refreshableElement = that.element.find("#refreshable");
		if(that.refreshableElement.length==0) that.refreshableElement=that.element;
	};
	
	
	//crawl tags with class "widget" to make children
	obj.findChildren = function() {
		var that=this;
		if (that.children.length>0) alert(that.dom_id + " setting children when not empty! count=" + that.children.length);
		that.children = new Array();
		
		//helper function for crawling through children to find widgets
		widgetCrawl = function(el) {
			el.children().each(function(index,Element) {
				curEl=$(this);
				if(curEl.hasClass("widget")) {
					//widget!
					//find the widget info, make the child and push it.  don't traverse deeper
					that.makeChild(that.getWidgetInfo(curEl));
				} else {
					widgetCrawl(curEl);
				}
			});
		};
		
		widgetCrawl(that.element);
	};
	
	//make a child widget given widInfo obtained using obj.getWidgetInfo
	obj.makeChild = function (widInfo) {
		var that=this;
		var child;
		if (widInfo.type=="session") {
			child=sector67.makeSessionWidget(widInfo.dom_id, widInfo.id, '', 1);
		} else if (widInfo.type=="sessiontime") {
			child=sector67.makeSessionTimeWidget(widInfo.dom_id, widInfo.id, '', 1);
		}
		if (child!=null) that.addChild(child);
	};
	
	obj.addChild = function(child) {
		this.children.push(child);
		child.parent=this;
	};
	
	//given a jQuery element with the widget class,
	// returns info about it by checking and parsing the widget_info span inside it
	obj.getWidgetInfo = function (el) {
		var that=this;
		if (!el.hasClass("widget")) return {};
		var ret = {};
		var text = that.jQueryInElement("#widget_info",el).text();
		if (text=="") return {};
		
		var pieces = text.split("|");
		ret.type=pieces[0];
		ret.id=pieces[1];
		ret.dom_id=pieces[2];
		
		return ret;
	};
	
	obj.initFill = function () {
		var that=this;
		
		if ((that.initHTML != null) && (that.initHTML != "")) {
			//just insert the html from here
			that.element.html(that.initHTML);
			that.findRefreshableElement();
			that.refresh(true);
		} else {
			//pull it from the server
			curParams=Object.create(that.pageParams);
			curParams["full"]="true";
			curParamString = $.param(curParams);
			
			sector67.ajaxGet(that.pageURL, curParamString,
				function (data) {
					that.element.html(data);
					that.findRefreshableElement();
					that.refresh(true);
				}
			);
		}
	};
	
	obj.refresh = function(initialRefresh) {
		var that=this;
		if (that.refreshableElement==null) return;
		
		curParams=Object.create(that.pageParams);
		if (that.editMode) {
			curParams["edit"]="true";
			refreshEvent="editRefresh";
		} else {
			curParams["edit"]="false";
			refreshEvent="pageRefresh";
		}
		//serialize params object
		curParamsString = $.param(curParams);

		//alert("make ajax get for refresh");
		sector67.ajaxGet(that.pageURL, curParamsString,
			function(data) {
				that.refreshableElement.html(data);
				if(initialRefresh) that.findChildren();
				
				that.eachChild(function () { this.findElement(); });
				//since we just filled with data from server, none of the sub widgets should be in edi tmode
				that.eachChild(function () { this.editMode=false; });
				that.setPageEventListeners();
				if (that.editMode) that.element.addClass("editing_widget"); else that.element.removeClass("editing_widget");
				that.raiseEvent(refreshEvent);
			}
		);
	};
	
	obj.eachChild = function(func) {
		var that=this;
		for (child in that.children) {
			if((typeof that.children[child])!="function") {
				func.apply(that.children[child]);
				that.children[child].eachChild(func);
			}
		}
	}

	obj.jQueryInElement = function(query,el) {
		var that=this;
		
		if(el===undefined) el=that.element;
		var results = el.children(query);

		el.children().each(function (index, Element) {
			var child = $(this);
			if(!child.hasClass("widget")) results = results.add(that.jQueryInElement(query,child));
		});
		
		return results;
	};
	
	obj.setPageEventListeners = function() {
		var that=this;
		var el;
		//do children (recursively) first
		for (child in that.children) {
			if((typeof that.children[child])!="function") that.children[child].setPageEventListeners();
		}
		
		that.jQueryInElement("#save").bind('click', that.doSave(that));
		that.jQueryInElement("#cancel").bind('click', that.doCancel(that));
		that.jQueryInElement("#edit").bind('click', that.doEdit(that));

		that.raiseEvent("setPageEventListeners");
	};
	
	obj.doEdit = function(that) {
		if (that==null) var that=this;
		
		return function() {
			that.eachChild(function() {
				if(this.editMode) { ((this.doCancel()) ());}
			});
			that.cachePage = that.refreshableElement.html();
			that.editMode=true;
			that.refresh();
			return false; //cancel default click action
		};
	};
	
	obj.doSave = function(that) {
		if (that==null) var that=this;
		
		return function() {
			//post a save...
			that.eachChild(function() {
				if(this.editMode) { ((this.doCancel()) ());}
			});
			curParams=Object.create(that.pageParams);
			curParams["save"]="true";
			curParamsString=$.param(curParams);
			//curParamsString = curParamsString + "&" + that.element.find("form").serialize();
			curParamsString = curParamsString + "&" + that.refreshableElement.serializeAnything();

			sector67.ajaxPost(that.pageURL, curParamsString,
				function(msg) {
					//if we made a new one, then the returned id should be the first part should be the new ID followed by a space
					var newId=msg.split(" ",1)[0];
					if (newId == parseInt(newId)) {
						that.setId(newId);
					} else {
						alert(msg);
					}
					that.editMode=false;
					that.refresh();
				}
			);
		
			
			return false; //cancel default click action
		};
	};
	
	obj.setId = function (newId) {
		var that=this;
		that.id=newId;
		that.pageParams.id=newId;
	};
	
	obj.doCancel = function(that) {
		if (that==null) var that=this;
		return function() {
			that.editMode=false;
			if(that.cachePage!=null) {
				that.refreshableElement.html(that.cachePage); //load inner html with cached contents
				
				for (child in that.children) {
					if((typeof that.children[child])!="function") {
						that.children[child].findElement();
						// this gets called on children //that.children[child].setPageEventListeners();
						//***also find children and make them do this?
					}
				}
				
				that.setPageEventListeners();
				that.element.removeClass("editing_widget");
			} else {
				that.refresh();
			}
			return false; //cancel default click action
		};
	};
	
	
	obj.addListener = function(event, func) {
		var that=this;
		if(!that.eventsMap[event]) that.eventsMap[event]=new Array();
		that.eventsMap[event].push(func);
	};
	
	//adds a function to the click event of an element inside the widget (and not in the sub widget)
	// give it the id of the element to attach the event to, and a function.  context
	// will be of the widget (this will be reference to widget object)
	obj.addClickEvent = function(dom_id, func) {
		var that=this;
		that.addListener("setPageEventListeners", function() {
			var that=this;
			var test = that.element.children("#none");
			that.jQueryInElement("#" + dom_id).bind('click', function() { func.apply(that); });
		});
	};
	
  
	//calls an event of this widget
	obj.raiseEvent = function(event) {
		var that=this;
		var funcNum;
		var func;
		for (funcNum in that.eventsMap[event]) {
			func = that.eventsMap[event][funcNum];
			if (typeof func == 'function') {
				func.apply(that,arguments); //call func with first param of that, and next params as whatever else got passed to raiseEvent
			}
		}
	};
	
	obj.applyToChildren = function(func) {
		var that=this;
		var args = arguments;
		throwaway = arg.shift; //remove func from arguments array
		for (childNum in that.children) {
			child = that.children[childNum];
			alert("child type: " + typeof child = " NOT YET IMPLEMENTED");
			//func.apply(child, args);
		}
	};
	
	
	//actual constructor
	obj.init = function(dom_id,id,pageURL,pageParams,editMode,suppressRefresh) {
		var that=this;

		that.dom_id=dom_id;
		
		that.element=$("#"+dom_id);
		
		that.children = new Array();
		
		if(editMode) {
			that.editMode=editMode;
		} else {
			that.editMode=false;
		}

		
		that.pageURL=pageURL;
		that.pageParams=pageParams;
		if(!that.pageParams) that.pageParams = new Object();
		that.pageParams.elementId=that.dom_id;
		that.setId(id);
		
		if(!suppressRefresh) {
			that.initFill();
		} else {
			that.findRefreshableElement();

			that.setPageEventListeners();
			that.findChildren();
		}
	};
	
	return obj;
} ();


// *** ClassWidget **********************************************************

sector67.ClassWidget = function () {
	var obj = Object.create(sector67.EditableWidget);
	
	var super_init=obj.init;
	//obj.initHTML = "<div id='refreshable'></div><p>this text doesn't refresh</p>";
	obj.type="class"
	
	obj.init = function(dom_id,class_id,editMode,suppressRefresh) {
		var that=this;
		that.class_id=class_id;
		super_init.call(that,dom_id,class_id,"widClass.php",{},editMode,suppressRefresh);
	}
	
	obj.eventsMap = Object.create(obj.eventsMap);
	

	obj.addClickEvent("add_session", function() {
		var that=this;
		
		if(typeof(new_session_count)=="undefined") new_session_count=0;
		new_session_count += 1;
		dom_id="new_session_" + new_session_count;
		that.jQueryInElement("#session_table").append("<tr id='" + dom_id + "' class='widget'></tr>");
		child=sector67.makeSessionWidget(dom_id,0,1);
		that.addChild(child);
		child.pageParams["class_id"]=that.id;
		that.jQueryInElement("#session_table").css("display","block");
		
		return false; //cancel default click action
	});
	
	return obj;
} ();

sector67.makeClassWidget = function(dom_id,class_id,editMode,suppressRefresh) {
	var that = Object.create(sector67.ClassWidget);
	that.init(dom_id,class_id,editMode,suppressRefresh);
	return that;
}

// *** SessionWidget **********************************************************

sector67.SessionWidget = function () {
	var obj = Object.create(sector67.EditableWidget);
	
	var super_init=obj.init;
	obj.initHTML="";
	obj.type="session"
	
	obj.init = function(dom_id,session_id,editMode,suppressRefresh) {
		var that=this;
		that.session_id=session_id;
		super_init.call(that, dom_id,session_id,"widSession.php",{},editMode,suppressRefresh);
	}
	
	obj.eventsMap = Object.create(obj.eventsMap);

	obj.addClickEvent("cancel_session", function() {
		var that=this;
		
		if(confirm("Are you sure you want to cancel this session?")) {
			//cancel the session
			curParams=Object.create(that.pageParams);
			curParams["cancel"]="true";
			curParamsString=$.param(curParams);
			//curParamsString = curParamsString + "&" + that.refreshableElement.serializeAnything();

			sector67.ajaxPost(that.pageURL, curParamsString,
				function(msg) {
					alert(msg);
					that.refreshableElement.html("");
				}
			);
		
			
			return false; //cancel default click action
		}
	});
	
	obj.addClickEvent("add_time", function() {
		var that=this;
		
		if(typeof(new_time_count)=="undefined") new_time_count=0;
		new_time_count += 1;
		dom_id="new_time_" + new_time_count;
		that.jQueryInElement("#time_table").append("<div id='" + dom_id + "' class='widget'></tr>");
		child=sector67.makeSessionTimeWidget(dom_id,0,1);
		that.addChild(child);
		child.pageParams["session_id"]=that.id;
		return false; //cancel default click action
	});
	
	obj.addClickEvent("register", function() {
		alert("sub register");
		var that=this;
		
		curParams=Object.create(that.pageParams);
		curParams["register"]="true";
		curParamsString=$.param(curParams);
		//curParamsString = curParamsString + "&" + that.refreshableElement.serializeAnything();

		sector67.ajaxPost(that.pageURL, curParamsString,
			function(msg) {
				alert("register return: " + msg);
				that.refresh();
			}
		);
		return false; //cancel default click action
	});
	
	obj.addClickEvent("drop", function() {
		var that=this;
		
		curParams=Object.create(that.pageParams);
		curParams["drop"]="true";
		curParamsString=$.param(curParams);
		//curParamsString = curParamsString + "&" + that.refreshableElement.serializeAnything();

		sector67.ajaxPost(that.pageURL, curParamsString,
			function(msg) {
				alert("drop return: " + msg);
				that.refresh();
			}
		);
		return false; //cancel default click action
	});
	
	return obj;
} ();

sector67.makeSessionWidget = function(dom_id,session_id,editMode,suppressRefresh) {
	var that = Object.create(sector67.SessionWidget);
	that.init(dom_id,session_id,editMode,suppressRefresh);
	return that;
}

//*** SessionTimeWidget ****************************
sector67.SessionTimeWidget = function () {
	var obj = Object.create(sector67.EditableWidget);
	
	var super_init=obj.init;
	obj.initHTML="";
	obj.type="sessiontime";
	
	obj.init = function(dom_id,time_id,editMode,suppressRefresh) {
		var that=this;
		that.time_id=time_id;
		super_init.call(that, dom_id,time_id,"widSessionTime.php",{"time_id" : time_id},editMode,suppressRefresh);
	}
	
	obj.eventsMap = Object.create(obj.eventsMap);

	obj.addClickEvent("delete_time", function() {
		//delete the session time
		curParams=Object.create(that.pageParams);
		curParams["cancel"]="true";
		curParamsString=$.param(curParams);
	
		sector67.ajaxPost(that.pageURL, curParamsString,
			function(msg) {
				alert(msg);
				that.refreshableElement.html("");
				that.element.removeClass('editing_widget');
			}
		);
		return false; //cancel default click action
	});
	
	return obj;
} ();

sector67.makeSessionTimeWidget = function(dom_id,time_id,editMode,suppressRefresh) {
	var that = Object.create(sector67.SessionTimeWidget);
	that.init(dom_id,time_id,editMode,suppressRefresh);
	return that;
}
