String.prototype.isLeftSubstringOf = function(s){
	return s.substring(0,this.length)==this;
}

String.prototype.isRightSubstringOf = function(s){
	return s.substring(s.length-this.length,s.length)==this;
}

window.parseUri=function (str) {
	var	o   = parseUri.options,
		m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
		uri = {},
		i   = 14;

	while (i--) uri[o.key[i]] = m[i] || "";

	uri[o.q.name] = {};
	uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
		if ($1) uri[o.q.name][$1] = $2;
	});

	return uri;
};
window.parseUri.options = {
	strictMode: false,
	key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
	q:   {
		name:   "queryKey",
		parser: /(?:^|&)([^&=]*)=?([^&]*)/g
	},
	parser: {
		strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
		loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
	}
};

window.Collection=function(){
	this.hash={};
	this.count=0;
	this.store=function(k,v){
		if(!(k in this.hash))
			this.count++;
		this.hash[k]=v;
	}
	this.del=function(k){
		if(k in this.hash){
			this.count--;
			delete this.hash[k];
		}
	}
}
/*
I tried to make this library as fast as possible - so it has reduced functionality.

This library doesn't support:
	headers
	timeouts
	any specific handlers for connections except success and failure headers
	custom arguments for handlers (it's JS, baby!)
	
main features of this library:
	* controll to all openned connections from one place
	* reset connection poll
	* control of maximum number of ajax-requests - control of browser commitment
	* compatible with Yahoo.util.Connection.asyncRequest
	* supports reusing XMLHttpRequest objects
	
How does it work:
	There is a poll for openned connections, array of free XMLHttpRequests and queue of requests
	We can add requests to the top, or to the end of queue
	On timeout special function checks active connections readystates, searching the first ready connection
	Then connection ready - special handlers runned and XMLHttpRequests moves to free poll
	After that some requests from queue moves to active poll
*/	
	// limit of openned connections:
	window.conpoll_max_connections=0;
	
	// openned connections
	window.conpoll_poll=[];
	
	// Free XMLHttpRequest objects
	window.conpoll_freeconnections=[];
	
	//queue of requests
	window.conpoll_queue=[];
	
	//Interval for listening requests
	window.conpoll_listener=null;
	
////////////////////////////////////////////////////////////
// ajax_poll requires URI parser
// see ajax-stringutils.js

