var ct_temporaryMapdataStore = { "status": -1, "mapData" : {} }; // status: -1 default (not ready), 0 unused, 1 in process of getting data, 2 data retrieved, 3 expired or there's no data coming (probably a one-feature map)
var ct_mapBalloon = null;
var ct_mapPlacename = null;
var ct_framedCloudWide = null;
var ct_dialog;
//var pl_rest_version = 1;
ct_browserDetect();
var ct_usecache = true;

function ct_setKeysAndDialogFunctions()
{
	PL.restapi.setAPIKey(pl_properties.apiKey);

	plShowDialog = ct_showPanel; // overwrite the default.
	plShowPanel = ct_showPanel;
	plHideDialog = ct_hidePanel;
	plHidePanel = ct_hidePanel;
	plShowProcessing = ct_showProcessing;
	
	PLAdminShowEditDone = ct_showEditCallback;
}

function ct_onMapAndDataReady () {
	//only show dataset on map if it's really there
	ct_setupFramedCloudWide();
	if ( ct_temporaryMapdataStore["status"] == 2 )
	{
		ct_onNearbyDataUpdated ( { data:  ct_temporaryMapdataStore["mapData"] } );
		ct_temporaryMapdataStore["status"] = 3;
	}
}

function ct_setupMapDiv () { // maximize the hieght to fit window and set to re-do it on window resize
	ct_setMapDivHeight();
	jQuery(window).resize( ct_setMapDivHeight );
};

function ct_setMapDivHeight ()
{
	if (plById("eleHomeTop"))
	{
		var window_h = jQuery(window).height();
		var topH = jQuery("#eleHomeTop").height();
		var bottomH = 0;//plById("eleHomeBottom").clientHeight;
		var mastheadH = jQuery("#header").height();
		var h = window_h - topH - bottomH - mastheadH - 45;
		if (h>0) jQuery("#plEleMapContainer").height( h );
	}
}


function ct_onCalendarDataUpdated (args) {
	plRenderFeaturesAsBlog (args.data, args.callid);
	plDebug("ct_onCalendarDataUpdated done");
	}

/*
function ct_plScriptCallback()
{
	plDebug("Loading JS for page");
	ct_setKeysAndDialogFunctions();
}
*/

function ct_loadGoogleMapsAPI () {
	plDebug("ct_loadGoogleMapsAPI");
	//debugger;
	plLazyLoadGoogleMapsAPI ( googleMapsApiKey, "ct_loadGoogleMapsAPIcallback" );
}

function ct_loadGoogleMapsAPIcallback ()
{
	//debugger;
	plDebug("ct_loadGoogleMapsAPIcallback");
	plPublish ("googleMapsApiLoaded" );
	pl_messages.googleMapsApiLoaded = true;
}

function ct_loadBaseMap ()
{
	plDebug("ct_loadBaseMap");
	plGetMainMarkerStyleMap = ct_getMainMarkerStylemap;
	plLoadBaseMap();
	plPublish("baseMapLoaded");
	pl_messages.baseMapLoaded = true;
}

function ct_authCheck ()
{
	plDebug("ct_authCheck");
	if ( _admin == 1 ) PLAuth.startAuthenticationCheck("ct_afterUserProfileIsLoaded");
}

function ct_browserDetect()
{
	return;
	// valid are: IE7, IE8, FF3, Chrome
	if ( false ) // for testing. 
	{
		var support = jQuery.support;
		var test="";
		for ( var i in support )
		{
			test+= i + "=" + support[i] + ", ";
		}
		
		alert("in ct_browserDetect, browser.webkit= " + browser.webkit + ", support=" + test); //plDebug isn't avail yet
	}
	var browser = $.browser;
	//var v = parseInt(browser.version);
	if ( browser.mozilla || browser.msie ) return; //|| browser.msie || browser.webkit ) return; // TODO this isn't the right set!
	//"We apologize but your Internet browser is incompatible with this website. In order to visit our site, you must upgrade your browser version or download a compatible browser.\n\nInternet Explorer 8\nInternet Explorer 7\nFirefox 3\nGoogle Chrome 3"
	
	alert("We apologize but your Internet browser is incompatible with this website. In order to visit our site, please use Firefox 3.");
}

