/**
* @file xmlhttp.js
*
* description
* Handle xmlhttp requests on the client side
* 
* COPYRIGHT
*
*    This software Copyright The Regents of the University of California
*    and the UCSD Ubiquitous Presenter Group. All Rights Reserved.
*
*    Permission to use, copy, modify, and distribute any part of the
*    software for educational, research, and non-profit purposes, without
*    fee and without a written agreement, is hereby granted, provided that
*    the above copyright notice, this paragraph and the the following
*    paragraphs appear in all copies.
*
*    For permission to use this software for commercial purposes, contact
*    William G. Griswold (wgg@cs.ucsd.edu) or send U.S. Mail to:
*
*    William G. Griswold
*    Department of Computer Science and Engineering, 0114
*    University of California, San Diego
*    La Jolla, CA 92093-0114
*
*    IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
*    FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES
*    ARISING OUT OF THE USE OF SOFTWARE FROM THIS SITE, EVEN IF THE
*    UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
*    DAMAGE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
*    THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE
*    MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS OR MODIFICATIONS. THE
*    UNIVERSITY OF CALIFORNIA MAKES NO REPRESENTATIONS AND EXTENDS NO
*    WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT
*    NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS
*    FOR A PARTICULAR PURPOSE OR THAT THE USE OF THE MATERIAL WILL NOT
*    INFRINGE ANY PATENT, TRADEMARK OR OTHER RIGHTS.
*/

var debug = false;

function xmlhttpLogging(php_receivePage, mode, classroom, lecture, user) {
	// START xmlhttp object creation process

	if(arguments.length != 5) {
		alert("Invalid # of paramaters passed to xmlhttpLogging constructor");
	}
	this.receivePage = php_receivePage;
	this.classroom = classroom;
	this.lecture = lecture;
	this.mode = mode;
	this.user = user;
	
	// XML strings
	var xml_header = "<\?xml version='1.0' encoding='UTF-8'?>";
	var statStartTag = "<upStat hashver='1.0.0'>";
	var statEndTag   = "</upStat>";

	this.getXMLHttpRequestObj = function () {
		req = false;
		// branch for native XMLHttpRequest object
		if(window.XMLHttpRequest) {
			try {
				req = new XMLHttpRequest();
			} catch(e) {
				req = false;
			}
			// branch for IE/Windows ActiveX version
		} else if(window.ActiveXObject) {
			try {
				req = new ActiveXObject("Msxml2.XMLHTTP");
			} catch(e) {
				try {
					req = new ActiveXObject("Microsoft.XMLHTTP");
				} catch(e) {
					req = false;
				}
			}
		}
		if(req){
			req.open("POST", this.receivePage, true);
		}
		else{
			if(debug)
				alert("Unable to retrieve xmlhttp object");
		}
		req.setRequestHeader("Content-Type", "text/xml");
		return req;
	}

	// Get the xmlhttp object...(call the function above)
	this.xmlhttpObj = this.getXMLHttpRequestObj(); 

	// Did we get an object?
	if(!this.xmlhttpObj) {
		// Silent exit.
		return;
	}


	// END CONSTRUCTOR code.

	this.sendPageRefresh = function(toStaticPage) {
		if(!this.logCheck('sendPageRefresh', 1, arguments.length))
			return;	
		var message = xml_header;
		message += statStartTag;
		message += this.defaultTags();
		message += this.stringStat('action', 'refresh');
		message += this.boolStat('isStatic', toStaticPage);
		message += statEndTag;
		this.xmlhttpObj = this.getXMLHttpRequestObj();
		if(this.xmlhttpObj) {
			this.xmlhttpObj.send(message);
		}
	}

        this.sendBlogState = function(classroom, lecture, slide_id, blogger, watcher) {
		if(!this.logCheck('sendBlogState', 5, arguments.length))
			return;	
		var message = xml_header;
		message += statStartTag;
		message += this.defaultTags();
		message += this.stringStat('action', 'blogState');
		message += this.stringStat('classroom', classroom);
		message += this.stringStat('lecture', lecture);
		message += this.stringStat('slide_id', slide_id);
		message += this.stringStat('blogger', blogger);
		message += this.stringStat('watcher', watcher);
		message += statEndTag;
		this.xmlhttpObj = this.getXMLHttpRequestObj();
		if(this.xmlhttpObj) {
			this.xmlhttpObj.send(message);
		}
	}

	this.sendPageState = function(type, id, iter, numIter, slide_id) {
		if(!this.logCheck('sendPageState', 5, arguments.length))
			return;
		var message = xml_header;
		message += statStartTag;
		message += this.defaultTags();
		message += this.stringStat('action', 'newState');
		message += this.stringStat('type', type);
		message += this.intStat('id', id);
		message += this.intStat('iter', iter);
		message += this.intStat('numIter', numIter);
		message += this.intStat('slide_id', slide_id);
		message += statEndTag;
		this.xmlhttpObj = this.getXMLHttpRequestObj();
		if(this.xmlhttpObj) {
			this.xmlhttpObj.send(message);
		}
	}
	this.defaultTags= function() {
		return  this.stringStat('classroom', this.classroom) + 
			this.stringStat('lecture', this.lecture) + 
			this.stringStat('mode', this.mode) +
			this.stringStat('user', this.user);
	}
	
	this.stringStat = function(name, value) {
		return "\t<scalar type='string' name='" + name + "' value='" + value + "' />\n";
	}

	this.intStat = function(name, value) {
		return "\t<scalar type='int' name='" + name + "' value='" + value + "' />\n";
	}

	this.boolStat = function(name, value) {
		return "\t<scalar type='bool' name='" + name + "' value='" + value + "' />\n";
	}

	this.logCheck = function(name, requestedArgNum, actualArgNum) {
		if(requestedArgNum != actualArgNum) {
			alert("Programmer error: calling xmlhttpUtil." + name + "() with " + actualArgNum + " arguments");
			return false;
		}
		if(!this.xmlhttpObj) {
			return false;
		}
		return true;
	}

}

