
var My_App = {
	ajaxPath: '/',//TODO ajaxPath can be read from BASE html tag, otherwise /
	userRegistered: false,
	NOT_REGISTERED_ERROR_CODE:500,
	includedScriptCache: new Array(),
	_reloadPage : false,
	init: function(){
		//this.initEvents();
		this.initMenu();
		this.gotoAnchor();
		
		//init link clicks logging
		$('a[rel*=log_]').live('click', My_App.logLinkClick);
	},
	loggedin: function() {
		return $('meta[name=isuser]').length 
			? parseInt($('meta[name=isuser]').attr('content')) 
			: 0;
	},
	fcSignOut:function(){
		google.friendconnect.requestSignOut();
		this._reloadPage = true;
		//this._signedIn = false;
	},
	fbSignOut:function(){
		FB_RequireFeatures(["Connect"], function(){
			FB.init(_fb_key, "/xd_receiver.htm", {
					"ifUserConnected":function(ccc){
						FB.Connect.logout(function() { 
							location.href = '/user/fb/logout/1'; 
						});
					}
			});
			
			
		});
		
		//FB.Connect.logout(function() { 
		//	location.href = '/user/fb/logout/1'; 
		//});
		//this._reloadPage = true;
		//this._signedIn = false;
	},
	initMenu: function(){
		
		//init main menu
		if ($("ul.sf-menu").length > 0) {
			$("ul.sf-menu").superfish({
				autoArrows:false
			}).find('ul').bgIframe({opacity:false,delay:200});
		}
		
		//init slidedown popup
		$(window).scroll(function () { 
			$('#alert').css({top:$(document).scrollTop()+"px"}); 
	    });
		
	},
	showAlert: function(text, className){

		var $alert = $('#alert').show();
		if(className) $alert.addClass(className);

		if($alert.length)
		{
			$alert.html(text);
			var alerttimer = setTimeout(function () {
				$alert.trigger('click');
			}, 3000);
			$alert.css({top:$(document).scrollTop()+"px"});
			$alert.animate({height: $alert.css('line-height') || '50px'}, 200)
			.click(function () {
				window.clearTimeout(alerttimer);
				$alert.animate({height: '0'}, 200, '', function(){ $alert.removeClass().hide();});
				
			});
		}
	},
	showDismissAlert: function(text, className){
		var $alert = $('#alert').show();
		if(className) $alert.addClass(className);
		if($alert.length) {
			$alert.html(text).append('<span><b>[</b> <i> '+ clickAndHide +' </i> <b>]</b></span>');
			$alert.css({top:$(document).scrollTop()+"px"});
			$alert.animate({height: $alert.css('line-height') || '50px'}, 200)
				.click(function () {
					$alert.animate({height: '0'}, 200, '', function(){ $alert.removeClass().hide();});
				});
		}
	},
	inlineFlash: function(el, className, text, delay, destroy) {
		$(el).addClass(className).html(text).css({opacity:'1'});
		window.clearTimeout(window.alerttimer);
		
		var delay = (delay) ? delay : 2000;
		
		//fade away
		alerttimer = setTimeout(function(){
			
			if(destroy) {
				$(el).animate({opacity: '0'}, 200, '', function(){ $(el).remove();});
			} else {
				$(el).animate({opacity: '0'}, 200);
			}
		}, delay);
	},
	gotoAnchor:function() {
		if($('meta[name=anchor]').length) {
			var anchorId = $('meta[name=anchor]').attr('content');
			//get achor position
			var $anchor = $('a[name='+anchorId+']');
			this.scrollToElement($anchor);
		}
	},
	scrollToElement:function($el, v_offset) {
		if($el.length) {
			var offset = v_offset ? v_offset : 0;
			var pos = $el.offset().top + offset;
			//window.scrollBy(pos.left,pos.top - 20);
			//var scrollTo = $(".wrap_top").offset().top;		
			$('html, body').animate({scrollTop:pos}, 300);
		}
	},
	logLinkClick: function(ee) {
		//alert('howdy');
		//click happened
		var $el = $(ee.target);
		if($el.tagName != 'a') $el = $el.parents('a');
		
		var parts = $el.attr('rel').split('_');
		var type = (parts[1]) ? parts[1] : 0;
		var itemId = (parts[2]) ? parts[2] : 0; 
		$.post("/ajax/loglinkclick", {"type":type,curr_url:location.href, id: itemId});
		//ee.preventDefault();
		
	},
	includeScript: function(src, type) {
//		var html_doc = document.getElementsByTagName('head').item(0);
//	    var js = document.createElement('script');
//	    js.setAttribute('language', 'javascript');
//	    js.setAttribute('type', 'text/javascript');
//	    js.setAttribute('src', src);
//	    html_doc.appendChild(js);
//	    return false;

		var $head = $('head');
		if(type.indexOf('javascript')) {	//javascript
			var script = $('script').attr('type',type).attr('src',src);
			$head.append(script);
		} else {	//css
			//var link = $('link').attrib('type',type).attrib('src',src);
			//$meta.append(script);
		}
	}

}


// executed on document load
$(document).ready(function(e){
	My_App.init(); //mostly alert messages
	My_Forms.init();//post forms using ajax
	makeEnabled();
	initJsFunctions();
	
	//submit buttons
	//enable click on the whole btn area
	$('.btn div span').each(function(){
		if($(this).hasClass('nolink')) return;
		$(this).click(function(e){
			$(e.target).parents('form').submit();
			e.preventDefault();
		});
		$(this).css('cursor','pointer');
	});
	
});


/**
 * GENERAL FUNCTION - reusable
 * Return false if no link was clicked, redirect to the link
 * otherwise.
 * @param event object  (pass event to function)
 */
function forwardLink(e) {
	$el = $(e.target || e.srcElement);
	
	if(!$el.attr('href')) {
		$el = $el.parent('a');
	}
	if($el.attr('href')) {
		//location.href = $el.attr('href');
		return true;
	} else {
		return false;
	}
}


function thumbUpDown (_comment_id, _thumb) {
	 $.post("/news/thumbupdown/comment_id/"+_comment_id+"/thumb/"+_thumb+"/", {format:'ajax'}, 
		function(data){
		 	if(data.error) {
		 		if(parseInt(data.errorCode) == My_App.NOT_REGISTERED_ERROR_CODE) {
		 			My_App.showDismissAlert(data.error);
		 		} else {
		 			My_App.showAlert(data.error);
		 		}
		 		
		 	} else {
		 		My_App.showAlert(data.msg);
			    param = (_thumb > 0 ) ? "up_"+_comment_id : "down_"+_comment_id;
			    subThumb(param, data.count);
		 	}
	 }
	, 'json');	
}


function chooseNewsByDate(monthChosen, yearChosen, callback)
{
	 $.post(
		 "/news/choosenewsbydate/monthChosen/"+monthChosen+"/yearChosen/"+yearChosen+"/",
		 {format:'ajax'},
		 function(data)
		 {
		 	//eval("var dateUrls=" + data);
		 	callback(data);
		 },
	 	
		 'json');
}

var Archive_Navigator=
{
	year: null,
	month: null,
	day: null,
	dayUrls: null,
	monthsInWords: null,
	gotoUrl: null,
	
	updateGotoUrl: function()
	{
		//month set? year set? day set?
		this.gotoUrl = this.dayUrls[this.day-1];
			
	}
		
}




function subThumb(param, _add){
	var num;
	var sum;
	var add  = parseInt(_add);

	if (add > 0) {
		if ( $("#"+param).length && $("#"+param).html()) {
			num = $("#"+param).html();
	
			if (num.replace(" ","") == "") {
				num = 0;
			}
			
			sum = (num - 0)  + (add - 0);

			$("#"+param).html(sum);
		}
	}
}




/**
 * loops through all comments on page and sets their timer to a second less
 * @return
 */
function checkTimeOnComments() {
	$('.item.comment_template.checkTime', '.comments').each(function(){	//go through all comments
		// see which one needs to have it's countdown timer updated ie. hidden
		var timeLeft = $(this).attr('rel');
		var commentId = $(this).attr('id');
		var countId = 'counter_' + commentId.substring(8);	// counter's id (place where we put numbers for counting)
		
		if (timeLeft <= 0) {	//editing time is up
			
			if ($('#'+countId).length > 0) {	// if counter is not already hidden
				if ($('#'+countId).parent().hasClass('div_countdown')) {

					$('#'+countId).parent().animate({opacity:0}, 300, null,  function(){		// we have a counter in editor, hide counter 
						$('#'+countId).parent().animate({height:0}, 200, null, function(){
							$('#'+countId).parent().remove();
						});
			 		});
				} else {
					$("#"+commentId).removeClass('checkTime');
					$('#'+countId).parents('.remaining').fadeOut('slow', function(){		// no editor, hide all editing options 
						$('#'+countId).parents('.remaining').remove();
			 		});
				}
			}
			
			
			// a submit button with a counter might exist
			var button = $('.submit_comment:first:not(.editAlways)', this);
			if (button.length > 0) {	// there is a button so editor on this comment is present
				var buttonTime = button.attr('rel');	// some time left so proceed with countdown
				if (buttonTime > 0) {
					button.attr('rel', buttonTime-1);
					if (!button.attr('for')) {
						button.attr('for', button.val());
					}
					button.val(button.attr('for') + ' ( '+button.attr('rel')+' ) ');
				} else if(buttonTime != null) {	// button present, also has timer,  but time is up
					if (!button.hasClass('buttonDone')) {	
						button.addClass('buttonDone');	//mark button that its comment has been posted
						$.post("/comments/getcomment/comment_id/"+$(this).attr('comid'), {format:'ajax'}, 
						    function(data){
								$("#"+commentId).removeClass('checkTime');
								$("#"+commentId).animate({opacity:0}, 300, null, function() {
									$("#"+commentId).animate({height:0}, 200, null, function(){
										var comment = $(data).css({visibility:'hidden', position:'absolute'});
										$("#"+commentId).empty();
										$('body').append(comment);	//to get height only
										h = comment.height();
										comment.remove();
										comment.css({height:0, position:'block'});
										$("#"+commentId).append(comment.html());
										$("#"+commentId).animate({height:h}, 300, null, function(){
											$("#"+commentId).animate({opacity:1}, 300);
										});
									});
								});
						   	}
						);
					}
				}
						
				
				// is the comment being edited - time is up so disable editing and start counting on submit button 
				var textArea = $('textarea.editable',this);
				if (textArea.length > 0) {
					textArea.removeClass('editable');
					textArea.attr("readonly","readonly");
					textArea.css("color","#bbb");
					
					// add 10s counter to button
					$('.submit_comment', this).attr('rel', 10);
				}
			}
			
		} else {	//update counter 
			$(this).attr('rel', timeLeft-1);
			displayTimeLeft($('#'+countId), $(this));
		}
	});
}

/**
 * displays time that is left for editing a comment
 * @param counter - jquery object of the counter placeholder
 * @param comment - jquery object of a div representing the comment
 * @return
 */
function displayTimeLeft (counter, comment) {
	var timeLeft = comment.attr('rel');
	var mins = Math.floor((timeLeft)/60);
	var niceTime = '';
	if (mins > 0) {
		niceTime = mins + ' min ' + ((timeLeft) - mins*60) + ' s';
	} else {
		niceTime = timeLeft + ' s';
	}
	counter.html(niceTime);
}




/**
 * @param _news_id 		: id of the news 
 * @param _comments_id	: id of the comment belonging to the news at _news_id
 * @param _container_id	: id of the container (div) placing the comment editor
 * @return void
 */
