Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}
Number.prototype.toDeg = function() {  // convert radians to degrees (signed)
  return this * 180 / Math.PI;
}


var keywordInput;
var locationInput;
var klsi;
var klsi_3col = false;

var postLoadingDiv;
var resultsLoadingDiv;



function preLoadPost(){
	$('#wordcloud').hide();
	$('#ofa_fullpost').empty();
	$('#ofa_fullpost').append($(postLoadingDiv).show());
}
function noPostLoaded(){
	$('#wordcloud').show();
	$('#ofa_fullpost').empty();
}

function postShowPost(){
	
}
function errorShowPost(){

}
function getAdvancedQueryParamaters(){
	var q = '&lfkw='+ulToBinary($('#advanced_col_keywords ul'));
	q += '&match='+$('#advanced_match_number').text();
	q += '&jtype='+ulToBinary($('#advanced_col_type ul'));
	q += '&edu='+ulToBinary($('#advanced_col_edu ul'));
	return q;
}
function ulToBinary(list){
	var b = '';
	$(list).children().each(function(){
		if ($(this).hasClass('selected')) b = b+'1';
		else b = b+'0';
	});
	return b;
}

function initializeSmartScroll(){
	var winheight = $(window).height();
	//set center container to the height of the window
	$('#ofa_center_container').css( {
			'height' : winheight
//			, 'background-color' : 'red'
	} );
	
	var top = $('#ofa_center_container').offset().top;
	var fullheight = $('#ofa_center_container').height();
	var docscroll = $(window).scrollTop();
	var eltop = $('#ofa_right_col').offset().top;
	var search_results_header_height = $('#ofa_mid_search_results_container').offset().top - $('#ofa_mid_search_header').offset().top;
	var mid_search_results_container_and_right_col = $('#ofa_mid_search_results_container, #ofa_right_col');
	
	if (docscroll < top) { //if there is scrolling
		//set the height of the search results container and the columns; consider the search results header
		$('#ofa_mid_search_results_container').css({
			'height' : (winheight - eltop + docscroll - search_results_header_height)+'px'
		});
		$('#ofa_right_col').css({ height : (winheight - eltop + docscroll )+'px' });
		//move columns - the header and the right column - to the top
		$('#ofa_mid_search_header, #ofa_right_col').css({ 'margin-top': (0)+'px' });
	} else {
		//mid_search_results_container_and_right_col.css({ 'height' : (top + fullheight - eltop)+'px' });
		
		$('#ofa_mid_search_results_container').css({
			'height' : (top + fullheight - eltop - search_results_header_height)+'px'
		});
		$('#ofa_right_col').css({
			'height' : (top + fullheight - eltop )+'px'
		});
		
		
		//move columns down, so they are visible on the page
		$('#ofa_mid_search_header, #ofa_right_col').css({ 'margin-top': (docscroll - top)+'px' });
	}
}

function initializeSearchHelp(){
	
	$('.ofa_help_square').click(function(){
		$(this).siblings().filter('.ofa_help_info').fadeIn();				 
	});
	$('.ofa_help_info').click(function(){
		$(this).fadeOut();							   
	});
}