// Get a lecture status from a given php page for a certain classroom and lecture.
function xmlhttpLectureStatus(phpSendingPage, classroom, lecture) {
	this.sendingPage = phpSendingPage;  // Address of php page that sends a response.
	this.classroom = classroom;
	this.lecture = lecture;
	reqobj = false;

	this.makeRequest = function (url) {
		if(reqobj)
			return;
		// branch for native XMLHttpRequest object
		if(window.XMLHttpRequest) {
			try {
				reqobj = new XMLHttpRequest();
			} catch(e) {
				reqobj = false;
			}
			// branch for IE/Windows ActiveX version
		} else if(window.ActiveXObject) {
			try {
				reqobj = new ActiveXObject("Msxml2.XMLHTTP");
			} catch(e){
				try{
					reqobj = new ActiveXObject("Microsoft.XMLHTTP");
				} catch(e){
					reqobj = false;
				}
			}
		}
		if(reqobj) {
			reqobj.onreadystatechange = this.waitForProcessing;
			// Get the submission status given the passed in info.
			reqobj.open("GET", url, true);
			reqobj.send('');
		}
		else {
			if(debug){
				alert("Couldn't get request object");
			}
		}
	}
	
	// Assign the handler function and make the xmlhttp request.
	this.requestSubmissionStatus = function(processFunction, type, id) {
		responseFunction = processFunction;
		var url = this.sendingPage + "?request_type=submission_status&classroom=" + this.classroom + "&lecture=" + this.lecture + 
				"&type=" + type + "&id=" + id;
		this.makeRequest(url);
	}

	this.requestCurrentInfo = function(processFunction) {
		responseFunction = processFunction;
		var url = this.sendingPage + "?request_type=current_info&classroom=" + this.classroom + "&lecture=" + this.lecture;
		this.makeRequest(url);
	}

	// Wait until the load completes.  And send the response text to the defined handler.
	this.waitForProcessing = function () {
		// only if req shows "loaded"
		if (reqobj.readyState == 4) {
			// only if "OK"
			if (reqobj.status == 200) { 
				// ...processing statements go here...
				// (previously we sent only the text, but now we send the whole reqobj)
				//responseFunction(reqobj.responseText);
				responseFunction(reqobj);
			} 
			else {
				// Die silently?
			}
			reqobj = false;
		}
	}

}

