/*
    PxMap - a GMap2 for PawTrax

    has a message control

    get/setMode() -- one of showing-all, showing-some, loading, zoom-in, zoom-out
    get/setMaxMappedMarkerCount(int)
    get/setMessageControl(ctrl)
    get/setPreviousBounds(bounds);
    get/setOldZoom(zoom)
    getOffViewMarkers()

    start/endDelicateProcedure()

    getOverlays()
    getMarkers()
    mapArray()

    has onZoomIn, onZoomOut, and onMoveEnd handlers

*/

function PxMap() {
    GMap2.apply(this,arguments);

	// setup map helpers
	setupGetOverlays(this);
	setupGetMarkers(this);
	setupMapArray(this);
    setupGetOffViewMarkers(this);
    setupZoomToMarkers(this);

	// setup controls
	this.setMessageControl(new BpControl('', new GSize(70,7)));
	this.addControl(this.getMessageControl());

	this.addControl(new GLargeMapControl());
	this.addControl(new GMapTypeControl());
	this.addControl(new GScaleControl());

    this.setDataUrl('/map/locations/json');
    this.setMaxMappedMarkerCount(50);

    GEvent.addListener(this, 'infowindowclose', this.setInfoWindowOpener);
}

for (var prop in GMap2.prototype)
    PxMap.prototype[prop] = GMap2.prototype[prop];

//var infoWindowOpener;
PxMap.prototype.requestData = function() {
    var postArgs = this.getParams();

	if (typeof(postArgs) == 'undefined')
		return;
    
	if (postArgs.mappedMarkerCount >= this.getMaxMappedMarkerCount()) {
		this.removeOverlays();
		this.mapVisibleAreas();
		this.setMode('area');
		return;
	}

    this.startDelicateProcedure();

    this.setMode('loading');
    BpDownloadUrl(this.getDataUrl(),GEvent.callback(this,this.processData),false,postArgs);
};

PxMap.prototype.processData = function(responseText) {
	// is the JSON good?
	var dataArray;
	try {
		dataArray = eval(responseText);
	}
	catch(e) {
		alert('Error evaluating responseText (PxMap0.1.js line ~72: ' + e + '): ' + responseText);
		this.endDelicateProcedure();
		return;
	}

	// did we get good data or an error message
	if (!dataArray[0]) {
		alert(dataArray[1]);
		this.endDelicateProcedure();
		return;
	}
	else {
		dataArray = dataArray[1];
	}

	// if this is the max that we can show, it's deemed to be showing-some, in which case we
	//  should show regions if there's more than one region to show, or areas, if there's more than
	//  one area to show
	if (dataArray.length + this.getMarkers().length >= this.getMaxMappedMarkerCount()) {
		// showing-some - show either area or region labels
		if (this.getZoom() <= 6) {
			this.removeOverlays();
			for (var i = 0; i < regions.length; i++)
				this.addOverlay(regions[i]);
			this.setMode('region');
		}
		// area mode
		else {
			this.removeOverlays();
			for (var i = 0; i < areas.length; i++)
				this.addOverlay(areas[i]);
			this.setMode('area');
		}
		this.setPreviousBounds(null);
		this.endDelicateProcedure();
		return;
	}

	// remove mapped labels
	var o = this.getOverlays();
	for (var i = 0; i < o.length; i++)
		if (o[i]._isRegionLabel || o[i]._isAreaLabel)
			this.removeOverlay(o[i]);

    if (dataArray.length == 0) {
        this.onAfterMapArray();
        return;
    }

    // limit the markers we're adding to the allowed limit
    dataArray.length = Math.min(dataArray.length, this.getMaxMappedMarkerCount() - this.getMarkers().length);

    var stepBy = 10;
	this.mapArray(dataArray, stepBy, createMarker, this.onAfterMapArray);
};

function createMarker(ud) {
	var lat = ud[LAT];
	var lng = ud[LNG];
	var latlng = new GLatLng(lat, lng);
	var marker = new PxMarker(latlng, ud);
	return marker;
}

PxMap.prototype.mapVisibleAreas = function() {
	var a = this.getVisibleAreas();
	for (var i = 0; i < a.length; i++)
		this.addOverlay(a[i]);
};