$(document).ready( function(){
	postLoadingDiv = document.getElementById('ofa_fullpost_loading');
	$(postLoadingDiv).hide();
	resultsLoadingDiv = document.getElementById('ofa_results_loading');
	$(resultsLoadingDiv).hide();


	initializeSearchHelp();
							
	klsi = new KLS.Interface(document.getElementById('ofa_map'), document.getElementById('ofa_left_locations_container'), document.getElementById('ofa_mid_search_results_container'), document.getElementById('ofa_fullpost'));
	klsi.setControllerUrl('http://organizersforamerica.org/jb_job_kls_controller.php?');
	klsi.hooks.preLoadPost = preLoadPost;
	//klsi.hooks.preSearch = ;
	klsi.hooks.noPost = noPostLoaded;
	klsi.hooks.getAdvancedQueryParams = getAdvancedQueryParamaters;
	
	//Add sortby fields
	klsi.sortby_add_fields( [
			{label : "Posted Date", field : "posted", orderdirection : "DESC"},
			{label : "Organization", field: "organization_name", orderdirection : "ASC"},
			{label : "Job Title", field: "title", orderdirection : "ASC"}
		]
	)


	//advanced search stuff	
	$('#ofa_searchbox_advanced').hide();
	$('#ofa_searchbox_advanced li').addClass('selected');
	$('#ofa_searchbox_advanced li').click(function(){
		if ($(this).hasClass('selected')){
			$(this).removeClass('selected');
			 klsi.refreshQueryTotals(); klsi.refreshResults();
		} else {
			$(this).addClass('selected');
			klsi.refreshQueryTotals(); klsi.refreshResults();
		}
	});
	$('#ofa_advanced_show_link').click(function(){
		if ($('#ofa_searchbox_advanced').css('display') == 'none') $('#ofa_searchbox_advanced').slideDown();
		else $('#ofa_searchbox_advanced').slideUp();
	});
	$('#ofa_advanced_hide_link').click(function(){
		$('#ofa_searchbox_advanced').slideUp();
	});	
	$('#ofa_advanced_match_less').click(function(){
		var n = parseInt($('#advanced_match_number').text());
		if (n != '1'){
			$('#advanced_match_number').text((n - 1));
		}
	});
	$('#ofa_advanced_match_more').click(function(){
		var n = parseInt($('#advanced_match_number').text());
		$('#advanced_match_number').text((n + 1));
	});

	keywordInput = $("#ofa_search_keywords").fcbkcomplete({
		json_url: "http://organizersforamerica.org/keywordSuggestions.php?table=jobs_keywords&style=fcbkcomplete",
		json_cache: false,
		filter_case: false,
		filter_hide: true,
		filter_selected: true,
		newel: true,
		shownewel: true,
		firstselected: true,
		complete_text: 'Type a keyword, press enter to add...',
		onselect: function(){ klsi.refreshQueryTotals(); klsi.refreshResults(); },
		onremove: function(){ klsi.refreshQueryTotals(); klsi.refreshResults(); }
		}).get(0);
	
	locationInput = $("#ofa_search_locations").fcbkcomplete({
		filter_case: false,
		filter_hide: true,
		filter_selected: true,
		newel: true,
		shownewel: false,
		complete_text: 'Type a location, press enter to add...',
		onselect: klsi.addRegionByDescription,
		onremove: klsi.removeRegionHandler
	});

	klsi.firstRefresh();

	//smart scroll css and js - notice the footer adjustments
	initializeSmartScroll();
		$('#ofa_footer').css( { 'margin-top':'0px' } );
		$(window).scroll(initializeSmartScroll);
		$(window).resize(initializeSmartScroll);
		//to fix fast scrolling and allow time for results to be populated
		setInterval( 'initializeSmartScroll()',500);
})

