var m = null;

var RAD_TO_DEG = (180.0 / Math.PI);
var TILES_MEDIA_URL = "/media/tiles/t/";
var TILES_IMG_FORMAT = ".gif";
var TILES_OPACITY = 0.67;

var ENTRIES_MIN_ZOOM_DISPLAY_ALL = 4;
var REFRESH_RATE_MS = 75*1000;

var globalSavedMapPositionZoom = null;
var globalSavedMapPositionCenter = null;

var globalLanguage = 'bg';
var globalDistrict = 'Sofia';

var globalMapsSettings = {
		
	'traffic': ['this.preStartClickEvent()', 'this.preAddEntries()', 'this.restrictMapZoom(11,17)', 'this.preAddTiles()'],
	'entries': ['this.preStartClickEvent()', 'this.preAddEntries()', 'this.restrictMapZoom(11,17)', 'this.preAddTiles()'],
	'routes':  ['this.stopClickEvent()', 'this.preAddEntries()', 'this.restrictMapZoom(11,17)', 'this.preAddTiles()'],
	'ptroutes':['this.stopClickEvent()', 'this.removeEntries()', 'this.restrictMapZoom(11,17)', 'this.preAddTiles()'],
	'sumcroutes':['this.stopClickEvent()', 'this.restrictMapZoom(11,17)'],
	'sumcmap':['this.preStartClickEvent()', 'this.preAddEntries()', 'this.preAddTiles()', 'this.restrictMapZoom(11,17)']
};




//$(document).unload(GUnload);

function Map(aDivId) {

	this.map = null;
	this.mapDivId = aDivId;

	this.fZoom = 12;
	this.fZoomMin = 12;
	this.fZoomMax = 16;
	this.fCenterZoom = 15;
	this.fCenterCoords = [42.690511,23.316421];
	this.fAllowedBounds = new GLatLngBounds(new GLatLng(42.574574, 23.111114), new GLatLng(42.833873, 23.570137));
	this.fAberration = 0.2;

	this.fIsMapEmbedded = false;

	this.fTilesEnabled = true;

	this.fEntriesEnabled = true;

	this.fLegendEnabled = true;

	this.fClickEventEnabled = true;

	this.fTixTileLayer = null;
	this.fSetIntervalId = null;

	this.fClickedEntry = {pathEnc: null, areaEnc: null, path: null, area: null};


	this.entries = [];
	this.entriesBounds = [];

	this.crossroadIcon = new GIcon();
	this.crossroadIcon.image = '/media/img/sign_crossroad.gif';
	this.crossroadIcon.iconSize = new GSize(24,36); 
	this.crossroadIcon.iconAnchor = new GPoint(10, 36); 

}

Map.prototype.setSettings = function(aSettings) {
	
	this.fZoom 			= typeof(aSettings.zoom) !== 'undefined' ? aSettings.zoom : this.fZoom;
	this.fZoomMin 		= typeof(aSettings.zoomMin) !== 'undefined' ? aSettings.zoomMin : this.fZoomMin;
	this.fZoomMax 		= typeof(aSettings.zoomMax) !== 'undefined' ? aSettings.zoomMax : this.fZoomMax;
	this.fCenterZoom 	= typeof(aSettings.centerZoom) !== 'undefined' ? aSettings.centerZoom : this.fCenterZoom;

	this.fCenterCoords 	= typeof(aSettings.centerCoords) !== 'undefined' ? aSettings.centerCoords : this.fCenterCoords;

	this.fIsMapEmbedded = typeof(aSettings.isMapEmbedded) !== 'undefined' ? aSettings.isMapEmbedded : this.fIsMapEmbedded;
	this.allowedBounds 	= typeof(aSettings.allowedBounds) !== 'undefined' ? aSettings.allowedBounds : this.allowedBounds;
	this.fAberration 	= typeof(aSettings.aberration) !== 'undefined' ? aSettings.aberration : this.fAberration;

	this.fTilesEnabled 	= typeof(aSettings.tilesEnabled) !== 'undefined' ? aSettings.tilesEnabled : this.fTilesEnabled;
	this.fEntriesEnabled = typeof(aSettings.entriesEnabled) !== 'undefined' ? aSettings.entriesEnabled : this.fEntriesEnabled;

	this.fClickEventEnabled = typeof(aSettings.clickEventEnabled) !== 'undefined' ? aSettings.clickEventEnabled : this.fClickEventEnabled;
};



