
function ge(id){
	document.getElementById(id);
}

var Request = new function () {
	this.reqs = Array();
	
	this.createRequest = function (params, resultFunc, cache_params) {
		if (cache_params){
			if (data = Cache.Load(cache_params.cache)){
				//trace('[Request]: cache loaded ' + cache_params.cache);
				resultFunc(data);
				return null;
			}
		}
		var req = new Object();  
		req.params = this.prepareParams(params);
		req.resultFunc = resultFunc;
		req.cache = cache_params;
		
		req.handleResponse = function (data){
			if (this.cache){
				//trace('[Request]: cache <b>saved</b> ' + cache_params.cache);
				if (this.cache.t)
					Cache.Save(this.cache.cache, data, this.cache.t);
				else 
					Cache.Save(this.cache.cache, data);
			}
			this.resultFunc(data);
		};
		
		req.destroy = function(){};
		var rnum = Math.floor(Math.random()*1000);
		req.num = rnum;
		req.running = 1;
		this.reqs[rnum] = req;
		return req;
	}
	this.prepareParams = function (params){
		var result = "?";
		for (name in params){
			if (params[name] instanceof Object || params[name] instanceof Array){
				for (i in params[name])
					result += name + "["+i+"]=" + params[name][i] + "&";
			}
			else
				result += name + "=" + params[name] + "&";
		}
		return result;
	}
	this.doRequest = function (params, resultFunc, cache_params, onFail) {
		var req = this.createRequest(params, resultFunc, cache_params);
		if (onFail) {
			setTimeout("refreshOnFail("+req.num+", '"+onFail+"')", 10000);
		}
		if (req!=null)
			this.sendRequest(req);
	}
	
	this.sendRequest = function (req) {
		this.attachScript('req'+req.num, config.api_url+req.params+'sid='+Auth.getCookie('sid')+'&back=Request.reqs['+req.num+'].handleResponse');
		
	}
	
	this.attachScript = function (id, src) {
		var i;
		var newreqs = [];
		
		for (reqnum in this.reqs) {
			req = this.reqs[reqnum];
			if (req.running == 0 && (!pending_request || req.num != pending_request.num)) {
				ge('req'+req.num).parentNode.removeChild(ge('req'+req.num)); 
				this.reqs[reqnum] = null;
			} else {
				newreqs[reqnum] = req;
			}
		}
		this.reqs = newreqs;
		
		var element = document.createElement('script');
		element.type = 'text/javascript';
		element.src = src;
		element.id = id;
		document.getElementsByTagName('head')[0].appendChild(element);
	}
	
	this.debugCallback = function (some){
		Debug.Trace(some);
	}
}

var Debug = new function (){
	this.Trace = function (obj){
		alert(Debug.ShowMe(obj, 0));
	}
	this.Get = function (obj){
		return Debug.ShowMe(obj,0);
	}
	this.ShowMe = function (arr, level){
		var str = "";
		if (level>5) return str;
		if (arr instanceof Object || arr instanceof Array){
			for (index in arr){
				str+="\n";
				for (i=0; i<level; i++)	str+="  ";
				str+="["+index+"] = " + Debug.ShowMe(arr[index], level + 1);
			}
		} else return arr;
		return str+"\n";
	}
	
	
}


var MainDataProvider = new function(){
	this.getFApplications = function (){
		Request.doRequest({'method':'show_favorite'}, Displayer.ShowFApplications);
	}
	this.getFAppBlock = function (){
		Request.doRequest({'method':'show_favorite','partial':5}, Displayer.ShowFAppBlock, {'cache':'fapps', 't':60*60});
	}
	this.getCatTop = function (limit){
		Request.doRequest({'method':'show_cat_top','limit':limit}, Displayer.ShowCatTop);
	}
	this.CurUser = null;
	this.getUserApps = function (data){
		data['method'] = 'show_app_user';
		if (data['uid']) 
			MainDataProvider.CurUser = data['uid'];
		else 
			data['uid'] = MainDataProvider.CurUser;
		Request.doRequest(data, Displayer.ShowUserApps);
	}
	this.getApplication = function (id, act){
		Request.doRequest({'method':'show_app','id':id, 'act':act}, Displayer.ShowApplication);
	}
	this.getTopApplications = function (limit){
		Request.doRequest({'method':'show_top','limit':limit}, Displayer.ShowTopApplications);
	}
	this.login = function (uid, soc_id, seed, auth_key) {
		document.location = config.api_url+"?method=login&uid="+uid+"&auth_key="+auth_key+"&soc_id="+soc_id+"&seed="+seed+"&ref="+(document.location.toString());
	}
	this.logout = function (){
		Request.doRequest({'method':'logout'}, Displayer.ShowLogout);
	}
	
}