// KLS = KeywordLocationSearch
var KLS = new Object();
KLS.Interface = function(mapNode, regionListNode, resultsNode, postNode){
	var thisObj = this;
	var regions = Array();
	var selectedRegion;
	var lastLocation;
	var posts = Array();
	var controllerUrl;
	var showAllBox;					
	var selectedPostId;				//the id of the post that is currently being viewed
	var resultsPage;
	var numResultsPages;
	var prevDbox;				//links for next and previous page of results
	var nextDbox;				//
	
	this.sortby_fields = Array(); 	//name value pairs
	this.hooks = Object();
	
	//functions to add regions and handle geocoding of region descriptions
	var checkStateCode = function(description){
		if (description.length != 2) return false;
		description = description.toUpperCase();
		for (var i in data_us){
			if (description == data_us[i].abr) return data_us[i];
		}
		return null;
	}
	var checkStateName = function(description){
		//put it into the proper capitalized format
		description = description.substr(0,1).toUpperCase() + description.toLowerCase().substr(1);
		for (var i in data_us){
			if (description == data_us[i].name) return data_us[i];
		}
		return null;
	}
	var checkLocationForVirtual = function(description){
		description = description.toUpperCase();
		if (description == 'VIRTUAL') return true;
		if (description == 'TBD') return true;
		if (description == 'TELECOMMUTING') return true;
		if (description == 'INTERNET') return true;
		if (description == 'ONLINE') return true;
		if (description == 'ON-LINE') return true;
		if (description == 'ON LINE') return true;
		if (description == 'WEB') return true;
		if (description == 'WEB BASED') return true;
		if (description == 'ANYWHERE') return true;
		return false;
	}
	this.addRegionByDescription = function(){
		//checks the typed location if its a state or region, then geocodes it, and calls addRegion after creating the postset object
		
		lastLocation = $(this).text();
		//trim extra spaces
		lastLocation = lastLocation.replace(/^\s+|\s+$/g,'').replace(/\s+/g,' ');
		$(this).text(lastLocation);
		
		var fbnode = this;
		
		//if its virtual, add it and exit
		if (checkLocationForVirtual(lastLocation)){
			thisObj.addRegion(new KLS.Region(lastLocation, KLS.RegionTypes.VIRTUAL , null, fbnode));
			return true;
		}
		
		//if its a state, create the state overlay and add it
		if (lastLocation.length < 25){		//location description is short
			var stateObj;
			if (lastLocation.length == 2) stateObj = checkStateCode(lastLocation);
			else stateObj = checkStateName(lastLocation);
			if (stateObj != null){
				thisObj.addRegion(new KLS.Region(lastLocation, KLS.RegionTypes.STATE , stateObj, fbnode));
				return true;
			}
		}
		
		//check for a smart distance query (ex: Less than 20 miles from 123 Dixie St., MD 20202)
		var matched = lastLocation.match(/(within|under|less than|<)?[ ]?([0-9]+)[ ]?(mile|miles|mi|kilometer|kilometers|km|kms|k) (of|from)[ ]?(.+)/i);
		var distance;
		if (matched != null){
			distance = matched[2];
			if (matched[3].toUpperCase().substr(0,2) == 'MI') {
				distance /= 0.621371192;
			}
			lastLocation = matched[5];	
		}
		
		//otherwise, use the returned latlng bounds
		thisObj.geocoder.getLocations(lastLocation, function(result) {
		  if (result.Status.code != 200) {
			alert('Sorry, the location you added could not be added. Try something else');
			//TODO: remove location from fcbk controller
		  } else {
			  if (result.Placemark.length == 1){
				  //there is only 1 response, we can handle it directly
					var center = new GLatLng(result.Placemark[0].Point.coordinates[1], result.Placemark[0].Point.coordinates[0]);
					var R = 6371;	//radius of earth in KM
					var data = new Object();
					if (distance != null){
						//adjust bounding box						
						result.Placemark[0].ExtendedData.LatLonBox.west = center.lng() + Math.atan2(-Math.sin(distance/R)*Math.cos(center.lat().toRad()), Math.cos(distance/R)-Math.sin(center.lat().toRad())*Math.sin(center.lat().toRad())).toDeg();
						result.Placemark[0].ExtendedData.LatLonBox.east = center.lng() + Math.atan2(Math.sin(distance/R)*Math.cos(center.lat().toRad()), Math.cos(distance/R)-Math.sin(center.lat().toRad())*Math.sin(center.lat().toRad())).toDeg();
						result.Placemark[0].ExtendedData.LatLonBox.north = Math.asin( Math.sin(center.lat().toRad())*Math.cos(distance/R) + Math.cos(center.lat().toRad())*Math.sin(distance/R) ).toDeg();
						result.Placemark[0].ExtendedData.LatLonBox.south = Math.asin( Math.sin(center.lat().toRad())*Math.cos(distance/R) - Math.cos(center.lat().toRad())*Math.sin(distance/R) ).toDeg();
					}
					thisObj.addRegion(new KLS.Region(lastLocation, KLS.RegionTypes.BOX, result.Placemark[0].ExtendedData.LatLonBox, fbnode));
					return true;
			  } else {
				alert("The location you entered had "+result.Placemark.length+" matches! Try something more specific...");
				//TODO: clear the added location
			  }			
		  }
		});
	}
	this.refreshQueryTotals = function(){}
	this.refreshResults = function(){}

	this.addRegion = function(newRegion){
		regions.push(newRegion);
		newRegion.getDbox().onclick = function(){thisObj.selectRegion(newRegion);}
		regionListNode.appendChild(newRegion.getDbox());
		if (regions.length>1) {				//stops this from happening when the "Everywhere" region is added during initialization
			thisObj.refreshQueryTotals();		
			if (selectedRegion == regions[0]) thisObj.selectRegion(regions[0]);
		}
	}
	this.removeRegion = function(region){
		var switchToAll = false;
		if (selectedRegion == region || selectedRegion == regions[0]) switchToAll = true;
		for (var i=1; i<regions.length; i++){
			if (regions[i]==region) {
				regions.splice(i,1);
				break;
			}
		}
		regionListNode.removeChild(region.getDbox());
		thisObj.refreshQueryTotals();
		if (switchToAll) this.selectRegion(regions[0]);
	}
	this.removeRegionHandler = function(){
		for (var i=1; i<regions.length; i++){
			if (regions[i].getFbNode().text()==this.text()) {
				thisObj.removeRegion(regions[i]);
				break;
			}
		}
	}
	
	this.selectRegion = function(r){
//		if (selectedRegion == r) return;
		selectedRegion = r;
		$(regionListNode).children().removeClass('result_selected');
		$(r.getDbox()).addClass('result_selected');
		resultsPage = 1;
		numResultsPages = r.getNumPosts();

		thisObj.refreshResults();
		/*
		if (r.getBounds()){
			this.map.setCenter(r.getBounds().getCenter(), this.map.getBoundsZoomLevel(r.getBounds())); 
		}
		
		this.refocusMap();
		*/
	}
	
	this.clearPosts = function(){
		for (var j=0; j<posts.length; j++){
			//this.map.removeOverlay(posts[j].getMarker());
			if (!posts[j].isVirtual()){
				posts[j].getMarker().hide();
			}
		}
		posts = new Array();
		$(resultsNode).empty();
	}
	
	//create "sortby control"
	this.sortby_add_fields = function( fields_to_add ) {
		//add fields
		var x;
		for (x in fields_to_add) {
			sortby_field = fields_to_add[x];
			this.sortby_fields.push( sortby_field );
			if ( this.sortby_fields.length == 1 ) {
				//if it is the first field added, create the button and select the first sort field
				$('#ofa_search_field').click( function () {
					if ( $('#ofa_sortby_menu').is(':hidden') ) {
						$('#ofa_sortby_menu').css({ 'margin-top': $(this).height() }).show();
					} else {
						$('#ofa_sortby_menu').hide();
					}
				});
				this.sortby_select( sortby_field.field );
			}
		}
		this.sortby_update_menu();
	}
	this.sortby_select = function( selected_field ){
		//marks one of the objects in this.sortby_fields as selected
		//label, field, table, selected
		var x;
		for (x in this.sortby_fields) {
			if ( this.sortby_fields[x].field == selected_field ) {
				this.sortby_fields[x].selected = 1;
				$('#ofa_sortby_menu').hide();
				$('#ofa_search_field').html(this.sortby_fields[x].label+' &#9660;');
				this.sortby_update_menu();
			} else {
				this.sortby_fields[x].selected = 0;
			}
		}
	}
	this.sortby_update_menu = function() {
		$('#ofa_sortby_menu ul#ofa_sortby_list').html('');
		var x;
		for (x in this.sortby_fields) {
			var li = document.createElement('li');
			if (this.sortby_get_selected().field == this.sortby_fields[x].field) $(li).addClass('selected_sort_field');
			$(li).text(this.sortby_fields[x].label);
			$(li).click(function(i){
				return function(){
					thisObj.sortby_select(thisObj.sortby_fields[i].field);
					thisObj.refreshResults();
				}
			}(x));
			$('#ofa_sortby_menu ul#ofa_sortby_list').append(li);
			//$('#ofa_sortby_menu ul#ofa_sortby_list').append('<li ' + ( (this.sortby_get_selected().field == this.sortby_fields[x].field) ? 'class="selected_sort_field"' : '' ) + ' onclick="klsi.sortby_select(\''++'\')">'++'</li>');
		}
	}
	this.sortby_get_selected = function() {
		var x;
		for (x in this.sortby_fields) {
			if ( this.sortby_fields[x].selected == 1 ) {
				return this.sortby_fields[x];
			}
		}
	}
	
	this.setControllerUrl = function(newUrl){
		//check for "?" and handle is smartly if its missing or not
		controllerUrl = newUrl;
	}

	this.highlightSearchKeywords = function(){
		$(postNode).removeHighlight();
		$('#ofa_search_keywords > option.selected').each(function(){
			$(postNode).highlight($(this).text());
		});	
	}

	this.loadPost = function(id){
		//highlight the job in the results list - highlights multiple entries if it has multiple locations and is listed more than once
		for (var i=0; i<posts.length; i++){
			if (posts[i].getId() == id) posts[i].getDbox().className = 'result_selected';
			else posts[i].getDbox().className = '';
		}
		
		if (selectedPostId == id) {
			//just to remove highlighting of any removed keywords
			thisObj.highlightSearchKeywords();
		} else {
			selectedPostId = id;
			if (typeof this.hooks.preLoadPost == 'function') this.hooks.preLoadPost();
			$(postNode).load(controllerUrl+'action=getpost&id='+id, null, function(){
				thisObj.highlightSearchKeywords();											   
			});
		}
	}
	
	var getCurrentKeywords = function(){
		//returns an array of the current keywords. Should this be a hook instead?
		var keywords = new Array();
		$('#ofa_search_keywords > option.selected').each(function(){
			keywords.push($(this).text());
		});
		return keywords;
	}
	var getAllRegionsQueryString = function(){
		var curRegions = new Array();
		for (var i=1; i<regions.length; i++){
			curRegions.push( regions[i].toQueryString() );
		}
		return curRegions.join('/');
	}
	var getSelectedRegionQueryString = function(){
		if (selectedRegion == regions[0]) return getAllRegionsQueryString();
		else return selectedRegion.toQueryString();
	}
	var parseResultsXml = function(xml){
		thisObj.clearPosts();
		
		$("searchresults>post", xml).each(function(){
			posts.push(new KLS.Post(this));						  
		});
		
		//add the "previous page" link
		if (resultsPage > 1) {
			prevDbox.innerHTML = 'Load Page '+(resultsPage-1)+' of '+numResultsPages;
			resultsNode.appendChild(prevDbox);
		}
		//alert(resultsPage +' - '+ numResultsPages);
		//update posts
		var trueIndex = 0;
		var jobIsSelected = false;
		for (var i=0; i<posts.length; i++){
			var p = posts[i];
			resultsNode.appendChild(p.getDbox());
			if (!p.isVirtual()){
				p.changeIndex(trueIndex++);
				thisObj.map.addOverlay(p.getMarker());
				p.getMarker().show();
				GEvent.addListener(p.getMarker(), 'click', function(post){
					return function(){
						post.getDbox().onclick();
					}
				}(p)); 
			}			
			p.getDbox().onclick = function(post){ 
				return function(e){
					//post.getDbox().scrollIntoView();
					thisObj.loadPost(post.getId());
					if (!post.isVirtual()){
						var marker = post.getMarker();
						//thisObj.map.checkResize();
						thisObj.map.panTo(marker.getLatLng());
						
						/*
						//bounce the maker (works ONLY with google maps api v2.123 as specified in head_ided... :(
						if (!marker.Xa)	{
							marker.Xa = true;
							marker.qo(false);
						}
						marker.Pa = 25; // Current height
						marker.ri = 25; // Max height
						marker.av = 1; // Direction (+ = down)
						marker.tc(); // Go baby!
						*/
					}
				}
			}(p);
			if (p.getId() == selectedPostId) {
				jobIsSelected = true;
			}
		}
		if (resultsPage < numResultsPages){
			nextDbox.innerHTML = 'Load Page '+(resultsPage+1)+' of '+numResultsPages;
			resultsNode.appendChild(nextDbox);
		}
		if (jobIsSelected == true){
			thisObj.loadPost(selectedPostId);
		} else {
			selectedPostId = null;
			if (typeof thisObj.hooks.noPost == 'function') thisObj.hooks.noPost();
		} 
	}

	this.refreshResults = function(){
		var sortby_string = '';		
		var offset_string = '';
		if(typeof this.sortby_get_selected == 'function') {
			//if ( this.sortby_get_selected() ) {
			sortby_string = '&orderby='+this.sortby_get_selected().field+'&orderdirection='+this.sortby_get_selected().orderdirection;
		} else {
			//alert('See 489 -- sortby_string can be created.')
		}
		//alert(selectedRegion+' , '+selectedRegion.getNumPosts());
		numResultsPages = Math.ceil(selectedRegion.getNumPosts()/99);
		if (numResultsPages > 1){
			//theres more than 1 page of results
			offset_string = '&poffset='+resultsPage;
		}
		
		$.ajax({
			type: "GET",
			url: 	controllerUrl+'action=search' + '&keywords='+getCurrentKeywords().join('/') + '&where='+getSelectedRegionQueryString() + thisObj.hooks.getAdvancedQueryParams() + sortby_string + offset_string,
			dataType: "xml",
			error: function (xhr, desc, exceptionobj) {
					alert('RESULTS ERROR: '+desc+" (URL="+controllerUrl+'action=search' + '&keywords='+getCurrentKeywords().join('/') + '&where='+getSelectedRegionQueryString() + thisObj.hooks.getAdvancedQueryParams() + sortby_string + offset_string);
			},
			success: function(data){
				var xml;
				if (typeof data == "string") {
					xml = new ActiveXObject("Microsoft.XMLDOM");
					xml.async = false;
					xml.loadXML(data);
				} else {
				   xml = data;
				}
				parseResultsXml(xml);
				//thisObj.refocusMap();
			}
		});		
	}

	this.refreshQueryTotals = function(){
		$.ajax({
			type: "GET",
			url: 	controllerUrl+'action=totals' + '&keywords='+getCurrentKeywords().join('/') + '&where='+getAllRegionsQueryString() + this.hooks.getAdvancedQueryParams(),
			dataType: "xml",
			error: function (xhr, desc, exceptionobj) {
					alert('TOTALS ERROR: '+desc);
			},
			success: function(data){
				var xml;
				if (typeof data == "string") {
					xml = new ActiveXObject("Microsoft.XMLDOM");
					xml.async = false;
					xml.loadXML(data);
				} else {
				   xml = data;
				}
				regions[0].updatePostCount($("searchtotals", xml).attr('total'));
				$("searchtotals>location", xml).each(function(i){
					regions[i+1].updatePostCount($(this).attr('total'));
				});
				numResultsPages = Math.ceil(selectedRegion.getNumPosts()/99);
			}
		});
	}
	this.firstRefresh = function(){
		this.refreshQueryTotals();
		this.selectRegion(regions[0]);
	}
	this.loadNextPage = function(){
		if (resultsPage < numResultsPages){
			resultsPage++;
			thisObj.refreshResults();
		}
	}
	this.loadPrevPage = function(){
		if (resultsPage > 1) {
			resultsPage--;
			thisObj.refreshResults();
		}
	}

	
	this.refocusMap = function(){
		// recenter/rezooms map onto currently displayed markers
		var centerLat = 0;
		var centerLng = 0;
		var avgDistance = 0;
		var numVirtual = 0;
		for (var i = 0; i < posts.length; i++){
			if (!posts[i].isVirtual()){
				centerLat += posts[i].getMarker().getLatLng().lat();
				centerLng += posts[i].getMarker().getLatLng().lng();
			} else {
				numVirtual++;
			}
		}
		centerLat /= posts.length - numVirtual;
		centerLng /= posts.length - numVirtual;
		
		for (var i = 0; i < posts.length; i++){
			if (!posts[i].isVirtual()){
				avgDistance += Math.sqrt(Math.pow(posts[i].getMarker().getLatLng().lat() - centerLat, 2) + Math.pow(posts[i].getMarker().getLatLng().lng() - centerLng, 2));
			}
		}
		avgDistance /= posts.length - numVirtual;
		
		this.map.setCenter(new GLatLng(centerLat, centerLng), 4);
	}

	

	
	//initialize map
	if (GBrowserIsCompatible()) {
	  	// Create and Center a Map
		this.map = new GMap2(mapNode);
		//centered and showing entire continental US
		this.map.setCenter(new GLatLng(38.27268853598097, -95.09765625), 4);
		this.map.addControl(new GSmallMapControl());			
		//Create Geocoding object
		this.geocoder = new GClientGeocoder();
	}
	
	//create "show all" link	
	thisObj.addRegion(new KLS.Region("All Results", KLS.RegionTypes.EVERYWHERE));
	selectedRegion = regions[0];
	
	//create next/prev page links
	prevDbox = document.createElement('A');
	prevDbox.className = 'switchPage';
	prevDbox.innerHTML = 'Load Previous Page';
	prevDbox.onclick = thisObj.loadPrevPage;
	nextDbox = document.createElement('A');
	nextDbox.className = 'switchPage';
	nextDbox.innerHTML = 'Load Next Page';
	nextDbox.onclick = thisObj.loadNextPage;
	
}