Map.prototype.initMap = function() {
	if (GBrowserIsCompatible()) {
		this.map = new GMap2(document.getElementById(this.mapDivId), {mapTypes:[G_NORMAL_MAP]});
		this.map.enableScrollWheelZoom();
		globalSavedMapPositionZoom = this.fZoom;
		globalSavedMapPositionCenter = new GLatLng(this.fCenterCoords[0], this.fCenterCoords[1]);
		this.map.setCenter(globalSavedMapPositionCenter, globalSavedMapPositionZoom);

		if (globalMapTypes) {
			if (globalMapType != globalMapTypes.news) {
				this.map.addControl(new GLargeMapControl());
			} 
		}
		this.restrictMapZoom(this.fZoomMin, this.fZoomMax);
		this.boundsClickEvent();
		
		$(".prMapPage").bind("click", this, this.printMapPage);
		
		GEvent.bind(this.map, "infowindowclose", this, this.clearMap);
		
		
		if (this.fLegendEnabled) {
			this.addLegend();
		}

		if (this.fIsMapEmbedded) {
			HOTZONES_URL = "/embedded/hotzones/";
		} else {
			HOTZONES_URL = "/zones/hotzones/";
		}		
		
		
	}
};

Map.prototype.clearMap = function() {

	if (this.fClickedEntry.pathEnc) {
		this.map.removeOverlay(this.fClickedEntry.pathEnc);
	}

	if (this.fClickedEntry.path) {
		this.map.removeOverlay(this.fClickedEntry.path);
	}

	if (this.fClickedEntry.area) {
		this.map.removeOverlay(this.fClickedEntry.area);
	}	
	
	if (this.fClickedEntry.areaEnc) {
		this.map.removeOverlay(this.fClickedEntry.areaEnc);		
	}	
	
};



Map.prototype.loadMap = function(aMapName) {

	if (globalMapsSettings[aMapName]) {
		
		for (var i = 0; i < globalMapsSettings[aMapName].length; i++) {
			eval(globalMapsSettings[aMapName][i]);
		}
	}
};

Map.prototype.preStartClickEvent = function() {	
	if (this.fClickEventEnabled) {
		this.startClickEvent();
	}	
};

Map.prototype.preAddTiles = function() {
	if (this.fTilesEnabled && (this.fTixTileLayer == null)) {
		this.addTiles();
		this.removeStaticImagesOnTilesLoaded();
		this.fSetIntervalId = setInterval('updateZoneInfo();', REFRESH_RATE_MS);	
	}
	
};

Map.prototype.preAddEntries = function() {
	if (this.fEntriesEnabled && (this.entries.length === 0)) {
		this.addEntries();
	}
};


Map.prototype.zoom = function(aZoomLevel) {
	this.map.setZoom(aZoomLevel);
};


Map.prototype.finMap = function() {
	this.entriesBounds = [];	
	
	this.removeEntries();
	this.removeTiles();
};

Map.prototype.stopUpdateZoneInfo = function() {
	if (this.fSetIntervalId) {
		clearInterval(this.fSetIntervalId);
	}
};

Map.prototype.addLegend = function() {

	this.$legend = $("#dLegend");
	this.$legendWrapper = $("#dLegendWrapper");
	this.$btnCloseLegend = $("#iClose");

	this.$legend.bind("click", this, this.handleLegendOpenEvent);
	this.$btnCloseLegend.bind("click", this, this.handleLegendCloseEvent);

};

Map.prototype.removeStaticImagesOnTilesLoaded = function() {
	this.tilesLoadedListener = GEvent.bind(this.map, "tilesloaded", this, this.handleTilesLoaded);
};