function editComment (_news_id, _comments_id, _container_id) {
	
	// blur main comment editor
	//TODO
	
	//TODO replace URL
	//$('#'+_container_id).html('bla');
	 $.ajax({
		   type: "POST",
		   url: "/news/show/comment_editing/"+_comments_id,
		   success: function(comment_editor){
		 	
		 		var commentEditor = $(comment_editor);
		 		$('#'+_container_id).html(commentEditor);
//		 		alert($('#'+_container_id).attr('rel'));
		 		displayTimeLeft($('.div_countdown span', commentEditor), $('#'+_container_id));
		 	
		 	
		 	//checkTimeOnComments();

		   }
		 });
	 return false;
}




/**
 * 
 * @param _value		- id of the search
 * @param _nextElement	- to which element to fill results
 * @return
 */
function makeEvents(_value, _nextElement, noHitsUpdate, noCount){
	
	noHitsUpdate = noHitsUpdate ? true : false;
	noCount = noCount ? true : false;
	
	// Enable Models select box
	$("#"+_nextElement).attr("disabled","");
	$("[name='"+_nextElement+"']").attr("disabled","");
	
	// Fill models select box with make model values
	$.post('/ajax/ajax/make/'+_value+'/format/ajax',{'noCount':noCount ? 1 : 0},function(options){
			$('#'+_nextElement).html(options);
		 	$("[name='"+_nextElement+"']").html(options);
		 	if(!noHitsUpdate) setNumOfHits();
	});
	return false;
	
}


function openAdListDetails ( _adId ) {
	$("#"+_adId).css("display","");
	alert(_adId);
}

/**
 * Function applies filter to the car list table
 * @param _source - input element containing filter value
 * @return void
 */
filterCache = null;
filterOpenCache = null;
filterTimeout = null;
filterChars = 0;
function applyFilter (_event, _source ) {
	clearTimeout(filterTimeout);
	filterTimeout = setTimeout(function(){doit();}, 300);
	
	function doit() {
		//console.log('doingit');
		var query = '';
		var text = '';
		// collect all filter values
		var newFilterChars = 0;
		$(".filter_input").each(function (i) {
			if(this.value != "") {
				var fname = $(this).attr("id")
				var val = this.value.toLowerCase();
				if(fname == 'price_filter' || fname == 'inumber_filter') {
					val = val.replace(/[^0-9]/ig, '');
					query += '['+fname+'^="'+val+'"]';
				} else if(fname == 'year_filter') {
					val = val.replace(/[^0-9]/ig, '');
					query += '['+fname+'*="'+val+'"]';
				}else if(fname == 'vechile_filter') {
					var parts = val.split(' ');
					for( var i in parts) {
						query += '['+fname+'*="'+parts[i]+'"]';
					}
					
				} else {
					query += '['+fname+'*="'+val+'"]';
				}
				//text representation
				
				text += text ? ', ' : '';
				if(fname == 'vechile_filter') text += tsl_vehicle_filter+': <b>'+val+'</b>';
				else if(fname == 'price_filter') text += tsl_price_filter+': <b>'+val+'</b>';
				else if(fname == 'year_filter') text += tsl_production_year_filter+': <b>'+val+'</b>';
				else if(fname == 'internal_number_filter') text += tsl_internal_number_filter+': <b>'+val+'</b>';
				
				newFilterChars += val.length;
			}
		});
		
		if(filterCache == null) {
			filterCache = $('#tab_ad_list_cars tr.ad_row');
		}
		if(filterOpenCache == null) {
			filterOpenCache = $('#tab_ad_list_cars tr.car_details');
		}
		//$container = $('#tab_ad_list_cars');
		if(query.length) {
			//if(newFilterChars > filterChars) {
			//	filterCache.filter(query).show();
			//	filterChars = newFilterChars;
			//} else {
				filterCache.filter(':visible').hide();
				filterOpenCache.filter(':visible').hide();
				
				filterCache.filter(query).show().each(function(i){
					$('.ad_iteration_number', this).html(i+1);
				});
			//}
			//query = query.substring(2);
				//console.log(text);
				$('#filterUsed').css('display', 'block');
				$('#filterText').html(text);
			
			//$(query, filterCache).show();
			//$('#tab_ad_list_cars > tr.ad_row').hide();
			//$('#tab_ad_list_cars > tr.ad_row'+query).show();
		} else {
			//$('#tab_ad_list_cars > tr.ad_row').show();
			$('#filterUsed').css('display', 'none');
			$('#filterText').html(text);
			filterCache.show().each(function(i){
				var $nbr = $('.ad_iteration_number', this);
				$nbr.html($nbr.attr('nbr'));
			});
		}
	}
	
}

function removeAdsFilter() {
	$('#filterUsed').css('display', 'none');
	$(".filter_input").each(function (i) {
		this.value = '';
	});
	filterCache.show();
	//filterOpenCache.show();
}

function makeEnabled () {
	if ($("#ad_id_model")) {
		$("#ad_id_model").attr('disabled',false);
	}
}

/**
 * This function select changed search parameters and returns count of the results, 
 * the same number as firing the search would return!
 * @param _element			- on which element the event was called on
 * @param _updateElement	- which element to update after action returns data
 * @return
 */
function retreiveChangeCount ( _element, _updateElement ) {

	var exLabel = $(_updateElement).val();
	var url = window.location.pathname;
	
	var urlParams = url.split('/');
	var urlAddParams = new Array();
	var paramExistsInUrl = false;
	
	$(".change_selection select").each(function(i){
		paramExistsInUrl = false;
		
		if ( $(this).val() != -1 ) {
				
			for ( var i in urlParams ) {
				if ( urlParams[i] == $(this).attr('id') ) {
					
					var next = parseInt(i) + 1;
					urlParams[next] = $(this).val();
					paramExistsInUrl = true;
				}
			}
			
			// this param does not exist in url string yet
			if ( paramExistsInUrl == false ) {

				urlAddParams.push($(this).attr('id'));
				urlAddParams.push($(this).val());
			}
		}
	});	

	
	urlParams = urlParams.concat( urlAddParams );
	url = urlParams.join("/");
	
//	 $.ajax({
//		   type: "POST",
//		   url: url + "/ajax/1/retrieve_count/1/",
//		   success: function(count){
//		 	
//		 	var label = exLabel.split(' ');
//
//		 	label[1] = count;
//	 		label = label.join(' ');
//	 		$(_updateElement).val(label);
//	 		
//		   }
//		 });
	 
	 var changeSelectionForm = $('.change_selection');
	 var formParams = changeSelectionForm.serialize();
	 $.post(location.href, formParams + '&format=ajax&retrieve_count=1', function(count){
		 	var label = exLabel.split(' ');
		 	label[1] = count;
	 		label = label.join(' ');
	 		$(_updateElement).val(label);
	 });
}


/**
 * 
 * @return int number of search results with current selections in form
 */
function setNumOfHits()
{	
	//get all form parameters, send them to server and get back number of search results
	searchParamsUrl = "";
	$("#mainSearchForm select").each(function()	//get all select values
	{	
		searchParamsUrl += $(this).attr("id") + "/" + $(this).val() + "/";
	});
	
	$("#mainSearchForm input[type='text']").each( function() {
		searchParamsUrl += $(this).attr('id') + "/" + encodeURIComponent($(this).val()) + "/";
	});
	
	$("#mainSearchForm input[type='checkbox']").each(function()
	{
		if ($(this).is(':checked'))
		{
			searchParamsUrl += $(this).attr("id") + "/" + $(this).val() + "/";
		} else
		{
			searchParamsUrl += $(this).attr("id") + "/0/";
		}
	});
	
	
	//$.post("/avto-oglasi/iskanje/" + searchParamsUrl,
	//alert(searchParamsUrl);
	$.post("/search/search/" + searchParamsUrl,
		   {getHitsAjax:1, format:'ajax'},
		   function(numOfHits)
		   {
			   //change num of hits container value
			  if (numOfHits == 0)
			  {
				  $(".res_btn").addClass("disabledLink");
				  $(".res_btn span").addClass("disabledLink");
				  
				  $(".res_btn").unbind("click");
				  $(".res_btn").click(function(e){
					  e.preventDefault();
					});
				  
				  if ($("#noHits").length == 0)		//append nohits notice to orange box if it's not already there
				  {
					  $(".res").append("<p id='noHits'>" + noHits + "</p>");
				  } 
			  } else
			  {
				  $("#noHits").remove();

				  $(".res_btn").removeClass("disabledLink");
				  $(".res_btn span").removeClass("disabledLink");
				  
				  $(".res_btn").unbind("click");	//disable preventing default click action
				  $(".res_btn").click(function(e){
					  e.preventDefault();
					  $('#mainSearchForm').submit();
				  });
			  }
			   
			   $("#hitNum").empty().append(numOfHits);
		   });		
}


/**
 * This function appends event actions to the search form inside display search results 
 * @return
 */
function initJsFunctions () {
	
	$(".change_selection select").each(function(i){
		$(this).change(function(i){
			retreiveChangeCount(this, $('#submit_search_form_button'));
		});
	});
}




function moreMentions(el, type, id) {
	var $el = $(el);
	var currNbr = $el.prevAll('div').length;
	//loading
	$el.before('<div class="mention_loading"><img src="/gfx/ajax-loader_bar_small.gif" border="0"></div>');
	//fetch
	$.post('/ajax/morementions',{currNbr:currNbr,format:'ajax',mentionType:type, 'id':id}, function(data){
		
		if(!data.error) {
			$('.mention_loading').remove();
		}
		$el.prev().before(data.html);
		if(!data.hasMore) {
			$el.replaceWith('<span class="moreLink">'+$el.text()+'</span>');
		}
		
	}, 'json');
}


/*****************     functions for ajax navigating between ads.     ***********************/
/**
 * we are keeping track of some global variables:
 * headerData	:	array of ads' data that we replace instanly
 * currentPos	: 	current position of the ad in search results set
 * currentType  :	the template we are currently viewing (current state)
 * startPos		:	position of the ad we started ajaxing from (if aplicable)
 * startType	:	template we started from
 * firstLoad	:	for init functions; is this the first page load (no ajax)
 * firstAdLoad	:	is this the first time we are loading an ad	XXX:DEPRECATED
 * 
 * have to make sure the vars are set because we can ajax from searchResults pages to adView pages and viceversa
 */