KLS.Region = function(locString, ntype, data, fNode){
	var thisObj = this;
	var description = locString;
	var dbox;
	var type = ntype;
	var numPosts;
	
	var bounds;	//type GLatLngBounds
	var stateCode;	
	var fbNode = fNode;

	this.getDbox = function(){ return dbox; }
	this.getType = function(){ return type; }
	this.getBounds = function(){ return bounds; }
	this.getStateCode = function(){ return stateCode; }
	this.getFbNode = function(){ return fbNode; }
	this.getNumPosts = function(){ return numPosts; }

	this.updatePostCount = function(num){
		numPosts = num;
		dbox.innerHTML = description+' - '+numPosts;
	}
	
	this.toQueryString = function(){
		if (this.getType() == KLS.RegionTypes.STATE) return this.getStateCode();
		else if (this.getType() == KLS.RegionTypes.VIRTUAL) return 'virtual';
		else if (this.getType() == KLS.RegionTypes.EVERYWHERE) return 'everywhere';
		else return this.getBounds().getSouthWest().lat()+"+"+this.getBounds().getSouthWest().lng()+"+"
					+this.getBounds().getNorthEast().lat()+"+"+this.getBounds().getNorthEast().lng()+"/" ;	
	}
	
	if (type == KLS.RegionTypes.STATE){
		stateCode = data.abr;
		description = data.name;
		bounds = new GLatLngBounds();
		for (var shapeIndex in data.shapes){				
			var shapeObject = data.shapes[shapeIndex];
			var ptarray = [];
			var p;
			for (var pointIndex in shapeObject){
				p = new GLatLng(shapeObject[pointIndex][1],shapeObject[pointIndex][0]);
				bounds.extend(p);
				ptarray.push(p);
			}
		}
	} else if (type == KLS.RegionTypes.BOX){
		bounds = new GLatLngBounds();
		bounds.extend(new GLatLng(data.south, data.west));
		bounds.extend(new GLatLng(data.north, data.west));
		bounds.extend(new GLatLng(data.north, data.east));
		bounds.extend(new GLatLng(data.south, data.east));
	} else {
		//figure out some bounds for "everywhere?"	
	}
	dbox = document.createElement('A');
	dbox.innerHTML = description+' - ';
}
//types of locations
KLS.RegionTypes = new Object();
KLS.RegionTypes.EVERYWHERE = 1;
KLS.RegionTypes.STATE = 2;
KLS.RegionTypes.BOX = 3;
KLS.RegionTypes.VIRTUAL = 4;

