

function Viewport( map ) {
	this.tileDimensions = { x: 3, y: 3 };
	this.map = map;
	
	this.DISPLAY_CLUSTER_THRESHOLD = 6;
	this.USE_SUMMARY_REQUEST_STRATEGY = true;
	this.MAX_ZOOM_IN = 15;
	this.sb = null;
	this.tours = []; // list of tours that will be displayed in Viewport

	this.cm = new ClusterManager( this.map );
		
	this.DEBUG = false;
	
}

Viewport.prototype.showLoading = function() {
	$j('#gmapLoadingIcon').show();
}
Viewport.prototype.hideLoading = function() {
	$j('#gmapLoadingIcon').hide();
}

Viewport.prototype.debug = function( msg ) {
	if( this.DEBUG == true ) { GLog.write( "VirePort: " + msg ); } 
}

Viewport.prototype.setSideBar = function( sb ) {
	this.sb = sb;
}

Viewport.prototype.needUpdate = function() {
	return ( this.currentViewport == null || !this.currentViewport.bounds.containsBounds( this.map.getBounds() ) 
			|| this.currentViewport.zoom != this.map.getZoom() );
}

Viewport.prototype.update = function() {
	this.setCurrentViewport();
	this.updateActivities();	
}

Viewport.prototype.setCurrentViewport = function() {
	this.currentViewport = this.getCurrentViewport();
}

Viewport.prototype.click = function( overlay, latlng ) {
	
	if( overlay instanceof Cluster ) {
		clu = overlay;
	} else if ( overlay == null ) {
		clu = this.cm.getClusterButtonAt( latlng );
	} 
	
	if( clu instanceof Cluster ) {
		if( clu.getNumberOfMarkers() == 1 ) {
			var cluData = clu.getClusterData();			
			if( param.smallMap ) {
				if( cluData[0].detailLink ) {
					
					// prepend domain if url starts with /
					if( cluData[0].detailLink.indexOf('/') == 0 ) { reLink = param.hostName; }
					reLink += cluData[0].detailLink;
					location.href = reLink;
				}
			}
			else if( this.sb != null ) { 
				if( !this.sb.setActiveElement( cluData[0] ) ) {
					this.sb.handleViewPortClickOnActivity();
				}
			}
		}
		else {
			//if( this.sb != null ) { this.sb.setActiveElement( null ); }
			var newZoom = this.map.getBoundsZoomLevel( this.cm.getTileAt( clu.getCenter() ).getBounds() );
			this.map.setZoom( ( ( newZoom < this.MAX_ZOOM_IN ) ? newZoom : this.MAX_ZOOM_IN ) );
			this.map.setCenter( clu.getCenter() );		
		}		
	}
	else {		
		if( this.sb != null ) { this.sb.setActiveElement( null ); }
	}
	
	return;
} 

Viewport.prototype.getCurrentViewport = function() {
	var bounds = this.map.getBounds();
	var span = bounds.toSpan();
	
	var extendedBounds = new GLatLngBounds( 
		new GLatLng( bounds.getSouthWest().lat() - span.lat(), bounds.getSouthWest().lng() - span.lng() ),
		new GLatLng( bounds.getNorthEast().lat() + span.lat(), bounds.getNorthEast().lng() + span.lng() )
	);	
		
	return { bounds: extendedBounds, zoom: this.map.getZoom() };
}

Viewport.prototype.getVPCenter = function() {
	return this.currentViewport.bounds.getCenter();	
}

Viewport.prototype.getViewportParameters = function() {
	var b = this.currentViewport.bounds;
	
	rv = "rectX=" + b.getSouthWest().lng();
	rv += "&rectY=" + b.getSouthWest().lat();
	rv += "&rectWidth=" + b.toSpan().lng();
	rv += "&rectHeight=" + b.toSpan().lat();
	
	return rv;
}

