/**
 * 
 * SolrMap class
 * 
 * --
 * This class loads and manages the SOLR-driven Google maps component in Page Builder
 * 
 */    

/**
 * This array will hold a list of all SOLR-driven Google maps on the page,
 * indexed by their componentId
 */
var SolrMaps = new Array();

/**
 * Constructor
 * 
 * @param id The ID of the page element to attach the Google map to
 * @return SolrMap
 */
var SolrMap = function( id )
{
	
	// We store our page element's ID in CSS notation, makes jQuery stuff easier later on
    this.id = '#' + id;
    
    // A marker showing the loading graphic in between AJAX reloads
    this.loadingMarker = null;
    
    // A flag to switch AJAX reloading on and off
    this.noreload = false;

    this.data = [];
    this.dataIdMap = [];
    
    /**
     * Method to initialize the map
     */
    this.init = function()
    {
        $( this.id ).css( 'background', 'none' );
        this.map = new GMap2( $( this.id )[0] );
        this.bounds = new GLatLngBounds( );
        this.zoom = 14;
        
        // Initialize our marker icon objects
        this.initIcons();
        
        this.map.setUIToDefault( );
        this.map.setCenter( new GLatLng( this.latitude, this.longitude ), this.zoom );
        this.map.enableContinuousZoom();
        this.drawMarkers( true );
        
        // Setup the events that trigger our AJAX reload
        eval( 'var func = function() { SolrMaps[ \'' + this.id + '\' ].reload(); }' );
        GEvent.addListener( this.map, 'dragend', func );
        GEvent.addListener( this.map, 'zoomend', func );
        GEvent.addListener( this.map, 'moveend', func );
       
        // Close our info window, reenabling AJAX reloading, and clearing the state of the info window cookie
        eval( 'var func3 = function() { jQuery.cookie( \'' + this.componentId + '_showInfo\', \'\' ); }' );
        GEvent.addListener( this.map, 'infowindowclose', func3 );
    }

    /** ICON SETTINGS **/
    
    /**
     * This array stores a list of all marker icons we will use, indexed by name
     * Most of these fields are fed directly into the GIcon object's properties
     * Fields: href image, href shadow, GSize iconSize, GSize shadowSize, GPoint iconAnchor, GPoint infoWindowAnchor
     * 
     * Where the field default is set to true, we instantiate a default GMarker to build on
     */
    this.icons = [];

    this.icons.red = {
    		              'default' : true,
    		              'image' : 'http://www.google.com/intl/en_us/mapfiles/ms/micons/red-dot.png',
    		              'iconSize' : new GSize( 32, 32 )
                        };
    this.icons.blue = {
    		              'default' : true,
    		              'image' : 'http://www.google.com/intl/en_us/mapfiles/ms/micons/blue-dot.png',
    		              'iconSize' : new GSize( 32, 32 )
                        };
    
    this.icons.restaurant = {
    							'default': true,
    							'image' : '/london/img/v3/micons/restaurants.png',
    							'iconSize': new GSize( 28, 39 )
    						};
    
    this.icons.loading = {
    		'default': true,
			'image' : '/images/maps/ajax-loader2.gif',
			'shadowImage' : '',
			'iconSize': new GSize( 32, 32 ),
			'iconAnchor': new GPoint( 32, 32 )
		};

    // Doesn't look as pretty as the ones above, but default is a keyword in JS and Chrome gets upset
    this.icons[ 'default' ] = {
			'default': true,
			'image' : '/images/maps/generic-map-pin.png',
			'iconSize': new GSize( 43, 35 )
		};

    /**
     * Processes the icon settings, creating appropriate GIcon objects
     */
    this.initIcons = function()
    {
        for ( key in this.icons )
        {

            var setup = this.icons[ key ];
            
            var icon;
            if ( setup[ 'default' ] != undefined && setup[ 'default' ] )
            {
                icon = new GIcon( G_DEFAULT_ICON );
            }
            else
            {
                icon = new GIcon();
            }
            for ( key2 in setup )
            {
                if ( key2 != 'default' )
                {
                    icon[ key2 ] = setup[ key2 ];
                }
            }
            this.icons[ key ][ 'iconObject' ] = icon;
        }
    }
    
    /** TEMPLATE SETTINGS **/
    
    /**
     * This array stores a list of all info window templates we will use, indexed by name
     * Each template consists of an array of arrays which will be processed in turn.
     * 
     * Where the 'function' field is set, a templating function is called, and 'arguments' passed along
     * with our data to be represented.
     * 
     * Where the 'html' field is set, its contents are placed directly into the output
     */
    this.templates = [];
    
    
    this.templates.basic = [ { 'html': '<div style="line-height: 1.5em">' },
                                { 'function': 'templateLink', 'arguments': { 'field': 'title', 'url': 'url', 'class': 'title' } },
                                { 'html': '<br />' },
                                { 'function': 'templateCuisineType', 'arguments': { 'field': 'cuisine_type' } },
                                { 'html': '<br />' },
                                { 'function': 'templateAddress', 'arguments': { 'field': 'address' } },
                                { 'html': '</div><br />' },
                                { 'html': '<div>' },
                                { 'html': '<div style="float: left; clear: none;">' },
                                { 'function': 'templateStarRating', 'arguments': { 'field' : 'star_rating' } },
                                { 'html': '</div>' },
                                { 'html': '<div style="float: left; clear: none;">' },
                                { 'function': 'templatePriceBand', 'arguments': { 'field' : 'price_band' } },
                                { 'html': '</div></div>' },
                                { 'function': 'templateSpecialOffer', 'arguments': { 'field' : 'offer', 'count_field': 'offer_count', 'url_field' : 'url' } },
                                { 'html': '<br /><br />' },
                                { 'function': 'templateLink', 'arguments': { 'text': 'Book online', 'url': 'book_url', 'class': 'title' } } ];

    /**
     * The restaurant template - this include an image, book online button and special offer information
     */
    this.templates.restaurant = [ { 'html': '<div class="leftColumn"><h2>' },
                             { 'function': 'templateLink', 'arguments': { 'field': 'title', 'url': 'url', 'class': 'title' } },
                             { 'html': '</h2><div class="flags-container">' },
                             { 'function': 'templateCuisineType', 'arguments': { 'field': 'cuisine_type' } },
                             { 'html': '<div class="icon-container">' },
                             { 'function': 'templateStarRating', 'arguments': { 'field' : 'star_rating' } },
                             { 'function': 'templatePriceBand', 'arguments': { 'field' : 'price_band' } },
                             { 'html': '<div class="details">' },
                             { 'function': 'templateAddress', 'arguments': { 'city': 'area', 'postcode': 'postcode' } },
                             { 'html': '</div><div class="clear"></div></div>' },
                             { 'function': 'templateSpecialOffer', 'arguments': { 'field' : 'offer', 'count_field': 'offer_count', 'url_field' : 'url' } },
                             { 'html': '<div class="tags-container">&nbsp;</div>' },
                             { 'html': '</div></div>' },
                             { 'html': '<div class="rightColumn">' },
                             { 'html': '<div class="buttons">' },
                             { 'function': 'templateButton', 'arguments': { 'text': 'Book online', 'url': 'book_url' } },
                             { 'html': '</div>' },
                             { 'function': 'templateImage', 'arguments': { 'field' : 'image', 'url_field' : 'url' } },
                             { 'html': '</div>' } ];

    
    /**
     * The events template - this include an image, book online button and special offer information
     */
    this.templates.event = [ { 'html': '<div class="leftColumn"><h2>' },
                             { 'function': 'templateLink', 'arguments': { 'field': 'title', 'url': 'url', 'class': 'title' } },
                             { 'html': '</h2><div class="flags-container">' },
                             { 'function': 'templateCategoryCrumbs', 'arguments': { 'color': 'section', 'text': 'category_crumbs' } },
                             { 'html': '</div><div class="clear"></div><div class="details">' },
                             { 'function': 'templateDateVenue', 'arguments': { 'date': 'date', 'venue': 'venue', 'postcode': 'postcode' } },
                             { 'html': '</div>' },
                             { 'html': '<div class="clear"></div>' },
                             { 'function': 'templateSpecialOfferEvent', 'arguments': { 'offerDesc' : 'offer_desc' } },
                             { 'html': '</div><div class="rightColumn">' },
                             { 'html': '<div class="buttons">' },
                             { 'function': 'templateButton', 'arguments': { 'text': 'Book online', 'url': 'ticket_url' } },
                             { 'html': '</div>' },
                             { 'function': 'templateImage', 'arguments': { 'field' : 'image', 'url_field' : 'url' } },
                             { 'html': '</div>' } ];
    
    
    /**
     * Renders the category bread crumbs, where present
     */
    this.templateCategoryCrumbs = function ( data, arguments )
    {
    	var color = '';
    	if ( data[ arguments[ 'color' ] ] != undefined && data[ arguments[ 'color' ] ] != '' )
    	{
    	    var color = data[ arguments[ 'color' ] ];
    	}
    	
    	var text = '';
    	if ( data[ arguments[ 'text' ] ] != undefined && data[ arguments[ 'text' ] ] != '' )
    	{
    	    var text = data[ arguments[ 'text' ] ];
    	}
    	return '<h4 class="category color-' + color + '">' + text + '</h4>';
    };

    /**
     * Renders the venue name, link and postcode
     */
    this.templateDateVenue = function ( data, arguments )
    {
    	var date = '';
    	if ( data[ arguments[ 'date' ] ] != undefined && data[ arguments[ 'date' ] ] != '' )
    	{
    	    var date = '<div><span class="date"><span>' + data[ arguments[ 'date' ] ] + '</span></span></div><div class="clear"></div>';
    	}
    	
    	var venue = '';
    	if ( data[ arguments[ 'venue' ] ] != undefined && data[ arguments[ 'venue' ] ] != '' )
    	{
    	    var venue = venue + '<a class="more">' + data[ arguments[ 'venue' ] ] + '</a>';
    	}
    	
    	var postcode = '';
    	if ( data[ arguments[ 'postcode' ] ] != undefined && data[ arguments[ 'postcode' ] ] != '' )
    	{
    	    var venue = venue + ', ' + data[ arguments[ 'postcode' ] ];
    	}
    	venue = '<address>' + venue + '</address>';
    	
    	return date + venue;
    };
    
    
    /**
     * Renders the special offer information
     */
    this.templateSpecialOfferEvent = function ( data, arguments )
    {
        if ( data[ arguments[ 'field' ] ] != '' )
        {
            var html = '<div class="review-container" style="margin-bottom:10px;"><p class="review"><strong class="color-london">Special offer:</strong> ';
            html += data[ arguments[ 'offerDesc' ] ];
             
            return html + '</p></div>';
        }
        return '';
    }
    
    
    /**
     * Renders the special offer information, adding a More offers link where appropriate
     */
    this.templateSpecialOffer = function ( data, arguments )
    {
        if ( data[ arguments[ 'field' ] ] != '' )
        {
            var html = '<div class="review-container"><p class="review"><strong class="color-london">Special offer:</strong> ';
            html += data[ arguments[ 'field' ] ];
            if ( data[ arguments[ 'count_field' ] ] != undefined
                    && parseInt( data[ arguments[ 'count_field' ] ] ) > 1
                    && data[ arguments[ 'url_field' ] ] != undefined
                    && data[ arguments[ 'url_field' ] ] != ''  
                    )
            {
                html += '<br /><a href="' + data[ arguments[ 'url_field' ] ] + '" title="More offers">More offers</a>';
            } 
            return html + '</p></div>';
        }
        return '';
    }

    /**
     * Renders an image
     */
    this.templateImage = function ( data, arguments )
    {
    	var html = '';
        if ( data[ arguments[ 'field' ] ] != '' )
        {
            html = '<img src="' + data[ arguments[ 'field' ] ] + '" alt="" />';
            if ( data[ arguments[ 'url_field' ] ] != undefined
                    && data[ arguments[ 'url_field' ] ] != ''  
                    )
            {
                html = '<a href="' + data[ arguments[ 'url_field' ] ] + '">' + html + '</a>';
            } 
            
            
        }
        return '<div class="image-container">' + html + '</div>';
    }
    
    /**
     * Renders a link
     */
    this.templateLink = function ( data, arguments )
    {
        if ( data[ arguments[ 'url' ] ] != '' )
        {
            var html = '';
            var text = ( arguments[ 'text' ] != undefined ) ? arguments[ 'text' ] : data[ arguments[ 'field' ] ];
            if ( text != '' )
            {
                text = text.replace( '"', '&quot;' );
                html += '<a class="' + arguments[ 'class' ] + '" href="' + data[ arguments[ 'url' ] ] + '" title="' + text + '">' + text + '</a>';
                return html;
            }
        }
        return '';
    }

    /**
     * Renders a blue button
     */
    this.templateButton = function ( data, arguments )
    {
        if ( data[ arguments[ 'url' ] ] != '' )
        {
            var html = '';
            var text = ( arguments[ 'text' ] != undefined ) ? arguments[ 'text' ] : data[ arguments[ 'field' ] ];
            if ( text != '' )
            {
                text = text.replace( '"', '&quot;' );
                html += '<a class="blue little-button" href="' + data[ arguments[ 'url' ] ] + '" title="' + text + '">';
                html += '<span class="inner-button"><span class="label-wrapper">';
                html += text + '</strong></span></span></a>';
                return html;
            }
        }
        return '';
    }

    /**
     * Renders a short address
     */
    this.templateAddress = function ( data, arguments )
    {
        var city = data[ arguments[ 'city' ] ];
        var postcode = data[ arguments[ 'postcode' ] ];
        return '<address class="inline"><span class="more">' + city + '</span>, ' + postcode + '</address>';
    }
    
    /**
     * Renders "Restaurant" followed by the cuisine type, where present
     */
    this.templateCuisineType = function ( data, arguments )
    {
    	var html = '';
    	if ( data[ arguments[ 'field' ] ] != undefined && data[ arguments[ 'field' ] ] != '' )
    	{
    	    var cuisineType = data[ arguments[ 'field' ] ];
    	    html = ': ' + cuisineType;
    	}
    	return '<h4 class="category color-restaurants">Restaurant' + html + '</h4>';
    }
    
    /**
     * Renders the star rating
     */
    this.templateStarRating = function ( data, arguments )
    {
    	if ( data[ arguments[ 'field' ] ] != undefined && data[ arguments[ 'field' ] ] != '' )
    	{
    	    var rating = parseInt( data[ arguments[ 'field' ] ] );
    	    return '<div class="ratings-wrapper"><span class="png-fix rating-v2 star' + rating + '">&nbsp;</span></div>';
    	}
    	return '';
    }

    /**
     * Renders the price band
     */
    this.templatePriceBand = function ( data, arguments )
    {
        if ( data[ arguments[ 'field' ] ] != undefined && data[ arguments[ 'field' ] ] != '' )
        {
        	var pb = '' + data[ arguments[ 'field' ] ];
            var priceBand = pb.toLowerCase();
            return '<div class="price-wrapper"><span class="png-fix price-band price-band-' + priceBand + '">&nbsp;</span></div>';
        }
        return '';
    }
    
    /**
     * Triggers an info window by its marker, as referenced by its index in the central data store
     */
    this.showInfo = function( id )
    {
    	var index = this.dataIdMap[ id ];
    	
    	// Store the id of the item we're displaying, to deal with a page refresh/reload
    	jQuery.cookie( this.componentId + '_showInfo', this.data[ 'items' ][ index ][ 'id' ] );
    	
        // Load appropriate template
        var templateName = this.data[ 'items' ][ index ][ 'template' ];
        if ( templateName == undefined || templateName == null || this.templates[ templateName ] == undefined || this.templates[ templateName ] == null )
        {
            templateName = 'basic';
        }

        var template = this.templates[ templateName ];
        var data = this.data[ 'items' ][ index ];

        // Construct our templated info window
        var html = '<div class="solrMapBubble">';
        for ( var i = 0; i < template.length; i++ )
        {
            var part = template[ i ];
            if ( part[ 'function' ] != undefined )
            {
                html += this[ part[ 'function' ] ]( data, part[ 'arguments' ] );
            }
            else if ( part[ 'html' ] != undefined )
            {
                html += part[ 'html' ];
            } 
        }
        html += '</div>';

        // Display bubble
        data[ '__marker' ].openInfoWindow( html );
    }
    
    /**
     * Renders the markers on the map
     * 
     * @param doZoom If true, the map will automatically zoom to include all markers in its display
     */
    this.drawMarkers = function( doZoom )
    {
        this.dataIdMap = new Array();
    	this.bounds = new GLatLngBounds( );
    	for ( var i = 0; i < this.data[ 'items' ].length; i++ )
        {
    		// If we've already got a marker on the map, don't redraw it
    		if ( this.data[ 'items' ][ i ][ '__marker' ] == undefined || this.data[ 'items' ][ i ][ '__marker' ] == null )
    		{
	            var point = new GLatLng( parseFloat( this.data[ 'items' ][ i ][ 'latitude' ] ), parseFloat( this.data[ 'items' ][ i ][ 'longitude' ] ) );
	            var markerOptions = new Object();
	            if ( this.data[ 'items' ][ i ][ 'marker_icon' ] != undefined
	            	    && this.data[ 'items' ][ i ][ 'marker_icon' ] != ''
	            	    && this.icons[ this.data[ 'items' ][ i ][ 'marker_icon' ] ][ 'iconObject' ] != undefined )
	            {
	            	markerOptions.icon = this.icons[ this.data[ 'items' ][ i ][ 'marker_icon' ] ][ 'iconObject' ];
	            }
	            
	            var marker = new GMarker( point, markerOptions );
	            this.map.addOverlay( marker );
	            this.bounds.extend( point );
	            this.data[ 'items' ][ i ][ '__marker' ] = marker;

	            // Attach the onclick event to launch an info window for this marker
	            eval( 'var func = function() { SolrMaps[ \'' + this.id + '\' ].showInfo( \'' + this.data[ 'items' ][ i ][ 'id' ] + '\' ); }' );
	            GEvent.addListener( marker, 'click', func );
    		}

            this.dataIdMap[ this.data[ 'items' ][ i ][ 'id' ] ] = i;
        }

    	this.openInfo = false;
        if ( doZoom ) // If we're on our first load
        {
        	// If we have a state remembered, load our state and reload the map data
        	if ( jQuery.cookie( this.componentId + '_zoom' ) )
        	{
        		this.zoom = parseInt( jQuery.cookie( this.componentId + '_zoom' ) );
        		this.latitude = jQuery.cookie( this.componentId + '_latitude' );
        		this.longitude = jQuery.cookie( this.componentId + '_longitude' );
        		point = new GLatLng( parseFloat( this.latitude ), parseFloat( this.longitude ) );
        		this.map.setZoom( this.zoom );
        		this.map.setCenter( point );
        		this.openInfo = true;
        		this.reload();
        		return;
        	}
        	else
        	{
        		this.zoom = this.map.getBoundsZoomLevel( this.bounds );
        		this.map.setZoom( this.zoom );
        	}
        }
        
        this.stats();
    }

    /**
     * Makes the AJAX call to update the map
     */
    this.reload = function()
    {

        var point = this.map.getCenter();
        var latitude = point.lat();
        var longitude = point.lng();

        var zoom = this.map.getZoom();
        
        // Save zoom, longitude and latitude in session cookie
        try
        {
            jQuery.cookie( this.componentId + '_zoom', zoom );
            jQuery.cookie( this.componentId + '_longitude', longitude );
            jQuery.cookie( this.componentId + '_latitude', latitude );
        }
        catch ( e )
        {
        	// Cookies not saved;
        }
    	
        var bounds = this.map.getBounds();
    	var ne = bounds.getNorthEast();
        var sw = bounds.getSouthWest();
        

        // Clear any existing loading Marker
        
        $( '#solrMainLoader_' + this.componentId ).css( 'display', 'none' );
        
        var size = this.map.getSize();
        var sMLHeight = $( '#solrMainLoader_' + this.componentId ).height();
        var sMLWidth = $( '#solrMainLoader_' + this.componentId ).width();
        $( '#solrMainLoader_' + this.componentId ).css( 'top', ( ( size.height - sMLHeight ) / 2 ) );
        $( '#solrMainLoader_' + this.componentId ).css( 'left', ( ( size.width - sMLWidth ) / 2 ) );
        $( '#solrMainLoader_' + this.componentId ).css( 'display', 'block' );

        var request = 'latitude=' + latitude
        			+ '&longitude=' + longitude
        			+ '&__preview='
        			+ this.preview
        			+ '&component_id=' + this.componentId
        			+ '&ne_latitude=' + ne.lat()
        			+ '&ne_longitude=' + ne.lng()
        			+ '&sw_latitude=' + sw.lat()
        			+ '&sw_longitude=' + sw.lng();
   
        this.longitude = longitude;
        this.latitude = latitude;
            
        var url = this.updateUrl;

        eval( 'var func = function( data, textStatus, XMLHttpRequest ) { SolrMaps[ \'' + this.id + '\' ].loadData( data, textStatus, XMLHttpRequest ); } ' );
        
        jQuery.ajax( {
        	  type: 'POST',
        	  url: url,
        	  data: request,
        	  success: func,
        	  dataType: 'json'
        	} );
    }

    /**
     * Displays the "Showing x of y results" message as appropriate
     */
    this.stats = function()
    {
    	// Showing x of y results
    	var total = this.data.total_item_count;
    	var showing = this.data.item_count;
    	
    	var str = 'Showing ' + showing + ' of ' + total + ' result' + ( ( total == 1 ) ? '' : 's' ) + '. Please scroll to see more.';
    	$( '#mapCount_' + this.componentId ).html( str );
    	$( '#mapCount_' + this.componentId ).css( 'visibility', ( total > showing ) ? 'visible' : 'hidden' );
    }
  
    /**
     * The callback from reload(). Loads the response and figures which results to maintain and which to ditch
     */
    this.loadData = function( data, responseStatus, XMLHttpRequest )
    {
    	$( '#solrMainLoader_' + this.componentId ).css( 'display', 'none' );
    	var openInfo = this.openInfo;
    	
    	// Run through each data item, comparing ids
    	var newdata = new Array();
    	var newDataIdMap = new Array();
    	for ( var i = 0; i < data[ 'items' ].length; i++ )
    	{
    		// If a marker already exists
    		if ( this.dataIdMap[ data[ 'items' ][ i ][ 'id' ] ] != undefined )
    		{
    			var index = this.dataIdMap[ data[ 'items' ][ i ][ 'id' ] ];
    			newdata[ newdata.length ] = this.data[ 'items' ][ index ];
    		}
    		else
    		{
    			newdata[ newdata.length ] = data[ 'items' ][ i ];
    		}
    		newDataIdMap[ data[ 'items' ][ i ][ 'id' ] ] = i;
    	}

    	var currentInfoBubble = jQuery.cookie( this.componentId + '_showInfo' );
    	if ( newDataIdMap[ currentInfoBubble ] == undefined )
    	{
			var index = this.dataIdMap[ currentInfoBubble ];
			if ( this.data[ 'items' ][ index ] != undefined )
			{
				newdata[ newdata.length ] = this.data[ 'items' ][ index ];
	    		newDataIdMap[ currentInfoBubble ] = newdata.length - 1;
			}
    	}
    	
    	var clearCount = 0;
    	
    	// Run through the previous data, removing markers that we no longer need
    	for ( var i = 0; i < this.data[ 'items' ].length; i++ )
    	{
    		var newId = this.data[ 'items' ][ i ][ 'id' ];
    		if ( newDataIdMap[ newId ] == undefined || newDataIdMap[ newId ] == null )
    		{
    			var index = this.dataIdMap[ this.data[ 'items' ][ i ][ 'id' ] ];
    			var marker = this.data[ 'items' ][ index ][ '__marker' ];
    			this.map.removeOverlay( marker );
    			clearCount++;
    		}
    	}
    	
        this.data[ 'items' ] = newdata;
        this.data.total_item_count = data.total_item_count;
        this.data.item_count = data.item_count;
        this.drawMarkers( false );
        
        // If we need to reload an info window (on our first call after map initialization)
        if ( openInfo )
        {
        	var infoId = jQuery.cookie( this.componentId + '_showInfo' );
        	if ( infoId )
        	{
        		this.showInfo( infoId );
        	}
        }
        this.openInfo = false;

    }

    // Save this object in the main index
    SolrMaps[ this.id ] = this;
   
}