KLS.Post = function(xml){
	var jxml = $(xml);
	var thisObj = this;
	var id;
	var index;			//true index in the results list
	var dindex;			//displayed index (virtual jobs are skipped)
	var description;
	var marker;
	var dbox;
	var circle;
	var virtual;	//cannot be placed on the map because it is available online (show a computer icon instead of a letter)

	this.getId = function(){ return id; }
	this.getIndex = function(){ return index; }
	this.getMarker = function(){ return marker; }
	this.getDbox = function(){ return dbox; }
	this.isVirtual = function(){ return virtual; }

	this.changeIndex = function(newIndex){
		index = newIndex;

		newCode = index + 1;
		if (KLS.marker_prefs.use_letters) newCode = String.fromCharCode(("A").charCodeAt(0) + index);
		//cannot use setImage because the icon hasnt necessarily been loaded onto the map yet
		// this might cause a little delay because its not hiding it until it loads properly...

		//change the marker letter on the map
		if (marker != null){
			if (marker.isHidden()) marker.getIcon().image = KLS.marker_prefs.map_image + newCode + ".png";
			else marker.setImage(KLS.marker_prefs.map_image + newCode + ".png");

			var newCircle = document.createElement('IMG');
			newCircle.src = KLS.marker_prefs.circle_image + newCode + ".png";
			circle.parentNode.replaceChild(newCircle,circle);
			circle = newCircle;
		}	
	}




	dbox = document.createElement('A');
	circle = document.createElement('IMG');
	dbox.appendChild(circle);
	dbox.appendChild(function(){var t = document.createElement('SPAN'); t.className='title'; t.innerHTML=jxml.attr('title'); return t;}());
	dbox.appendChild(function(){var t = document.createElement('SPAN'); t.innerHTML=jxml.attr('subtitle'); return t;}());

	id = jxml.attr('id');
	if (jxml.attr('virtual') == null){
		marker = new GMarker(new GLatLng(jxml.attr('lat'),jxml.attr('lng')), {icon:new GIcon(KLS.baseIcon)});
	} else {
		virtual = true;
		circle.src = KLS.marker_prefs.virtual_image;
	}

}