PxMap.prototype.getVisibleAreas = function() {
	var a = [];
	for (var i = 0; i < areas.length; i++)
		if (this.getBounds().contains(areas[i].getPoint()))
			a.push(areas[i]);
	return a;
};

PxMap.prototype.getVisibleRegions = function() {
	var a = [];
	for (var i = 0; i < regions.length; i++)
		if (this.getBounds().contains(regions[i].getPoint()))
			a.push(regions[i]);
	return a;
};

PxMap.prototype.onAfterMapArray = function() {
    if (this.getMarkers().length == this.getMaxMappedMarkerCount()) {
        this.setMode('showing-some');
	}
    else if (this.getMarkers().length == 0) {
		this.setMode('zoom-out');
    } else {
        this.setMode('showing-all');
	}

    this.endDelicateProcedure();
};

PxMap.prototype.onMoveEnd = function() {
    this.removeOffViewMarkers();

	manageCrumbs();

    if (this.getMode() != 'loading')
        this.requestData();
};

var message_for = {
    'loading' :     'Loading...',
    'region':       'Showing Region Labels',
    'area':         'Showing Area Labels',
    'showing-all':  'Showing All [count] Reports in View',
    'showing-some': 'Showing First [count] Reports in View',
	'zoom-out':     'No Reports in View<br/>Zoom Out to see Reports'
};
PxMap.prototype.onZoomIn  = function(oldZoom,newZoom) {
    if (!this.zoomingEnabled())
        return;

    // do something if we're in region or area mode
	var mode = this.getMode();
    if (mode == 'region' || mode == 'area') {
        this.setPreviousBounds(null);
        this.requestData();
    }
    // showing some - remove and reload
    else if (mode == 'showing-some') {
        this.removeOverlays();
        this.setPreviousBounds(null);
        this.requestData();
    }
    // showing all, remove old
    else if (mode == 'showing-all') {
        this.setPreviousBounds(this.getBounds());
        this.removeOffViewMarkers();
        var map = this;
        setTimeout(function(){
            var m = map.getMarkers();
            var msg;
            if (m.length > 0) {
                msg = message_for['showing-all'].replace(/\[count\]/,map.getMarkers().length);
                map.getMessageControl().setContent(msg);
            }
            else {
                map.setMode('zoom-out');
            }
        },50);
    }
	else if (mode == 'zoom-out') { // most likely a setCenter?
		this.removeOverlays();
		this.setPreviousBounds(null);
		this.requestData();
	}
    else {
    	alert('unknown mode "'+mode+'" in onZoomIn');
    }
	manageCrumbs();
};

PxMap.prototype.onZoomOut = function(oldZoom,newZoom) {
    if (!this.zoomingEnabled())
        return;

	manageCrumbs();

	// we're out as far as we can go
    if (this.getMode() == 'region')
        return;

    // find out if we can show areas or locations
	else
	    this.requestData();
};

var first = true;
PxMap.prototype.setCenter = function(latlng,zoom) {
    GMap2.prototype.setCenter.apply(this,arguments);

	if (first)
		first = false;
	else
		return;

    // setup listeners
    setupOnEndListeners(this,{
        'zoomIn'  : this.onZoomIn,
        'zoomOut' : this.onZoomOut,
        'moveEnd' : this.onMoveEnd
    });

	// setup the tooltip
/*
	var tooltip = new BpTooltip(this.getCenter(),'',true);
	tooltip.isTooltip = true;
	tooltip._ignoreOverlay = true; // for getOverlays() & friends
    this.setTooltip(tooltip);
	this.addOverlay(tooltip);
*/
    this.setMode('region');
    this.getMessageControl().show();
};