Map.prototype.handleTilesLoaded = function() {
	$dStaticMapDiv = $('#dMapStatic');
	if ($dStaticMapDiv.length > 0) {
		$dStaticMapDiv.hide();
	} else {
		$dStaticMapDivSmall = $('#dMapStaticSmall');
		if ($dStaticMapDivSmall.length > 0) {
			$dStaticMapDivSmall.hide();
		}
	}
};

Map.prototype.addTiles = function() {
	var copyright = new GCopyrightCollection('');
	copyright.addCopyright(new GCopyright('Tix.bg', new GLatLngBounds(
			new GLatLng(-90, -180), new GLatLng(90, 180)), 0, '©2010 tix.bg'));
	
	var tilelayer = new GTileLayer(copyright);
	tilelayer.getTileUrl = function(aTile, aZoom) {
		
		//////////////////////TODOTODOT:!!!!!!!!!!!!!!!!!!!!!

		return  TILES_MEDIA_URL + LAST_BN + '/' + aZoom + '/' + aTile.x + '_' + aTile.y + TILES_IMG_FORMAT;
	};
	tilelayer.isPng = function() {
		return false;
	};
	tilelayer.getOpacity = function() {
		return TILES_OPACITY;
	};

	this.fTixTileLayer = new GTileLayerOverlay(tilelayer);
	this.map.addOverlay(this.fTixTileLayer);
	return this.fTixTileLayer;
};


Map.prototype.removeTiles = function() {
	if (this.fTixTileLayer) {
		this.map.removeOverlay(this.fTixTileLayer);
		this.fTixTileLayer = null;
	}
	this.stopUpdateZoneInfo();
};

Map.prototype.addEntries = function() {
	if (globalEntries && this.map) {

		this.entries = [];
		for (var i in globalEntries) {
			var e = globalEntries[i];
			var mr = null;
			var eb = new GLatLngBounds();

			if (e.lat && e.lng) {
				mr = new MarkerLight(new GLatLng(e.lat, e.lng), {image: '/media/img/entries/' + e.entrytype_id + '-16.gif', width: 16, height: 24});
				eb.extend(mr.getPoint());
			}

			eb.entryInfo = e;
			eb.overlay = mr;
			this.entriesBounds.push(eb);

			if (mr != null) {
				mr.entryId = parseInt(e.id);
				mr.entryTypeId = parseInt(e.entrytype_id);
				mr.marker = mr;

				mr.PEP = e.PEP;
				mr.PEL = e.PEL;
				mr.path = e.path;
				
				mr.AEL = e.AEL;
				mr.AEP = e.AEP;
				mr.area = e.area;


				this.entries.push(mr);
				this.map.addOverlay(mr);
			}
		}
	}
};

Map.prototype.removeEntries = function() {

	for (var i = 0; i < this.entries.length; i++) {
		if (this.entries[i]) {
			this.map.removeOverlay(this.entries[i]);
		}
	}
	
	this.entries = [];
};



////-----------------------------------------------------


Map.prototype.startClickEvent = function() {
	if (this.clickEventListener == null) {
		this.clickEventListener = GEvent.bind(this.map, "click", this, this.handleMapClick);
	}
};


Map.prototype.stopClickEvent = function() {
	if (this.clickEventListener != null) {
		GEvent.removeListener(this.clickEventListener);
		this.clickEventListener = null;
	}
};

Map.prototype.boundsClickEvent = function() {
	this.boundsEventListener = GEvent.bind(this.map, "move", this, this.checkMapBounds);  
};

Map.prototype.addEntryInfoToMap = function(aOverlay) {
	this.clearMap();
			
	this.fClickedEntry = aOverlay;
	this.fClickedEntry.path = null;
	this.fClickedEntry.area = null;

	if (aOverlay.AEP && aOverlay.AEL) {

		var area = new GPolygon.fromEncoded({
			polylines: [
						{points: aOverlay.AEP,
						 levels: aOverlay.AEL,
						 color: "#0000ff",
						 opacity: 0.2,
						 weight: 3,
						 numLevels: 4,
						 zoomFactor: 32}
			],
			fill: true,
			color: "#0000ff",
			opacity: 0.2,
			outline: true
		});
		
		this.fClickedEntry.areaEnc = area;	
		this.map.addOverlay(area);			
	} else if (aOverlay.area) {
		
	}
	
	//polyline
	if (aOverlay.PEP && aOverlay.PEL) {
		var path = new GPolyline.fromEncoded({
						points: aOverlay.PEP,
						levels: aOverlay.PEL,
						color: "#FF0000",
						opacity: 0.7,
						weight: 5,
						numLevels: 4,
						zoomFactor: 32
					});
		
		this.fClickedEntry.pathEnc = path;	
		this.map.addOverlay(path);		
	} else if (aOverlay.path) {
		//
	}


};