function ct_showGeorankHelp () {
	var text  = "Geo-rank your favorite city features by clicking one of the radio buttons below. A number will appear in each flag on the map. Lower numbers (e.g. 1,2,3) may represent more desirable cities (lower overall crime, higher school scores or more golf courses). These numbers are based on independent public and private data feeds that we believe to be correct.  However, we do not guarantee the accuracy of these data feeds or the resulting scores.  Users are encouraged to do their own independent research and to rely solely on those results."
	ct_showPanel ( "ct_dialogEle", "What is &quot;Geo Rank&quot;", text, { modal: true, width: 300 }) 
}
function ct_prepareGeorankDialog () {
	plDebug("ct_prepareGeorankDialog");
	var gRank = jQuery("#ct_georankEle");
	gRank.dialog({"autoOpen":false});
	for ( var i = 0; i < pl_criteria.length; i ++ )
		{
		plDebug("i="+i);
		var code = ct_getCriteriaRowCode ( i );
		plDebug(code);
		gRank.append (  code );
		}
	
}
function ct_onClickGeoRank ()
{
	jQuery("#ct_georankEle").dialog("open");
}
function ct_onClickCriteria (idx)
{
	jQuery("#ct_georankEle").dialog("close");
	ct_startSearch(idx);
}
function ct_getCriteriaRowCode ( i ) { // i is the index
		var id, desc, label;
		var checked = "";
		if (i < 0 ) // default "no rank"
		{
			id = "critieriaItemDiv__";
			desc = "Shows now ranking.";
			label="No ranking";
			checked = "checked";
		}
		else
		{	
			pl_criteria[i].weight = 0;
			id = "critieriaItemDiv_" + i;
			desc = pl_criteria[i].description;
			label = pl_criteria[i].label;
		}
		//return '<div id="'+id+'"><input name="rankbyRadio" type="radio" value="'+i+'" ' + checked + ' onchange="ct_onClickLayersRadio('+i+')" >'  + label +'</div>';
		var newNode = document.createElement("div");
		plAddHtmlAttribute (newNode, "id", id );
		newNode.innerHTML = '<input name="rankbyRadio" type="radio" value="'+i+'" ' + checked + ' onchange="ct_onClickCriteria('+i+')" >'  + label;
		/*
		var tip = new YAHOO.widget.Tooltip("myTooltip"+i, {
			context: newNode,
			text: desc,
			showDelay:500,
			zIndex:2000
			} );
		*/
		return newNode;
		}
		
function ct_onFeatureMouseover (feature)
{ 
	if ( ct_mapPlacename ) ct_mapPlacename.destroy();
	ct_mapPlacename = new OpenLayers.Popup("ct_placename_popup",
				   feature.geometry.getBounds().getCenterLonLat(),
				   new OpenLayers.Size(200,30),
				   feature.attributes.name,
				   true);
	ct_mapPlacename.autoSize = true;
	pl_map.addPopup(ct_mapPlacename);				
}
	
	
function ct_onFeatureSelectOnMap ( feature ) {
	plDebug("ct_onFeatureSelectOnMap");
	//debugger;
	if ( ct_mapPlacename ) ct_mapPlacename.hide();
	jQuery("#currentPlace").empty(); // get rid of the old place
	currentPlaceLocation = {"type":"Point","coordinates":[ feature.geometry.x , feature.geometry.y ]};
	var rootpath = ( typeof ctv_rootpath == "undefined" ) ? "/" : ctv_rootpath;
	if (ct_usecache) var source = rootpath + "cache/" + feature.fid +".php?format=html";//"&b=" + ctv_isagent + "&c=" + _admin;
	else var source = rootpath + "blog_one.php?i=1&a=" + feature.fid + "&b=" + ctv_isagent + "&c=" + _admin;
	jQuery("#currentPlace").ajaxError (function(e, xhr, settings, exception) {debugger;});
	jQuery.get( source, null, ct_onFeatureSelectOnMapCallback )

	//var iframe = jQuery("<iframe />", { src: source, id: "ct_balloonIframe" } );
	//var callbackFn = function() { this.hide(); this.destroy(); ct_mapBalloon = null;  }
	//p.append(iframe);
	//ct_showMapBalloon ( p.html(), feature.geometry.getBounds().getCenterLonLat(), callbackFn);
	//var tb2 = jQuery("#mapBalloon_tabs", iframe);
	//var tb0=tb[0];
	//var a = tb.html();
//debugger;


//var tabs = jQuery("#mapBalloon_tabs", iframe.contents());
	//alert(tabs);
	//plDebug(tabs);
	//debugger;
	//tabs.tabs();
	//p.empty();
	/*
	var html = "<div id=\"mapBalloon_wrapper\">	\
			  <div id=\"mapBalloon_profile\">" +  feature.attributes.description +  "</div>	\
				<div id=\"mapBalloon_tabbedContent\"></div>  \
				</div>";
	p.append(html);
	var tabs = $("<div>", { id: "tabs"} );
	var list = $("<ul>");
	list.append( $("<li>", { html : "<a href=\"#tabs-1\">Video</a>"} ) );
	list.append( $("<li>", { html : "<a href=\"#tabs-2\">Details</a>"} ) );
	list.append( $("<li>", { html : "<a href=\"#tabs-3\">Blog</a>"} ) );
	tabs.append(list)
	tabs.append( $("<div>", { id : "tabs-1", html: feature.attributes.mediahtml } ) );
	tabs.append( $("<div>", { id : "tabs-2", html: feature.attributes.details } ) );
	var moreHtml = feature.attributes.blog_feed + "<br />";
	tabs.append( $("<div>", { id : "tabs-3", html: moreHtml } ) );

	var selectedTab = 0;
	if ( _admin)
	{
		var canedit = (PLAdmin?PLAdmin.hasEditPrivileges():false); //If PLAdmin module is accessible for customer and user has edit privs
		if ( canedit ) // TODO revert to canedit
			{
			selectedTab = 3;
			list.append( $("<li>", { html : "<a href=\"#tabs-4\">Admin</a>"} ) );
			var adminHtml =  '<div class="ct_adminButtons"><span class="edit" onclick="PLAdmin.showEditFeaturePanel(\'expert\',' + feature.data.featureSetId +',' + feature.fid +')">edit</span><span class="add" onclick="PLAdmin.showAddFeaturePanel(\'Expert\',' + feature.data.featureSetId +')">add</span></div>';
			tabs.append( $("<div>", { id : "tabs-4", html: adminHtml } ) );
			}
	}

	$("#mapBalloon_tabbedContent").append(tabs);
	tabs.tabs( { selected: selectedTab});
	
	*/
}

