
/*
 * CoinksMap
 * 
 * Functionality for managing Google Maps-based search map
 * 
 */
var CoinksMap = function(locations, fromPoint, options){

    var _this = this;
    $.extend(_this, new CoinksBase());		

    _this.locations = locations;
    _this.options = options;

    if(!fromPoint){
        fromPoint = new Array(_this.options.default_map_center[0],
			                  _this.options.default_map_center[1]);
    }

    _this.mapIconPrefix = _this.options.mapIconPrefix == undefined ? '' : _this.options.mapIconPrefix;

    _this.fromPoint = new GLatLng(fromPoint[0], fromPoint[1]);
    _this.initialize();
        
}

/*
 * Constants
 */

CoinksMap.MIN_SMALL_MARKER_ZOOM = 6
CoinksMap.MAX_SMALL_MARKER_ZOOM = 8
CoinksMap.MIN_LARGE_MARKER_ZOOM = 9
CoinksMap.MAX_LARGE_MARKER_ZOOM = 15
CoinksMap.MAX_NUM_MARKERS = 30

/*
 * Methods
 */

CoinksMap.prototype.addLocations = function(locations){
    var _this = this;

    var smallMarkers = new Array();
    var largeMarkers = new Array();
	
	var max_markers = locations.length;
	
	if (max_markers > CoinksMap.MAX_NUM_MARKERS){
	    max_markers = CoinksMap.MAX_NUM_MARKERS;    
	}
	
    for(var i = 0; i < max_markers; i++){
        
        var location = locations[i];
	    var marker = new CoinksMarker(this, location);

	    _this.markerMap[location.id] = marker;
        _this.markerList.push(marker);

    	smallMarkers.push(marker.smallIconMarker);
    	largeMarkers.push(marker.largeIconMarker);
    
    }

    _this.min_small_marker_zoom = _this.options.min_small_marker_zoom || CoinksMap.MIN_SMALL_MARKER_ZOOM;
    _this.max_small_marker_zoom = _this.options.max_small_marker_zoom || CoinksMap.MAX_SMALL_MARKER_ZOOM;
    _this.min_large_marker_zoom = _this.options.min_large_marker_zoom || CoinksMap.MIN_LARGE_MARKER_ZOOM;
    _this.max_large_marker_zoom = _this.options.max_large_marker_zoom || CoinksMap.MAX_LARGE_MARKER_ZOOM;
    
    var mgr = new MarkerManager(_this.gmap, { maxZoom : CoinksMap.MAX_LARGE_MARKER_ZOOM });
    mgr.addMarkers(smallMarkers, 
		           _this.min_small_marker_zoom, 
		           _this.max_small_marker_zoom);
    mgr.addMarkers(largeMarkers, 
		           _this.min_large_marker_zoom, 
		           _this.max_large_marker_zoom);
    mgr.refresh();
        
    _this.manager = mgr;
    
}

CoinksMap.prototype.initialize = function(){

    var _this = this;
    
    _this.defaultZoom = _this.options.default_map_zoom;
    _this.can_select = true;
    
    _this.gmap = new GMap2(document.getElementById("map"));		
    _this.gmap.addControl(new GLargeMapControl());
    //_this.gmap.addControl(new GMapTypeControl());
    _this.gmap.setCenter(_this.fromPoint, _this.defaultZoom);
    _this.markerMap = new Object;
    _this.markerList = new Array;
            
    // If the number of locations if greater than the max allowed, we need to reload
    // locations each time
    
    if (_this.locations.length > CoinksMap.MAX_NUM_MARKERS){
        _this.showSearchResultsOnly = true;
    } else {
        _this.showSearchResultsOnly = false;
    }
        
    _this.addLocations(_this.locations);

    var mapTypes = _this.gmap.getMapTypes();
    for (var i=0; i < mapTypes.length; i++){
	    var mapType = mapTypes[i];
	    mapType.getMinimumResolution = function(){ return _this.min_small_marker_zoom; }
	    mapType.getMaximumResolution = function(){ return _this.max_large_marker_zoom; }		
    }
    
    _this.resetSearchInput();
    $('#reset_map').hide();
    
    $('.category_filter').click(function(){ 
        _this.filterCategories();
        _this.reload(_this.locations); 
    });
    
    GEvent.addListener(_this.gmap, "zoomend", function(oldlevel, newlevel){
        _this.filterCategories();
    });
    
    GEvent.addListener(_this.manager, "changed", function(bounds, markerCount){
        _this.filterCategories();
    });
    
    $('.open_offer').live('click', function(){
        var offer_id = $(this).pk();
        _this.displayOffer(offer_id, function(response){
            _this.renderOffer(offer_id, response);
        });
    });     

    $('.takeup_offer').live('click', function(){
        var offer_id = $(this).pk();
        var signature = $('#signature').val();
        var ns_coinks = $('#ns_coinks').val();
        var params = { signature : signature, ns_coinks : ns_coinks };
        _this.takeupOffer(offer_id, params, function(message, error){
            _this.renderOffer(offer_id, message);
        });
    });

    $('.cancel_offer').live('click', function(){
        var offer_id = $(this).pk();
        _this.cancelOffer(offer_id);
    });

    $('.open_review').live('click', function(){
       var location_id = $(this).pk();
       $.pk('review', location_id).toggle();
       return false;
    });

    $('.open_tandc').live('click', function(){
        var location_id = $(this).pk();
       $.pk('tandc', location_id).toggle();
        return false;
    });

    $('#select_all_categories').click(function(){
        _this.selectAllCategories();
        _this.filterCategories();
        _this.reload(_this.locations);
    });

    _this.filterCategories();
}	