////////////////////////////////////////////////////////////
// ajax_poll itself
	// reset all active connections and queue
	window.conpoll_reset=function(){
		conpoll_queue=[];//.splice(0,conpoll_queue.length);
		for(i=0;i<conpoll_poll.length;i++){
			conpoll_poll[i].connection.abort();
			conpoll_freeconnections.push(conpoll_poll[i].connection);
		}
		conpoll_poll=[];//.splice(0,conpoll_poll.length);
	}
	
	//create XMLhttpRequest -crossbrowser version
	window.createXhrObject=function(){
		var conpoll_msxml_progid=[
			'MSXML2.XMLHTTP.5.0',
			'MSXML2.XMLHTTP.4.0',
			'MSXML2.XMLHTTP.3.0',
			'MSXML2.XMLHTTP',
			'Microsoft.XMLHTTP'
		];
		var http;
		try	{
			// Instantiates XMLHttpRequest in non-IE browsers and assigns to http.
			http = new XMLHttpRequest();
		} catch(e) {
			for(var i=0; i<conpoll_msxml_progid.length; ++i){
				try {
					// Instantiates XMLHttpRequest for IE and assign to http.
					http = new ActiveXObject(conpoll_msxml_progid[i]);
				} catch(e){ continue; }
				break;
			}
		} finally {
			return http;
		}
	}
	
	
	window.cond_use_get=function(uri)
	{
		// changed by jenya 11.02.2011
		//return (parseUri(uri).host==location.hostname || /*!authenticated || */xs_ajax_works!='get')?uri:("/get.php?url="+encodeURIComponent(uri));
		return (parseUri(uri).host==location.hostname)?uri:("/get.php?url="+encodeURIComponent(uri));
	}
	
	//push request to the end of queue
	//compatible with  Yahoo.util.Connection.asyncRequest
	window.asyncRequest=function(method, uri, callback, postData)
	{
		console.log('ajax-poll::asyncRequest("'+method+'", "'+uri+'", ", ...) begin');
		conpoll_queue.push({handlers:callback,_method:method,_uri:cond_use_get(uri),_data:postData,connection:null});
		console.log('ajax-poll::asyncRequest("'+method+'", "'+uri+'", ", ...) end');
	}
	
	//push request to the top of queue - used for critical requests
	window.fastRequest=function(method, uri, callback, postData)
	{
		console.log('ajax-poll::fastRequest("'+method+'", "'+uri+'", ", ...) begin');
		//debug_message('Fast request to '+uri+' queued');
		conpoll_queue.splice(0,0,{handlers:callback,_method:method,_uri:cond_use_get(uri),_data:postData,connection:null,isFast:true});
		console.log('ajax-poll::fastRequest("'+method+'", "'+uri+'", ", ...) end');
	}
	
	window.conpoll_freeze=function(){
		document.body.style.display='none';
		for (i in conpoll_queue)
			conpoll_queue[i].handlers={success:function(){}, failure:function(){}};
	}
	
	// Activate new request from queue
	window.conpoll_look_through_queue=function(){	
		if(!conpoll_queue[0] || !conpoll_freeconnections[0] || conpoll_poll.length >= conpoll_max_connections)
			return;
		conpoll_queue[0].connection = conpoll_freeconnections[0];
		conn = conpoll_queue[0].connection;
		conn.open(conpoll_queue[0]._method, conpoll_queue[0]._uri, true);
		//if (/iy-in-f105/.test(conpoll_queue[0]._uri)) alert("requesting google");
		if(conpoll_queue[0]._data){
			conn.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
			conn.send(conpoll_queue[0]._data);
		}else{
			//conn.setRequestHeader('Content-Type', 'text/html');
			//if (/iy-in-f105/.test(conpoll_queue[0]._uri)) alert("sending request");
			conn.send(null);
		}
		conpoll_poll.push(conpoll_queue[0]);
		conpoll_queue.splice(0,1);
		conpoll_freeconnections.splice(0,1);
	}
	
	// Listening active connections 
	window.conpoll_listening=function(){
		var ii=0;		
		// Look through active poll
		for(ii=0;ii<conpoll_poll.length;ii++){	
			if(conpoll_poll[ii].connection.readyState == 4){
				connection = conpoll_poll[ii].connection;
				conpoll_handleresponce(conpoll_poll[ii]);
				conpoll_freeconnections.push(connection);
				conpoll_poll.splice(ii,1);
				//ii--;
				break;
			}
		}
		// activate new requests
		while(conpoll_poll.length<conpoll_max_connections && conpoll_queue[0])
			conpoll_look_through_queue();
	}
	
	// create responce-object for connection
	// similar to yui
	window.conpoll_create_response=function(conn){
		var obj = {};
		try	{
			obj.getAllResponseHeaders = conn.getAllResponseHeaders();
			obj.status = conn.status;
			obj.statusText = conn.statusText;
			obj.responseText = conn.responseText;
			obj.responseXML = conn.responseXML;
		} catch(e){
			//
		} finally {
			return obj;
		}
	}
	
	//handle responce - create responce object and run needed handler
	window.conpoll_handleresponce=function(request){
		var httpStatus, responseObject;
		var callback = request.handlers;
 		
		httpStatus = request.connection.status;
		responseObject = conpoll_create_response(request.connection);
		
		if(httpStatus >= 200 && httpStatus < 300 || httpStatus === 1223){ // it is ok
			if(callback && callback.success){
				callback.success(responseObject);
			}
		} else {
			if(callback && callback.failure){
				// in firefox ajax fails before onunload. to prevent error messages we simply throw them later
				setTimeout(function(ro){return function(){callback.failure(ro)}}(responseObject),4000);
			}
		}
		responseObject = null;
	}

	//init poll - create new XMLHttpRequests and run listener
	// parameters - limit of XMLHttpRequest objects and interval for listening function
	window.conpoll_init=function (limit,timeout){
		// changed by jenya 11.02.2011
		//if(window.authenticated && window.xs_ajax_works=='get')
		if(window.authenticated)
			limit=2;
		for(i=conpoll_max_connections;i<limit;i++)
			conpoll_freeconnections.push(createXhrObject());
		conpoll_max_connections = limit;
		if(conpoll_listener)
			clearInterval(conpoll_listener);
		conpoll_listener = setInterval(conpoll_listening,timeout);	
		window.onunload=conpoll_freeze;
	}

	
	///////////////////////////////////
	// check if ajax-xss works
	window.conpoll_preinit=function(continue_prepare_document){
		var debug_message=function(){};
		//window.xs_ajax_works = null; // removed by jenya 11.02.2011
		window.normal_ajax_works = null;
		window.xhr_l=createXhrObject();
		window.xhr=createXhrObject();

		if(false && 'jar:'==location.protocol && window.netscape && netscape.security && netscape.security.PrivilegeManager && netscape.security.PrivilegeManager.enablePrivilege){
			xhr.constructor.prototype.open=function(p_oldopen){return function(){
				try{
					netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
					netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
					Set_Cookie('moz_user_accepts_xss_0210', 'yes');
				}catch(e){
					Set_Cookie('moz_user_accepts_xss_0210', 'no');
					//()(FIXME) what to do if stupid user suddenly refuses?
				}
				debug_message('open ...');
				p_oldopen.apply(this,arguments);
				debug_message('end req '+arguments[1]+' ...');
			}}(xhr.constructor.prototype.open);
			debug_message('conpoll_preinit 3');
		}

		window.timer_pi=null;
		xhr.open('GET', 'http://'+location.host+'/4xsstest', true);
		xhr.send(null);
		debug_message('check if ajax-xss works');
		debug_message('conpoll_preinit 1');
		try{
			try{
				debug_message('conpoll_preinit 2');
				xhr_l.open('GET', 'http://serpanalytics.net/4xsstest', true);
				xhr_l.send(null);
			} catch(e){
				debug_message("failed to request seranalytics.net");
				// we believe in:
				//xs_ajax_works = false; // removed by jenya 11.02.2011
				// we know that:
				normal_ajax_works = true;
				//alert('xss failed');
				//alert(e);
				throw 'xss failed';
			}
			var x=0;
			var n=0;			
			handler = function(){
				debug_message('conpoll_preinit:handler:n='+n);
				debug_message('handler');
				debug_message('1)timer_pi='+window.timer_pi);
				debug_message('2)timer_pi='+window.timer_pi);
				debug_message('conpoll_preinit:handler:normal_ajax_works:'+xhr_l.readyState);
				// changed by jenya 11.02.2011
				//if(xs_ajax_works==null){
				if(false){
					if(xhr_l.readyState == 4){
						debug_message('conpoll_preinit:handler:normal_ajax_works:'+xhr_l.readyState+':'+xhr_l.status);
						if((xhr_l.status >= 200 && xhr_l.status < 300 || xhr_l.status === 1223) && xhr_l.responseText=='hello from serpanalytics.net'){							
							clearInterval(timer_pi);
							// changed by jenya 11.02.2011
							//xs_ajax_works = true;
							normal_ajax_works = true;
							continue_prepare_document.success();
							xhr_l.abort();
						} else {
							clearInterval(timer_pi);
							continue_prepare_document.failure();
							debug_message("bad ajax responce from seranalytics.net");
						}
					}
					x++;
				}
				debug_message('conpoll_preinit:handler:!normal_ajax_works:'+xhr.readyState);
				if(normal_ajax_works==null){
					if(xhr.readyState == 4){
						debug_message('conpoll_preinit:handler:normal_ajax_works:'+xhr.readyState+':'+xhr.status);
						if ((xhr.status >= 200 && xhr.status < 300 || xhr.status === 1223) && xhr.responseText=='hello from serpanalytics.com'){
							normal_ajax_works = true;
						} else {
							clearInterval(timer_pi);
							continue_prepare_document.failure();
							debug_message("bad ajax responce from seranalytics.com");
						}
					}
					n++;
				}
				debug_message('conpoll_preinit:handler 2:n='+n);				
				if (n>50){
					clearInterval(timer_pi);
					continue_prepare_document.failure();
					debug_message("no ajax responce from seranalytics.com");
				}
				if (x>50){
					clearInterval(timer_pi);
					continue_prepare_document.failure();
					debug_message("no ajax responce from seranalytics.net");
				}
				if (x>n*3+5){
					clearInterval(timer_pi);
					continue_prepare_document.failure();
					debug_message("coeff");
				}
			}
			window.timer_pi = setInterval(handler,200);
		} catch(e){
			if (0/*confirm("it's a placeholder. If you are logged in and want to use get.php, press OK")*/){
				// changed by jenya 11.02.2011
				//xs_ajax_works='get';
				continue_prepare_document.success()
			} else {
				continue_prepare_document.failure();
			}
			//debug_message("error: " + e);
		}
	}