Map.prototype.handleMapClick = function(aOverlay, aGLatLng) {
	
	if (aOverlay != null) {
		if (aOverlay.entryId) {
			// all entry overlays have "marker" property
			this.showEntryInfo(aOverlay.marker, aOverlay.entryId);
			this.addEntryInfoToMap(aOverlay);
		}
	}
};

Map.prototype.restrictMapZoom = function(aFromZoomLevel, aToZoomLevel) {
	if (
			(0 < aFromZoomLevel && aFromZoomLevel <= 19)
			&& (0 < aToZoomLevel && aToZoomLevel <= 19)
			&& (aFromZoomLevel < aToZoomLevel)
		) {
		var maptypes = this.map.getMapTypes();
		// Overwrite the getMinimumResolution() and getMaximumResolution() methods
		for (var i = 0; i < maptypes.length; i++) {
			maptypes[i].getMinimumResolution = function() {return aFromZoomLevel;};
			maptypes[i].getMaximumResolution = function() {return aToZoomLevel;};
		}

	} else {
		//alert???
	}
};

Map.prototype.checkMapBounds = function () {
	// Perform the check and return if OK
	var currentBounds = this.map.getBounds();
	var cSpan = currentBounds.toSpan(); // width and height of the bounds
	var offsetX = cSpan.lng() / (2 + this.fAberration); // we need a little border
	var offsetY = cSpan.lat() / (2 + this.fAberration);
	var C = this.map.getCenter(); // current center coords
	var X = C.lng();
	var Y = C.lat();

	// now check if the current rectangle in the allowed area
	var checkSW = new GLatLng(C.lat()-offsetY,C.lng()-offsetX);
	var checkNE = new GLatLng(C.lat()+offsetY,C.lng()+offsetX);
	
	if (this.fAllowedBounds.containsLatLng(checkSW) &&
			this.fAllowedBounds.containsLatLng(checkNE)) {
		return; // nothing to do
	}

	var AmaxX = this.fAllowedBounds.getNorthEast().lng();
	var AmaxY = this.fAllowedBounds.getNorthEast().lat();
	var AminX = this.fAllowedBounds.getSouthWest().lng();
	var AminY = this.fAllowedBounds.getSouthWest().lat();

	if (X < (AminX+offsetX)) {X = AminX + offsetX;}
	if (X > (AmaxX-offsetX)) {X = AmaxX - offsetX;}
	if (Y < (AminY+offsetY)) {Y = AminY + offsetY;}
	if (Y > (AmaxY-offsetY)) {Y = AmaxY - offsetY;}

	this.map.setCenter(new GLatLng(Y,X));
};


Map.prototype.centerFeature = function(aPolygon, aPolyline, aPoint, aBounds) {

	var bPolygon = (aPolygon == null) ? null : aPolygon.getBounds();
	var bPolyline = (aPolyline == null) ? null : aPolyline.getBounds();
	var bounds =  null;

	if (aBounds) {
		bounds = aBounds;
	} else if (bPolygon && bPolyline) {
		if (bPolygon.containsBounds(bPolyline)) {
			bounds = bPolygon;
		} else
		if (bPolyline.containsBounds(bPolygon)) {
			bounds = bPolyline;
		} else {
			bounds = new GLatLngBounds(bPolygon.getSouthWest(), bPolygon.getNorthEast());
			bounds.extend(bPolyline.getNorthEast());
			bounds.extend(bPolyline.getSouthWest());
		}
	} else if (bPolygon) {
		bounds = bPolygon;
	} else if (bPolyline) {
		bounds = bPolyline;
	}

	if (bounds) {
		var zoom = this.map.getBoundsZoomLevel(bounds);
		var center = bounds.getCenter();
		this.map.setCenter(center, zoom);
	} else if (aPoint) {
		this.map.setCenter(aPoint, this.fCenterZoom);
	}
};