function constructBrowserCompatibleXMLHttpRequestObj() {
	var reqobj;
	
	// branch for native XMLHttpRequest object
	if(window.XMLHttpRequest) {
		try {
			reqobj = new XMLHttpRequest();
		} catch(e) {
			reqobj = false;
		}
		// branch for IE/Windows ActiveX version
	} else if(window.ActiveXObject) {
		try {
			reqobj = new ActiveXObject("Msxml2.XMLHTTP");
		} catch(e){
			try{
				reqobj = new ActiveXObject("Microsoft.XMLHTTP");
			} catch(e){
				reqobj = false;
			}
		}
	}

	if(!reqobj) {
		if(debug){
			alert("Couldn't get request object");
		}
	}
	
	return reqobj;
}

// class to exchange tags between web view and database
function xmlTagExchange(phpSendingPage, phpReceivePage, classroom, lecture, user) {
	this.sendingPage = phpSendingPage;  // Address of php page that sends a response.
	this.receivePage = phpReceivePage;

	this.classroom = classroom;
	this.lecture = lecture;
	this.user = user;

	var xml_header = "<\?xml version='1.0' encoding='UTF-8'?>";
	var tagStartTag = "<upTag hashver='1.0.0'>";
	var tagEndTag   = "</upTag>";

	this.requestTags = function(processFunction, element, expanded) {

		var url = this.sendingPage + "?request_type=get_tags&classroom=" + this.classroom +
			"&lecture=" + this.lecture + "&slide_id=" + element['slide_id'] + "&type=" + element['type'] +
			"&id=" + element['id'] + "&user=" + this.user + "&tagsexpanded=" + expanded;
	
		xhr = constructBrowserCompatibleXMLHttpRequestObj();

		if (!xhr) return;

		xhr.open("GET", url, true);
		xhr.send(null);

		xhr.onreadystatechange = function () {
			if (xhr.readyState == 4) {
				// only if "OK"
				if (xhr.status == 200) { 
					processFunction(xhr);
				} 
				else {
					// Die silently?
				}	
				xhr = false;
			}
		}	
	}

	this.defaultTags= function() {
		return  this.stringStat('classroom', this.classroom) + 
			this.stringStat('lecture', this.lecture) + 
			this.stringStat('mode', this.mode) +
			this.stringStat('user', this.user);
	}
	
	this.stringNode = function(name, value) {
		return "\t<scalar type='string' name='" + name + "' value='" + value + "' />\n";
	}

	this.intNode = function(name, value) {
		return "\t<scalar type='int' name='" + name + "' value='" + value + "' />\n";
	}

	this.sendNewTagString = function(tags, element) {

		var xhrObj;
		var message = xml_header;
		message += tagStartTag;
		message += this.stringNode('action', "newTagString");
		message += this.stringNode('classroom', this.classroom);
		message += this.stringNode('lecture', this.lecture);
		message += this.stringNode('user', this.user);	
		message += this.intNode('id', element['id']);
		message += this.intNode('slide_id', element['slide_id']);
		message += this.stringNode('type', element['type']);
		message += this.stringNode('tags', escape(tags));
		message += tagEndTag;

		xhrObj = constructBrowserCompatibleXMLHttpRequestObj();
		if(xhrObj) {
			xhrObj.open("POST", this.receivePage, true);
			xhrObj.send(message);
		}
	}
}