Viewport.prototype.getViewportParametersObject = function() {
	b = this.currentViewport.bounds;
	
	return { 	
		"rectX": b.getSouthWest().lng(),
		"rectY": b.getSouthWest().lat(),
		"rectWidth": b.toSpan().lng(),
		"rectHeight": b.toSpan().lat() 
 	};
}

Viewport.prototype.addTour = function( tour ) {
	this.tours.push( tour );
}


Viewport.prototype.getRegionRequestObj = function() {
	if( param.admregion && param.regionId ) { return { "parentOregion": param.regionId }; }
	if( !param.admregion && param.regionId ) { return { "parentRegion": param.regionId }; }
	else { return {}; }
}

Viewport.prototype.updateActivities = function() {
	
	this.showLoading();
	this.map.clearOverlays();
	this.cm.init( this.tileDimensions );
	
	requests = [];
	var activityRequest  = {};
	
	if( param.tourId ) {
		activityRequest = 
			{ "partner": "Summer",
			  "activityType": "A",
			  "requestObj": "MIXED",
			  "firstElementType": skiinfoMap.TYPE_TOUR,
			  "firstElementId": param.tourId,
			  "offset": 0,
			  "limit": 1			
			}; 
	}
	else {
		if( this.USE_SUMMARY_REQUEST_STRATEGY ) {
			var summaryWhen = this.DISPLAY_CLUSTER_THRESHOLD;	// Default.
			if( this.map.getZoom() >= this.MAX_ZOOM_IN - 1 ) {
				// At maximum zoom level, only make clusters when absolutely
				// necessary.
				summaryWhen = 40; 
			}
			activityRequest = jQuery.extend( 
				{ "partner": "Summer",
				  "summaryWhen": summaryWhen,
				  "activityType": "A",
				  "requestObj": "MULTIMIXED"
				},
				skiinfoMap.getFilters(),
				this.getViewportParametersObject(),
				this.cm.getGridParametersObject()
				// show all activities
				//, this.getRegionRequestObj()
			);
		} 
	}

	requests.push( activityRequest );
	var newRequest = jQuery.toJSON( { "requests": requests } );	
	this.XHR( newRequest );
}

Viewport.prototype.XHR = function( newRequest ) {
	this.queryCounter++;	
	jQuery.getJSON( skiinfoMap.gmapFeedURL + "?callback=?", { "postdata": newRequest }, this.parseResult.bind( this ) );		
}

Viewport.prototype.parseResult = function( reply ) {
	
	dests = [];
	
	this.debug( "reply.length = " + reply.length );
	
	for( var i = 0; i < reply.length; i++ ) {
		dests = dests.concat( reply[i].result );
		this.debug( "reply[" + i + "].result.length (how many 'clu's are in this request) = " + reply[i].result.length );
	}
				
	skiinfoMap.destList = dests;
		
	for( var i = 0; i < dests.length; i++ ) {
		var dest = dests[i];
		dest.destid = dest.i;
		dest.destname = dest.n;
		dest.countrycode = dest.c;
		dest.rank = dest.r;
		dest.latitude = dest.y;
		dest.longitude = dest.x;

		if( dest.x == 0 || dest.y == 0 ) {
			continue;
		}
		if( dest.x > dest.y ) {
			continue;
		}
			
		point = new GLatLng( dest.y, dest.x );
		this.cm.addDestination( dest, point );		
	}
	
	
	var clusters = this.cm.getClusters();
	for( var key in clusters ) {
		if( clusters[key] instanceof Cluster ) {
			this.map.addOverlay( clusters[key] );
		}			
	}
	
	if( this.tours.length > 0 ) {
		for( var t in this.tours ) {
			if( this.tours[t] instanceof Tour ) {
				this.map.addOverlay( this.tours[t].getOverlay() );
			}
		}
	}
	this.hideLoading();	
	
	skiinfoMap.fireEvent( "ViewportUpdated", [ this ] );
}