Map.prototype.printMapPage = function() {
	if (document.all) { // handle IE
		var ieOpacity = parseInt(TILES_OPACITY*100);
		var ieOpacityFilterStr = 'alpha(opacity=' + ieOpacity + ')';
		
		// TODO: reference to m
		var $tiles = $("#" + m.mapDivId + " img[src*=" + TILES_MEDIA_URL + "]");
		$tiles.each(function(aIdx) { 
			this.style.filter = null;
		});
		
		window.print();
		
		$tiles.each(function(aIdx) { 
			this.style.filter = ieOpacityFilterStr;
		});
	} else {
		window.print();
	}
};
/////////-----------------------------Legend functionallity-------------------------------


Map.prototype.handleLegendOpenEvent = function(aEvent) {
	aEvent.preventDefault();
	var self = aEvent.data; //"this" here points to the DOM element; aEvent.data contains the DetailedMap instance
	self.$legend.hide();
	self.$legendWrapper.show();
	return false;
};

Map.prototype.handleLegendCloseEvent = function(aEvent) {
	aEvent.preventDefault();
	var self = aEvent.data; 


	self.$legendWrapper.hide();
	self.$legend.show();
	return false;
};



/////----------------------------------Tiles and zones update----------------------------------------------


function updateZoneInfo() {
	updateHotzoneInfo(); // this sets new value of the LAST_BN and CALC_DATE
	updateTileLayers();
	updateCalculationDate();
}

function updateCalculationDate() {
	if (typeof(CALC_DATE) !== 'undefined') {
		$('#dCalcDate').html(CALC_DATE);
	}
}

function updateHotzoneInfo() {
	
	var prevOpenZlDiv = $("div[class=dhtzelement] div[class=dhtzLoc accordActive]").parent("div[class=dhtzelement]");
	var prevOpenZlDivId = (prevOpenZlDiv.length > 0) ? prevOpenZlDiv.attr('id') : "" ;

	globalSavedMapPositionZoom = m.map.getZoom();
	globalSavedMapPositionCenter = m.map.getCenter();

	
	$.ajax({
		url : HOTZONES_URL + "?r="+ Math.random(),
		data: null,
		type : "get",
		async : true,
		success: function (aData) {
			var $tb = $('#dTrafficBox');
			if ($tb.length > 0) {
				$tb.html(aData);
			} else {
				var $tbSmall = $('#dTrafficBoxSmall');
				if ($tbSmall.length) {
					$tbSmall.html(aData);
				}
			}

			if (prevOpenZlDivId) {
				$dhtz = $('#' + prevOpenZlDivId + ' .dhtzLoc');
				if ($dhtz.length > 0) {
					$dhtz.click(); // this focuses the map again and "reset" the marker 
				} else {
					// remove only the marker from the map
					if (globalLocationMarker) {
						m.map.removeOverlay(globalLocationMarker);
					}
				}
			}	
			
//			return the map to the prev position
			m.map.setCenter(globalSavedMapPositionCenter, globalSavedMapPositionZoom);
		},
		error: function (aXMLHttpRequest, aTextStatus, aErrorThrown) {
			// return
		}
	});
}

function updateTileLayers() {
	$tiles = $("#dMap img[src*=" + TILES_MEDIA_URL + "]");
	
	var tileRegex = new RegExp('(?:' + TILES_MEDIA_URL + ')' + '(\\d+)/', 'g');
	tileRegex.compile(tileRegex);
	
	$tiles.each(function(aIdx) { 
		this.src = this.src.replace(tileRegex, TILES_MEDIA_URL + LAST_BN + '/');
	});
}


//////////////-------------------------------Entries---------------------------------------

Map.prototype.getEntry = function(aEntryId) {
	for (var i=0; i < m.entries.length; i++) {
		var e = m.entries[i];
		if (e.entryId == aEntryId) {
			return e;
		}
	}	
};

