var Booster = (function(){
	var _reFileNameParts = new RegExp('[^\/]+\\.[^\/\?#]+', 'g');
	var _rePathFromURL = new RegExp('(?:[^\/]+\/\/[^\/]+)?(\/.*)');
	if(!Prototype.Browser.IE) {
		if(!window.cpage) window.cpage = document.location.href;
		if(!window.cint) window.cint = setInterval(function(){
			if(window.cpage != document.location.href) {
				window.cpage = document.location.href;
				if(document.location.hash) {
					var href;
					if(document.location.match) href = document.location;
					else href = document.location.href;
					var hash = href.match(/#page=(.+)/);
					if(hash && hash[1]) Booster.go({'url':hash[1],'ni':1,'nh':Booster.isOldOpera});
				} else {
					Booster.go({'url':document.location.href, 'ni':1,'nh':1});
				}
			}
		}, 500);
	}

	var _inRequest = 0;
	var _loadedScripts = {};
	var _waitingScripts = {};
	var _pv = {};		// page vars
	var _banners = {};
	var _timeouts = [];
	var _intervals = [];
	var _timings = {}; _timings.i = [];
	var _supported_counters = {'li': 1,'tns': 1,'top': 1};
	var _clNoexecScript = 'bstr-noexec';
	
	var ERR_PARSE_DOC = 1;
	var ERR_PARSE_SCRIPT = 2;
	var ERR_TIMEOUT_INCLUDE_SCRIPT = 3;
	var ERR_PARSE_FILE_NAME = 4;
	
	var AJAX_REQ_MAX_RETRIES = 3;
 	var AJAX_ERROR_TEXT = '<div class="mf_errorPageH1">Внимание!</div>В результате многолетних исследований, команда Mail.Ru выяснила, как сделать Мир лучше.<br>В данный конкретный момент мы завершаем работу над очередным этапом.<br>Пожалуйста, обновите страницу через 30 секунд.';
	var AJAX_ERROR_IMG = 'http://img0.imgsmail.ru/0.gif';
	
	var TIMEOUT_INCLUDE_SCRIPT = 5000;
	
	var _cln_get = 'http://rs.mail.ru/sn';
	
	window.bannerContent = {};
	window.nativeSetTimeout = window.setTimeout;
	window.setTimeout = function(a, t) {
		var t = window.nativeSetTimeout(a, t);
		_timeouts[_timeouts.length] = t;
		return t;
	}
	
	window.nativeSetInterval = window.setInterval;
	window.setInterval = function (a, t) {
		var t = window.nativeSetInterval(a, t);
		_intervals[_intervals.length] = t;
		return t;
	}
	
	var _parseFileName = function( url ){
		
		var n = url.match(_reFileNameParts);
		if(!n) {
			Booster.error(ERR_PARSE_FILE_NAME, url);
			return url;
		} else {
			return n[n.length-1];
		}
	}
	var _onResponse = function(t){
		_inRequest = 0;
		_timeInterval('server');
		_requestCln();
		Booster.fetchPage( t.responseText );
		Booster.wait('unset');
		if(Prototype.Browser.Opera) 
		    for(var i = 0;i < document.forms.length;i++) {
				var f = $(document.forms[i]);
				if(f.getInputs('radio').length) f.update(f.innerHTML);
		    }
	}
	
	var _requestCln = function() {
		if(!Booster.cln_url) return;
		if(!Booster.cln_element) {
			var el = new Element('img', {'id': 'bstr-cln', 'width': '0px', 'height': '0px'});
			document.body.appendChild(el);
		}
		var rnd = 0;
		while(rnd == Booster.cln_rnd) rnd = Math.floor(Math.random() * 100000);
		Booster.cln_rnd = rnd;
		el.src = Booster.cln_url + '?' + rnd;		
	}
	
	var _onFail = function(t){
		Booster.retries++;
		if(t.status > 500 && Booster.retries < AJAX_REQ_MAX_RETRIES) {
			new Ajax.Request(Booster.ajax_url, Booster.ajax_params);
		}
		else {
			_showError();
			_inRequest = 0; 
			Booster.wait('unset');					
		}
	}
	
	var _showError = function(){
	    if(!Booster.error_container) {
		Booster.error_container = new Element('div', {'id':'bstr-error-container','class':'mf_errorPageContainer','style':'display:none;'});
		Booster.error_container.innerHTML = '<div class="mf_errorPage">' +
		    '<a id="bstr-error-close" class="mf_spIco mf_iDel2 mf_flr mr10 mf_cp">закрыть</a>' +
		    '<div class="mf_errorPageDiv">' + AJAX_ERROR_TEXT + '</div></div>';
		document.body.appendChild(Booster.error_container);
		document.body.appendChild(new Element('img', {
		    'src':'http://rs.mail.ru/d215980.gif?' + Math.floor(Math.random() * 100000),'width':'1','height':'1'}));
		Booster.error_container.closeBtn = $('bstr-error-close');
		Booster.error_container.closeBtn.observe('click', function() {_hideError()});
	    }
		Booster.error_container.style.top = (document.documentElement.scrollTop + document.documentElement.clientHeight/2)+'px';
	    Booster.error_container.style.display = 'block';
	}
	var _hideError = function() { if(Booster.error_container) Booster.error_container.style.display = 'none' }
	var _writeScript = function( url ){
        var scr = new Element('script',  {'src': url, 'type': 'text/javascript'} );
        Booster.storage.appendChild(scr);		
	}
	var _enumIncludedScripts = function(){
		var scripts = document.getElementsByTagName('script');
		var scripts_len = scripts.length;
		for(var i = 0; i < scripts_len; i++){
			if(scripts[i].src != '') {
				_loadedScripts[_parseFileName(scripts[i].src)] = 1;
			}
		}
	}
	var _regoupPage = function(){
		var webagent = $('waHolder');
		if(/*@cc_on!@*/false) {
			if(webagent) {
				var wa = $('waWebAgent');
				if(/*@cc_on!@*/false) {
					wa.setAttribute('waNativeFixed', '1');
					wa.style.removeExpression('filter');
				}
				wa.style.top = '-22px';
				wa.style.position = 'absolute';
				webagent.style.position = 'absolute';
				webagent.style.top = '100%';
				webagent.style.width = '100%';
				webagent.style.left = '0';
				wa = null;
				webagent = null;
			}
		}
	}
	var _timeInterval = function( t ) {
		if (!_timings[t]) _timings[t] = new Date();
	    else {
            _timings.i[_timings.i.length] = t + '=' + ( (new Date()).getTime() - _timings[t].getTime() );
            delete _timings[t];
	    }
	}
	
	var _renderTimings = function() {
		if(!Booster.show_timings) return;
		
		var _fmt = function(a) {
			return (Math.floor(a*1000)/1000)/1000;
		};
		
		var srv_time = 0;
		var render_time = 0;
		var ti = '';
		var iGet = '';
		for(var i = 0; i < _timings.i.length; i++) {
			if(_timings.i[i].split('=')[0] == 'server') {
				srv_time = parseInt(_timings.i[i].split('=')[1]);
			}
			else {
				ti += _timings.i[i].split('=')[0] + ' = <b>' + _fmt(_timings.i[i].split('=')[1]) + '</b> сек<br>';
				iGet += ((iGet.length > 0) ? ',' : '') + _timings.i[i].split('=')[0] + ':' + (_fmt(_timings.i[i].split('=')[1])*1000);
				render_time += parseInt(_timings.i[i].split('=')[1]);
			}
		}
		var d = document.createElement('div');
		d.id = 'renderBlock';
		d.innerHTML = (_fmt(srv_time)) + ' server + ';
		d.innerHTML += (_fmt(render_time)) + ' rendering(browser) = <b>' + _fmt( srv_time + render_time ) + '</b> total<br />';
		d.innerHTML += ti;
		d.innerHTML += '<div style="position: relative;"><div id="renderBlockTOGgLE" style="position: absolute; bottom: 0; left: -60px;">TOGgLE</div></div>';
		//Booster.canvas.appendChild(d);
		
		d = document.createElement('div');
		d.id = 'radar_graphBlock';
		d.innerHTML += '<img id="radar_graph" src="http://img.imgsmail.ru/0.gif" onclick="this.src=\'http://img0.imgsmail.ru/0.gif\'" />';
		//Booster.canvas.appendChild(d);
		
		d = document.createElement('img');
		d.width = '1px'; d.height = '1px';
		d.src='http://my.radar.imgsmail.ru/update?p=my&t=&v=' + (_fmt(render_time)*1000) + '&i=' + iGet + '&rnd=' + Math.floor(Math.random()*1000*1000) + (this.prevURL ? '&r=' + escape(this.prevURL) : '') + '';
		Booster.canvas.appendChild(d);
		
		_timings = {}; _timings.i = [];
	}
	
    var _prepareURL = function(url, nohash) {
    	url = url.replace(/%23page%3d[^&]+(&)?/i, '$1');
    	if(nohash) url = url.replace(/(&|\?)?(back=)[^&]+(&|$)?/i, '$1'+'$2'+escape(Booster.currentURL)+'$3');
    	var cln = url.match(/^http:\/\/r.mail.ru\/cln(\d+)\/(.*)/);
    	if(cln && cln.length == 3) {
    		url = 'http://' + cln[2];
    		Booster.cln_url = _cln_get + cln[1] + '.gif';
    	} else {
    		Booster.cln_url = '';
    	}
        return url;
    }	
	
	var _cleanUp = function() {
	    _pv = {};
	    _banners = {};
	    window.bannerContent = {};
	    for(var i = 0; i < _timeouts.length; i++) clearTimeout(_timeouts[i]);
	    for(var i = 0; i < _intervals.length; i++) clearInterval(_intervals[i]);
	    var chlds = Booster.storage.childNodes;
	    var r_chlds = [];
	    for(var i = 0; i < chlds.length; i++) 
		if(chlds[i].tagName.toLowerCase() == 'script' && chlds[i].readAttribute('src') == null) r_chlds[r_chlds.length] = chlds[i];
	}
	var _hitsCount = 0;
	return {
		init: function(show_timings, fetch_only){
			this.fetch_only = fetch_only;
			if(Prototype.Browser.Opera) 
			    if(window.navigator.appVersion.match(/([^\s]+)\s/)[1] < 9.7) this.isOldOpera = 1;
//			    else window.history.navigationMode = 'compatible';
			
			this.show_timings = show_timings;
			_regoupPage();
			
			this.canvas = $('boosterCanvas');
			this.storage = $('boosterStorage');
			this.storage.hide();
			
			
			_enumIncludedScripts();
			
			this.fetchAnchors();
			this.inited = !this.fetch_only;
			this.cln_url = '';
			if(Prototype.Browser.IE) {
			    window.hframe = new Element('iframe', {'id':'history_frame','style':'display:none!important'});
			    window.hframe.src = location.protocol + '//' + location.hostname + '/boost.html?q=' + (new Date()).getTime() + '#page=' + location.pathname;
			    document.body.appendChild(window.hframe);
			}
			this.currentURL = document.location.toString();
		},
		setHash: function(){
			if(typeof console != 'undefined'){
				console.log('setHash RUN');
				console.log(arguments);
				
			}

			var v_url = arguments[0];

			if(Prototype.Browser.IE) {
			    if(!window.hframe) {
				window.hframe = new Element('iframe', {'id':'history_frame','style':'display:none!important'});
				window.hframe.src = 'javascript:;';
				document.body.appendChild(window.hframe);
			    }
			    window.hframe.src = location.protocol + '//' + location.host + '/boost.html?q=' + (new Date()).getTime() + '#page=' + (v_url.replace(_rePathFromURL, '$1') || v_url);
			}

			document.location.hash = 'page=' + v_url.replace(_rePathFromURL, '$1');

			this.prevURL = this.currentURL || document.URL;
			this.currentURL = v_url;
			if(!Prototype.Browser.IE) window.cpage = document.location.href;
			

		},
		go: function(v){
			if(this.fetch_only) return true;
			Event.fire(window.document, 'booster:unload');
			if(Object.isString(v)) { // old
			    var i = 1, a = arguments,v = {'url':v};
			    ['m','d','conf','sc','upl','ni','nh','be'].each(function(t){v[t] = a[i++]});
			}
			_hideError();
			if(_inRequest) return false;
			if(v.conf) if(!confirm(v.conf)) return false;
			this.wait();
			if(!v.m) v.m = 'get';
			if(v.d && v.m.toLowerCase() == 'get') v.url += '?' + v.d + (v.d = '');
			v.url = _prepareURL(v.url, v.nh);
			if(v.d) v.d = _prepareURL(v.d, v.nh);
			if(Prototype.Browser.IE) {
			    if(!window.hframe) {
					window.hframe = new Element('iframe', {'id':'history_frame','style':'display:none!important'});
					window.hframe.src = 'javascript:;';
					document.body.appendChild(window.hframe);
			    }
			    if(!v.ni) window.hframe.src = location.protocol + '//' + location.host + '/boost.html?q=' + (new Date()).getTime() + '#page=' + (v.url.replace(_rePathFromURL, '$1') || v.url);
			}
			_timeInterval('server');
			var ajax_url = v.url;
			if(v.m == 'get') { 
			    if(ajax_url.indexOf('?') < 0) ajax_url += '?booster=1';
			    else {
					if(ajax_url.split('?').length == 1) ajax_url += 'booster=1';
					else ajax_url += '&booster=1';
			    }
			    if(v.be) ajax_url += '&boost_enc=1';
			} else {
			    if(v.d) v.d += '&booster=1';
			    else v.d =  'booster=1';
			}
			this.scroll = v.sc;
			
			_inRequest = 1;
			if(!v.nh) document.location.hash = 'page=' + v.url.replace(_rePathFromURL, '$1');
			if(Prototype.Browser.IE) {
				if(_hitsCount > 30) window.updatePage();
				else _hitsCount++;
			}
			this.retries = 0;
			this.ajax_url = ajax_url;
			this.ajax_params = {
				method: v.m,
				parameters: v.d,
				contentType: v.upl ? 'multipart/form-data' : 'application/x-www-form-urlencoded',
				onFailure: _onFail,
				onSuccess: _onResponse
			};
			new Ajax.Request(this.ajax_url, this.ajax_params);
			
			if(!v.nh) {
			    this.prevURL = this.currentURL || document.URL;
			    this.currentURL = v.url;
			    if(!Prototype.Browser.IE) window.cpage = document.location.href;
			}
			return false;
		},
		wait: function(f) {
		    if(f == 'unset') document.body.className = 'no_wait';
		    else document.body.className = 'wait';
		    return;
		},
		checkIframe: function(page) {
		    if(!page) this.go({'url':document.location.pathname,'ni':1});
		    var cp = document.location.href.match(/#page=(.*)/);
		    if(cp) cp = cp[1];
		    else return;
		    if(page != cp) this.go({'url':page,'ni':1});
		},
		error: function( errno, param ){
			if(window.console) console.log('Booster error: '+[errno, param].join(', '));
		},
		
		fetchPage: function( str ){
			if(str) {
				window.rb_innerhtml = 1;
				_cleanUp();
				_timeInterval('render');
				str = '<div style="display: none;"><br></div>' + str;
				var o_wr = document.write;
				document.write = function(t){ if(window.console) console.log('WRITE ', t) };
				this.canvas.innerHTML = str;//.replace(_reScripts, '');
				this.scrollPage();
				this.fetchAnchors();
				_timeInterval('render');
				this.evaluateScripts();// str.match(_reScripts) );
				document.write = o_wr;
				this.callCounters();
				_renderTimings();
				Event.fire(window.document, 'booster:loaded');
				document.title = this.title;
			}
		},
		fetchAnchors: function(c){
		    if(!c) c = this.canvas;
		    var links = c.getElementsByTagName('a');
		    var mrim = {'el':[],'em':[],'t':[]}, mail = null;
		    for(var i = 0;i < links.length;i++) {
				if(links[i].type == 'mrim-status-9' || links[i].type == 'mrim-status-13') {
					mail = links[i].href.match(/to\=([^\@]+\@[^\&\"]+)/);
					if(mail && mail.length) {
						mrim.el.push(links[i]);
						mrim.em.push(mail[1]);
						mrim.t.push(links[i].type == 'mrim-status-9' ? 9 : 13);
					}
				}
				if(links[i].type == 'booster') links[i].onclick = function() {
					var c = this.attributes.getNamedItem('name'), bC = this.attributes.getNamedItem('bstr-confirm');
					return Booster.go({'url': this.href, 'conf': bC ? bC.value : null, 
					'sc': /booster-sc/.test(this.className), 'nh': /booster-nh/.test(this.className)});
				};
		    }
			if(window.MRIM) MRIM.get(mrim);
			else {
				while(mrim.em.length) (new Ajax.Request('http://' + location.hostname + '/proxy-mrim-status?' + mrim.em.splice(0,50).join(','), {
					method: 'get',
					onSuccess: function(t) {
						var a = t.responseText.toArray();
						for(var i=0;i < a.length;i++) 
							t.request.t[0][i].className += ' mrim-'+(a[i]==0?'offline':a[i]==1?'online':a[i]==2?'away':'offline')+'_'+t.request.t[1][i];
					}
				})).t = [mrim.el.splice(0,50), mrim.t.splice(0,50)];
			}
		    links = document.getElementsByTagName('form');
		    for(var i = 0;i < links.length;i++) if($(links[i]).readAttribute('type') == 'booster') links[i].onsubmit = function(){
				var f = $(this);
				return Booster.go({'url': f.readAttribute('action'),'m': f.readAttribute('method'),'d': f.serialize(),
					'sc': /booster-sc/.test(f.className),'upl': /booster-up/.test(f.className),
					'nh': /booster-nh/.test(f.className),'be': /booster-enc/.test(f.className)
				});
		    }
		},
        evaluateScripts: function(){
        	_timeInterval('scripts');
            var scripts = this.canvas.getElementsByTagName('script');
            var scripts_len = scripts.length;

            if(scripts_len && _pv.incScr == undefined)
            _pv.incScr = [];
            for(var i=0; i<scripts_len; i++){
                if(scripts[i].className.indexOf(_clNoexecScript) == -1) {
                    var act = false;
                    var url = scripts[i].src;
                    if( url != undefined && url != '' ){
                        act = ['inc', url];
                    } else if(scripts[i].text != '') {
                        act = ['evl', scripts[i].text];
                    }

                    if( act )
                        _pv.incScr[_pv.incScr.length] = act;
                }
            }
            this.evalNextScript();
            _timeInterval('scripts');
        },
                	
		evalNextScript: function(){
			if(_pv.incScr != undefined && _pv.incScr.length != 0){
				var script = _pv.incScr.shift();
				
				switch(script[0]){
					case 'inc':
						this.includeScript(script[1]);
						break;
					case 'evl':
						this.inlineScript(script[1]);
						break;
				}
			}
		},
		

		includeScript: function( url ){
			
				
			var filename = _parseFileName( url );
			if(_loadedScripts[filename] == undefined) {
				
				_loadedScripts[filename] = 1;
				_writeScript( url );
				this.evalNextScript();
			
			} else if( _waitingScripts[filename] != undefined ) {
			} else {
				this.evalNextScript();
			}
			
		},
		
        inlineScript: function( script ){
            var s = new Element("script");
            s.text = script;
            Booster.storage.appendChild(s);
            this.evalNextScript();
        },		
		
		setPageTitle: function ( title ) {
			title = title.replace(/\r|\n/gi, ' ');
			this.title = title.replace(/\s{2,}/gi, ' ');
			document.title = this.title;
		},
		
		callCounters: function () {
			_timeInterval('counters');
			var tc = $('top_counters');
			var bc = $('bottom_counters');
			tc.innerHTML = ''; bc.innerHTML = '';

			var r = escape(this.prevURL ? this.prevURL : document.referrer);
			var u = escape(this.currentURL ? this.currentURL : document.URL);			
			if(_supported_counters['li']) {
				var url = "http://counter.yadro.ru/hit?r"+
							r + ((typeof(screen)=="undefined") ? "" :
							";s" + screen.width+"*"+screen.height+"*"+(screen.colorDepth ?
							screen.colorDepth : screen.pixelDepth) )+ ";u" + u +
							";" + Math.random();
				var img = new Element('img', {'width': 1, 'height': 1, 'alt': '', 'src': url});
				tc.appendChild(img);
			}
			if(_supported_counters['tns']) {
				var mod = V.get('MainPage') ? '-main/' : '-other/';
				var url = "http://www.tns-counter.ru/V13a****mail_ru/ru/CP1251/tmsec=mail_my" + mod + Math.floor(Math.random()*1000*1000);
				var img = new Element('img', {'width': 1, 'height': 1, 'alt': '', 'src': url});
				bc.appendChild(img);
			}
			if(_supported_counters['top']) {
				var js = 13;
				var a = ';r='+r+';j='+navigator.javaEnabled()+
						';s='+screen.width+'*'+screen.height+
						';d='+(screen.colorDepth?screen.colorDepth:screen.pixelDepth);
				var url = 'http://top3.mail.ru/counter'+
							'?id=1243438;js='+js+a+';rand='+Math.random();
				var img = new Element('img', {'width': 1, 'height': 1, 'alt': '', 'src': url});
				bc.appendChild(img);
			}
			_timeInterval('counters');
		},
		
		scrollPage: function () {
		    if(!this.scroll) return;
		    window.scroll(0,0);
		    this.canvas.scrollTop = 0;
		}
	}
})();
