var History = {
	prev:[ ],
	next:[ ],
	actual:null,
	//uso interno.
	set:function( state ){
		var page = state.page;
		this.locked = true;
		DOM.empty( this.target );
		Cache('general.section',page.type);
		var title = page.getAttribute("title").truncate(18);
		var back = this.btnBack;
		if( this.prev.length ){
			DOM.text( back, this.prev[this.prev.length-1].page.getAttribute("title").truncate( 15 - Math.ceil(title.length/2) ), true );
			DOM.removeClass( back, 'blue' );
			DOM.addClass( back, 'blueLeft' );
		}else{
			DOM.text( back, 'About', true );
			DOM.removeClass( back, 'blueLeft' );
			DOM.addClass( back, 'blue' );
		}		
		this.target.appendChild( page );
		this.actual = state;
		DOM.text( this.title, title, true );
		document.title = page.getAttribute("title") + ' > iZami';
		resetScroll();
		this.locked = false;
		// One time callback
		var callback = this.oneCallback;
		if( callback ){
			this.oneCallback = null;
			callback.call( this, state );			
		}
	},
	addPage:function( page, pop ){
		if( !this.ready ) 
			this.init();
		if( pop )
			History.pop( pop );
		this.next.length = 0;
		if( this.actual )
			this.prev.push( this.actual );
		this.set( new State(page) );
		this.actual.cookies = persist.last;
		this.addEntry();		
	},
	swap:function( replace ){
		this.actual.cookies = persist.last;
		this.actual = replace;
		persist.apply(null, replace.cookies||[]);
	},
	//carga la url en el pane de contenido, y guarda el contenido actual en el stack de historial.
	//si se manda un numero 'pop' saca esa cantidad de elementos del stack, antes de cargar.
	load:function( url, callback, pop ){
		Tip.delayed(Lex.get('loading'));
		Remote.get( url, function( response ){
			Tip.abortDelay();
			var page =  DOM.create(response, true);
			History.addPage( page, pop );
			if( callback )
				callback( page );
			Analytics.notify( url );
		});
	},
	//saca 'num' elementos ( o 1 ) del historial de back.
	pop:function( num ){
		num = num || 1;
		//history.go( -num );
		while( num-- )
			this.actual = this.prev.pop();
		return this.actual;
	},
	skip:function(){
		this.actual = null;
		return this;	
	},
	// saca el ultimo elemento del stack de historial, y lo reemplaza por el contenido actual.
	back:function( set ){
		if( this.prev.length ){
			this.next.push( this.actual );
			this.swap( this.prev.pop() );
			if( set )
				this.set( this.actual );
			Analytics.back();
			//if( !this.prev.length )
			//	loadCitiesPage();
		}
	},
	// saca el ultimo elemento del stack de forward, y lo reemplaza por el contenido actual.
	forward:function( set ){
		if( this.next.length ){
			this.prev.push( this.actual );
			this.swap( this.next.pop() ); 
			if( set )
				this.set( this.actual );
			Analytics.forward();
		}
	},
	//interna
	init:function(){
		DOM.extend( this, {
			target: DOM.$('contentHolder'),
			title: DOM.$('pageTitle'),
			btnBack: DOM.$('backButton'),
			ready: true,
			on: false
		});		
		this.btnBack._click_ = this.btnBack.onclick = function(){
			if( !History.prev.length )
				return loadAboutPage();
			if( !History.locked && !requestsLocked ){
				History.locked = true;
				setTimeout(function(){ History.locked = false; },500);
				history.back();
			}
		};		
		revertSave();		
		var regex = /(?:#(\d+))?$/;
		setInterval(function(){
			// replaced: parseInt(location.href.match(regex) && RegExp.$1) || 0;
			var hash = parseInt(location.hash.slice(1)) || 0;
			if( !History.on || History.guid == hash )
				return;

			var done;
			if( hash < History.guid ){
				revertSave();
				do{
					done = --History.guid == hash;
					History.back( done );
				}while( !done );
			}else{
				do{
					done = ++History.guid == hash;
					History.forward( done );
				}while( !done );
					
				var form = DOM.$('addstore');
				if( form && (form = DOM.$$('form',form)[0]) && form.id )
					turnSave(form);
			}
			setTimeout(keepStatic,0);
		}, 200);
	},
	addEntry:function(){
		this.on = true;
		location.href = '#' + (++this.guid);
	},
	guid:0
};

window.addEventListener('load',function(e){
	Tip.elm = DOM.$('tip');							 
	//History.addEntry();
	History.init();
	if( location.pathname.indexOf('confirm') == -1 ){
		if( location.search )
			loadFromURL();
		else
			loadCitiesPage();
	}
	resetScroll();
}, false );

/* Stop links from modifying the address bar */
document.addEventListener('click',function(e){
	var a = e.target;
	if( a.parentNode && a.parentNode.nodeName == 'A' )
		a = a.parentNode;
	if( a.href && a.href.indexOf('#') != -1 ){
		e.preventDefault();
		a.blur();
	}
}, false );

/* Stop forms from submitting */
document.addEventListener('submit',function(e){
	e.preventDefault();
}, false );

function Page( hasfilter, format, title ){
	var type = title.capitalize();
	title = Lex.get(title);
	this.wrapper = DOM.extend( DOM.create('div'), {
		id:'wrapper',
		title:format.format([].slice.call(arguments,2)),
		selected:true,
		type:type
	});
	this.lists = DOM.append( this.wrapper, 'div' );
	this.lists.id = 'lists';
	
	if( hasfilter ){
		this.filterWrap = DOM.append( this.wrapper, 'div' );
		this.filterWrap.id = 'index';
		this.filter = DOM.append( this.filterWrap, 'ol' );
	}
};
Page.prototype = {
	set:function(){
		if( !this.wrapper.parentNode )
			History.addPage( this.wrapper );
	},
	getFilter:function(){
		return this.filter;	
	},
	getList:function(){
		return this.lists;
	}
};
function State( page ){
	this.page = page;
};
State.prototype = {
	set:function(){
		this.page.set();
	}	
};

function resetScroll( y ){
	if( y && typeof y == 'object' )
		y = DOM.offset( y ).top - headerHeight;
	if( !y || y < 0 ) 
		y = 1;
	scrollTo( 0, y );
	setTimeout(keepStatic,0);
};
/* Keep the header and filters in view */
function keepStatic(){
	var head = DOM.$('head'),
		me = arguments.callee, acc = 6,
		actual = parseInt(head.style.top,10) || 0;
	
	if( me.timer )
		clearInterval(me.timer);
	
	if( window.pageYOffset == actual ){
		move();
	}else{
		me.timer = setInterval( move, 80 );
		setTimeout(move,0);
	}
	
	function move(){
		var diff = window.pageYOffset - actual;
		if( acc > 2 )
			--acc;
		actual += diff / acc;
		if( Math.abs(diff) < 1 ){
			actual = Math.floor(actual);
			clearInterval(me.timer);
		}
		head.style.top = actual + 'px';
		Tip.elm.style.top = actual + 200 + 'px';
		var index = DOM.$('index');
		if( index )
			index.style.top = actual + 33 + 'px';
	};
}

function getBottomPos(){
	return document.documentElement.offsetHeight - window.innerHeight;
};

/* handler for all the loading events */
window.addEventListener( 'scroll', function(){
	setTimeout(keepStatic,0);											
	var Section = Cache('general.section'),
		section = Section.toLowerCase(),
		handler = window['loadMore'+Section];
	if( !handler || scrollLocked || History.locked ) return;
	
	var pos = window.pageYOffset,
		top = Cache(section+'.top'),
		bottom = Cache(section+'.bottom');
	if( pos == 1 ) return;	
	if( pos < 1 && ( !top || !top.done ) )
		handler( true );
	else if( pos >= getBottomPos() - befEnd && ( !bottom || !bottom.done ) )
		handler( false );
}, false );

/* I extend the methods of the engine to catch the events of request and response */
(function(){
	var ex = dwr.engine._execute;
	dwr.engine._execute = function(){
		if( requestsLocked ) return;
		if( !DOM.$('loading') )
			Tip.delayed(Lex.get('loading'));
		requestsLocked = true;
		ex.apply(this,arguments);
	};	
	var hcb = dwr.engine._remoteHandleCallback;
	dwr.engine._remoteHandleCallback = function( a, b, obj ){
		Tip.abortDelay();
		hcb.apply(this,arguments);
		setTimeout( Tip.hide, 0 );
		requestsLocked = false;
		Analytics.notify( obj );
	};
	var he = dwr.engine._handleError;
	dwr.engine._handleError = function(){
		he.apply(this,arguments);
		Tip.show( Lex.get('conn_failed') );
		scrollLocked = requestsLocked = false;
	};
	var hw = dwr.engine._handleWarning;
	dwr.engine._handleWarning = function(){
		hw.apply(this,arguments);
		Tip.show( Lex.get('conn_failed') );
		scrollLocked = requestsLocked = false;
	};
})();
/* */

function US( str ){//temporary, to tell whether it's a US city/street/store or not, should be normalized in the future
	return US.regex.test(str);
};

US.regex = /^(U\.?S\.?A?|United States)$/;

var Analytics = {
	parents:[ 'country', 'state', 'city', 'street', 'store' ],
	build:function( obj ){
		var url = [], attr, pos, arr,
			attrs = this.parents.concat();
	
		while( attrs.length ){
			if( !obj ) break;
			attr = attrs.pop();
			if( obj.length !== undefined )//list(array)
				obj = obj[0];
			else if( !obj.name && (arr = obj[attr+'s']) ){//view
				obj = arr[0];
				if( obj && typeof obj.number == 'number' )
					url.unshift(this.encode( obj.number + '-' + arr[arr.length-1].number ));
			}
			if( obj && typeof obj[attr] == 'object' ){
				if( extra ){
					url.unshift(extra);
					extra = null;
				}
				obj = obj[attr];
				if( level ){
					if( level != attr )
						continue;
					level = null;
				}
				if( attr != 'state' || US(obj.country.name) ){
					attr = this.encode( obj.abbreviation || obj.name || 'unnamed' );				
					url.unshift(attr);						
				}				
			}
		}
		level = null;
		return url;
	},
	encode:encodeURIComponent,
	stack:[ ],
	revStack:[ ],
	actual:null,
	back:function(){
		if( this.stack.length ){
			this.revStack.push(this.actual);
			this.actual = this.stack.pop();
			this.send( this.actual );			
		}
	},
	forward:function(){
		if( this.revStack.length ){
			this.stack.push(this.actual);
			this.actual = this.revStack.pop();
			this.send( this.actual );			
		}
	},
	clean:function( url ){
		if( typeof url == 'object' ){
			if( url.constructor != Array || typeof url[0] != 'string' )
				url = this.build(url);
			url = url.join('/');
		}
		return url;
	},
	log:function( msg ){
		if( Cookie.get('dolog') && window.console && console.log )
			console.log( msg );	
	},
	send:function( url ){
		if( url.charAt(0) != '/' )
			url = '/' + url;
		pageTracker._trackPageview( url );
		this.log(url);
	},
	notify:function( url ){
		try{//temporary
			url = '/' + this.clean(url);
			this.send(url);
		}catch(e){
			url = e.message || e;
			this.log(url);
		}
		if( this.actual )
			this.stack.push(this.actual);
		this.actual = url;
	}	
};