PxMap.prototype.getParams = function() {
    var postData = {};

	// set the custom search params here

	postData.species    = document.getElementById('species').value;
	postData.name       = document.getElementById('name').value;
	postData.type       = document.getElementById('type').value;
	postData.postcode   = document.getElementById('postcode').value;

	if (/^\d\d\/\d\d\/\d\d\d\d$/.test(document.getElementById('start_date').value)) {
		postData.start_date = document.getElementById('start_date').value;
	}
	else if (/\d/.test(document.getElementById('start_date').value)) {
		alert('Start Date must be in the form: DD/MM/YYYY');
		return;
	}

	// end custom search param setting

	postData.mappedMarkerCount = this.getMarkers().length;

    var bounds = this.getBounds();
	postData.top    = bounds.getNorthEast().lat();
	postData.bottom = bounds.getSouthWest().lat();
	postData.left 	= bounds.getSouthWest().lng();
	postData.right 	= bounds.getNorthEast().lng();

    var prevBounds = this.getPreviousBounds();
	if(prevBounds) {
		postData.notop 		= prevBounds.getNorthEast().lat();
		postData.nobottom   = prevBounds.getSouthWest().lat();
		postData.noleft 	= prevBounds.getSouthWest().lng();
		postData.noright 	= prevBounds.getNorthEast().lng();
	}

	this.setPreviousBounds(bounds);

    return postData;
};
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
// Marker methods
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////

GMarker.prototype.whenClicked = function() {
	var map = this.getMap();
	map.closeInfoWindow();
	map.setInfoWindowOpener(this);

	var userData = this.getUserData();
	this.openInfoWindowHtml(getInfoWindowContent(userData));
}

function getInfoWindowContent(userData) {
    return  'This is the default infoWindow content.';
}

var gmarker_remove_ = GMarker.prototype.remove;
GMarker.prototype.remove = function() {
    if (map.getInfoWindowOpener() === this)
        map.closeInfoWindow();

    gmarker_remove_.apply(this,arguments);
};

function escapeHTML(html) {
    return html.replace(/</,'&lt;').replace(/>/,'&gt;').replace(/&/,'&amp;').replace(/"/,'&quot;');
}

GMarker.prototype.getMap = function() {
    return this._map;
};

GMarker.prototype.setMap = function(map) {
    this._map = map;
};

GMarker.prototype.getUserData = function() {
    return this._userData;
};

GMarker.prototype.setUserData = function(userData) {
    this._userData = userData;
};

////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
// ho-hum routines below
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

PxMap.prototype.removeOffViewMarkers = function() {
    var m = this.getOffViewMarkers();
    for (var i = 0; i < m.length; i++)
        this.removeOverlay(m[i]);
};

PxMap.prototype.getMode = function() {
    return this._mode;
};

var modes = [];
for(var prop in message_for) {
	modes.push(prop);
}
PxMap.prototype.setMode = function(mode) {
	var found = false;
	for (var i = 0; i < modes.length; i++) {
		if (modes[i] == mode) {
			found = true;
			break;
		}
	}
    if (!found) {
        alert('Only these map modes are valid: ' + modes.join(', ') + '; not: ' + mode);
        return;
    }

    this._mode = mode;

    var message = message_for[mode].replace(/\[count\]/, this.getMarkers().length);
    this.getMessageControl().setContent(message);
};

PxMap.prototype.getMessageControl = function() {
    return this._control;
};

PxMap.prototype.setMessageControl = function(ctrl) {
    this._control = ctrl;
};

PxMap.prototype.getMaxMappedMarkerCount = function() {
    return this._maxMappedMarkerCount;
};

PxMap.prototype.setMaxMappedMarkerCount = function(maxMappedMarkerCount) {
    this._maxMappedMarkerCount = maxMappedMarkerCount;
};

PxMap.prototype.getPreviousBounds = function() {
    return this._previousBounds;
};

PxMap.prototype.setPreviousBounds = function(previousBounds) {
    this._previousBounds = previousBounds;
};

PxMap.prototype.getTooltip = function() {
    return this._tooltip;
};

PxMap.prototype.setTooltip = function(tooltip) {
    this._tooltip = tooltip;
};

PxMap.prototype.getDataUrl = function() {
    return this._dataUrl;
};

PxMap.prototype.setDataUrl = function(dataUrl) {
    this._dataUrl = dataUrl;
};

PxMap.prototype.getInfoWindowOpener = function() {
    return this._infoWindowOpener;
};

PxMap.prototype.setInfoWindowOpener = function(infoWindowOpener) {
    this._infoWindowOpener = infoWindowOpener;
};