KLS.marker_prefs = new Object();

/*  Default Google Icons
KLS.baseIcon = new GIcon(G_DEFAULT_ICON);
KLS.baseIcon.shadow = "http://www.google.com/mapfiles/shadow50.png";
KLS.baseIcon.iconSize = new GSize(20, 34);
KLS.baseIcon.shadowSize = new GSize(37, 34);
KLS.baseIcon.iconAnchor = new GPoint(9, 34);
KLS.baseIcon.infoWindowAnchor = new GPoint(9, 2);

KLS.marker_map_image = 'http://www.google.com/mapfiles/marker';
KLS.marker_circle_image = 'http://www.google.com/mapfiles/circle';

KLS.marker_prefs.use_letters = true;
*/



KLS.baseIcon = new GIcon();
KLS.baseIcon.image = "http://organizersforamerica.org/config_central/ofa_markers/lightred/marker.png";
KLS.baseIcon.iconSize = new GSize(21, 21);
KLS.baseIcon.shadow = "http://organizersforamerica.org/config_central/ofa_markers/marker_shadow.png";
KLS.baseIcon.shadowSize = new GSize(39, 21);
KLS.baseIcon.iconAnchor = new GPoint(10, 20);
KLS.baseIcon.infoWindowAnchor = new GPoint(10, 0);
/*KLS.baseIcon.transparent = "mytran.png";
KLS.baseIcon.printImage = "mymarkerie.gif";
KLS.baseIcon.mozPrintImage = "mymarkerff.gif";
KLS.baseIcon.printShadow = "myshadow.gif";
KLS.baseIcon.imageMap=[9,0,6,1,4,2,2,4,0,8,0,12,1,14,2,16,5,
19,7,23,8,26,9,30,9,34,11,34,11,30,12,26,13,24,14,21,
16,18,18,16,20,12,20,8,18,4,16,2,15,1,13,0];

KLS.baseIcon = new GIcon(G_DEFAULT_ICON);
KLS.baseIcon.shadow = "http://organizersforamerica.org/config_central/ofa_markers/marker_shadow.png";
KLS.baseIcon.iconSize = new GSize(21, 21);
KLS.baseIcon.shadowSize = new GSize(29, 13);
KLS.baseIcon.iconAnchor = new GPoint(10, 20);
KLS.baseIcon.infoWindowAnchor = new GPoint(10, 0);
*/

KLS.marker_prefs.map_image = 'http://organizersforamerica.org/config_central/ofa_markers/darkred/marker_';
KLS.marker_prefs.circle_image = 'http://organizersforamerica.org/config_central/ofa_markers/darkred/marker_';
KLS.marker_prefs.virtual_image = 'http://organizersforamerica.org/config_central/ofa_markers/radio.png';

KLS.marker_prefs.use_letters = false;