function ct_onFeatureSelectOnMapCallback ( html, status)
{
	if (status == "success")
	{
		jQuery("#currentPlace").html( html ); // write it to DOM so location var becomes avail.
		ct_showFeature ();
	}
}

function ct_showPreloadedFeature () // if there is content, show it in a balloon. this funciton gets called automatically, but will only show a ballon if there's content in the appropriate div tag, and that content will only be there if the URL param "a" passes a fid 
{
	plDebug("ct_showPreloadedFeature");
	if ( currentPlaceLocation && currentPlaceLocation.coordinates )
	{
		//var html = jQuery("#currentPlace").html();
		plDebug("ct_showPreloadedFeature, there was one");
		ct_showFeature( ct_startSearch );
	}
}
function ct_showFeature ( closeFunction )
{
		jQuery("#mapBalloon_tabs").tabs();
		var location = new OpenLayers.LonLat ( currentPlaceLocation.coordinates[0], currentPlaceLocation.coordinates[1]);
		var callbackFn = function (){
			this.hide();
			this.destroy();
			ct_mapBalloon = null;
			ct_temporaryMapdataStore["status"] = 3; // TODO this is a bit of a hack ...
			currentPlaceLocation = null;
			if ( typeof closeFunction == "function" ) closeFunction.call();
			};
		ct_showMapBalloon ( location, callbackFn);
}


function ct_showMapBalloon ( location, closeBoxCallbackFunct )
{
	if ( ct_mapBalloon ) ct_mapBalloon.destroy();
	plDebug("ct_showMapBalloon");
	ct_mapBalloon = new ct_framedCloudWide (
			"mapPopup", // id. could be a problem with multple popups
			location, // lonlat
			new OpenLayers.Size(835,440), // contentSize. it will autosize
			"<div id=\"ct_mapBalloon_contentWrapper\"></div>", // contentHTML
			null, // anchor
			true, // closeBox
			closeBoxCallbackFunct // close function. may need to pan back to center TODO
			);
	ct_mapBalloon.panMapIfOutOfView=true;
	//ct_mapBalloon.setBackgroundColor("#7C97C2");
	ct_mapBalloon.autoSize = false;
	//ct_mapBalloon.maxSize = new OpenLayers.Size(900,700);
	//feature.popup = popup;
	pl_map.addPopup(ct_mapBalloon);
	
	jQuery("#ct_mapBalloon_contentWrapper").append (jQuery("#currentPlace").children() ); // this way it will retain it's listeners, etc.
	
	return ct_mapBalloon;
	//ct_mapBalloon.setContentHTML(html);

}
function ct_onFeatureUnselectOnMap ( feat ) { // hide it
	//alert("ct_onFeatureUnselectOnMap");
	if (feat.popup && feat.popup.hide ) feat.popup.hide();
	}

function ct_generateFormula (crit, loctype)
	{
		var id = pl_main[0].id;
		var xml = '<formula><main id="' + id + '">';
		xml += '<parameter name="premium" value="' + _premium + '" />';
		xml += '<parameter name="agentuid" value="' + ctv_agentuid + '" />';
		xml += '<parameter name="type" value="' + loctype + '" />';
		xml += '</main>';
		//xml += '<parameter name="attribute_TYPE" value="TEXT(' + loctype + ')" /></main>';
		// ZONE
		var olGeoJson = new OpenLayers.Format.GeoJSON();
		var mapExtentAsGeoJson = olGeoJson.write ( pl_map.getExtent().toGeometry() );
		//debugger;
        xml += '<context format="geojson"><![CDATA[' + escape(mapExtentAsGeoJson) + ']]></context>';
		// CRITERIA
		xml += '<criteria id="' + crit.fsid + '" key="' + crit.key + '">'; // key is required
		xml += '<label>' + escape(crit.label) + '</label>';
		//xml += '<parameter name="spatialFunction" value="' + crit.defaultSpatialFunction + '" />'
		xml += '<parameter name="spatialFunction" value="' + crit.defaults["spatialFunction"] + '" />';
		//xml += '<attribute name="spatialFunctionResult" scorable="1" priority="' + crit.weight + '" preference="' + crit.defaultPreference + '" />';
		xml += '<attribute name="spatialFunctionResult" scorable="1" priority="1" preference="' + crit.defaults["preference"] + '" floor="' + crit.defaults["floor"] + '" ciel="' + crit.defaults["ciel"] + '" />';
		for ( var param in crit.params )
		{
			xml += '<parameter name="' + param + '" value="' + crit.params[param] + '" />';
		}
		xml += '</criteria>';
		xml += '</formula>';
        return xml;
   }