var Ajax_Navigator = {

	startType : null,
	startPos : null,
	currentType : null,
	currentPos : null,
	headerData : null,
	someAjaxDone : false,
	firstLoad : true,			//first time loading search or show template
	firstAdLoad : true,			//first time loading show template XXX:DEPRECATED
	maxCPos : null,
	minCPos : null,
	numOfAllSearchResults : null,
	headerDataSize : 40,		//size of the headerData we keep in memory (ie. +20, -20 around current ad position)
	cPoint : 10,				//defines critical boundary for position in headerData, where we need to load new headerData
	preloadSize : 5, 			//should be always smaller than cPoint, so that we have urls of the ads we want to preload in headerData
	
	/**
	 *	checks if we came to an url with hash directly, if so we redirect to the url in hash (but need to extract url from hash)
	 *	it's executed first thing in show.tpl and search.tpl TODO: add to search.tpl
	 **/
	checkHash : function() {
		var hash = location.hash;
		if (hash) {	//remove hash if we reload page after ajaxed somewhere
			hash = hash.replace('#', '');
			//hash is structured as :  "hashType : url" 
			var hashType = hash.substring(0, hash.indexOf(':'));
			hash = hash.substring(hash.indexOf(':')+1);
			switch (hashType) {
				case "search":	//to searchResults
					hash = hash.substring(hash.indexOf(":")+1);
					location.href = hash;
					break;
				case "show":		//if hashtype is show the destination is show template, in url part at the end is position of the ad we need to show
					hash = hash.replace(/\/cPos\/(0|[1-9][\d]*)/g, "");	//get rid of cPos parameter
					hash = hash.replace(/\/imgId\/(0|[1-9][\d]*)/g, ""); //get rid of imgId parameter (if it exists)
					hash = hash.substring(hash.indexOf(":")+1);
					location.href = hash;
					break;
			}
		}
	},
	
	/**
	 *	bind events to previous, next links and arrowkeys, initialize history plugin
	 *	this function is called whenewer we load whole show template or whole body of show template
	 *  ie when first coming to this page & when coming to this page from searchresults	 
	 **/
	initAdNavigation : function() {
		if (!Ajax_Navigator.headerData) {
			$.post(location.href, {format:'ajax', getHeaderData:true, headerDataSize:Ajax_Navigator.headerDataSize}, function(data){Ajax_Navigator.initShowLinksAndHeaderData(data);}, "json");
		} else {
			Ajax_Navigator.initShowLinks();
		}
	},
	
	initShowLinksAndHeaderData : function(data) {
	 	Ajax_Navigator.headerData = data['headerData'];
	 	Ajax_Navigator.currentPos = data['adPos'];	 	
	 	Ajax_Navigator.minCPos = data['from'];
	 	Ajax_Navigator.maxCPos = data['to'];
	 	Ajax_Navigator.firstAdLoad = false; 	
	 	
	 	if (Ajax_Navigator.firstLoad) {		//set start descriptions only if this is the first init call	TODO: remove this condition
		 	Ajax_Navigator.firstLoad = false;
	 		$.history.init(Ajax_Navigator.pageload);
	 		Ajax_Navigator.startType = "show";
	 		Ajax_Navigator.startPos = data['adPos'];
	 		Ajax_Navigator.numOfAllSearchResults = data['numOfAllResults'];
	 	}
	 	
	 	Ajax_Navigator.initShowLinks();
	},

	
	initShowLinks : function() {
		Ajax_Navigator.currentType = "show";
	
		$("#prevAd").die("click");
		$("#nextAd").die("click");
		$("#backToResultsLink").die("click");
		$("a[rel=tabLink]").die("click");
		$(".imageThumb a").die("click");
		$(".big_img a").die("click");
		$(".showOnMapLink").die("click");
				
		$("#prevAd").live("click",function(e){
			e.preventDefault();
			$.history.load("show:"+Ajax_Navigator.headerData[Ajax_Navigator.currentPos]['prev_ad_link']+"/cPos/"+(Ajax_Navigator.currentPos-1));
		});
	
		$("#nextAd").live("click", function(e){
			e.preventDefault();
			$.history.load("show:"+Ajax_Navigator.headerData[Ajax_Navigator.currentPos]['next_ad_link']+"/cPos/"+(parseInt(Ajax_Navigator.currentPos)+parseInt(1)));
		});
		
				
		$("#backToResultsLink").live("click", function(e){
			e.preventDefault();
			var link = $("#backToResultsLink").attr("href");	//get url to which we need to post if link clicked
			$.history.load("search:"+link);
		});
		
	 	
	 	$(document).keydown(function(e){	//keydown is unbound when going back to searchResults
			switch (e.keyCode) {
				case 37:
					if (Ajax_Navigator.headerData[Ajax_Navigator.currentPos]['prev_ad_link'] != null) {
						$.history.load("show:"+Ajax_Navigator.headerData[Ajax_Navigator.currentPos]['prev_ad_link']+"/cPos/"+(Ajax_Navigator.currentPos-1));
					}
					break;
				case 39:
					if (Ajax_Navigator.headerData[Ajax_Navigator.currentPos]['next_ad_link'] != null) {
						$.history.load("show:"+Ajax_Navigator.headerData[Ajax_Navigator.currentPos]['next_ad_link']+"/cPos/"+(parseInt(Ajax_Navigator.currentPos)+parseInt(1)));
					}
			}			
		});
	 	
	 	
	 	//tabs
	 	$("a[rel=tabLink]").live("click", function(e){
	 		e.preventDefault();
	 		$.history.load("show:"+$(this).attr("href")+"/cPos/"+Ajax_Navigator.currentPos);
	 	});
	 	
	 	//images on main tab
	 	$(".imageThumb a, .big_img a").live("click", function(e){
	 		e.preventDefault();
	 		$.history.load("show:"+$(this).attr("href")+"/cPos/"+Ajax_Navigator.currentPos+"/imgId/"+$('img',this).attr('id'));
	 	});
	 	
	 	//map
	 	$(".showOnMapLink").live("click", function(e){
	 		e.preventDefault();
	 		$.history.load("show:"+$(this).attr("href")+"/cPos/"+Ajax_Navigator.currentPos);
	 	});

		Ajax_Navigator.preloadAdData(Ajax_Navigator.preloadSize);
	},
	
		
	
	/**
	 * append events to clicks on ad title links on search results
	 * append click events to paginator links
	 * @return
	 */
	initSearchResultsNavigation : function() {
		if (!Ajax_Navigator.headerData) {//if header data hasn't been loaded yet at all load it now
			var first = $("div[id^=search_item_]:first h3 a").attr('rel');	//select first result pos
			var last = $("div[id^=search_item_]:last h3 a").attr('rel');	//select last result pos
			var middle = Math.round((parseInt(last) + parseInt(first)) / 2);
			var from = middle - Ajax_Navigator.headerDataSize / 2;		//controller checks for boundaries
			var to = middle + Ajax_Navigator.headerDataSize / 2;
			$.post(location.href, {format:'ajax', getHeaderData:true, from:from, to:to}, function(data){Ajax_Navigator.initSearchLinksAndHeaderData(data);}, "json");
		} else {
			Ajax_Navigator.initSearchLinks();
		}
	},
	
	
	/**
	 * initialize headerDataArray and it's boundaries
	 */
	initSearchLinksAndHeaderData : function(data) {
		Ajax_Navigator.headerData = data['headerData'];
	 	Ajax_Navigator.minCPos = data['from'];
	 	Ajax_Navigator.maxCPos = data['to'];
		
		if (Ajax_Navigator.firstLoad) {
			Ajax_Navigator.firstLoad = false;
			Ajax_Navigator.startType = "search";
			$.history.init(Ajax_Navigator.pageload);
			Ajax_Navigator.numOfAllSearchResults = data['numOfAllResults'];
		}
		Ajax_Navigator.initSearchLinks();
	},
	
	initSearchLinks : function() {
		Ajax_Navigator.currentType = "search";
		$(".pagination a").die("click");	//unbind already bound links from previous page loads
		$(".adTitleLink").die("click");
		$(".imageThumb a").die("click");
		
		$(".adTitleLink").live("click", function(e){	//only prevent default for now, we need to load hidden add template first
			e.preventDefault();
		});
						
		//get paginator links and bind ajax action to them
		$(".pagination a").live("click", function(e){
			e.preventDefault();
			var pageLink = $(this).attr('href');
			$.history.load("search:" + pageLink);
		});
		
		$(".imageThumb a").live("click", function(e){
			e.preventDefault();
			var imageLink = $(this).attr('href');
			var imgId = $('img', this).attr('id');
			var cPos = $('img', this).attr('rel');	//rel attribute in <a> tag holds the position of the ad in paginator
			$.history.load("show:" + imageLink + "/cPos/" + cPos + '/imgId/' + imgId);
		});
		
		//set action to order select form
			//parse hash and set action to 'pure' url in hash
		var hash = location.hash;
		hash = hash.replace('#', '');	//remove '#' char if it exists
		hash = hash.substring(hash.indexOf(":")+1);	//url is what is after : if there is something (if not action will be set to '' which will submit form tu current url)
		$("#ad_result_display_order_form").attr("action", hash);
		$("#ad_result_display_order_form").change(function(e){
			//changing order should hide results and display loader gif before reloading page
			var firstItem = $("div[id^=search_item_]:first");
			Ajax_Navigator.appendLoaderAt(firstItem.offset().left + firstItem.width()/2, firstItem.offset().top + 1.5*firstItem.height());
			$("#searchResultItemsPage > *:not(.pagination)").css('visibility', 'hidden');
		});
		
		
		
		//append hidden ad template(use first ad on page) to the end of body, so we can go to add view smoothly (by using header data)
		var dummyAdLink = $("div[id^='search_item_']:first h3 a").attr("href");	//TODO: check for empty search!!
		$.get(dummyAdLink, {format:'ajax', getShowBody:true, noScript:true}, 
			function(data){
				var tpl = data['tplBody'];
				tpl = "<div id=\"dummyAdShow\" style=\"display:none\">"+tpl+"</div>";
				$('body').append(tpl);
				
				$(".adTitleLink").live("click", function(e){	//only now we can make ad's clickable (we loaded hidden template, that gets shon right on click)
					var adLink = $(this).attr('href');
					adLink += "/cPos/" + $(this).attr('rel');	//rel attribute in <a> tag holds the position of the ad in paginator
					$.history.load("show:"+adLink);
				});
			}, 
		"json");
	},
	
	
	/**
	 * preloads all ad data offset ads to the left and offset ads to the right
	 * @param offset
	 * @return
	 */
	 preloadAdData : function(offset) {
		   //preload thumb header images around new position (5 left 5 right)
		   var images = []; var k=0;
		   var leftBorder = Ajax_Navigator.currentPos - offset >= Ajax_Navigator.minCPos ? Ajax_Navigator.currentPos - offset : Ajax_Navigator.minCPos;
		   var rightBorder = parseInt(Ajax_Navigator.currentPos) + parseInt(offset) <= Ajax_Navigator.maxCPos ? parseInt(Ajax_Navigator.currentPos) + parseInt(offset) : Ajax_Navigator.maxCPos;
		   for (var i=leftBorder; i<=rightBorder;i++) {
			   if (i == Ajax_Navigator.currentPos) {	//skip current, it's already loaded
				   continue;
			   }
			   images[k] = new Image();
			   images[k].src = Ajax_Navigator.headerData[i]['headerImgSrc'];
			   k++;
		   }
		   
		   //preload ads that are close to the one we are viewing				   
		   for (var i=leftBorder; i<=rightBorder;i++) {
			   if (i == Ajax_Navigator.currentPos) {	//skip current, it's already loaded
				   continue;
			   }
			   $.get(Ajax_Navigator.headerData[i]['this_ad_link'], {format:'ajax'}, null, "json");
		   }
	},
	
	
	/**
	 *	make ajax request for the ad we want to view, hash is already in url, history plugin makes sure of that, preload neighbouring data
	 */
	changeAd : function(adRequestedUrl) {
		$.get(adRequestedUrl,
				{format:'ajax'},
				function(data) {
				if (Ajax_Navigator.headerData[Ajax_Navigator.currentPos]['ad_id'] == data['ad_id']) {		//change content only if data returned from ajax request is
					$(".ajaxLoader").remove();	//removes ajax loader (they should all have class ajaxLoader)
					$("div#mainContent").empty().append(data['tpl']);		//belonging to the ad whose header is currently displayed
					
					
					Ajax_Navigator.preloadAdData(Ajax_Navigator.preloadSize);
					
					//if we are viewing the ad at least 2 secs log ad view so //post another request to make sure we log view of the ad (ajax requests in general are not logged)
					setTimeout("Ajax_Navigator.logAdView("+Ajax_Navigator.currentPos+",\""+adRequestedUrl+"\","+data['ad_id']+")", 2000);
					
					if ((Ajax_Navigator.currentPos > Ajax_Navigator.maxCPos - Ajax_Navigator.cPoint && Ajax_Navigator.maxCPos < Ajax_Navigator.numOfAllSearchResults-1) || 									//we are close to headerData boundaries so need to load new header data
						(Ajax_Navigator.currentPos < parseInt(Ajax_Navigator.minCPos) + parseInt(Ajax_Navigator.cPoint) && Ajax_Navigator.minCPos > 0)) {	//TODO: define this witht00 constants

						var from = Ajax_Navigator.currentPos - Ajax_Navigator.headerDataSize/2;	//the boundaries will be checked in controler
						var to = parseInt(Ajax_Navigator.currentPos) + parseInt(Ajax_Navigator.headerDataSize/2);
						$.post(adRequestedUrl, {format:'ajax', getHeaderData:true, from:from, to:to}, function(data){
							Ajax_Navigator.headerData = data['headerData'];
						 	Ajax_Navigator.minCPos = data['from'];
						 	Ajax_Navigator.maxCPos = data['to'];
						}, "json");
					}
				}
			}, 
		"json");
		Ajax_Navigator.someAjaxDone = true;
	},
	
	/**
	 * log view of the ad if it's been viewed for at least 2 seconds
	 */
	logAdView : function(adOnViewPos, adRequestedUrl, adId ) {
		if (adOnViewPos == Ajax_Navigator.currentPos) {	//if we are still viewing the same ad that triggered this callback, then log ad view
			$.post("/adds/logajaxaddisplay", {logUrl:adRequestedUrl, adId:adId});
			//pageTracker._trackPageview(adRequestedUrl);	//log to google analytics
			logToAnalytics(adRequestedUrl);
		}
	},
	
	/**
	 * log that sponsored ads were listed on results page
	 * is called from exposedItems.tpl
	 */
	logSponsoredListing : function() {
		var adIds = "";
		$(".exp_ad").each(function() {
			adIds += $(this).attr("rel") + "," ;
		});
		if (adIds.length > 0) {
			adIds = adIds.slice(0, -1);	//remove last comma
			$.post("/adds/logsponsored", {type:"listing", id:adIds,curr_url:location.href});
		}
	},
	
	
	/**
	 * log that sponsored ad was clicked 
	 */
	sponsoredOnClickLog : function() {
		$(".exp_cnt a").click(function(e){
				var id = $(this).attr("rel");
				$.post("/adds/logsponsored", {type:"view", id:id,curr_url:location.href});
		});
	},
	
	
	/**
	 * move to an ad specified by the position in headerData array, load data from this array instantly and call changeAd() to get everything else, displays loaders for meanwhile
	 * @param position
	 */
	adListMoveTo : function(position) {
		
		if (position in Ajax_Navigator.headerData) {	//check if the position even exists
			Ajax_Navigator.currentPos = position;
			$("#sections .view_ad, #mainSection .lcol, #mainSection .rcol").css('visibility', 'hidden'); 		//hide content that will be fetched with ajax and reloaded
			Ajax_Navigator.changeAdHeader(position);
			Ajax_Navigator.changeAd(Ajax_Navigator.headerData[position]['this_ad_link']);
		}
	},
	
	/**
	 * only changes the header data of the ad (gets it from array so that it happens instanly)
	 */
	changeAdHeader : function(position) {
		
		//-- loader gifs --//
		$(".ajaxLoader").remove();	//removes ajax loader (they should all have class set to 'ajaxLoader')
				//$("#sections .view_ad, #mainSection .lcol, #mainSection .rcol, #mainSection .col2").fadeTo(100, 0);	disable fadeout for now, uncomment to enable
		Ajax_Navigator.appendLoaders($("#sections .view_ad"));
		var left = $("#mainSection .col1").offset().left + $("#mainSection .col1").width() / 2;
		var top = $("#mainSection").offset().top + $("#mainSection").height()/2;	//not exact, should substract header hegight
		Ajax_Navigator.appendLoaderAt(left, top);		//special case, because there is not one container to which we center loader

		//-- show instant data from array --//
		$("#adTitle, #adTitleCrumb").empty().append(Ajax_Navigator.headerData[position]['ad_title']);	
		$("#adPriceAndLocation").empty().append('<span>'+Ajax_Navigator.headerData[position]['ad_price']+'</span> '+Ajax_Navigator.headerData[position]['location_string']);
		$("#headerImage").attr('src', Ajax_Navigator.headerData[position]['headerImgSrc']);
		$("#crumbPos").empty().append(parseInt(position)+parseInt(1));
		document.title = Ajax_Navigator.headerData[position]['pageTitle'];
		
		var prevLinkHtml = $("#prevAd").html();	//get link text (link might be grayed out so we need to replace it as <a>, or might be <a> and need to replace it as <span>)
		var nextLinkHtml = $("#nextAd").html();
		
		if (Ajax_Navigator.headerData[position]['prev_ad_link'] != null) {		//check if link to previous ad exists (or are we at the first ad)
			$("#prevAd").replaceWith("<a id=\"prevAd\" href=\"" + Ajax_Navigator.headerData[position]['prev_ad_link'] +"\">"+prevLinkHtml+"</a>");
		} else {
			$("#prevAd").replaceWith("<span id =\"prevAd\" class=\"linkDisabled\">"+prevLinkHtml+"</span>");	//if no ad to the left grayout link, make it unclickable
		}
		if (Ajax_Navigator.headerData[position]['next_ad_link'] != null) {	//check if next ad exists or are we at the last ad
			$("#nextAd").replaceWith("<a id=\"nextAd\" href=\"" + Ajax_Navigator.headerData[position]['next_ad_link'] +"\">"+nextLinkHtml+"</a>");
		} else {
			$("#nextAd").replaceWith("<span id =\"nextAd\" class=\"linkDisabled\">"+nextLinkHtml+"</span>");	//if no ad to the right grayout link, make it unclickable
		}
	},
	
	
	/**
	 *This function is called:
	 *1. after calling $.historyInit();	[NOT ANYMORE why would we need that]
	 *2. after calling $.historyLoad();
	 *3. after pushing "Go Back" button of a browser 
	 */
	pageload : function(hash) {
		// hash doesn't contain the first # character.
		if(hash) {	// restore ajax loaded state
			//hash is structured as :  "hashType : url" 
			var hashType = hash.substring(0, hash.indexOf(':'));
			hash = hash.substring(hash.indexOf(':')+1);
			
			// depending on which template we are currently on (currentType) and
			// where we are going to(hashType) we have the folowing  cases:
				// show -> show		:	only change position of the ad
				// show -> search	:
				// search -> show	:	display ad requested, load header data again
				// search -> search	:
				
			if (Ajax_Navigator.currentType == 'show' && hashType == 'show') {		// show -> show
				//Ajax_Navigator.currentType = "show";	already is
				var position = hash.match(/\/cPos\/(0|[1-9][\d]*)/g);	//get position in headerData we have to move to from hash
				position = position[0].replace(/\/cPos\//g, "");
				position = parseInt(position);
				
				var imgId = hash.match(/\/imgId\/([0-9]+)/g);
				
				
				if (position == Ajax_Navigator.currentPos || imgId) {	//if position stays the same we can be sure(realy?) that we are only changing tab, so just fetch from url
					//if we are going to image tab, we might have clicked on an image. if so an imgId parameter is in hash. extract and remove it from hash, and scroll to that image in callback
				//	var imgId = hash.match(/\/imgId\/([0-9]+)/g);
					if (imgId) {
						imgId = imgId[0].replace(/\/imgId\//g, "");
						hash = hash.replace(/\/imgId\/(0|[1-9][\d]*)/g, "");
					}
					
					hash = hash.replace(/\/cPos\/(0|[1-9][\d]*)/g, "");	//get rid of cPos parameter to get url only
					$.get(hash, {format:'ajax', tabSwitch:true}, function(data){
						$("div#mainContent").empty().append(data['tpl']);
						document.title = data['pageTitle'];
						if (imgId) {
		 					window.scrollTo(0, $('img#'+imgId).offset().top);
						}
						
					}, "json");
				} else {	//otherwise we are moving from one ad to another...
					Ajax_Navigator.adListMoveTo(position);
				}
			} else 	
			if (Ajax_Navigator.currentType == 'show' && hashType == 'search') {	// show -> search
				Ajax_Navigator.currentType = "search";
				Ajax_Navigator.goBackToSearchResults(hash);
			} else
			if (Ajax_Navigator.currentType == 'search' && hashType == 'show') {	// search -> show
				Ajax_Navigator.currentType = "show";
				Ajax_Navigator.goToAdView(hash);
			} else
			if (Ajax_Navigator.currentType == 'search' && hashType == 'search') {	// search -> search
				//Ajax_Navigator.currentType = 'search';	already is
				Ajax_Navigator.changeSearchPage(hash);
			} else
			{
				console.log("source dest not defined: from: \"" + Ajax_Navigator.currentType + "\" to: \"" + hashType + "\"" );
			}
			
		} else	{	// if we came back to start page with back button after ajaxed somewhere else (so we don't have hash but might need to change contents)
			if (Ajax_Navigator.currentType == "show" && Ajax_Navigator.startType == "show") {
				//Ajax_Navigator.currentType = "show";	is already set
				Ajax_Navigator.adListMoveTo(Ajax_Navigator.startPos);	//need to reload start state
			} else 
			if (Ajax_Navigator.currentType == 'show' && Ajax_Navigator.startType == 'search') {	// show -> search
				Ajax_Navigator.currentType = "search";
				hash = location.href;
				Ajax_Navigator.goBackToSearchResults(hash);
			} else
			if (Ajax_Navigator.currentType == 'search' && Ajax_Navigator.startType == 'show') {	// search -> show
				Ajax_Navigator.currentType = "show";
				Ajax_Navigator.goToAdView(location.href+"/cPos/"+Ajax_Navigator.startPos);	//form hash with cPos in it because goToAdView expects it
			} else
			if (Ajax_Navigator.currentType == 'search' && Ajax_Navigator.startType == 'search') {	// search -> search
				//Ajax_Navigator.currentType = "search";	is already set
				hash = location.href;
				Ajax_Navigator.changeSearchPage(hash);
			} else
			{
				alert("start  source dest not defined");
			}
		}
	},
	
	
	
	
	
	/**
	 * loads results page with ajax. in hash is the url of the search results
	 * @param hash
	 * @return
	 */
	goBackToSearchResults : function(hash) {
		$(document).unbind('keydown');	//unbind keydown event for search results page
		$.get(hash, {format:'ajax', getSearchBody:true}, 
				function(data) {
					$('body').empty().append(data['tpl']);
					document.title = data['pageTitle'];
//					pageTracker._trackPageview(hash);	//log to google analytics
					logToAnalytics(hash);
				},
				"json"
		);
	},
	
	
	/**
	 * reloads search results items part of the search results page
	 */
	changeSearchPage : function(hash) {
		var firstItem = $("div[id^=search_item_]:first");
		Ajax_Navigator.appendLoaderAt(firstItem.offset().left + firstItem.width()/2, firstItem.offset().top + 1.5*firstItem.height());
		$("#searchResultItemsPage > *:not(.pagination)").css('visibility', 'hidden'); 		//hide content that will be fetched with ajax and reloaded
		var scrollTo = $(".wrap_top").offset().top;		
		$('html, body').animate({scrollTop:scrollTo}, 1000);
		$.get(hash, {format:'ajax', getResultItems:true}, 
				function(data) {
					$(".ajaxLoader").remove();
					$("#searchResultItemsPage").empty().append(data['tpl']);
					document.title = data['pageTitle'];

					//check if we need new headerData
					var first = $("div[id^=search_item_]:first h3 a").attr('rel');	//select first result pos
					var last = $("div[id^=search_item_]:last h3 a").attr('rel');	//select last result pos
					if ((first < Ajax_Navigator.minCPos + Ajax_Navigator.cPoint && Ajax_Navigator.minCPos > 0) ||	//see if any of them is close enough to headerData boundary and reload headerData if necessary
						last > Ajax_Navigator.maxCPos - Ajax_Navigator.cPoint && Ajax_Navigator.maxCPos < Ajax_Navigator.numOfAllSearchResults - 1 ) {	//don't need header data if we are actually at the border af all search results
						var middle = Math.round((parseInt(last) + parseInt(first)) / 2);
						var from = middle - Ajax_Navigator.headerDataSize / 2;		//controller checks for boundaries
						var to = middle + Ajax_Navigator.headerDataSize / 2;
						$.post(hash, {format:'ajax', getHeaderData:true, from:from, to:to}, 		//get new header data
								function(data) {
									Ajax_Navigator.headerData = data['headerData'];
								 	Ajax_Navigator.minCPos = data['from'];
								 	Ajax_Navigator.maxCPos = data['to'];
								}, 
						"json");
					}
					//pageTracker._trackPageview(hash);	//log to google analytics
					logToAnalytics(hash);
				}, 
				"json"
		);
		
	},
	
	/**
	 * ajaxes to ad view. for now only from search results....
	 * reload body with ad that was clicked template, but get it with ajax, 
	 * @param hash	the url we are postion to
	 * @return
	 */
	goToAdView : function(hash) {
		
		/**	two cases (for now :) ), branches on imgId parameter :
		*		1. we came from search results by clicking on an ad (imgId param doesn't exist in hash)
		*			in this case show empty hidden dummy template with loaders over them, change available content immediately, fetch new content and replace it
		*		2. we came from search results by clicking on a small thumbnail image (imgId param exists in hash)
		*			in this case only fetch body (containing image tab), replace content and scroll to appropriate image
		*/		
		
		
		
		// we might have clicked on an image, in that case go directly to image tab. if so an imgId parameter is in hash. extract and remove it from hash, and scroll to that image in callback
		var imgId = hash.match(/\/imgId\/([0-9]+)/g);
		if (imgId) {
			imgId = imgId[0].replace(/\/imgId\//g, "");
			hash = hash.replace(/\/imgId\/(0|[1-9][\d]*)/g, "");
		}  else {
			$("#dummyAdShow").prevAll("body > div").remove();
			$("#sections .view_ad, #mainSection .lcol, #mainSection .rcol").css('visibility', 'hidden'); 		//hide content that will be fetched with ajax and reloaded
			$("#dummyAdShow").css("display", "block");
			window.scrollTo(0,0);
		}
			
		var position = hash.match(/\/cPos\/(0|[1-9][\d]*)/g);	//get position in headerData we have to move to from hash
		position = position[0].replace(/\/cPos\//g, "");
		Ajax_Navigator.currentPos = position;
		hash = hash.replace(/\/cPos\/(0|[1-9][\d]*)/g, "");	//get rid of cPos parameter (for posting to url)

		if (!imgId) {
			Ajax_Navigator.changeAdHeader(position);	//changes the part of ad that we have data for(in headerData array), overlays with loaders everytihing else
		} else {
			document.title = Ajax_Navigator.headerData[position]['pageTitle'];
		}
		
		$.get(hash, {format:'ajax', getShowBody:true, showFromSearch:true}, 
			function(data){
				//coming from search headerData is already set!			
				var tpl = data['tplBody'];
	 			$('body').empty().append(tpl);
	 			if (imgId) {
 					window.scrollTo(0, $('img#'+imgId).offset().top);
	 			}
	 			logToAnalytics(hash);
//	 			pageTracker._trackPageview(hash);	//log to google analytics
			}, 
		"json");
		
	},
	
	
	
	/**
	 * shows ajax loader gif over (in the center) the set of jquery elements given in loadingElements if they exists
	 */
	appendLoaders : function(loadingElements){
		//determine loader image's height and width
		$(document.body).append('<img id="loaderGif" src="/gfx/ajax-loader_bar_small.gif" border="0">');
		loaderWidth = $("#loaderGif").width();
		loaderHeight = $("#loaderGif").height();
		$("#loaderGif").remove();
		
		$(loadingElements).each(function(){	//for all elements pased in loadingElements, append one loader
			loaderDiv = $('<div class="ajaxLoader"><img src="/gfx/ajax-loader_bar_small.gif" border="0"></id>').appendTo("body");
			loaderLeft = $(this).offset().left + ($(this).width()/2) - (loaderWidth/2);
			loaderTop = $(this).offset().top + ($(this).height()/2) - (loaderHeight/2);
			loaderDiv.css({'position':'absolute','left':loaderLeft, 'top':loaderTop, 'z-index':'1'});
		});
	},
	
	/**
	 * show ajax loader centered to custom position (left, top)[should be x , y actualy because we are passing center of the loader] in the document 
	 */
	appendLoaderAt : function(left, top){
		//determine loader image's height and width
		$(document.body).append('<img id="loaderGif" src="/gfx/ajax-loader_bar_small.gif" border="0">');
		loaderWidth = $("#loaderGif").width();
		loaderHeight = $("#loaderGif").height();
		$("#loaderGif").remove();
		
		loaderDiv = $('<div class="ajaxLoader"><img src="/gfx/ajax-loader_bar_small.gif" border="0"></id>').appendTo("body");
		loaderLeft = left - (loaderWidth/2);
		loaderTop = top - (loaderHeight/2);
		loaderDiv.css({'position':'absolute','left':loaderLeft, 'top':loaderTop, 'z-index':'1'});
	}
	
	
	
	/**********************                         *************                                     *******************************/
}

/**
 * 	log to google analytics
 */
function logToAnalytics(url) {
	tracker = _gat._getTracker("UA-269021-1");
	tracker._trackPageview(url);	
}



/********  functions for navigating the galery in news  ********/

var Gallery_Navigator = {

	/**
	 * before anything else, when coming to the gallery page check if url contains hash and redirect to that url if so
	 */
	checkHash : function() {
		var hash = location.hash;
		if (hash) {	//remove hash if we reload page after ajaxed somewhere. and reload to that url
			hash = hash.replace('#', '');
			location.href = hash;
		}
	},
	
	/**
	 * initializes history plugin, and binds events of changing the image(pageload) to next and previous links
	 * gets triggered only once per gallery visit
	 */
	initGalleryNavigation : function()
	{
		$.history.init(Gallery_Navigator.pageload);
		
		// clicks to links
		$("a[rel='otherImage']").live("click", function(event){
			event.preventDefault();		
			var imageRequestedUrl = $(this).attr("href");
			someAjaxDone = true;
			$.history.load(imageRequestedUrl);
		});
		
		// arrow keys		
		$(document).keydown(function(e) {
			switch (e.keyCode)	{
				case 37:
					if ($("#prevLink").length > 0) {
						$.history.load($("#prevLink").attr("href"));
					}
					break;
				case 39:
					if ($("#nextLink").length > 0) {
						$.history.load($("#nextLink").attr("href"));
					}
			}
		});
	},
	
	/**
	 * callback function for history.load function
	 */
	pageload : function(hash) {
		if (hash) {
			Gallery_Navigator.changeImage(hash);
		} else {	//came back to first page (no hash) with back button (after ajaxing somewhere else)
			Gallery_Navigator.changeImage(location.href);
		}
		
	},
	
	/**
	 * send ajax request to server and change image
	 */
	changeImage : function(imageRequestedUrl) {
		$.post(imageRequestedUrl, {format:'ajax'},
			function(data) {
				$("#mainImage").empty().append(data);
		});
	}
	
}
/**********************                         *************                                     *******************************/


function removeOption(_element) {
	
	if ( $(_element).val() > 0) {
		if ( !$(_element).is(':checked') ) {
			
			var url = document.location.href;
			url = url.replace('rezultati','iskanje');
			url += '/remove_option/'+$(_element).val();
			
			$('#form_search_keyparams').attr('action',url);
			
			$('#form_search_keyparams').submit();			
			
		}
	}
}


/**
 * submits a change of options selection in a filter
 * change can be: 1)one option was set, 2)one option was unset, 3)all options in filter were set, 4)all options in filter were unset
 * @param element			the element that triggered the call (checkbox that was set/unset)
 * @param optionGroupId		the id of the option group to which the option belongs
 * @return void
 */
function toggleOption (element, optionGroupId ) {
	var url = document.location.href;
	if ( $(element).hasClass('selectAll')) {
		if ( $(element).is(':checked') ) {				// was the option set or unset
			url += '/set_all_options/' + optionGroupId;
		} else {
			url += '/remove_all_options/' + optionGroupId;
		}
	} else {
		
		if ( $(element).is(':checked') ) {				// was the option set or unset
			url += '/set_option/' + $(element).val();
		} else {
			url += '/remove_option/' +$(element).val();
		}
	}	
	var form = $('#form_' + optionGroupId);
	form.attr('action', url);
	form.submit();
}

/**
 * submits removal of all options from an option group
 * @param optionGroupId		id of the option group
 * @return void
 */
function removeAllOptions( optionGroupId ) {
	var url = document.location.href;
	url += '/remove_all_options/' + optionGroupId;
	var form = $('#form_' + optionGroupId);
	form.attr('action', url);
	form.submit();
}


function disableOptionContainer( _containerId ){
	$("#"+_containerId).css("display","none");
}

function initializeGoogleMap(lon,lat) {
	    var latlng = new google.maps.LatLng(lon,lat);
	    var myOptions = {
	      zoom: 12,
	      center: latlng,
	      mapTypeId: google.maps.MapTypeId.ROADMAP
	    };
	    var map = new google.maps.Map(document.getElementById("location_google_map"), myOptions);
	    
	    var marker = new google.maps.Marker({
	        position: latlng, 
	        map: map, 
	        title:"Hello World!"
	    });   	    
  }

My_Seller_Map = {
		makerData:[],
		container:null,
		map:null,
		doCluster:false,
		fluster:null,
		init:function(container, markerData, lat, lon) {
			this.markerData = markerData ? markerData : [];
			this.container = container ? container : null;
			
			var latlng = new google.maps.LatLng(lat,lon);
		    var myOptions = {
		      zoom: 9,
		      center: latlng,
		      mapTypeId: google.maps.MapTypeId.ROADMAP
		    };
		    
		    var placeholder = $(this.container)[0];
		    this.map = new google.maps.Map(document.getElementById("seller_map"), myOptions);
		    
		    //Initialize Fluster and give it a existing map
		    if(this.doCluster) {
		    	this.fluster = new Fluster2(this.map);
		    }
		    
		    this.updateMarkers();
		},
		
		openInfoWindow: function(e, marker, i, disablePan, closeAllOpen) {
			var infoWindow = new google.maps.InfoWindow({
				content:My_Seller_Map.markerData[i].html,
				disableAutoPan:disablePan
			});
			
			var closeAllOpen = (closeAllOpen == undefined) ? false : closeAllOpen;
			//close infowindows ...
			if(closeAllOpen) {
				My_Seller_Map.closeAllInfoWindows();
			}
			
			infoWindow.open(My_Seller_Map.map, marker);
			google.maps.event.addListener(infoWindow, "closeclick", (function(marker, j){
				return function(event) {
					My_Seller_Map.onInfoWindowClose(event, marker, j);
				}
			})(marker,i));
			
			My_Seller_Map.markerData[i].infoWindow = infoWindow;
		},
		
		closeAllInfoWindows: function() {
			console.log('closing all');
			for(var i = 0; i < My_Seller_Map.markerData.length; i++) {
				if(My_Seller_Map.markerData[i].infoWindow) {
					My_Seller_Map.markerData[i].infoWindow.close();
					My_Seller_Map.markerData[i].infoWindow = null;
					My_Seller_Map.markerData[i].open = 0;
				}
			}
		},
		
		onMarkerOver: function(e,marker, i) {
			if(!My_Seller_Map.markerData[i].infoWindow) {
				My_Seller_Map.openInfoWindow(e, marker, i, true);
				My_Seller_Map.markerData[i].open = 0;
			}
		},
		
		onMarkerOut: function(e,marker, i) {
			if(My_Seller_Map.markerData[i].open == 0) {
				My_Seller_Map.markerData[i].infoWindow.close();
				My_Seller_Map.markerData[i].infoWindow = null;
			}
		},
		
		onMarkerClick: function(e,marker, i) {
			
			
			if(My_Seller_Map.markerData[i].infoWindow) {
				My_Seller_Map.markerData[i].infoWindow.close();
			}
			My_Seller_Map.openInfoWindow(e, marker, i, false, true);
			My_Seller_Map.markerData[i].open = 1;
			
		},
		
		onInfoWindowClose: function(e, marker, i) {
			My_Seller_Map.markerData[i].open = 0;
			My_Seller_Map.markerData[i].infoWindow = null;
		},
			
		updateMarkers: function() {
			var self = this;
			
			for(var i=0;i<this.markerData.length; i++) {
				var lat = this.markerData[i].lat;
				var lon = this.markerData[i].lon;
				var latLng = new google.maps.LatLng(lon,lat);
				var gm = new google.maps.Marker({
					position:latLng
				});
				gm.open = 0;
				gm.infoWindow = null;
				
				google.maps.event.addListener(gm, 'click', (function(marker, j){
					return function(event) {
						My_Seller_Map.onMarkerClick(event, marker, j);
					}
					
				})(gm,i));
				
				google.maps.event.addListener(gm, 'mouseover', (function(marker, j){
					return function(event) {
						My_Seller_Map.onMarkerOver(event, marker, j);
					}
					
				})(gm,i));
				
				google.maps.event.addListener(gm, 'mouseout', (function(marker, j){
					return function(event) {
						My_Seller_Map.onMarkerOut(event, marker, j);
					}
					
				})(gm,i));
				
				// Add the marker to the Fluster
				if(this.doCluster) {
					this.fluster.addMarker(gm);
				} else {
					gm.setMap(this.map);
				}
			}
			
			if(this.doCluster) {
				// Set styles
				// These are the same styles as default, assignment is only for demonstration ...
				this.fluster.styles = {
					// This style will be used for clusters with more than 0 markers
					0: {
						image: 'http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m1.png',
						textColor: '#FFFFFF',
						width: 53,
						height: 52
					},
					// This style will be used for clusters with more than 10 markers
					10: {
						image: 'http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m2.png',
						textColor: '#FFFFFF',
						width: 56,
						height: 55
					},
					20: {
						image: 'http://gmaps-utility-library.googlecode.com/svn/trunk/markerclusterer/1.0/images/m3.png',
						textColor: '#FFFFFF',
						width: 66,
						height: 65
					}
				};
				
				// Initialize Fluster
				// This will set event handlers on the map and calculate clusters the first time.
				this.fluster.initialize();
			}
			
		}
		
}


/**
 * Handle comparison functions - add/remove from comparison,
 * status update
 */
My_Comparison = {
		someAjaxDone: false,
		cmpItemWidth:180,//width of an ad in comparison
		cmpHeaderWidth:180,//width of the left groups column
		init: function(){
			this.cmpWidthUpdate();
			//attach row highlight events
			$('#comparison tr').live('mouseover',function(e){
				
				// live sees all mouseover events within the selector
			    // only concerned about events where the selector is the target
//			    if (this != e.target) return; 
//			    // examine relatedTarget's parents to see if target is a parent. 
//			    // if target is a parent, we're "leaving" not entering
//			    var entering = true;
//			    $(e.relatedTarget).parents().each(function (i, el) {
//			            if (el == e.target) {
//			                entering = false;
//			                return false; // found; stop searching
//			            }
//			    });
//			    if (!entering) return;

				My_Comparison.cmpHighlightRow(e);
			});
		},
		add: function(adId, adPage) {
			$.post('/comparison/manage/add/1/adId/'+adId,{format:'ajax',refurl:location.href}, function(data) {
				if(data.error) {
					alert(data.error);
					return;
				}
				
				//do animation, move ad to comparison, update container
				if(adPage) {
					My_Comparison.updateOneAd('add', adId, data.compare_link);//data.ad
				} else {
					My_Comparison.updateContainer('add', adId, data.compare_link);//data.ad
				}
				
				
			}, 'json');
		},
		remove: function(adId, adPage) {
			var callback = function(data){
				
					if(data.error) {
						alert(data.error);
						return;
					}
					
					//do animation, move ad to comparison, update container
					if(adPage) {
						My_Comparison.updateOneAd('remove', adId);//data.ad
					} else {
						My_Comparison.updateContainer('remove', 1);//data.ad
						//update ad comparison links
						$('.ad_'+adId).html('<a href="#" onClick="My_Comparison.add('+adId+');return false;">'+tsl_cmp_add+'</a>');
					}
					
					
					
				
			};
			
			//post
			this.removeRequest(adId, callback);
		},
		toggleRemove: function(adId) {
			//just reload page with corrected url
			
			var callback = function(data){
				
				if(data.error) {
					alert(data.error);
					return;
				}
				
				My_Comparison.someAjaxDone = true;
				
				//do animation, move ad to comparison, update container
				//remove from locked or from list
				var $tb = $('.cmp_ad_'+adId);
				$tb.remove();
				//remove placeholder
				$placeholder = $('.placeholder_locked_'+adId);
				if($placeholder.length) {
					$placeholder.remove();
				}
				
				//update all widths
				My_Comparison.cmpWidthUpdate();
			};
			
			//post
			this.removeRequest(adId, callback);
		},
		removeRequest: function(adId, callback) {
			$.post('/comparison/manage/remove/1/adId/'+adId,{format:'ajax'}, function(data){callback(data);}, 'json');
		},
//		ajaxRenderComparison: function(url, addHash) {
//			$.post(url,
//					   {format:'ajax'},
//					   function(data)
//					   {
//						   $("div#comparison").empty().append(data);
//						});
//			if (addHash)
//			{
//				window.location.hash = url;
//			}
//		},
		updateOneAd: function(mode, adId, cmp_link) {
			if(mode == 'add') {
				$('.ad_'+adId).html('<a href="'+cmp_link+'">'+tsl_cmp_go+'</a> | <a href="#" onClick="My_Comparison.remove('+adId+',1);return false;">'+tsl_cmp_remove+'</a>');
			} else {
				$('.ad_'+adId).html('<a href="#" onClick="My_Comparison.add('+adId+',1);return false;">'+tsl_cmp_add+'</a>');
			}
		},
		updateContainer: function(mode, data, cmp_link) {
			var currentCount = parseInt($('#compare_container #cmp_count').text());
			if(mode == 'add' && data) {
				//run animation Transfer
				//var options = {to: '#compare_container',className: 'ui-effects-transfer'};
				//var options = {percent:2, direction:'both', origin:['bottom','left'],scale:'both'};
				//transfer from ad to container
				var $el = $('#search_item_'+data);
				if($el.length == 0) {
					$el = $('.compare_btns.ad_'+data);
				}
				if($el) {
					if(location.hash == '#ham')My_Comparison.effect_image_drop($el, data, cmp_link);
					else My_Comparison.effect_title_shrink($el, data, cmp_link);
				}
				//TODO append ad to container
				
			} else if(mode == 'remove' && data) {
				//TODO remove data from container
				//fix counter
				$('#compare_container #cmp_count').text(currentCount - 1);
			} else {
				//fetch content from ajax
				//TODO
			} 
		},
		effect_title_shrink: function($el, adId, cmp_link) {
			$title = $('h3 span:first', $el);
			//clone
			$clone = $title.clone();
			$clone.css('position','absolute');
			$title.before($clone);
			$clone.css('backgroundColor','white');
			
			var orig_pos = $title.position();
			$clone.css({left:orig_pos.left + "px", top:orig_pos.top + "px"});
			var fallDist = $('#search_item_'+adId).innerHeight() - 42;

			$clone.stop().animate({marginTop:fallDist+"px",left:"0px"}, { queue:false, duration:800,easing:"easeOutExpo"})
							.animate({fontSize:"5px"}, 800 ,"easeInExpo", function() {
								//finish
								$clone.remove();
								$('.ad_'+adId).html('<a href="'+cmp_link+'">'+tsl_cmp_go+'</a> | <a href="#" onClick="My_Comparison.remove('+adId+');return false;">'+tsl_cmp_remove+'</a>');
								$('a:first','.ad_'+adId).effect('highlight',{},5000);
							});
			
		},
		//deprecated
		effect_image_drop: function($el, adId, cmp_link) {
			$img = $('img.thumb', $el).parent();
			//clone
			$clone = $img.clone();
			$clone.css('position','absolute');
			$clone.css('left','0px');
			$img.before($clone);
			$img.css('visibility','hidden');
			
			var fallDist = $('#search_item_'+adId).innerHeight() - 140;
			//let the block fall
			$clone.stop().animate({marginTop: fallDist+"px"},fallDist*10, "easeOutBounce", function(){
				$clone.animate({height:'0px',marginTop:fallDist+119+'px'},140,null, function(){
					$clone.remove();
					setTimeout(function() {$img.css('visibility','visible');},800);
					
					$('.ad_'+adId).html('<a href="'+cmp_link+'">'+tsl_cmp_go+'</a> | <a href="#" onClick="My_Comparison.remove('+adId+');return false;">'+tsl_cmp_remove+'</a>');
					$('a:first','.ad_'+adId).effect('highlight',{},5000);
				});
			});
						

		},
		expandList: function(contId) {
			$cont = $(contId);
			$('#left', $cont).css('height', 'auto');
			$('#right_container', $cont).css('height', 'auto');
			//update link
			$('#more').remove();
		},
		toggleLock: function(adId) {
			var $tb = $('.cmp_ad_'+adId);
			$tb.css('visibility','hidden');
			var $parent = $tb.parent();
			var $clone = $tb.clone();
			
			if($parent.attr('id') == 'locked_container') {
				//unlock
				
				$clone.css('visibility','visible');
				$('.placeholder_locked_'+adId).replaceWith($clone);
				$('.lock_link', $clone).text(tsl_cmp_lock);
				$tb.remove();
				
				//enable lock links if 2 locked ads
				if($('#locked_container').children().length == 2) {
					//disable lock links
					$('.lock_link', $('#right_container')).removeClass('hidden');
				}
				
				My_Comparison.cmpWidthUpdate();
				
			} else {
				
				//lock
				$('.lock_link', $clone).text(tsl_cmp_unlock);
				
				//delay + blur lock
				$clone.appendTo('#locked_container');
				$clone.css('visibility','visible');
				$tb.replaceWith('<div class="placeholder_locked_'+adId+'" style="display:none;"></div>');
				
				//disable lock links if more that 3
				if($('#locked_container').children().length == 3) {
					//disable lock links
					$('.lock_link', $('#right_container')).addClass('hidden');
				}
				
				My_Comparison.cmpWidthUpdate();
			}
		},
		cmpWidthUpdate: function() {
			var cnt_locked = $('#locked_container TABLE').length;
			var cnt_regular = $('#right TABLE').length;
			
			//now update widths
			var left_width = cnt_locked * My_Comparison.cmpItemWidth + My_Comparison.cmpHeaderWidth;
			//hide right container temporary
			$('#comparison #right').css('display','none');
			$('#comparison #left').css('width',left_width + "px");
			$('#comparison #right').css('width',$('#comparison').width() - left_width - 0 + "px");
			$('#comparison #right').css('display','block');
			//update right_container
			$('#comparison #right_container').css('width',cnt_regular * My_Comparison.cmpItemWidth + "px");
		},
		cmpHighlightRow: function(event) {
			var $el = $(event.target);
			var $tr = $(event.target).parent('tr');

			var rownbr = $tr.prevAll().length +1;
			if(rownbr > 1 && !$tr.hasClass('section')) {
				$('#comparison tr').removeClass('sel');
				$('#comparison TABLE TR:nth-child('+rownbr+')').addClass('sel');
			}
		}
}

function activateAdExposedOption() {
	// blur background, show confirmation panel
	$(".exposeLink").click(function(ee){
		ee.preventDefault();
		
		$(ee.target).addClass('activeModalTrigger');
		
		if ($("#overlayBlur").length != 0) {
			$("#overlayBlur").remove();
		}
		$overlay = $('<div id ="overlayBlur"></div>').appendTo($("body"));
		$overlayPanel = $('<div id="overlayPanel"></div>').appendTo($overlay);
		
		//fetch temlplate for confirmation panel to display
		$.post("/user/exposead/confirmDiv/1/ad/"+$(this).attr("id"), null, function(data){
			$overlayPanel.html(data);
			
			$("#overlayBlur").fadeIn(300);
			
		});
		
		//$overlayPanel.html('Expose AD, ad_info...<a class="exposeAdConfirmLink" id="'   +$(this).attr("id")+  '" href="">Expose Ad</a>');
		
	});

	// remove blur, hide confirmation panel, show exposition sent, hide it, post exposition
	$(".exposeAdConfirmLink").live("click", function(ee){
		ee.preventDefault();

		$adId = $(this).attr("id");
		
		if(!$('#rules:checked').length) {
			$('.exposeDialog .msgError').remove();
			$('.exposeDialog').prepend('<div class="msgError">Strinjati se morate s pravili.</div>');
			//setTimeout(function(){$('.exposeDialog .msgError').remove()}, 2000);
			updateWindowHeight();
			return;
		}
		
		$.post("/user/exposead/ad/"+$adId, {format:'ajax'}, function(data){
			
			if(data.error) {
				alert(data.error);
			} else {
				
				//show msg
				$('.exposeDialog').html('<div class="msgOk">Add will be exposed till '+data.till+'</div>');
				updateWindowHeight();
				window.setTimeout(function(){cancelExposeDialog(data.updateHtml);},2000);
			}
			
		}, "json");
		
		//$("#overlayPanel").remove();
		//$overlayPanel = $('<div id="overlayPanel"></div>').appendTo($("#overlayBlur"));
		
		
	});
	$(".exposeAdCancelLink").live("click", function(ee){
		ee.preventDefault();
		cancelExposeDialog();
	});
	
	function cancelExposeDialog(updateHtml){
		
		if(updateHtml){
			//update page with expose till date
			$('.activeModalTrigger').replaceWith(updateHtml);
		}
		$("#overlayBlur").fadeOut(300,function(){$(this).remove();});
	}
	
	function updateWindowHeight(){
		var height = $('table.exposeTable').height();
		$('#overlayPanel').css('height', parseInt(height) + 20 +'px');
		
	}

}

function activateNotifications(notParam, notType) {
	$("#notOrderLink").click(function(e){
		e.preventDefault();
		$("#notConfirmNewUser").hide();
		$("#notConfirmNotLoggedIn").hide();
		$("#notConfirm").hide();
		$("#notOrderForm").show();
		
	});
	
	$("#order_btn").click(function(e){
		e.preventDefault();
		email = $("#notOrderForm #user_email").val();
		freq = $("#notOrderForm #not_freq").val();
		if ($("#notOrderForm #price_change_not").is(':checked')) {
			priceNot = 1;
		} else {
			priceNot = 0;
		}
				
		if (notType == 'location') {
			locId = notParam;
			searchFilter = null;
		} else {
			locId = null;
			searchFilter = notParam;
		}
		$.post("/search/notajax", {format:'ajax', email:email, freq:freq, priceNot:priceNot, notType:notType, locId:locId, searchFilter:searchFilter}, function(data){
			switch (data.userType) {
			case 'newUser':
				$("#notOrderForm").hide();
				$("#notConfirmNewUser").show();
				break;
			case 'notLoggedIn':
			case 'fbLoggedIn':
				$("#notOrderForm").hide();
				$("#notConfirmNotLoggedIn").show();
				break;
			case 'loggedIn':
				$("#notOrderForm").hide();
				$("#notConfirm").show();
				break;
			}
		}, "json");
		
		
		
		//<!-- Google Website Optimizer Conversion Script -->
		if(typeof(_gat)!='object')
			document.write('<sc'+'ript src="http'+
							(document.location.protocol=='https:'?'s://ssl':'://www')+
							'.google-analytics.com/ga.js"></sc'+'ript>');
		
		try {
			var gwoTracker=_gat._getTracker("UA-11970517-1");
			gwoTracker._trackPageview("/0540210311/goal");
		}catch(err){}
		//<!-- End of Google Website Optimizer Conversion Script -->
	
	});
}

/**
 * My_Forms options object
 * @return
 */
function My_Forms_Data(opts) {
	
	if(!(this instanceof arguments.callee))
		return new My_Forms_Data(opts);
		
	this.on_success = null;										//callback on successful validation - form, data, type
	this.on_error = null;										//callback to be executed on form errors - form, data, type
	this.on_is_activated = null;								//callback when 
	this.fetch_template = false;								//fetch full form template
	this.submit_btn = null;										//pressed submit button name
	this.msg_placeholder = null;
	this.activated = null;
	this.activatedAll = false;
	
	this.setOptions = function(opts){							//set options
		if(opts.on_success) {
			this.on_success = opts.on_success;
		}
		if(opts.on_error) {
			this.on_error = opts.on_error;
		}
		if(opts.on_is_activated) {
			this.on_is_activated = opts.on_is_activated;
		}
		if(opts.fetch_template) {
			this.fetch_template = opts.fetch_template;
		}
		if(opts.submit_btn) {
			this.submit_btn = opts.submit_btn;
		}
		if(opts.msg_placeholder) {
			this.msg_placeholder = opts.msg_placeholder;
		}
		if(opts.events) {
			this.events = opts.events;
		}
		if(opts.activatedAll) {
			this.activatedAll = opts.activatedAll;
		}
		//this = $.extend(this, opts);
	};
	
	this.markActivated = function(key) {		//add to activated list
		if(this.activated == null) this.activated = new Array();
		if(key != '') this.activated.push(key);
	}
	
	this.isActivated = function(key, disableUserFunction) {			//is key on activated list
		if(this.on_is_activated && !disableUserFunction) return this.on_is_activated(key, this);
		if(this.activatedAll) return true;
		if(this.activated == null) this.activated = new Array();
		return ($.inArray(key, this.activated) < 0) ? false : true;
		//return true;
		//return (key in this.activated);
	}
	this.activatedList = function() {			//(genearate id1,id2,id3|'' when activatedAll)
		if(this.activatedAll) return '';
		var real = new Array();
		var data = this.activated ? this.activated : new Array();
		for(var i = 0; i< data.length; i++) {
			if(this.isActivated(data[i])) {
				real.push(data[i]);
			}
		}
		return (real.length) ? real.join(',') : '';
	}
	
	// constructor
	this.setOptions(opts);
}
var My_Forms = {
	//date key holding My_Forms_Data object within a form element
	class_handle: 'ajaxform',
	def_msg_placeholder: '.formdesc',
	init:function(){
		//ajaxify all forms having a specific class
		//fails on ajax pages, as submit event is not live
		//$('.'+this.class_handle).bind('submit', {}, My_Forms.submitForm);
	},
	ajaxify:function(form){
		this.attachHandlers(form);			//atach user defined handlers
		
		//keep track of activated
		$('input, select', form).bind('focus',function(e){My_Forms.keepTrack(e,form);});
	},
	keepTrack: function(ev, form) {
		//delay 400ms
		setTimeout(function(){
			
			var $el = $(ev.target);
			$form = $(form);
			var dataObj = $form.data('ajaxform');
			if(!dataObj.isActivated($el.attr('id'))) {
				dataObj.markActivated($el.attr('id'));
			}
			
		}, 400);
		
	},
	attachHandlers: function(form) {
		//elements.bind('submit', {}, My_Forms.submitForm);
		var $form = $(form);
		var dataObj = $form.data('ajaxform');
		var events = dataObj.events;
		for(var i = 0; i < events.length; i++) {
			var eventData = events[i];
			if(eventData.length == 3 && $(eventData[0]).length) {
				$(eventData[0]).bind(eventData[1], eventData[2]);
			}	
		}
	},

	pass: function(form) {
		$(form).unbind('submit');
		var data = $(form).data('ajaxform');
		if(data && data.submit_btn && $('[name='+data.submit_btn+']', form).length ) { 
			$('[name='+data.submit_btn+']', form).click();
		} else {
			form.submit();
		}
	},
	submitForm: function(ev, type, partial){
		ev.preventDefault();									//do not submit form old HTML way
		
		var $form = $(ev.target);
		if($form[0].tagName != 'FORM') {
			$form = $form.parents('form');
		}
		
		var optsObj = $form.data('ajaxform');	
		
		if(type == undefined) {
			//mark all fields as checked, as the whole form is beeing submited
			optsObj.activatedAll = true;
		}
		
		
		
		var method = $form.attr('method');
		var action = $form.attr('action');
		var serializedFields = $form.serialize();
		serializedFields += '&format=ajax';
		
							//extra options
		if(optsObj) {
				//submit btn
				if(optsObj.submit_btn) {
					var $btnEl = $('input[name='+optsObj.submit_btn+']', $form);
					serializedFields += '&'+$btnEl.attr('name')+'='+$btnEl.val();
				}
				//activated ids
				serializedFields += '&ajax_activated_ids='+optsObj.activatedList();
		}
		
		if(partial) {
			serializedFields += '&ajax_form_partial=1';
		}
		
		My_Forms.updateDescLoading($form);
		
		$.ajax({
			   type: method,
			   url: action ? action : window.location.href,
			   dataType:'json',
			   data: serializedFields,
			   success: function(response){							//expect: error,has_errors,element_errors,html,text_errors
			 		//$('#'+_container_id).html(comment_editor);
					if(response.error) {
						alert(data.error);
						return;
					}
					if(optsObj) {
					
						if(!response.has_errors && optsObj.on_success) {
							optsObj.on_success($form, response, type);
						} else if(response.has_errors && optsObj.on_error){
							optsObj.on_error($form, response, type);
						} else {
							My_Forms.updateDesc($form, response);	//default - update description
						}
						
					} else {
						alert('no opts');
					}
			   }
			 });
	},
	/**
	 * only show loading when error exists ...
	 */
	updateDescLoading: function(form) {
		var $form = $(form);
		var dataObj = $form.data('ajaxform');
		
		var $placeholder = (dataObj.msg_placeholder) ? $(dataObj.msg_placeholder) : false;
		var msg = null;
		if($placeholder.length) {		//custom div to put desc in
			msg = $placeholder.html();
		} else if( $(this.def_msg_placeholder, $form).length){		//replace existing description placeholder
			msg = $placeholder = $(this.def_msg_placeholder, $form);
			//$placeholder.replaceWith(response.text_errors);
		}
		if(msg != null && msg != '') {
			$(msg).addClass('loader');
			//alert('grega');
		}
		
	},
	/**
	 * Update forms msg with errors, other from response
	 */
	updateDesc: function(form, response) {
		var $form = $(form);
		var dataObj = $form.data('ajaxform');
		if(response.element_errors == '' && !response.force_display) {
			this.clearDesc(form, response);
			return;
		}
		
		
//		if($(response.text_errors).html() == '') {
//			this.clearDesc(form, response);
//			return;
//		}
		var $placeholder = (dataObj.msg_placeholder) ? $(dataObj.msg_placeholder) : false;
		var msg = null;
		if($placeholder.length) {		//custom div to put desc in
			msg = $placeholder.html(response.text_errors);
		} else if( $(this.def_msg_placeholder, $form).length){		//replace existing description placeholder
			$placeholder = $(this.def_msg_placeholder, $form);
			msg = $placeholder.replaceWith(response.text_errors);
		} else {		// not defined, default doesnt exist, prepend
			msg = $placeholder = $form.prepend(response.text_errors);
		}
		
		if(msg) {
			$(msg).removeClass('loader');
		}
		
	},
	clearDesc: function(form, response) {
		var $form = $(form);
		var dataObj = $form.data('ajaxform');
		var $placeholder = (dataObj.msg_placeholder) ? $(dataObj.msg_placeholder) : false;
		if($placeholder.length) {		//custom div to put desc in
			$placeholder.html('');
		} else if( $(this.def_msg_placeholder, $form).length){		//replace existing description placeholder
			$placeholder = $(this.def_msg_placeholder, $form);
			$placeholder.replaceWith('');
		}
	},
	scrollTop: function(form, v_offset) {
		var $form = $(form);
		var dataObj = $form.data('ajaxform');
		var $placeholder = (dataObj.msg_placeholder) ? $(dataObj.msg_placeholder) : false;
		if(!$placeholder.length && $(this.def_msg_placeholder, $form).length){		//replace existing description placeholder
			$placeholder = $(this.def_msg_placeholder, $form);
		}
		if(!$placeholder) {
			//pick form
			$placeholder = $form;
		}
		//scroll to placeholder
		My_App.scrollToElement($placeholder, v_offset);
	},
	inlineErrors: function(form, response) {
		
		$('.inlineAjaxError', form).remove();
		var dataObj = $(form).data('ajaxform');
		var elements = response.element_errors;
		$.each(elements, function(el_id, txt){
			//alert('el__id');
			//alert(dataObj.isActivated(el_id));
			//console.log(el_id + ", " + dataObj.isActivated(el_id) + dataObj.activated);
			if(dataObj.isActivated(el_id)) {
				$('#'+el_id, form).after('<span class="inlineAjaxError"><img src="/gfx/icons/errorOnLabel.png" alt="'+txt+'" title="'+txt+'"/></span>');
			}
		});
	}, 
	clearFields: function(form) {
		$('input[type!=submit], textarea', $(form)).each(function(i){
			$(this).val('');
		});
	}
};

// jQuery plugin softInput
(function($) {
	$.fn.zulusoftinput = function(options) {
		return new ZuluSoftInput(this, options);
	};
	
	var ZuluSoftInput = function(el, options) {
		this.el = $(el);
		this.interval = null;
		this.inFocus = false;
		this.options = {
				softClass:'soft',
				softText:'change me'
		};
		if(options) {$.extend(this.options, options);}
		this.initialize();
	};
	
	ZuluSoftInput.prototype = {
		
		initialize: function() {
			var self = this;
			
			//change to soft if empty
			if(this.el.val() == '') {
				this.el.addClass(this.options.softClass).val(this.options.softText);
			}
			self.interval = setInterval(function(){self.intervalCheck(self)}, 1500);
			
			//set up events
			self.el.focus(function(e){
				self.inFocus = true;
				if($(this).val() == self.options.softText) {
					$(this).removeClass(self.options.softClass).val('');
				} else {
					//select all text
					$(this).select();		
				}
			});
			self.el.blur(function(e){
				self.inFocus = false;
				if($(this).val() == '') {
					//add default string and blur
					$(this).val(self.options.softText).addClass(self.options.softClass);
				}
			}); 
			
			//store itself into the element
			self.el.data('zulusoftinput', self);
			
		},
		intervalCheck: function(self) {
			//console.log('interval check '+self.el.val() +"---");
			if(self.inFocus) return;
			if(self.el.val() == '') {
				console.log('setting blur');
				//add default string and blur
				self.el.val(self.options.softText).addClass(self.options.softClass);
			}
		},
		//API
		cleanInput: function() {
			if(this.el.val() == this.options.softText) {
				this.el.val('');
			}
		}
	};
	
})(jQuery);

//jquery plugin zulufilter
(function($) {

  $.fn.zulufilter = function(options) {
	return new ZuluFilter(this, options);
  };

  var fnFormatDesc = function(value, filter_id, filter_title, currentValue) {
  	return 'grega';
  };
  
  var ZuluFilter = function(el, options) {
    this.elements = $(el);
    this.cachedResponse = [];
    this.options = {
      delay: 100,
      minChars: 0,
      elPrefix: 'filter_',
      filterUpdateContainer: '',
      filterUpdateEl:'',
      filterRemoveBtn:'',
      associatedListSpacers:'h3.char',
      hideListSpacersIfLessThanVisible:30,
      onSpacersUpdate:null,
      elements: null,
      params: {},
      fnFormatDesc: fnFormatDesc
    };
    if (options) { $.extend(this.options, options); }
    this.initialize();
  };

  ZuluFilter.prototype = {

    killerFn: null,

    initialize: function() {

		var self;
		self = this; //keep reference to self

		//hide text
		if(this.options.filterUpdateContainer) {
    		$(this.options.filterUpdateContainer).css('display', 'none');
    	}
		
		//find inputs ... applyFilter(event, this);
		this._getInputs().each(function(){
			//attach event handlers
			$(this).keyup(function(e){ self.onKeyUp(e)});
		});

		if(this.options.filterRemoveBtn) {
			$(this.options.filterRemoveBtn).click(function(e){self.onRemoveFilterClick(e)});
		}

		
    },

    _getInputs: function() {
    	var prefix = this.options.elPrefix;
	    return $("[id^=" + prefix + "]");
    },

    clearFiltered: function() {
		//clear text
    	if(this.options.filterUpdateContainer) {
    		$(this.options.filterUpdateContainer).css('display', 'none');
    	}
    	//clear inputs
    	this._getInputs().each(function (i) {
    		this.value = '';
    	});
    	//show all results
    	this.elements.show();
    	
    	if(this.options.associatedListSpacers && this.options.hideListSpacersIfLessThanVisible) {
			this.updateListSpacers();
		}
		
    },
    
	executeFilter: function() {
    	var query = '';
		var text = '';
		var self;
		self = this;
		// collect all filter values
		self._getInputs().each(function (i) {
			if(this.value != "") {
				var fname = $(this).attr("id")
				var val = this.value.toLowerCase();
				//if(fname == 'price_filter' || fname == 'inumber_filter') {
				//	val = val.replace(/[^0-9]/ig, '');
				//	query += '['+fname+'^="'+val+'"]';
				//} else if(fname == 'vechile_filter') {
					var parts = val.split(' ');
					for( var i in parts) {
						query += '['+fname+'*="'+parts[i]+'"]';
					}
					
				//} else {
				//	query += '['+fname+'*="'+val+'"]';
				//}
				//text representation
				
				text += text ? ', ' : '';
				text += (($(this).attr('title')) ? $(this).attr('title') + ':' : '') + ' <b>' + val + '</b>';
			}
		});

		if(query.length) {
			//console.log(query);
				self.elements.filter(':visible').hide();
				self.elements.filter(query).show();

				if(self.options.filterUpdateContainer) {
					$(self.options.filterUpdateContainer).css('display', 'block');
				}
				if(self.options.filterUpdateEl) {
					$(self.options.filterUpdateEl).html(text);
				}
				
			
		} else {
			if(self.options.filterUpdateContainer) {
				$(self.options.filterUpdateContainer).css('display', 'none');
			}
			if(self.options.filterUpdateEl) {
				$(self.options.filterUpdateEl).html(text);
			}
			self.elements.show();
		}
		
		if(self.options.associatedListSpacers && self.options.hideListSpacersIfLessThanVisible) {
			self.updateListSpacers();
		}
    },
    
    updateListSpacers: function() {
    	var self = this;
    	var $spacers = $(self.options.associatedListSpacers);
    	var count = self.options.hideListSpacersIfLessThanVisible;
    	var show = false;
    	if(self.elements.filter(':visible').length <= count) {
    		//hide he
    		$spacers.hide();
    	} else {
    		$spacers.show();
    		show = true;
    	}
    	if(self.options.onSpacersUpdate){
    		self.options.onSpacersUpdate(count, show, $spacers, self.elements.filter(':visible'));
    	}
    },
    
    onKeyUp: function(e) {
        var self;
        self = this;
    	clearTimeout(this.filterTimeout);
    	this.filterTimeout = setTimeout(function(){self.executeFilter()}, this.options.delay);
    },

    onRemoveFilterClick: function(e) {
		e.preventDefault();
		var self;
		self = this;
		self.clearFiltered();
    	
    }
  };
})(jQuery);


/**
	initializes the option to add another set of fields for choosing make, model and car name triplet
 */
waitForLocField = false;	// prevents two location form fields being fetched at the same time
function initAddAnotherMakeModelCarName() {
	$('#addMakeModelCarNameInput').click(function(e){
		e.preventDefault();
		// TODO: make sure something is chosen in the above
		// determine how many are there now
		// add another with a name next in row
		var lastName = $('#mainSearchForm select[name^=make_ID_]:last').attr('name');
		var lastNum = lastName.substring(8);
		
		$.post('/search/getmakemodelcarnameform', {format:'ajax', lastNum:lastNum},
			function(data){
				// in data there is whole part of the form from template. just append it after the last div containing car name field
				var lastCarName = $('#mainSearchForm input[name^=form_car_name_]:last');
				var lastCNDiv = lastCarName.parents('div:first');
				lastCNDiv.after(data);
			},
		'json');
		
	});
	
	$('#addLocationInput').click(function(e){
		e.preventDefault();
		
		if  (!waitForLocField) {
			waitForLocField = true;
			var lastName = $('#mainSearchForm select[name^=form_location_]:last').attr('name');
			var lastNum = lastName.substring(14);
			$.post('/search/getlocationform', {format:'ajax', lastNum:lastNum}, 
					function(data){
						var lastLocationField = $('#mainSearchForm select[name^=form_location_]:last');
						var lastLocationDiv = lastLocationField.parents('div:first');
						lastLocationDiv.after(data);
						waitForLocField = false;
				});
		}
	});
}



