var ajaxify = {
		initialised : false,
		axready:false,
		posting : false,
		added_initial_click_events : false,
		strip_script: false,
		filter_response : true,
		auto_collect_links : true,
		http_host : '',
		initial_path : '/',
		request_uri : '',
		url : '',
		last_uri : '',
		hash : '',
		page : '',
		is_homepage : 0,
		requests : 0,
		loading_link : 'ajaxify-load',
		default_load_into : '#ajaxify-data',
		ajaxify_class : 'ajaxified',
		target : '',
		filter : '#ajaxify-data',
		homepage : 'home',
		ext : '/',
		selectors : [],
		links : [],
		cache : [],
		ready_events : [],
		on_before_ajax_events : [],
		on_after_ajax_events : [],
		on_ajax_click_events : [],
		relcache : [],
		last : {'rel':'','href':''},
		current : {},
		
		setup : function(args){
			for(var key in args){
				this[key] = args[key];	
			}
		},
		
		start : function(){
			//console.log('start called');
			if(!ajaxify_running){				
				if(!this.initialised){
					this.initialise();	
				}
			}
		},
		
		initialise : function(){
			//console.log('initialise called');
			this.initialise_state_from_url();
			this.initialised = true;			
		},
		
		initialise_state_from_url : function(){
			
			if(window.location.hash)
			{		
				//console.log('hash exists');
				var url = window.location.hash;
				this.hash = url;
				url = url.split("#");
				url = url[1];
				url = this.make_ajax_url(url);
				this.request_uri = url;
				//console.log('requesting '+url);
				ajaxify_running = true;
				this.start_timer();
				this.request(url);
			}else if(window.location != 'http://'+this.http_host+this.initial_path){
				//console.log('location not http://'+this.http_host+this.initial_path);
				var url = window.location;
				url = this.make_hash_url(url);
				window.location = url;				
			}else{				
				//console.log('no hash, no URL: send to homepage');
				var url = this.homepage+this.ext;
				url = this.make_hash_url(url);
				window.location = url;
				this.initialise_state_from_url();				
			}
		},
		
		make_hash_url : function(url){
			url = url.toString();
			url = url.replace('http://','');
			url = url.replace(this.http_host+this.initial_path,"");
			var parsed_url = (this.initial_path == '/') ? url : url.replace(this.initial_path,'');
			url = '/'+this.initial_path+"/#/"+parsed_url;
			url = url.replace(/\/+/g,'/');
			//console.log('made hash url: '+url);
			return url;
		},
		
		make_ajax_url : function(url){
			url = url.toString();
			url = url.replace('http://'+this.http_host+this.initial_path,"");
			var parsed_url = (this.initial_path == '/') ? url : url.replace(this.initial_path,'');
			url = this.http_host+'/'+this.initial_path+"/"+parsed_url;
			url = url.replace(/\/+/g,'/');
			//console.log('made ajax url: http://'+url);
			return 'http://'+url;			
		},
		
		start_timer : function(){
			setInterval(function()
			{
				if (window.location.hash.split('#')[1] != ajaxify.hash.split('#')[1] && (!ajaxify.posting))
				{
					ajaxify.initialise_state_from_url();
				}
			}, 100);
	
		},
		
		request : function(url,load_into,absolute){
			if(!this.posting){
				if(url == this.make_ajax_url(this.homepage+this.ext)){
					this.is_homepage = 1;	
				}else{
					this.is_homepage = 0;	
				}
				if(!this.added_initial_click_events){
					this.add_initial_click_events();	
				}
				if(!this.axready){
					var ajaxify = this;
					this.do_ready(function(){ajaxify.request(url,load_into,absolute)});	
				}else{
					this.posting = true;
					var url = this.make_ajax_url(url);
					//console.log('ajax request to '+url);
					this.url = url;
					
					if(!load_into)
					{
						var target = jQuery(this.default_load_into);	
					}else{
						var target = jQuery(load_into);		
					}
					
					this.target = target;
					this.do_before_ajax(target);
				}
			}
		},
		
		on_ajax_click : function(){
				
		},
		
		do_ajax_click : function(){
			
		},
			
		on_before_ajax : function(fn){
			this.on_before_ajax_events.push(fn);
		},
		
		do_before_ajax : function(target){
			var ajaxify = this;
			if(this.on_before_ajax_events.length){
				for(var i in this.on_before_ajax_events){
					this.on_before_ajax_events[i](target);	
				}
			}else{
				target.fadeOut(function(){
					ajaxify.load_url();
				});		
			}
		},
		
		ready : function(fn){
			this.ready_events.push(fn);
		},
		
		do_ready : function(continue_fn){
			this.axready = true;
			if(this.ready_events.length){
				for(var i in this.ready_events){
					this.ready_events[i]();	
				}				
				continue_fn();	
			}else{
				continue_fn();	
			}
		},
		
		on_after_ajax : function(target){
			var ajaxify = this;
			target.fadeIn(function(){
				ajaxify.on_after_fade_in();
			});	
			this.add_new_click_events(target);
		},
		
		on_after_fade_in : function(){
			//console.log('Finished fade in');
		},
		
		load_url : function(return_data){
			if(array_key_exists(this.url,this.cache)){
				var data = this.cache[this.url]
				this.target.html(data);
				/*this.last = this.current;
				var rel = this.relcache[this.url];
				var url = this.url;
				this.current = {'rel':rel,'href':url};*/
				this.posting = false;
				this.requests = this.requests + 1;
				this.on_after_ajax(this.target);				
			}else{
				var ajaxify = this;
				jQuery.post(this.url,{'ajax':'true'},function(data){
					data = ajaxify.strip_script ? data.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,"") : data;
					if(ajaxify.filter_response){
						data = jQuery("<div>").append(data).find(ajaxify.filter).html();
						//console.log('filtered data for '+ajaxify.filter);
					}
					//console.log('data: '+data);
					
					ajaxify.cache[ajaxify.url] = data;
					ajaxify.posting = false;
					ajaxify.requests = ajaxify.requests + 1;
					if(!return_data){
						ajaxify.target.html(data);
						ajaxify.on_after_ajax(ajaxify.target);
					}else{
						return data;	
					}
				});
			}
			
			
		},
		
		add_initial_click_events : function(){
			//console.log('adding initial click events...');
			var ajaxify = this;
			var abs_host = this.http_host+this.initial_path;
			abs_host = abs_host.replace(/\/+/g,'/');
			//console.log('click events for a[href^="http://'+ abs_host+'"], a[href^="'+this.initial_path+'"]');
			if(ajaxify.auto_collect_links){
				jQuery('a[href^="'+ abs_host+'"], a[href^="'+ajaxify.initial_path+'"]').each(function(){
					//console.log(('Found link '+jQuery(this).attr('href'));
					jQuery(this).addClass(ajaxify.ajaxify_class);
					ajaxify.handle_click(jQuery(this));
				});
					console.log('Auto collecting');
			}
			
			for(i in ajaxify.selectors){
				var this_selector = ajaxify.selectors[i];
				jQuery('' + this_selector).each(function(){
					if(!jQuery(this).hasClass(ajaxify.ajaxify_class)){
						jQuery(this).addClass(ajaxify.ajaxify_class);
						ajaxify.handle_click(jQuery(this));
					}
				});
			}
			
			ajaxify.added_initial_click_events = true;
		},
		
		add_new_click_events : function(target){
			//console.log('adding new click events...');
			var ajaxify = this;
			var abs_host = this.http_host+this.initial_path;
			abs_host = abs_host.replace(/\/+/g,'/');
			if(ajaxify.auto_collect_links){
				target.find('a[href^="http://'+ abs_host+'"], a[href^="'+this.initial_path+'"]').each(function(){
					//console.log('Found link '+jQuery(this).attr('href'));
					if(!jQuery(this).hasClass(ajaxify.ajaxify_class)){
						jQuery(this).addClass(ajaxify.ajaxify_class);
						ajaxify.handle_click(jQuery(this));
					}
				});
			}
			
			for(i in ajaxify.selectors){
				var this_selector = ajaxify.selectors[i];
				jQuery('' + this_selector).each(function(){
					if(!jQuery(this).hasClass(ajaxify.ajaxify_class)){
						jQuery(this).addClass(ajaxify.ajaxify_class);
						ajaxify.handle_click(jQuery(this));
					}
				});
			}
			
		},
		
		handle_click : function(linkobj){
			var href = linkobj.attr('href');
			linkobj.click( function(ev) {		
				ev.preventDefault();
				ajaxify.handle_link(linkobj);
			});	
		},
		
		handle_link : function(linkobj){
			linkobj.blur();
			var url= linkobj.attr('href');
			if(typeof(url) != 'undefined'){
				var hash_url = ajaxify.make_hash_url(url);
				var ajax_url = ajaxify.make_ajax_url(url);
				window.location = hash_url;
				ajaxify.hash = hash_url;
				ajaxify.on_ajax_click(linkobj);
				var rel = linkobj.attr('rel');
				ajaxify.relcache[ajax_url] = rel;
				ajaxify.last = ajaxify.current;
				ajaxify.current = {'rel':rel,'href':ajax_url};
				ajaxify.request(ajax_url);
			}
		},
		
		uri : function(){
			return this.url.replace('http://'+this.http_host+this.initial_path,'');	
		},
		
		segments : function(){
			return this.uri().split('/');	
		},
		
		segment : function(n){
			return this.segments()[n]	
		}
};

if(!ajaxify_running){
	var ajaxify_running = false;
}

/*
--------------
*/

function strpos(haystack, needle, offset) {
    var i = (haystack+'').indexOf(needle, (offset ? offset : 0));
    return i === -1 ? false : i;
}

function in_array (needle, haystack, argStrict) {
    
    var key = '', strict = !!argStrict;

    if (strict) {
        for (key in haystack) {
            if (haystack[key] === needle) {
                return true;
            }
        }
    } else {
        for (key in haystack) {
            if (haystack[key] == needle) {
                return true;
            }
        }
    }

    return false;
}

function array_key_exists ( key, search ) {
    if (!search || (search.constructor !== Array && search.constructor !== Object)){
        return false;
    }

    return key in search;
}

/*
--------------
*/