CoinksMap.prototype.hideSelectAllCategoriesButton = function(){
    $('#select_all_categories_container').hide();
    //$('#category_filter_box').css('margin-top', '30px');
}

CoinksMap.prototype.showSelectAllCategoriesButton = function(){
    $('#select_all_categories_container').show();
    //$('#category_filter_box').css('margin-top', '0');
}

CoinksMap.prototype.cancelOffer = function(offer_id){

    var _this = this;
    
    var offer_detail = $.pk('offer_detail', offer_id);
    
    //var bgcolor = "#FFFFFF";
    var bgcolor = _this.options.deselectedOfferColor || "#FFFFFF";
    
    offer_detail.hide();

    var parent = offer_detail.parent();
    
    parent.children('.main_detail').show();
    parent.children('.prize_draw').show();
    
    parent = parent.parent();
    
    parent.children('.offer_button').show();
    parent.css('background-color', bgcolor);

}

CoinksMap.prototype.renderOffer = function(offer_id, response){

    var _this = this;
    
    var offer_detail = $.pk('offer_detail', offer_id);

    //var bgcolor = "#D2EEFF";
    var bgcolor = _this.options.selectedOfferColor || "#D2EEFF";
    
    offer_detail.html(response).show();

    var parent = offer_detail.parent();
    
    parent.children('.main_detail').hide();
    parent.children('.prize_draw').hide();
    
    parent = parent.parent();
    
    parent.children('.offer_button').hide();
    parent.css('background-color', bgcolor);

    document.location.href = '#' + parent.attr('id');   
    
}


/*
 * Resets the search input text
 * 
 */
CoinksMap.prototype.resetSearchInput = function(){
    $('#id_location').click(function(){ $(this).val(''); }).val("Type in postcode or town");
}

/*
 * Resets map to original form
 * 
 */
CoinksMap.prototype.reset = function(){
    var _this = this;
    _this.initialize();
    
}

CoinksMap.prototype.getSelectedCategoryIDs = function(){
    var categoryIDs = new Array;
        
    $('.category_filter:checked').each(function(){
	    categoryIDs.push(parseInt($(this).val()));
    });
     
    return categoryIDs;
}
	
/*
*
* Filters markers by category ID
*/
CoinksMap.prototype.filterCategories = function(){
    var _this = this;
    var showAll = false;
    
    if(!_this.options.enable_category_filtering) return;
    
    var categoryIDs = _this.getSelectedCategoryIDs(); 
    if (categoryIDs.length == 0){
        showAll = true;
    }
    
    $.each(_this.markerList, function(index, marker){
        if(showAll || $.inArray(marker.location.category_id, categoryIDs) != -1){
            marker.show();
        } else {
            marker.hide();
        }
    });
    
    if(showAll){
        _this.hideSelectAllCategoriesButton();
    } else {
        _this.showSelectAllCategoriesButton();
    }
}

CoinksMap.prototype.selectAllCategories = function(){
    var _this = this;
    
    $('.category_filter').attr('checked', false);
}

/*
 * Reloads map with new set of locations
 * 
 */