function ct_afterUserProfileIsLoaded()
{
    plDebug("in afterUserProfileIsLoaded");
    var uele = plById("plUserNameEle");
    if ( pl_User.id != '' && pl_User.externalId != '') // user is logged in
    {
        uele.innerHTML = 'You are logged in as: ' + pl_User.profile.name + '';
        plById("plLoginContainerEle").style.display = "none";
        plById("plRegisterContainerEle").style.display = "none";
    }
    else
    {
        uele.innerHTML = "";
        plById("plLoginContainerEle").style.display = "inline";
        plById("plRegisterContainerEle").style.display = "inline";
    }
}



/* currently unused, but leave it for later:

function getCriteriaRowCode ( i ) { // i is the index
		var id, desc, label;
		var checked = "";
		if (i < 0 ) // default "no rank"
		{
			id = "critieriaItemDiv__";
			desc = "Shows now ranking.";
			label="No ranking";
			checked = "checked";
		}
		else
		{	
			pl_criteria[i].weight = 0;
			id = "critieriaItemDiv_" + i;
			desc = pl_criteria[i].description;
			label = pl_criteria[i].label;
		}
		//return '<div id="'+id+'"><input name="rankbyRadio" type="radio" value="'+i+'" ' + checked + ' onchange="ct_onClickLayersRadio('+i+')" >'  + label +'</div>';
		var newNode = document.createElement("div");
		plAddHtmlAttribute (newNode, "id", id );
		newNode.innerHTML = '<input name="rankbyRadio" type="radio" value="'+i+'" ' + checked + ' onchange="ct_onClickLayersRadio('+i+')" >'  + label;
		var tip = new YAHOO.widget.Tooltip("myTooltip"+i, {
			context: newNode,
			text: desc,
			showDelay:500,
			zIndex:2000
			} );
		return newNode;
		}
function ct_showCriteria ()
{
	var filtersDiv = plById("geoRankRadios");
	var row_one, row_two, row_three;
	var rows = 2; // only 2 or 3
	for ( var i = -1; i < pl_criteria.length; i += rows ) // puts them in columns with three rows in each col, starts at -1 for the 'no ranking' option
		{
		var newNode = plAddHtmlNode ( filtersDiv, "div", "", {"class":"layersSubsection"} );
		row_one = getCriteriaRowCode ( i );
		newNode.appendChild(row_one);
		if ( pl_criteria[i+1] ) {
			row_two = getCriteriaRowCode(i+1);
			newNode.appendChild(row_two);
			if ( pl_criteria[i+2] && rows == 3 ) {
				row_three = getCriteriaRowCode(i+2);
				newNode.appendChild(row_three);
				}
			}
		//plAddHtmlNode ( filtersDiv, "button", "Rank", { "onClick":"ct_startSearchWithRank();return false;"} );
		}
}

function ct_onClickLayersRadio ( a )
{
	//plById("measureCitiesButton").disabled = false;
	ct_startSearch();
}

*/

function ct_onClickExample (a)
	{ 
		var ele = plById("addressInput");
		ct_onClickAddressInput();
		ele.value = a;
		ct_onSubmitSearchForm ();
	}
	
function ct_onClickAddressInput () {
	var ele = plById("addressInput");
	if ( !ele.style.color) // first time
		{
			ele.value = "";
			ele.style.color="#000000";
		}
	}

function ct_onSubmitSearchForm () {
	var ele = plById("addressInput");
	if ( !ele.style.color || ele.value == "" || ele.value == null) 
		{
		alert("you didn't fill out the box at right yet") ; return 
		}
	ct_showProcessing(true);
	var v = ele.value;
	//if (v.substr(v.length - 2 ).toUpperCase() != "CA" ) v+=", CA";
	if ( pl_properties.center.address != v ) // the value has changed so geocode it
	{
		plDebug( "geocoding " + v );
		pl_properties.center.address = v;
		pl_properties.defaultRunProperties.map.zoomToLayer=false; // this is a bit of a hack -- says that after entering the address, don't soom to the extent, instead zoom to default zoom level
		pl_properties.geoCoder ( v, ct_geocodeCallback );
	}
	else ct_startSearch() // no change in address do don't geocode
	}

function ct_geocodeCallback ( cbData )
{
	// need to convert from 4326 to 900913
	var point = new OpenLayers.LonLat(cbData.lng(), cbData.lat());
	point.transform( new OpenLayers.Projection("EPSG:4326"), new OpenLayers.Projection("EPSG:900913"));
	pl_properties.center.lng = point.lon;
	pl_properties.center.lat = point.lat;
	pl_properties.defaultRunProperties.map.defaultCenter = { lng: point.lon, lat : point.lat }
	ct_startSearch();
}

function ct_getMapData () // document and props objects are ready. choose what to show
{
	if (currentPlaceLocation && currentPlaceLocation.coordinates) // this is a single-feature map, don't run the search or calendars
	{
		ct_temporaryMapdataStore["status"] = 3; // not going to load data
		plSubscribe("mapAndDataReady", null, ct_showPreloadedFeature ); // TODO what if map is ALREADY ready?
		//ct_startCalendar();
	}
	else 
	{
		ct_temporaryMapdataStore["status"] = 1; // loading in progress
		ct_startSearch();
	}
}