var Global = new function(){
	this.balance = 0;	
	
	this.getBalance = function (){
		Request.doRequest({'method':'getBalance'}, Global.setBalance, {'cache':'balance','t':60*5});
	}
	this.setBalance = function (b){
		Global.balance = b;
		Global.redrawBalance();	
	}
	this.redrawBalance = function (){
		DGlobal.ShowBalance(Global.balance);
	}
	
}

var AppConfig = new function() {
	this.balance = 0;
	this.flag = 0;
	this.setBalance = function (b){
		this.balance = b;
		this.Redraw();
	}
	this.getBalance = function (){
		return this.balance;
	}
	this.Redraw = function (){
		DAppConfig.ShowBalance(this.balance);
	}
	this.Save = function(){
		var req = Array();
		req.sub = document.getElementById(config.TAppConfig.SUB).value*100;
		req.add = document.getElementById(config.TAppConfig.ADD).value*100;
		req.app_id = Dispatcher.getQueryVariable('id');
		Request.doRequest({'method':'saveConfig', 'sub':req.sub, 'add':req.add, 'app_id':req.app_id}, AppConfig.onSave);
	}
	this.onSave = function(result){
		if (result!=0){
			Global.setBalance(Global.balance - result);
			AppConfig.balance = result*1 + AppConfig.balance*1;
			DAppConfig.ShowError('');
			AppConfig.Redraw();
		} else {
			DAppConfig.ShowError('Недостаточно средств на счету!');
		}
	}
	this.OnVote = function (vote){
		Request.doRequest({'method':'app_vote', 'vote':vote, 'id':Dispatcher.getQueryVariable('id')}, DVoter.OnSave);
	}
}

var Search = new function(){
	this.timer = null;
	this.init = function (){
		Request.doRequest({'method':'fetch_cat'}, Search.ShowCatalog, {'cache':'cat','t':3600*24*10});
	}
	this.ShowCatalog = function (cat){
		DSearch.ShowCatalog(cat);
		Search.MakeRequest(true);
	}
	this.ShowResults = function (res){
		DSearch.ShowResults(res);
	}
	this.go = function(params){
		var req = (params!=null)? params : {};
		req['type'] = document.getElementById(config.TSearch.CATALOG).value;
		req['sort'] = document.getElementById(config.TSearch.ORDER).value;
		req['text'] = document.getElementById(config.TSearch.TEXT).value;
		Dispatcher.HashParams = req;
		Dispatcher.setHash();
		this.MakeRequest(false);
	}
	this.DelayGo = function (){
		if (this.timer!=null)
			clearTimeout(this.timer);
		this.timer = setTimeout('Search.go()',1000);
	}
	this.MakeRequest = function (is_refresh){
		var req = Dispatcher.HashParams;
		if (is_refresh){
			for (i in req){
				switch (i){
					case 'type':document.getElementById(config.TSearch.CATALOG).value = req[i]; break;
					case 'sort':document.getElementById(config.TSearch.ORDER).value = req[i]; break;
					case 'text':document.getElementById(config.TSearch.TEXT).value = req[i]; break;
				}
			}
		}
		req['method'] = 'search_apps';
		req['on_page'] = 10;
		Request.doRequest(req, Search.ShowResults);
	}
}

var Editor = new function(){
	this.id = null;
	this.init = function (id){
		this.id=id;
		Request.doRequest({'method':'fetch_cat'}, DEditor.ShowCatalog, {'cache':'cat','t':3600*24*10});
		Request.doRequest({'method':'edit_app','id':id}, Editor.ShowApp);
	}
	this.SubmitUpload = function (form){
		AIM.submit(form, config.api_url+'upload/?api_id=' + Editor.id);
		return true;
	}
	this.ShowApp = function(data){
		if (data.error){
			document.location = config.search;
		} else 
			DEditor.ShowApp(data);
	}
	
	this.Save = function (){
		var el = helper.getBlock(config.TEdit.FORM).elements;	
		var ref = {}
		ref[config.TEdit.NAME] = "name";
		ref[config.TEdit.DESC] = "description";
		ref[config.TEdit.TYPE] = "type";
		ref[config.TEdit.STATE] = "visible";
		ref[config.TEdit.SSERVER] = "sserver";
		ref[config.TEdit.SCLIENT] = "sclient";
		var fields = {};
		for (var i=0; i<el.length; i++)
			switch(el[i].type){
				case 'text':
				case 'textarea':
				case 'select-one':
					fields[ ref[el[i].id] ] = el[i].value;
					break;
			}
		var req = {'method':'edit_app','id':this.id,'fields':fields};
		Request.doRequest(req, Editor.onSave);
	}
	this.onSave = function (result){
		if (result)
			alert('Настройки приложения сохранены.');
		else
			alert('Произошла ошибка в процессе редактирования приложения.');
	}
}
var Creator = new function (){
	this.init = function (){
		Request.doRequest({'method':'fetch_cat'}, DEditor.ShowCatalog, {'cache':'cat','t':3600*24*10});
	}
	this.Create = function (){
		var req = {'method':'create_app'};
		req['name'] = helper.getBlock(config.TEdit.NAME).value;
		req['description'] = helper.getBlock(config.TEdit.DESC).value;
		req['type'] = helper.getBlock(config.TEdit.TYPE).value;
		Request.doRequest(req, Creator.onCreate);
	}
	this.onCreate = function (res){
		document.location = config.edit + "?id="+res;
	}
}