CoinksMap.prototype.reload = function(locations, point, is_outside){
    var _this = this;
	    
    _this.deselect();
    _this.clearLocationsList();
	
    _this.bounds = new GLatLngBounds();    

	
    if(point){
	    point = new GLatLng(point[0], point[1]);
	    _this.bounds.extend(point);
    }

    var categoryIDs = _this.getSelectedCategoryIDs();     
    var showAll = categoryIDs.length == 0;
        
    if (_this.options.enable_category_filtering){
        locations = $.grep(locations, function(location, index){
            return (showAll || $.inArray(location.category_id, categoryIDs) != -1);
        });
    }

    var numMarkers = locations.length;
        
    for(var i=0; i<numMarkers; i++){
	    _this.bounds.extend(new GLatLng(locations[i].latitude, 
					                    locations[i].longitude));
    }


    if(numMarkers > 0){
	    _this.gmap.setZoom(_this.gmap.getBoundsZoomLevel(_this.bounds));
	    _this.gmap.setCenter(_this.bounds.getCenter());		
    } 

    if (numMarkers == 1){
        _this.selectMarker(locations[0].id);
    } else if (numMarkers == 0){
    	$('#locations_list').hide();
    	$('#default_filler').show();
    } else {
        _this.showLocationsList(locations);
    }
    
    if(is_outside){
    	$('#outside_distance_message').show();
    } else {
    	$('#outside_distance_message').hide();        	
    }

	
    $('#reset_map').show();	

    $('.open_review').live('click', function(){
       var location_id = $(this).pk();
       $.pk('review', location_id).toggle();
       return false;
    });

    $('.open_tandc').live('click', function(){
        var location_id = $(this).pk();
       $.pk('tandc', location_id).toggle();
        return false;
    });


    _this.filterCategories();

}

/*
 * Changes set of (small and large) markers
 */
CoinksMap.prototype.replaceMarker = function(smallMarker, largeMarker,
    newSmallMarker, newLargeMarker){
    var _this = this;
    
    _this.manager.removeMarker(smallMarker);
    _this.manager.removeMarker(largeMarker);

    _this.manager.addMarker(newSmallMarker, 
                            CoinksMap.MIN_SMALL_MARKER_ZOOM, 
	                        CoinksMap.MAX_SMALL_MARKER_ZOOM);

    _this.manager.addMarker(newLargeMarker, 
                            CoinksMap.MIN_LARGE_MARKER_ZOOM, 
	                        CoinksMap.MAX_LARGE_MARKER_ZOOM);

    _this.manager.refresh();
    _this.filterCategories();

}

/*
 * Cleans out list of locations
 * 
 */
CoinksMap.prototype.clearLocationsList = function(){
    $('#locations_list').html("");
}

/*
 * Displays locations in a list
 */
CoinksMap.prototype.showLocationsList = function(locations){
    var html = new Array();
    max_size = locations.length < 8 ? locations.length : 8;
    for(var i=0; i<max_size;i++){
        var location = locations[i];
	    html.push(location.list_view_html);
       $.pk('open_review', location.id).bind('click', function(){
            $('#review_' + location.id).toggle();       
       });
       
       $.pk('open_tandc', location.id).bind('click', function(){
            $('#tandc_' + location.id).toggle();       
       });

    }
    
    $('#locations_list').html(html.join("\n"));
    $('#default_filler').hide();
    $('#locations_list').show();
}

/*
 * Runs search AJAX
 */
CoinksMap.prototype.search = function(search_url){
    // does AJAX search and reloads functions accordingly.
    var _this = this;
    _this.deselect();
    _this.removeDetail();
    
    var location = $('#id_location').val();
    var params = {location : location}
    
    var callback = function(response){
        _this.locations = response.locations;
        if (_this.showSearchResultsOnly){
            _this.addLocations(_this.locations);
        }
	    _this.reload(_this.locations, response.point, response.is_outside);        
	    //_this.reload(response.locations, response.point, response.is_outside);

    }
    
    $.post(search_url, params, callback, "json");
	
}

/*
 * Hides the location detail and shows default content
 */
CoinksMap.prototype.removeDetail = function(){
    $('#rightpanel_detail').hide();	
    $('#rightpanel_default_content').show();
}

/*
 * Unselects the current selected marker (if any)
 */
CoinksMap.prototype.deselect = function(){
    var _this = this;
    
    if (!_this.selectedMarker) return;	
    _this.selectedMarker.deselect();
    _this.selectedMarker = null;
    $('#rightpanel_default_content').show();
    $('#rightpanel_detail').hide();	
    _this.manager.refresh();

}

/*
 * Selects the a marker to be highlighted and shown in detail panel
 */
CoinksMap.prototype.selectMarker = function(locationID){
    var _this = this;
    var marker = _this.markerMap[locationID];
    if (marker) {
	    marker.select();
    }    
}

/*
 * CoinksMarker
 * 
 * Manages state of single marker on map. Uses four markers: 
 * small/small selected/large/large selected
 * 
 * Data for the marker is kept in a location, returned from server as a JSON object.
 */