////////////////////////////////////////////////////////////
// these functions aren't required by ajax_poll
// but they are often used with it
window.invertShow=function(id){
	var style=document.getElementById(id).style; 
	if(style.display=='none')
		style.display='block';
	else
		style.display='none';
}
window.show=function(toshow){
	 document.getElementById(toshow).style.display='block';
}
window.hide=function(tohide){
	 document.getElementById(tohide).style.display='none';
}
/////////////////////////////////////////////////////////
// "Waiting ..." (show/hide the animations)
// TODO: maybe make a separate file for them
window.waiting=[];

window.waiting_on=function(element_id){
	//document.getElementById('style_decl').innerHTML='*{cursor:progress}';
	document.body.style.cursor='progress';
	if(document.getElementById(element_id))
		document.getElementById(element_id).style.visibility='visible';
	waiting[element_id]=1;
}
window.waiting_off=function(element_id){
	//document.getElementById('style_decl').innerHTML='*{}';
	if(document.getElementById(element_id))
		document.getElementById(element_id).style.visibility='hidden';
	delete waiting[element_id];
	document.body.style.cursor='';
	for (i in waiting){
		document.body.style.cursor='progress';
	}
}// IE6,7 has a buggy document.cookie implementation:
// if we set a cookie using JS multiple times, it sometimes appear multiple times with the same name
// be careful to use the first(?) one by order in document.cookie -- it's last chronologically
// and totally ignore others
// YAHOO and other UI libraries don't know this

window.cookie_cache={};

window.Set_Cookie=function(name, value) {
	var d = new Date();
	d.setFullYear(2100);
	var cc=encodeURIComponent(name)+'='+encodeURIComponent(value)+'; path=/; expires='+d.toGMTString();
	document.cookie=cc;
	cookie_cache[name]=value;
}

window.Set3pCookie=function(name, value, domain) {
	var d = new Date();
	d.setFullYear(2100);
	var cc=encodeURIComponent(name)+'='+encodeURIComponent(value)+'; path=/; expires='+d.toGMTString();
	document.cookie=cc;
	cookie_cache[name]=value;
}

window.Get_Cookie=function(check_name) {
	if (cookie_cache[check_name]==undefined){
		var chash=Object();
		var cookies=document.cookie.split('; ');
		for (i=0;i<cookies.length;i++){
			var cookie=cookies[i].split('=');
			if(!chash[decodeURIComponent(cookie[0])])
				chash[decodeURIComponent(cookie[0])]=decodeURIComponent(cookie[1]);
		}
		return chash[check_name];	
	} else {
		return cookie_cache[check_name];
	}
}			