function ct_startSearch ( criteriaIndex )
{
	//debugger;
	ct_showProcessing(true);
//	var type = plCoalesce( plGetFormElementValue (document.getElementsByName("ctEleMaplayerRadio")), -1) ; // default to video
	var type = jQuery("#findOptions input:checked").val();
	/*
	var criteriaIndex = plCoalesce ( plGetFormElementValue (document.getElementsByName("rankbyRadio")), -1); //measuer cities checked?
	*/
	if  ( criteriaIndex > -1 ) // rank the flags
	{
		plDebug("ct_startSearch, there was a criteria so use it");
		var xml = ct_generateFormula ( pl_criteria[criteriaIndex], type);
		plRun ( xml, "ct_startSearchWithRankCallback", null, "script" ); // uses the default properties 
	}
	else // no ranking
	{
		var pointGeoJson = JSON.stringify( { "type": "Point", "coordinates": [pl_properties.center.lng, pl_properties.center.lat ] });
		var args = {
			"callback":"ct_startSearchCallback"
			//,"uid": null // can't filter on this yet anyway
			,"geometry":pointGeoJson
			,"geometryformat":"geojson"
			,"order":"distance"
			,"buffer":10000
			//,"criteria":fsid
			,"limit":150
			,"offset":0
			//,"PARAMETERS": "type:2"
			//,"criteriaIndex":"0"
			}
		args.criteria = pl_main[0].id;
		args.type = type;
		args.agentuid = ctv_agentuid;
		args.premium = _premium;
		//plCallNearbyService ( "ct_startSearchCallback", pointGeoJson, "geojson", "200", "mile", fsid, attr, "distance", 150, 0, { }, "script" )
		//args.PARAMETERS = attr;
			//debugger;
		PL.restapi.nearby.run(args);
				      
				      
				      /* "callback": type : (string), default: (), required: (false), minlength: (0), maxlength: (100)
                
                    "uid": type : (int), default: (), required: (false), minlength: (0), maxlength: (19)
                
                    "geometry": type : (string), default: (), required: (true), minlength: (0), maxlength: (500)
                
                    "geometryformat": type : (string), default: (geojson), required: (false), minlength: (0), maxlength: (7)
                
                    "order": type : (string), default: (id), required: (false), minlength: (0), maxlength: (8)
                
                    "buffer": type : (double), default: (10), required: (false), minlength: (0), maxlength: (50)
                
                    "criteria": type : (long), default: (), required: (true), minlength: (0), maxlength: (20)
                
                    "limit": type : (integer), default: (20), required: (false), minlength: (0), maxlength: (3)
                
                    "offset": type : (integer), default: (0), required: (false), minlength: (0), maxlength: (3)
                
                    "PARAMET
		    */
	}	
}

function ct_startSearchCallback ( data, callid) { 
	plDebug("ct_startSearchCallback");
	//debugger;
	if (data.response.content.features.length > 0 ) 
	{
		if ( ct_temporaryMapdataStore["status"] == 3)  // 2nd time thru, just publish it
		{
			plPublish ( "searchDataUpdated", { "data": data } ); 
		}
		else { // data isn't ready
			ct_temporaryMapdataStore["mapData"] = data; // let conditionalPublish handle it
			ct_temporaryMapdataStore["status"] = 2; // data is loaded
		}
	}
	else 
	{
		//TODO need to clean up the publish and temp store ... if this is the first time, when you try again it fails.
		ct_temporaryMapdataStore["status"] = 3; // assumes there's been enough time and everything is now loaded
		//alert("There were no matches ... ");
		ct_showProcessing(false);
		ct_showPanel("ct_dialogEle","No matched","There were no matches ...", {modal:true,width:300});
		plDebug("There are no matches -- perhaps the location you entered is too distant?","warn");
	}
}

function ct_onNearbyDataUpdated ( args ) {
	plDebug("ct_onNearbyDataUpdated");
	var data = args.data;
	pl_properties.defaultRunProperties.map.properties.styleMap = plGetMainMarkerStyleMap(); // TODO this should be based on a property in pl_properties. ONly need to do this the first time.
	
	plMapAddGeoJsonLayer ( data.response.content, pl_properties.geometrySrid, pl_properties.defaultRunProperties, true);
	pl_map.getLayersByName("Videos")[0].setVisibility( 1 );
	ct_showProcessing(false);
	}
function ct_startSearchWithRankCallback ( data, callid )
{
	ct_setCityRankPositions (data);
	plRunFormulaCallback(data, callid);
}

function ct_setCityRankPositions ( data ) { // loops through results, sets a new feature property 'overallScorePosition' that indicates where the results put each city relative to overall. 
	var priorResult;
	var pos = 0;
	for ( var i = 0; i < data.response.content.features.length; i ++ )
	{
		if ( priorResult != data.response.content.features[i].properties.overallScore )
		{
			priorResult = data.response.content.features[i].properties.overallScore;
			pos ++; // increment only if the overallScore has changes (they shouod already be in order by score)
		}
		data.response.content.features[i].properties.overallScorePosition = pos;
	}
}

function ct_startCalendar (args) {
	ct_getCalendarEvent (0)
	}