Map.prototype.showEntryInfo = function(aMarker, aEntryId, aEntryData) {
	
	$.get("/" + globalLanguage + "/" + globalDistrict + "/entry/" + aEntryId, function(aData) {
		aMarker.openInfoWindowHtml(aData, {maxWidth: 350});
		if (aEntryData) {
			m.addEntryInfoToMap(aEntryData);
		}		
	});
};

Map.prototype.showEntryInfoByEntry = function(aEntry) {
	$.get("/" + globalLanguage + "/" + globalDistrict + "/entry/" + aEntry.entryId, function(aData) {
		m.map.openInfoWindowHtml(aEntry.marker.latlng, aData, {maxWidth: 350});
	});
};


Map.prototype.centerZoneLocation = function(aZlId) {
	for (var i=0; i < globalZoneLocationsData.length; i++) {
		var zl = globalZoneLocationsData[i];
		if (zl.zlId == aZlId) {
			var latLng = new GLatLng(zl.zlLat, zl.zlLng);
			this.centerFeature(null, null, latLng, null);
			
			var marker = new GMarker(latLng, {clickable: false, icon: this.crossroadIcon, zIndexProcess: function(marker,b) {return 1000;}});
			return marker;
		}
	}
};


Map.prototype.centerEntry = function(aEntryId) {
	
	for (var i=0; i < this.entries.length; i++) {
		var e = this.entries[i];
		if (e.entryId == aEntryId) {
			this.centerFeature(null, null, e.marker.latlng, null); //gives error: too much recursion in firefox
			this.showEntryInfo(e.marker, aEntryId, e);
			return;
		}
	}
};


function showTraffic() {	
	if (typeof(m) !== 'undefined' && m) {
		m.loadMap('traffic');
		//$(".infoBox").hide();
		$('#dTrafficBox').show();

		var trafficTab = $('#dTraffic');
		if (!trafficTab.hasClass('tabActive'))	{
			$('.tabBtn').removeClass('tabActive');
			trafficTab.addClass('tabActive');
		}
		
	}	
}

function showEntries() {
	
	if (typeof(m) !== 'undefined' && m) {
		
		//m.loadMap('traffic');
		m.loadMap('entries');
		$(".infoBox").hide();
		$('#dEventsBox').show();
		
		var eventsTab = $('#dEvents');
		if (!eventsTab.hasClass('tabActive'))	{
			$('.tabBtn').removeClass('tabActive');
			eventsTab.addClass('tabActive');
		}		
	}		
}

function showRoutes() {
	
	if (typeof(m) !== 'undefined' && m) {

		$(".infoBox").hide();
		m.loadMap('routes');
		$('#dRoutesBox').show();

		var routesTab = $('#dRoutes');
		if (!routesTab.hasClass('tabActive'))	{
			$('.tabBtn').removeClass('tabActive');
			routesTab.addClass('tabActive');
		}
					
		ptRoutesFinFunction();
		routesInitFunction();
	}	
}

function showPTRoutes(aPrefix) {
	
	if ((typeof(aPrefix) == 'undefined') || (aPrefix == null)) {
		aPrefix = PT_ROUTES_SUFFIX; //default parameter
	}
	
	if (typeof(m) !== 'undefined' && m) {
		$(".infoBox").hide();
		m.loadMap('ptroutes');
		$('#dRoutesPTBox').show();

		var routesTab = $('#dRoutesPT');
		if (!routesTab.hasClass('tabActive'))	{
			$('.tabBtn').removeClass('tabActive');
			routesTab.addClass('tabActive');
		}
			
		routeFinFunction();
		//aPrefix PT_ROUTES_SUFFIX
		ptRoutesInitFunction(aPrefix);
	}
}

function handleEntriesOnClick(aEvent) {
	if (m) {
		var id = $(this).attr('id');
		var eText = id.substring(0,1);
		if (eText == 'e') {
			var eId = id.substring(1);
			m.centerEntry(eId);
			document.getElementById("mapholder").scrollIntoView();
			return false;
		}
	}
}