var Aimer = new function (){
	this.queue = new Array();
	this.Add = function (aim, params){
		var task = {};
		task.handler = aim;
		task.params = params;
		this.queue.push(task);
	}
	this.Handle = function (){
		for (var i in Aimer.queue) if (typeof(Aimer.queue[i].handler)=='function'){
			Aimer.queue[i].handler(Aimer.queue[i].params);
		}
	}
}

var Dispatcher = new function (){
	this.BodyOnLoad = function(uid, seed,auth_key){
		Auth.uid = uid;
		Auth.seed = seed;
		Auth.auth_key = auth_key;
		Auth.Login();
		if (uid!='anonymous'){
			Global.getBalance();
			MainDataProvider.getFAppBlock();
		}
		
		this.loadQueryParams();
		if (this.Path == config.app_all || this.Path=="/"){
			Dispatcher.MainPage();
		} else 
		if (this.Path == config.app && this.getQueryVariable('c')=='view') {
			Dispatcher.AppPage();
		} else 
		if (this.Path == config.my_apps){
			MainDataProvider.getFApplications();	
		} else 
		if (this.Path == config.search){
			Search.init();	
		} else 
		if (this.Path == config.edit){
			Dispatcher.AppEdit();
		} else 
		if (this.Path == config.add){
			Creator.init();
		}
		Aimer.Handle();
	}
	this.AppEdit = function() {
		var id = this.QueryParams['id'];
		Editor.init(id);
	}
	this.MainPage = function(){
		MainDataProvider.getTopApplications(4);
		MainDataProvider.getCatTop(4);
	}
	this.AppPage = function (){
		switch (this.getQueryVariable('c')){
			case 'view':
				MainDataProvider.getApplication(this.getQueryVariable('id'),this.getQueryVariable('act'));
				break;
			case 'all':
				MainDataProvider.getApplications();
				break;
		}
	}
	this.Search = function (){
		MainDataProvider.getApplications();
	}
	this.GetUserApps = function (id){
		MainDataProvider.getUserApps({'page':1,'uid':id});
	}
	//
	// TOOLS 
	//
	this.isQueryAnalyzed = false;
	this.QueryParams = new Array();
	this.HashParams = {};
	this.Path = "";
	
	this.getQueryVariable = function (variable) {
		if ( ! this.isQueryAnalyzed){
			this.loadQueryParams();
			this.isQueryAnalyzed = true;
		}
		return this.QueryParams[variable];
	} 	
	this.loadQueryParams = function () {
		this.Path = window.location.pathname;
		var query = window.location.search.substring(1);
		
		var vars = query.split("&");
		for (var i=0; i<vars.length; i++) {
			var pair = vars[i].split("=");
			this.QueryParams[pair[0]] = pair[1];
		}
		
		var hash = window.location.hash.substring(1);
		var vars = hash.split("&");
		for (var i=0; i<vars.length; i++) {
			var pair = vars[i].split("=");
			this.HashParams[pair[0]] = pair[1];
		}
	}
	this.setHash = function(){
		var str = "#";
		for (i in this.HashParams){
			str += i+"="+this.HashParams[i] + "&";
		}
		window.location.hash = str.substring(0,str.length-1);
	}
}