function ct_getCalendarEvent ( offset )
{
	//plDebug("in ct_getCalendarEvent");
	//plById("blog_rows").innerHTML="Loading ... please wait.";
	var pointGeoJson = JSON.stringify( { "type": "Point", "coordinates": [pl_properties.center.lng, pl_properties.center.lat ] });
	var type = 0 ; // events
	var attr = (type > -1) ? "attribute_type=TEXT(" + type + ")&" : "";
	attr+="attribute_date=AGE_LT(1 day)";
	var tpl = '<div class="row"><div class="date">${date}</div><a class="description" onclick="ct_onClickCalendarEvent(${id})" href="javascript:void(0)">${name} <span>${edit}</span></a></div>';
	var limit = 8; // how many to show at once
	var offset = offset?offset:0;
	var formatters = { "date" : ct_formatBlogDate, "description": ct_formatBlogDescription }
	plCallNearbyService ( "ct_getCalendarEventCallback", pointGeoJson, "geojson", "200", "mile", pl_main[0].id, attr, "date,asc", limit, offset, { "formatters" : formatters, "container": "blog_rows", "template": tpl, "fsid": pl_main[0].id, "limit":limit, "offset": offset, "nextFunctionName":"ct_getCalendarEvent"}, "script" );
}

function ct_onClickCalendarEvent ( id ) // TODO grab just the one flag?
{
	return; // currently does nothing;
	/*
	var match;
	var layer = pl_map.getLayersByName("Events")[0];
	for ( var c = 0; c < layer.features.length; c++ )
	{
		if (layer.features[c].fid == id) 
		{
			match = c;
			break;
		}
		
	}
	if (match >= 0) 
	{
		document.getElementById("ctEleMaplayerRadio_events").checked=true;
		//ct_showLayer("Events");
		var mark = layer.features[match];
		ct_onFeatureSelectOnMap(mark);
	}
	else return false;
	*/
}

function ct_formatBlogDate ( date )
{
	plDebug("date 1 = " + date);
	var dateParts = date.split("-");
	var jDate = new Date( dateParts[0], dateParts[1] - 1, dateParts[2]);
	plDebug("DATE 2 =" + jDate);
	//var dateArray = date.split(" ", 1)[0].split ("-", 3);
	var months = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
	//var days=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]
	var days=["Sun","Mon","Tue","Wed","Thu","Fri","Sat","Sun"]	
	return days[jDate.getDay()] + ", " + months[dateParts[1]-1] + " " + dateParts[2];
}

function ct_formatBlogDescription ( description )
{
	return description.replace("<a ","<a target='_blank' ")
}

function ct_getCalendarEventCallback ( data, callid )
{
	plPublish("calendarDataUpdated", { data: data, callid: callid } );
}

function ct_onClickMaplayerRadio ()
{
	plDebug(" ct_onClickMaplayerRadio");
	ct_startSearch ();
}

function ct_showDialogFromFile (filename, title, big)
{
	var w = 10;
	var callback;
	if ( big == true ) // makes dialog 80% of avail. width and height
	{
		var callback = function(o, status) {
			if (status != "success") {alert("failed"); return;}
			 var w = parseInt ($(window).width() * .8);
			 var h = parseInt ($(window).height() * .8 );
			 ct_showPanel ( "ct_dialogEle", title, o, {width: w, height: h, modal: true, dialogClass: "ct_dialogFromFile" }) 
			 }
	}
	else // makes dialog size to content (?)
	{
		var callback = function(o, status) {
			if (status != "success") {alert("failed"); return;}
			 ct_showPanel ( "ct_dialogEle", title, o, { modal: true }) 
			 }
		
	}
	var path = ctv_rootpath + filename;
	jQuery.get( path, null, callback )
}

function ct_showPanel ( eleId, title, html, props )
{
	plDebug("ct_showPanel");
	var container;// = jQuery("#"+eleId);
	if (! plById (eleId) ) {
		container = $("<div>", { id: eleId, title: title, html: html });
		}
	else {
		if(PLAdmin && PLAdmin.cleanUpWidgets ) PLAdmin.cleanUpWidgets (eleId);
		//container.extend =  $("#" + eleId);
		var container = jQuery("#"+eleId);
		container.dialog("destroy");
		container.attr("title", title);
		container.html(html);
 		}
	//props.zIndex = 2000; // because openlayers items show thru
	//props.resize = function () { debugger;}
	//props.maxHeight = parseInt( $(window).height()* .8 ); // don't get bigger than 80% of the height;
	if ( container.dialog ) container.dialog  ( props ); // this may not be ready, particularly in IE8
	plDebug("ct_showPanel done");
}
function ct_hidePanel (eleId)
{
	var ele = $("#"+eleId);
	if ( ele.dialog) ele.dialog("close");
		//	ct_dialog.dialog("close");
}

function ct_showEditCallback () { // resize/recenter since rendering widgets made it larger
	/*
	var el = "#plFeatureEditorPanelEle";	
	$(el).dialog('option', 'position', $(el).dialog('option', 'position')); 
	*/
	}

function ct_showProcessing ( state )
{
	plDebug("ct_showProcessing");
	var openFunction = function(event, ui) { 
			//hide title bar
			$(this).parent().children('.ui-dialog-titlebar').hide();
			}
	if (state) ct_showPanel ( "ct_dialogEle", null, "<strong>Preparing tour data ...</strong>", { modal: true, minHeight: 10, resizable: false, draggable:false, open: openFunction }) 
	else ct_hidePanel ("ct_dialogEle");
}
function plCreateEditorWidget(parent, attributes, type)
{
	var rte;
	var t = type ? type : "simpleeditor"; // if type is missing use simple
   	var id = attributes["id"];
   	var arr = $('#'+id).rte({
		css: ['default.css'],
		width: 500,
		height: 300,
		controls_rte: rte_toolbar,
		controls_html: html_toolbar
	});
   return arr[id];
}

