// TODO - Add initial page loading and handlers
(function($,History){
	var State = History.getState(),
		Old = {},
		Key = null,
		flags = [],
		templates = [],
		flag = window.flag = function(name,value){
			if(exists(value)){
				flags[name] = value;
			}else{
				return exists(flags[name])?flags[name]:false;
			}
		},
		settings = {},
		exists = function(v){
			return typeof v != 'undefined';
		},
		get = window.get = function(s){
			return settings[s];
		},
		set = window.set = function(s,v){
			settings[s] = v;
			return v;
		},
		setKey = window.setKey = function(key){
			if(key !== null){
				console.log('Key change to '+key);
				Key = key;
				var d = new Date();
				d.setTime(d.getTime()+get('expire'));
				$.cookie('key',key,{
					expires: d
				});
			}else{
				console.log('Key deleted');
				Key = null;
				$.removeCookie('key');
			}
		},
		getKey = window.getKey = function(){
			return Key;
		},
		template = window.template = function(name,template){
			var d = +new Date,
				id = (function(name){
					for(var i in templates){
						if(templates[i].name == name){
							return i;
						}
					}
					return false;
				})(name);
			if(exists(template)){
				if(template === null){
					if(id!==false){
						templates.splice(id,1);
					}
					$.localStorage('templates',templates);
					console.log('Dropping template for: '+name);
					return '';
				}else{
					var o = {
						name: name,
						template: template,
						date: get('expire')+d
					}
					if(id===false){
						console.log('Storing new template for: '+name);
						templates.push(o);
					}else{
						console.log('Replacing old template for: '+name);
						templates[id] = o;
					}
					$.localStorage('templates',templates);
				}
			}else if(id!==false){
				console.log('Using cached template for: '+name);
				var template = templates[id].template;
				if(templates[id].date < d){
					delete templates[name];
					$.localStorage('templates',templates);
				}
				return template;
			}else{
				console.log('No cached template stored for: '+name);
				return '';
			}
		},
		apiCall = window.apiCall = function(data,callback){
			console.log('apiCall('+data.type+'-'+data.id+')');
			$('#loading').show();
			data.get = 'api';
			data.timestamp = +new Date;
			if(exists(templates[data.type+'-'+data.id])){
				data.template = false;
			}
			$.get(location.href,data,function(d){
				if(exists(d['error'])){
					error(d);
				}else{
					if(location.href.substr(location.href.lastIndexOf('/')+1) != d.state.url){
						console.log('Forced redirection to '+d.state.url);
						History.replaceState(d.state.data,d.state.title,d.state.url);
					}
				}
				if(exists(callback)){
					callback(d);
				}
			},'json');
		},
		loadState = window.loadState = function(href,callback){
			console.log('loadState('+href+')');
			$('#loading').show();
			var data = {
				get:'state',
				timestamp: +new Date
			};
			$.get(href,data,function(d){
				if(exists(d['error'])){
					error(d);
				}else{
					History.pushState(d.state.data,d.state.title,href);
					getNewState();
				}
				if(exists(callback)){
					callback(d);
				}
			},'json');
		},
		apiState = window.apiState = function(href,callback){
			console.log('apiState('+href+')');
			$('#loading').show();
			var data = {
				get:'state',
				timestamp: +new Date
			};
			$.get(href,data,function(d){
				if(exists(d['error'])){
					error(d);
				}else{
					History.replaceState(d.state.data,d.state.title,href);
					getNewState();
				}
				if(exists(callback)){
					callback(d);
				}
			},'json');
		},
		error = function(e){
			e = '['+State.url+']'+e.error;
			console.error(e+"\n"+(exists(e.state)?JSON.stringify(e.state):''));
			alert(e);
		},
		getNewState = function(){
			State = History.getState();
			console.log("State change. "+JSON.stringify(State.data));
			if (!window.location.origin) {
				window.location.origin = window.location.protocol + "//" + window.location.hostname + (window.location.port ? ':' + window.location.port: '');
			}
		},
		equal = function(o1,o2){
			for(var i in o1){
				if(!exists(o2[i])||o2[i]!=o1[i]){
					return false;
				}
			}
			for(i in o2){
				if(!exists(o1[i])||o2[i]!=o1[i]){
					return false;
				}
			}
			return true;
		},
		render = window.render = {
			topbar: function(t,c){
				$('#topbar').html(Handlebars.compile(t)(c));
				render.links('#topbar');
				$(window).resize();
			},
			content: function(t,c){
				$('#content').html(
					Handlebars.compile(t)(c)
				);
				render.links('#content');
				$(window).resize();
			},
			links: function(selector){
				$(selector).find('a').each(function(){
					var href = this.href;
					if(href.indexOf('#')!=-1&&(href.indexOf(location.origin)!=-1||href.indexOf('#')==0)){
						href = href.substr(href.indexOf('#')+1);
						$(this).click(function(e){
							try{
								if(($(this).hasClass('topbar-home') || $(this).hasClass('topbar-back'))&&$(window).width()<767){
									$('#topbar').children('div.topbar-right,div.topbar-left').toggle();
									$(window).resize();
								}else if($(this).hasClass('topbar-history')){
									History.back();
								}else{
									loadState(href);
								}
							}catch(error){
								console.error(error);
							}
							e.preventDefault();
							return false;
						});
					}
				});
			}
		};
	if(exists($.cookie('key'))){
		setKey($.cookie('key'));
	}else{
		setKey(null);
	}
	$(document).ready(function(){
		templates = $.localStorage('templates');
		if(templates === null){
			templates = [];
		}
		if(!exists($.support.touch)){
			$.support.touch = 'ontouchstart' in window || 'onmsgesturechange' in window;
		}
		$(window).on('statechange',function(){
			getNewState();
			if(!equal(State.data,Old)){
				document.title = State.title;
				switch(State.data.type){
					case 'page':case 'user':
						apiCall(State.data,function(d){
							if(exists(d.context)){
								if(!exists(d.context.key)&&Key!==null){
									console.log('Context detected logout');
									setKey(null);
								}
								if(exists(d.template)){
									template(State.data.type+'-'+State.data.id,d.template);
								}else{
									d.template = template(State.data.type+'-'+State.data.id);
								}
								render.topbar(d.topbar.template,d.topbar.context);
								render.content(d.template,d.context);
								$(window).resize();
								$('#loading').hide();
							}else{
								console.error('No context given');
								History.back();
							}
						});
					break;
					case 'action':break;
					default:
						error({
							url: State.url,
							error: "Something went wrong!"
						});
				}
				Old = State.data;
			}else{
				console.log(State.data,Old);
				console.warn('Stopped double load of '+Old.type+'-'+Old.id);
				$('#loading').hide();
			}
		});
		$('#content').niceScroll({
			cursorwidth: 10,
			nativeparentscrolling: false,
			preservenativescrolling: false
		});
		document.addEventListener('touchmove',function(e){
			e.preventDefault();
		});
		$(window).resize(function(){
			if($(window).width()>767){
				$('#topbar div.topbar-right, #topbar div.topbar-left').css({
					'display': ''
				});
			}
			$('#content').height($('body').height()-$('#topbar').height());
			$('#content').getNiceScroll().resize();
		});
		var data = {
			get: 'settings',
			timestamp: +new Date
		};
		$.get(location.href,data,function(d){
			settings = d;
			apiState(location.href);
		},'json');
	});
	shortcut.add('f12',function(){
		if(!flag('firebug-lite')){
			(function(F,i,r,e,b,u,g,L,I,T,E){
				if(F.getElementById(b))
					return;
				E=F[i+'NS']&&F.documentElement.namespaceURI;
				E=E?F[i+'NS'](E,'script'):F[i]('script');
				E[r]('id',b);
				E[r]('src',I+g+T);
				E[r](b,u);
				(F[e]('head')[0]||F[e]('body')[0]).appendChild(E);
				E=new Image;
				E[r]('src',I+L);
			})(document,'createElement','setAttribute','getElementsByTagName','FirebugLite','4','firebug-lite.js','releases/lite/latest/skin/xp/sprite.png','https://getfirebug.com/','#startOpened');
			flag('firebug-lite',true);
		}
	});
	$.fn.serializeObject = function(){
		var o = {},
			a = this.serializeArray();
		$.each(a,function(){
			if(o[this.name] !== undefined){
				if(!o[this.name].push){
					o[this.name] = [o[this.name]];
				}
				o[this.name].push(this.value || '');
			}else{
				o[this.name] = this.value || '';
			}
		});
		return o;
	};
	$.ajaxSetup({
		async: false
	});
})(jQuery,History);