var CoinksMarker = function(map, location){
    var _this = this;
	
    _this.map = map;
    _this.location = location;
    _this.point = new GLatLng(_this.location.latitude, 
                              _this.location.longitude);
    _this.selected = false;
    _this.size = "small";
    

    var largeAnchor = new GPoint(32, 63);
    var smallAnchor = new GPoint(9, 24);
    var prefix = map.mapIconPrefix;
    
    
    _this.smallIcon = _this.createIcon(location.map_icon_url + prefix + "default_small.png",
					location.map_icon_url + prefix + "shadow_small.png", 32, 32,
					smallAnchor);

    _this.largeIcon = _this.createIcon(location.map_icon_url + prefix + "default_large.png",
                                       location.map_icon_url + prefix + "shadow_large.png", 63, 63,
                                       largeAnchor);

    _this.selectedSmallIcon = _this.createIcon(location.map_icon_url + prefix + "selected_small.png", 
					    location.map_icon_url + prefix + "shadow_small.png", 32, 32,
					    smallAnchor);
				     
    _this.selectedLargeIcon = _this.createIcon(location.map_icon_url + prefix + "selected_large.png", 
                                               location.map_icon_url + prefix + "shadow_large.png", 63, 63,
                                               largeAnchor);
    
    _this.defaultIcon = _this.smallIcon;
    _this.selectedIcon = _this.selectedSmallIcon;

    _this.smallIconMarker = _this.createMarker(_this.smallIcon);
    _this.largeIconMarker = _this.createMarker(_this.largeIcon);
    _this.smallSelectedIconMarker = _this.createMarker(_this.selectedSmallIcon);
    _this.largeSelectedIconMarker = _this.createMarker(_this.selectedLargeIcon);
	
    
}

/*
 * Methods 
 */
 
/*
 * Runs AJAX query to get location details, highlights marker and shows in location 
 * detail panel
 */
CoinksMarker.prototype.select = function(){
    var _this = this;

    if (!_this.map.can_select) return;
    _this.map.can_select = false;

    if (_this.map.selectedMarker) _this.map.selectedMarker.deselect();
    var callback = function(response){
	    $('#rightpanel_detail_content').html(response);
	    $('#rightpanel_default_content').hide();
	    $('#rightpanel_detail').show();	
	    _this.map.replaceMarker(_this.smallIconMarker, 
				                _this.largeIconMarker,
				                _this.smallSelectedIconMarker,
				                _this.largeSelectedIconMarker);
	    _this.selected = true;
	    _this.map.selectedMarker = _this;
	    _this.map.can_select = true;

       $.pk('open_review', _this.location.id).bind('click', function(){
            $('#review_' + _this.location.id).toggle();       
       });
       
       $.pk('open_tandc', _this.location.id).bind('click', function(){
            $('#tandc_' + _this.location.id).toggle();       
       });
          
    }
    $.get(_this.location.detail_url, callback, "html");     
}

/*
 * Deselects the marker
 */
CoinksMarker.prototype.deselect = function(){
    var _this = this;
    
    _this.selected = false;
    _this.map.replaceMarker(_this.smallSelectedIconMarker, 
			                _this.largeSelectedIconMarker,
			                _this.smallIconMarker,
			                _this.largeIconMarker);
}

CoinksMarker.prototype.show = function(){
    var _this = this;

    if(_this.selected){
        _this.smallSelectedIconMarker.show();
        _this.largeSelectedIconMarker.show();
    } else {
       _this.smallIconMarker.show();
       _this.largeIconMarker.show();
    }
}

CoinksMarker.prototype.hide = function(){
    var _this = this;

    if(_this.selected){
        _this.smallSelectedIconMarker.hide();
        _this.largeSelectedIconMarker.hide();
    } else {
       _this.smallIconMarker.hide();
       _this.largeIconMarker.hide();
    }
}

/*
 * Creates a new marker
 */
CoinksMarker.prototype.createMarker = function(icon){
    var _this = this;  
	
    marker = new GMarker(this.point, icon); 
    GEvent.addListener(marker, "click", function() { _this.select(); });
    return marker;
}


CoinksMarker.prototype.createIcon = function(image, shadow, width, height, anchor){
    var icon = new GIcon();
    icon.image = image;
    icon.shadow = shadow;
    icon.iconSize = new GSize(width, height);

    // make shadow size 30% larger than icon size
    var shadow_width = Math.ceil(width + ((width/100) * 30))
    var shadow_height = Math.ceil(height + ((height/100) * 30))
    
    icon.shadowSize = new GSize(width, height);
    //icon.iconAnchor = new GPoint(32, 63);
    //icon.iconAnchor = new GPoint(9, 24);
    icon.iconAnchor = anchor;
    return icon
}
	