function plDestroyEditorWidget(wid)
    {
        wid.handle.destroy();
    }

function plGetEditorWidgetValue(wid)
    {
        return wid.handle.get_content();;
    }

function ct_getMainMarkerStylemap ()
	{
		//plDebug("this is the default plGetMainMarkerStyleMap");
		var rootpath = ( typeof ctv_rootpath == "undefined" ) ? "/" : ctv_rootpath;
		return new OpenLayers.StyleMap(new OpenLayers.Style(
				{
					"graphicWidth" : 17
					, "graphicHeight" : 19
					, "externalGraphic":"${getGraphicURL}"
				}
				, {
					"context" : 
						{
							"getGraphicURL": function(feature)
								{
									
									var rank = feature.attributes.overallScorePosition?feature.attributes.overallScorePosition:"";
									return rootpath + "res/images/mapmarkers/lightblue/lightblue" + rank + ".png";
								}
					}
				})
			)
	}

function ct_openNewWindow (url) {
	window.open(url, "popout_"+url, "")

}

function ct_addEditFeature (mode,fsid,fid)
{
	if (!pl_User || !(pl_User.id > 0)) 
	{
		alert("log in first");
		return; // only if logged in 
	}
	//TODO test if logged in
	if (mode == "add")
	{
		PLAdmin.showAddFeaturePanel("Add content",fsid);
	}
	else //edit
	{
		PLAdmin.showEditFeaturePanel("Edit content",fsid,fid);
	}
}