var Auth = new function(){
	this.islogin = false;
	
	this.Login = function (){
		//Debug.Trace({"cookie_sid":Auth.getCookie('sid'),"uid":this.uid, "cache_uid":Cache.Load('uid')});
		//prompt();
		if ( ! Auth.getCookie('sid') || Cache.Load('uid')!=this.uid){
			//alert('WTF?');
			Cache.Save('uid',this.uid, 60*60*60);
			Auth.writeCookie('sid',1);
			this.islogin = true;
			MainDataProvider.login(this.uid, config.soc_id, this.seed, this.auth_key);
		}
		
	}
	
	this.uid = null;
	this.seed = null;
	this.auth_key = null;
	
	this.ReLogin = function (){
		Auth.destroyCookie('sid');
		Auth.Login();
	}
	/*this.Authorize = function (result){
		if (result != 'false'){
			Auth.writeCookie('sid',result);
			//alert('авторизация прошла успешно ' + Auth.getCookie('sid'));
		} else {
			Auth.destroyCookie('sid');
			//alert('Авторизация провалена.');	
		}
	}*/
	this.writeCookie = function (name, value){
		document.cookie = name + " = " + value + "; expires=01/01/2017 00:00:00; path=/";
	}
	this.getCookie = function (name) {
		var prefix = name + "=";
		var start_ind = document.cookie.indexOf(prefix);
		if (start_ind == -1) return null;
		var end_ind = document.cookie.indexOf(";", start_ind + prefix.length);
		if (end_ind == -1) end_ind = document.cookie.length;
		return unescape(document.cookie.substring(start_ind + prefix.length, end_ind))
	}
	this.destroyCookie = function (name){
		document.cookie = name + "=;path=/ ;expires=Thu, 01-Jan-70 00:00:01 GMT";
	}
}

var Loader = new function(){
	this.included = Array();
	this.callback = null;
	this.include = function (filename, callback){
		// checking if we already include it
		for (i in this.included)
			if (this.included[i] == filename) return;
		var element = document.createElement('script');
		element.type = 'text/javascript';
		element.src = filename;
		document.getElementsByTagName('head')[0].appendChild(element);
		this.included.push(filename);
		
		if (callback != null){
			this.callback = callback;
			window.onload = this.Loaded();
		}
	}
	this.Loaded = function (){
		window.onload = "";
		this.callback();
	}
}

var Timer = new function(){
	this.REFRESH_APP = 6000; // 60 seconds
	this.timers = Array();
	this.RefreshApplications = function(){
		MainDataProvider.getTopApplications();
		this.timers['apps'] = setTimeout("Timer.RefreshApplications()", this.REFRESH_APP);		
	}
	this.Initialize = function(){
		this.timers['apps'] = setTimeout("Timer.RefreshApplications()", this.REFRESH_APP);
	}
	this.StopAll = function(){
		for (i in this.timers){
			clearTimeout(this.timers[i]);
		}
	}
}

var Error = new function (){
	
	this.is_relogin = false;
	this.reloaded = Array();
	this.message_show = false;
	
	this.ServerHandler = function (err){
		//Debug.Trace(err);
		//return;
		if (err.code == 1 || err.code == 0 || err.code == 4){
			if ( ! this.is_relogin) {
				this.is_relogin = true;
				//alert('relogining...' + this.is_relogin);
				
				if ( ! Auth.islogin)
					Auth.ReLogin();
			}
			
			var reg=/Request.reqs\[(\d+)\].resultFunc/
	        var arr=reg.exec(err.back);
			var id = arr[1];
			
			var key = Request.reqs[id].params;
			
			if ( ! this.reloaded[key]) {
				Request.sendRequest(Request.reqs[id]);
				this.reloaded[key] = true;
			} else {
				// UNRESOLVED PROBLEM
				if ( ! this.message_show){
					this.message_show = true;
					Timer.StopAll();
					//alert("Ошибка авторизации. Попробуйте обновить страницу позже.");
				}
			}
		}
	}
}

var AIM = new function (){
 	this.forms = {};
	this.frame =  function(c) {
 
		var n = 'f' + Math.floor(Math.random() * 99999);
		var d = document.createElement('DIV');
		d.innerHTML = '<iframe style="display:none" src="about:blank" id=\''+n+'\' name=\''+n+'\' onload="AIM.loaded(\''+n+'\')"></iframe>';
		document.body.appendChild(d);
 
		var i = document.getElementById(n);
		if (c && typeof(c.onComplete) == 'function') {
			i.onComplete = c.onComplete;
		}
 
		return n;
	}
 
	this.form = function(f, name, action) {
		f.target = name;
		f.action = action;
		f.method="POST";
		for (var i=0; i<f.elements.length; i++) if (f.elements[i].type=='submit')
			f.elements[i].disabled = true;
		AIM.forms[name] = f;
	}
 
	this.submit = function(f, action,  c) {
		var id = AIM.frame(c);
		AIM.form(f, id, action);
		return true;
	}
 
	this.loaded = function(id) {
		var f = AIM.forms[id];
		for (var i=0; i<f.elements.length; i++){
			if (f.elements[i].type=='submit')
				f.elements[i].disabled = false;
			if (f.elements[i].type=='file')
				f.elements[i].value = "";
		}
	}
 
}
function trace(data){}