function xmlhttpSearch(phpSendingPage, phpReceivePage, classroom, lecture) {
	this.sendingPage = phpSendingPage;  // Address of php page that sends a response.
	this.receivePage = phpReceivePage;
	this.classroom = classroom;
	this.lecture = lecture;
	
	this.getXMLFile = function(filename, processFunction) {
		var url = this.sendingPage + "?request_type=get_xml_file" 
		  + "&classroom=" + this.classroom + "&lecture=" + this.lecture 
		  + "&filename=" + filename;

		var reqobj = constructBrowserCompatibleXMLHttpRequestObj();
		if (!reqobj) return;

		reqobj.open('GET', url, true);
		reqobj.send(null);

		reqobj.onreadystatechange = function() {
			// construct cross-browser compatible dom tree from response
			var doc;
			if (reqobj.readyState==4) {
				// only if "OK"
				if (reqobj.status==200) {
					// code for IE
					if (window.ActiveXObject) {
						doc=new ActiveXObject("Microsoft.XMLDOM");
						doc.async="false";
						doc.loadXML(reqobj.responseText);
					}
					// code for Mozilla, Firefox, Opera, etc.
					else {
						var parser=new DOMParser();
						doc=parser.parseFromString(reqobj.responseText,"text/xml");
					}
					processFunction(doc);
				}
			}
		};
	};

	this.stringNode = function(name, value) {
		return "\t<scalar type='string' name='" + name + "' value='" + value + "' />\n";
	}
	
	this.intNode = function(name, value) {
		return "\t<scalar type='int' name='" + name + "' value='" + value + "' />\n";
	}
	
	this.saveSearchString = function(slide, searchText, startChar, endChar) {
		var message = "<?xml version='1.0' encoding='UTF-8'?>";
		message += "<upSearchStringInfo hashver='1.0.0'>";
		message += this.stringNode('action', "saveSearchTerm");
		message += this.stringNode('classroom', this.classroom);
		message += this.stringNode('lecture', this.lecture);
		message += this.stringNode('user', "");
		message += this.intNode('slide', slide);
		message += this.stringNode('searchText', searchText);
		message += this.stringNode('startChar', startChar);
		message += this.stringNode('endChar', endChar);
		message += "</upSearchStringInfo>";
		
		var reqobj = constructBrowserCompatibleXMLHttpRequestObj();
		if(reqobj) {
			reqobj.open("POST", this.receivePage, true);
			reqobj.setRequestHeader("Content-Type", "text/xml");
			reqobj.send(message);
		}
	};

  this.addSearchResult = function(slide, searchText, startChar, endChar, url, username) {
		var message = "<?xml version='1.0' encoding='UTF-8'?>";
		message += "<upAddSearchResultInfo hashver='1.0.0'>";
		message += this.stringNode('action', "addSearchResult");
		message += this.stringNode('classroom', this.classroom);
		message += this.stringNode('lecture', this.lecture);
		message += this.intNode('slide', slide);
		message += this.stringNode('searchText', searchText);
		message += this.stringNode('startChar', startChar);
		message += this.stringNode('endChar', endChar);
		message += this.stringNode('url', url);
		message += this.stringNode('user', username);
		message += "</upAddSearchResultInfo>";
		
		var reqobj = constructBrowserCompatibleXMLHttpRequestObj();
		if(reqobj) {
			reqobj.open("POST", this.receivePage, true);
			reqobj.setRequestHeader("Content-Type", "text/xml");
			reqobj.send(message);
		}
  };

  this.viewSearchResult = function(slide, searchText, startChar, endChar, url, username, searcher) {
		var message = "<?xml version='1.0' encoding='UTF-8'?>";
		message += "<upViewSearchResultInfo hashver='1.0.0'>";
		message += this.stringNode('action', "viewSearchResult");
		message += this.stringNode('classroom', this.classroom);
		message += this.stringNode('lecture', this.lecture);
		message += this.intNode('slide', slide);
		message += this.stringNode('searchText', searchText);
		message += this.stringNode('startChar', startChar);
		message += this.stringNode('endChar', endChar);
		message += this.stringNode('url', url);
		message += this.stringNode('user', username);
		message += this.stringNode('searcher', searcher);
		message += "</upViewSearchResultInfo>";

		var reqobj = constructBrowserCompatibleXMLHttpRequestObj();
		if(reqobj) {
			reqobj.open("POST", this.receivePage, true);
			reqobj.setRequestHeader("Content-Type", "text/xml");
			reqobj.send(message);
		}
  };

  this.removeSearchResult = function(slide, searchText, startChar, endChar, url, username) {
		var message = "<?xml version='1.0' encoding='UTF-8'?>";
		message += "<upRemoveSearchResultInfo hashver='1.0.0'>";
		message += this.stringNode('action', "removeSearchResult");
		message += this.stringNode('classroom', this.classroom);
		message += this.stringNode('lecture', this.lecture);
		message += this.intNode('slide', slide);
		message += this.stringNode('searchText', searchText);
		message += this.stringNode('startChar', startChar);
		message += this.stringNode('endChar', endChar);
		message += this.stringNode('url', url);
		message += this.stringNode('user', username);
		message += "</upRemoveSearchResultInfo>";
		
		var reqobj = constructBrowserCompatibleXMLHttpRequestObj();
		if(reqobj) {
			reqobj.open("POST", this.receivePage, true);
			reqobj.setRequestHeader("Content-Type", "text/xml");
			reqobj.send(message);
		}
  };
}