// our FramedCloud is same as OpenLayers.Popup.FramedCloud but allows for wider popups
function ct_setupFramedCloudWide () {
	ct_framedCloudWide = OpenLayers.Class(OpenLayers.Popup.Framed, {

    /** 
     * Property: contentDisplayClass
     * {String} The CSS class of the popup content div.
     */
    contentDisplayClass: "olFramedCloudPopupContent",

    /**
     * APIProperty: autoSize
     * {Boolean} Framed Cloud is autosizing by default.
     */
    autoSize: true,

    /**
     * APIProperty: panMapIfOutOfView
     * {Boolean} Framed Cloud does pan into view by default.
     */
    panMapIfOutOfView: true,

    /**
     * APIProperty: imageSize
     * {<OpenLayers.Size>}
     */
//    imageSize: new OpenLayers.Size(676, 736),
    imageSize: new OpenLayers.Size(1276, 736),

    /**
     * APIProperty: isAlphaImage
     * {Boolean} The FramedCloud does not use an alpha image (in honor of the 
     *     good ie6 folk out there)
     */
    isAlphaImage: false,

    /** 
     * APIProperty: fixedRelativePosition
     * {Boolean} The Framed Cloud popup works in just one fixed position.
     */
    fixedRelativePosition: false,

    /**
     * Property: positionBlocks
     * {Object} Hash of differen position blocks, keyed by relativePosition
     *     two-character code string (ie "tl", "tr", "bl", "br")
     */
    positionBlocks: {
        "tl": {
            'offset': new OpenLayers.Pixel(44, 0),
            'padding': new OpenLayers.Bounds(8, 40, 8, 9),
            'blocks': [
                { // top-left
                    size: new OpenLayers.Size('auto', 'auto'),
                    anchor: new OpenLayers.Bounds(0, 51, 22, 0),
                    position: new OpenLayers.Pixel(0, 0)
                },
                { //top-right
                    size: new OpenLayers.Size(22, 'auto'),
                    anchor: new OpenLayers.Bounds(null, 50, 0, 0),
                    //position: new OpenLayers.Pixel(-1238, 0)
                    position: new OpenLayers.Pixel(-1238, 0)
                },
                { //bottom-left
                    size: new OpenLayers.Size('auto', 19),
                    anchor: new OpenLayers.Bounds(0, 32, 22, null),
                    position: new OpenLayers.Pixel(0, -631)
                },
                { //bottom-right
                    size: new OpenLayers.Size(22, 18),
                    anchor: new OpenLayers.Bounds(null, 32, 0, null),
                    position: new OpenLayers.Pixel(-1238, -632)
                },
                { // stem
                    size: new OpenLayers.Size(81, 35),
                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
                    //position: new OpenLayers.Pixel(0, -688)
                    position: new OpenLayers.Pixel(0, -688)
                }
            ]
        },
        "tr": {
            'offset': new OpenLayers.Pixel(-45, 0),
            'padding': new OpenLayers.Bounds(8, 40, 8, 9),
            'blocks': [
                { // top-left
                    size: new OpenLayers.Size('auto', 'auto'),
                    anchor: new OpenLayers.Bounds(0, 51, 22, 0),
                    position: new OpenLayers.Pixel(0, 0)
                },
                { //top-right
                    size: new OpenLayers.Size(22, 'auto'),
                    anchor: new OpenLayers.Bounds(null, 50, 0, 0),
                    position: new OpenLayers.Pixel(-1238, 0)
                },
                { //bottom-left
                    size: new OpenLayers.Size('auto', 19),
                    anchor: new OpenLayers.Bounds(0, 32, 22, null),
                    position: new OpenLayers.Pixel(0, -631)
                },
                { //bottom-right
                    size: new OpenLayers.Size(22, 19),
                    anchor: new OpenLayers.Bounds(null, 32, 0, null),
                    position: new OpenLayers.Pixel(-1238, -631)
                },
                { // stem
                    size: new OpenLayers.Size(81, 35),
                    anchor: new OpenLayers.Bounds(0, 0, null, null),
                    //position: new OpenLayers.Pixel(-815, -687)
                    position: new OpenLayers.Pixel(-215, -687)
                }
            ]
        },
        "bl": {
            'offset': new OpenLayers.Pixel(45, 0),
            'padding': new OpenLayers.Bounds(8, 9, 8, 40),
            'blocks': [
                { // top-left
                    size: new OpenLayers.Size('auto', 'auto'),
                    anchor: new OpenLayers.Bounds(0, 21, 22, 32),
                    position: new OpenLayers.Pixel(0, 0)
                },
                { //top-right
                    size: new OpenLayers.Size(22, 'auto'),
                    anchor: new OpenLayers.Bounds(null, 21, 0, 32),
                    position: new OpenLayers.Pixel(-1238, 0)
                },
                { //bottom-left
                    size: new OpenLayers.Size('auto', 21),
                    anchor: new OpenLayers.Bounds(0, 0, 22, null),
                    position: new OpenLayers.Pixel(0, -629)
                },
                { //bottom-right
                    size: new OpenLayers.Size(22, 21),
                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
                    position: new OpenLayers.Pixel(-1238, -629)
                },
                { // stem
                    size: new OpenLayers.Size(81, 33),
                    anchor: new OpenLayers.Bounds(null, null, 0, 0),
                    //position: new OpenLayers.Pixel(-701, -674)
                    position: new OpenLayers.Pixel(-101, -674)
                }
            ]
        },
        "br": {
            'offset': new OpenLayers.Pixel(-44, 0),
            'padding': new OpenLayers.Bounds(8, 9, 8, 40),
            'blocks': [
                { // top-left
                    size: new OpenLayers.Size('auto', 'auto'),
                    anchor: new OpenLayers.Bounds(0, 21, 22, 32),
                    position: new OpenLayers.Pixel(0, 0)
                },
                { //top-right
                    size: new OpenLayers.Size(22, 'auto'),
                    anchor: new OpenLayers.Bounds(null, 21, 0, 32),
                    position: new OpenLayers.Pixel(-1238, 0)
                },
                { //bottom-left
                    size: new OpenLayers.Size('auto', 21),
                    anchor: new OpenLayers.Bounds(0, 0, 22, null),
                    position: new OpenLayers.Pixel(0, -629)
                },
                { //bottom-right
                    size: new OpenLayers.Size(22, 21),
                    anchor: new OpenLayers.Bounds(null, 0, 0, null),
                    position: new OpenLayers.Pixel(-1238, -629)
                },
                { // stem
                    size: new OpenLayers.Size(81, 33),
                    anchor: new OpenLayers.Bounds(0, null, null, 0),
                    //position: new OpenLayers.Pixel(-911, -674)
                    position: new OpenLayers.Pixel(-311, -674)
                }
            ]
        }
    },

    /**
     * APIProperty: minSize
     * {<OpenLayers.Size>}
     */
    minSize: new OpenLayers.Size(105, 10),

    /**
     * APIProperty: maxSize
     * {<OpenLayers.Size>}
     */
    maxSize: new OpenLayers.Size(1200, 660),

    /** 
     * Constructor: OpenLayers.Popup.FramedCloud
     * 
     * Parameters:
     * id - {String}
     * lonlat - {<OpenLayers.LonLat>}
     * contentSize - {<OpenLayers.Size>}
     * contentHTML - {String}
     * anchor - {Object} Object to which we'll anchor the popup. Must expose 
     *     a 'size' (<OpenLayers.Size>) and 'offset' (<OpenLayers.Pixel>) 
     *     (Note that this is generally an <OpenLayers.Icon>).
     * closeBox - {Boolean}
     * closeBoxCallback - {Function} Function to be called on closeBox click.
     */
    initialize:function(id, lonlat, contentSize, contentHTML, anchor, closeBox, 
                        closeBoxCallback) {

        this.imageSrc = OpenLayers.Util.getImagesLocation() + 'cloud-popup-relative.png';
	var rootpath = ( typeof ctv_rootpath == "undefined" ) ? "/" : ctv_rootpath;
        this.imageSrc =  rootpath + 'res/images/cloud-popup-relative-wide.png';
        OpenLayers.Popup.Framed.prototype.initialize.apply(this, arguments);
        this.contentDiv.className = this.contentDisplayClass;
    },

    /** 
     * APIMethod: destroy
     */
    destroy: function() {
        OpenLayers.Popup.Framed.prototype.destroy.apply(this, arguments);
    },

    CLASS_NAME: "OpenLayers.Popup.FramedCloud"
});


}

