function createXMLHttpRequest() {
	var req = null;
	// branch for native XMLHttpRequest object
	if (window.XMLHttpRequest) {
		try {
			req = new XMLHttpRequest();
		} catch(e) {
		}
	// 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(e2) {
				alert("Microsoft XMLHttpRequest create error: "+e2.message);
			}
		}
	}
	return req;
}


var ECSES_NOT_ENOUGH_LICENSES=11;
var ECSES_USERCOURSE_IN_USE=12;
var ECSES_SESSION_NOT_EXISTS=13;

function CourseSession() {
	this.url = null;
	this.session = null;
	this.req = null;
	this.pingCount = 0;
	this.pingInterval = 10000; // 10 seconds
	this.pingSuspended = false;
}

CourseSession.prototype.create = function(force,onevent) {
	if (this.req!=null)
		return false;
	this.req = createXMLHttpRequest();
	if (this.req==null) {
		return false;
	}
	this.log("Creating session"+(force?" (force)":"")+"...");
	var url = this.url;
	url = addParam(url,"action","create");
	if (force)
		url = addParam(url,"force","1");
	url = addParam(url,"CourseSession","1");
	var async = false;
	if (!isUndefined(onevent)) {
		async = true;
		this.req.onreadystatechange = onevent;
	}
	this.req.open( "GET", url, async );
	this.req.send(null);
	if (async)
		return true;
	return this.createProcess();
}
CourseSession.prototype.createProcess = function() {
	if (this.req==null)
		return false;
	var resp = this.req.responseText;
	var v = parseParams(resp);
	var e = parseInt(v.error);
	if (e==0) {
		this.session = v.session;
	}
	this.status = this.req.status;
	this.resp = resp;
	this.req = null;
	return e;
}
CourseSession.prototype.ping = function(onevent) {
	if (this.req!=null)
		return false;
	this.req = createXMLHttpRequest();
	if (this.req==null)
		return false;
	var url = this.url;
	url = removeParams(url);
	url = addParam(url,"session",this.session);
	url = addParam(url,"action","ping");
	url = addParam(url,"CourseSession","1");
	var async = false;
	if (!isUndefined(onevent)) {
		async = true;
		this.req.onreadystatechange = onevent;
	}
	this.req.open( "GET", url, async );
	this.req.send(null);
	if (async)
		return true;
	return this.pingProcess();
}
CourseSession.prototype.pingProcess = function() {
	if (this.req==null)
		return false;
	var resp = this.req.responseText;
	this.status = this.req.status;
	var v = parseParams(resp);
	var e = parseInt(v.error);
	this.status = this.req.status;
	this.resp = resp;
	this.req = null;
	if (e==ECSES_SESSION_NOT_EXISTS) {
		this.session = null;
	}
	return e;
}
CourseSession.prototype.close = function(onevent) {
	if (this.req!=null)
		return false;
	if (this.session==null)
		return false;
	this.req = createXMLHttpRequest();
	if (this.req==null)
		return false;
	var url = this.url;
	url = removeParams(url);
	url = addParam(url,"session",this.session);
	url = addParam(url,"action","close");
	url = addParam(url,"CourseSession","1");
	var async = false;
	if (!isUndefined(onevent)) {
		async = true;
		this.req.onreadystatechange = onevent;
	}
	this.req.open( "GET", url, async );
	this.req.send(null);
	return true;
}
CourseSession.prototype.isComplete = function() {
	if (this.req==null)
		return true;
	return this.req.readyState==4;
	
}
CourseSession.prototype.log = function() {
}
CourseSession.prototype.onterminated = function() {
	alert("You've been disconnected");
}
CourseSession.prototype.oncreatequery = function() {
	var s = "There is same user using this course.\nTerminate user session?";
	return confirm(s);
}
CourseSession.prototype.oncreated = function() {
}
CourseSession.prototype.oncreateerror = function(err) {
}
CourseSession.prototype.onpingerror = function(err) {
}

function AsyncCourseSession(id) {
	this.id = id;
}
AsyncCourseSession.prototype = new CourseSession(null);
AsyncCourseSession.prototype.createAsync = function(force) {
	var ev = this.id+".onSessionCreate()";
	var e = function(){eval(ev);};
	return this.create( force, e );
}
AsyncCourseSession.prototype.pingAsync = function() {
	var ev = this.id+".onSessionPing()";
	try {
		var e = function(){eval(ev);};
		return this.ping( e );
	} catch(ex) {
	}
}
AsyncCourseSession.prototype.onSessionCreate =  function () {
	if (!this.isComplete())
		return;
	var e = this.createProcess();
	this.error = e;
	if (e==0) {
		if (this.oncreated)
			this.oncreated();
		setTimeout(this.id+".startPing()",this.pingInterval);
		this.log("session "+coursesession.session+" created");
	} else if (e==ECSES_USERCOURSE_IN_USE) {
		if (this.oncreatequery && coursesession.oncreatequery()) {
			this.createAsync(true);
		} else {
			if (this.oncreateerror)
				this.oncreateerror(e);
			this.log("Creating session cancelled...");			
		}
	} else {
		if (this.oncreateerror)
			this.oncreateerror(e);
		this.log("Creating session error "+e);
	}
}
CourseSession.prototype.onSessionPing = function () {
	if (!this.isComplete())
		return;
	var e = this.pingProcess();
	this.error = e;
	if (e==0) {
		this.log("ping "+this.pingCount+" status "+this.status);
		setTimeout(this.id+".startPing()",this.pingInterval);
	} else if (e==ECSES_SESSION_NOT_EXISTS) {
		if (this.onterminated)
			this.onterminated();
		this.log("Disconnected");
	} else {
		if (this.onpingerror)
			this.onpingerror(e);
		this.log("Ping session error "+e+" resp "+this.resp+" status "+this.status);
	}
}
//var pingCount = 0;
CourseSession.prototype.startPing = function() {
	if (this.pingSuspended) {
		this.log("ping "+this.pingCount+" suspended ");
		setTimeout(this.id+".startPing()",this.pingInterval);
		return;
	}
	if (isUndefined(this.pingCount))
		this.pingCount = 0;
	this.pingCount++;
	this.log("ping "+this.pingCount);
	this.pingAsync();
}

