
var currentLat = false;
var currentLong = false;

var google_geocode = {
    'geocode': null,
    'get_geocode_component': function(component_type) {
        var found_component = null;
        
        if (this.geocode != null) {
            for (var component_offset = 0; component_offset < this.geocode.address_components.length && found_component == null; component_offset++) {
                var component = this.geocode.address_components[component_offset];
                
                for (var types_offset = 0; types_offset < component.types.length && found_component == null; types_offset++) {
                    if (component.types[types_offset] == component_type) {
                        found_component = component.short_name;
                    }
                }
            }
        }
        
        return found_component;
    }
};


var snapshot = {
    'geocode': null,
    'dealers': null,
    'get_geocode_component': function(component_type) {
        var found_component = null;
        
        if (this.geocode != null) {
            for (var component_offset = 0; component_offset < this.geocode.address_components.length && found_component == null; component_offset++) {
                var component = this.geocode.address_components[component_offset];
                
                for (var types_offset = 0; types_offset < component.types.length && found_component == null; types_offset++) {
                    if (component.types[types_offset] == component_type) {
                        found_component = component.short_name;
                    }
                }
            }
        }
        
        return found_component;
    },
    'get_geocode_postcode': function() {
        return this.get_geocode_component('postal_code');
    },
    'get_geocode_state': function() {
        return this.get_geocode_component('administrative_area_level_1');
    },
    'get_geocode_suburb': function() {
        return this.get_geocode_component('locality');
    },
    'get_geocode_latlng_string': function() {
        return this.geocode.geometry.location.lat() + ',' + this.geocode.geometry.location.lng();
    }
};

var google_map = {
    // Google.Map.Map object
    'dealer_map': null,
    'geocoder': new google.maps.Geocoder(),
    'directions_service': null,
    'directions_display': null,

    // Array of overlays (Google.Maps.Markers) added to the Google.Maps.Map
    'dealer_map_markers': [],
    // google.maps.LatLngBounds for various functions to add bounds to
    // so once completed the map will be panned/zoomed to fit.
    'dealer_map_new_bounds': new google.maps.LatLngBounds(),
    'dealer_map_infowindow': null,
    /**
     * Final method to present new data to the user.
     */
    'show': function() {
        this.dealer_map.fitBounds(this.dealer_map_new_bounds);
        
        return this;
    },
    'append': function(){
        var geocode_postcode = snapshot.get_geocode_postcode();
        
        for (var dealer_offset = 0; dealer_offset < snapshot.dealers.length; dealer_offset++) {
            var dealer = snapshot.dealers[dealer_offset];
            var dealer_lat_long = new google.maps.LatLng(dealer.latitude, dealer.longitude);


            var dealer_url_content = null;
            
            if (dealer.url == null) {
                dealer_url_content = $('<p>').html('N/A');
            }
            else {
                dealer_url_content = $("<a/>", {
                    "class": "visitButton",
                    "href": dealer.url,
                    'target':'_blank'
                }).text("Visit");
            }

            var dealer_tr = $("<tr/>").data(dealer).append(
                $("<td/>").html(
                    $("<a/>", {
                        "id": "dealer_" + (dealer_offset + 1)
                    }).text(dealer_offset + 1)
                )
            ).append(
                $("<td/>").html(
                    dealer.name
                )
            ).append(
                $("<td/>").html(
                    dealer.street_address
                )
            ).append(
                $("<td/>").html(
                    dealer.street_suburb
                )
            ).append(
                $("<td/>").html(
                    dealer.street_postcode
                )
            ).append(
                $("<td/>").html(
                    dealer.phone
                )
            ).append(
                $("<td/>").html(
                    dealer_url_content
                )
            )
            .append(
                $('<td/>').html(
                    $('<a/>', {'href': '#'}).html('Get Directions').click(function() {
                        var clicked_dealer = $(this).parents('tr').data();

                        google_map.directions_service.route({
                            origin: snapshot.get_geocode_latlng_string(),
                            destination: clicked_dealer.latitude + ',' + clicked_dealer.longitude,
                            travelMode: google.maps.TravelMode.DRIVING
                        }, function(response, status) {
                            if (status == google.maps.DirectionsStatus.OK) {
                                //var warnings = document.getElementById("warnings_panel");
                                //warnings.innerHTML = "" + response.routes[0].warnings + "";
                                google_map.directions_display.setDirections(response);
                                //showSteps(response);
                            }
                        });
                    })
                )
            );

            this.dealer_map_new_bounds.extend(dealer_lat_long);

            (function () { /* ################################################## */

            var dealer_marker = new google.maps.Marker({
                position: dealer_lat_long, 
                map: google_map.dealer_map, 
                title: $.trim(dealer.name),
                icon: new google.maps.MarkerImage(
                    BASE_URL + "images/bubbleicon" + (dealer_offset + 1) + ".gif",
                    new google.maps.Size(25,25),
                    null,
                    new google.maps.Point(6,20)
                ),
                data: dealer
            });

            google_map.dealer_map_markers.push(dealer_marker);

            google.maps.event.addListener(dealer_marker, 'click', function() {
                if (google_map.dealer_map_infowindow) {
                    google_map.dealer_map_infowindow.close();
                }

                google_map.dealer_map_infowindow = new google.maps.InfoWindow({

                    content: '<div class="infowindow">' +
                                '<img src="'+ BASE_URL + 'images/generic_dealer.jpg" alt="generic_dealer"/>' +
                                '<p class="infowindow_title">Name</p>' +
                                '<p>' + dealer_marker.data.name + '</p>' +
                                '<p class="infowindow_title">Address</p>' +
                                '<p>' + dealer_marker.data.street_address + '</p>' +
                                '<p>' + dealer_marker.data.street_suburb + '</p>' +
                                '<p>' + dealer_marker.data.street_state + ' ' + dealer_marker.data.street_postcode + '</p>' +
                                '<p class="infowindow_title">Phone</p>' +
                                '<p>' + dealer_marker.data.phone + '</p>' +
                                '<p class="infowindow_title">Distance</p>' +
                                 '<p>' + dealer_marker.data.distance_matrix.distance.text + ' (' + dealer_marker.data.distance_matrix.duration.text + ')</p>' +
                             '</div>'

                });

                google_map.dealer_map_infowindow.open(google_map.dealer_map, dealer_marker);

                // close_infowindows();

                // dealer_marker.infowindow.open(dealer_map, dealer_marker);
            });



           })(); /* ################################################## */

            // search for component named 'postal_code'(?)
            
            var is_pma = false;

            // search for 'postal_code'
            for (var pma_offset = 0; pma_offset < dealer.pma.length; pma_offset++) {
                if ( geocode_postcode == dealer.pma[pma_offset]) {
                    is_pma = true;
                }
            }

            if (is_pma == true) {
                $("#dealer_listing #preferred-dealers tbody").append(dealer_tr);
            }
            else {
                $("#dealer_listing #closest-dealers tbody").append(dealer_tr);
            }

            // The dealers come to use in order (by distance) from the ajax call
            // so the first dealer (== 0) is the preferred/closest dealer.
            /*
            if (dealer_offset == 0) {
                $("#dealer_listing #preferred-dealer tbody").append(dealer_tr);
            }
            else {
                $("#dealer_listing #other-dealers tbody").append(dealer_tr);
            }
*/
        }
        
        // Hide the preferred dealer if no dealer exists in the specified postcode.
        if ($("#preferred-dealers tbody tr").length > 0) {
            $("#preferred-dealers-wrap").show();
        }
        if ($("#closest-dealers tbody tr").length > 0) {
            $("#closest-dealers-wrap").show();
        }
        
        if ( $("#preferred-dealers tbody tr").length == 0 && $("#closest-dealers tbody tr").length == 0 ) {
        	$('#dealer_listing').prepend("<p class='no-results'>We couldn't find any dealers that match your request. You might like to try selecting a wider distance.</p>")
        }
        
        
        return this;
    },
    
    /**
     * Removes the stored markers from the map. Google map API >= V2 has
     * no method to remove the overlays.
     * 
     * @author: Geoff Green
     */
    'clear_markers': function() {
        for(var i = 0; i < this.dealer_map_markers.length; i++){ 
            this.dealer_map_markers[i].setMap(null); 
        } 
        this.dealer_map_markers.length = 0; 
        
        return this;
    },
    /**
     * Removes the stores markers from the map. Google map API >= V2 has
     * no method to remove the overlays.
     * 
     * @author: Geoff Green
     */
    'close_infowindows': function() {
        for(var i = 0; i < this.dealer_map_markers.length; i++){ 
            this.dealer_map_markers[i].infowindow.close();
        } 
        
        return this;
    },
    /**
     * @param google.maps.LatLng home_latlng Lat/Lng of the home
     */
    'set_home_marker': function(home_latlng) {
        this.dealer_map_new_bounds.extend(home_latlng);

        var home_marker = new google.maps.Marker({
            position: home_latlng, 
            map: this.dealer_map, 
            icon: new google.maps.MarkerImage(
                BASE_URL + "images/home.gif",
                new google.maps.Size(25,25),
                null,
                new google.maps.Point(6,20)
            )
        });

        this.dealer_map_markers.push(home_marker);
        
        return this;
    },
    /**
     * General method to 'reset' the page to blank for new data.
     * 
     * @author: Geoff Green
     */
    'scrub': function() {

        // Create the map object if it does not exist
        if (this.dealer_map == null) {
            this.dealer_map = new google.maps.Map(document.getElementById("map_canvas"), {
                zoom: 8,
                // center: latlng,
                mapTypeId: google.maps.MapTypeId.ROADMAP
            });
            
            this.directions_service = new google.maps.DirectionsService();
            
            this.directions_display = new google.maps.DirectionsRenderer({
                map: this.dealer_map
            });
        }

        this.directions_display.setRouteIndex(-1);

        // Remove all old markers.
        this.clear_markers();
        
        this.dealer_map_new_bounds = new google.maps.LatLngBounds();

        $("#dealer_listing #preferred-dealers tbody tr").remove();
        $("#dealer_listing #closest-dealers tbody tr").remove();
        
        return this;
    }
};

/**
 * Removes any dealers that have a driving distance over a passed distance (km)
 * 
 * @param float maximum_distance The maximum driving distance in km 
 */
function remove_dealers_gt_distance(maximum_distance) {
    for (var dealer_offset = 0; dealer_offset < snapshot.dealers.length; dealer_offset++) {
        if (snapshot.dealers[dealer_offset].distance_matrix.distance.value > maximum_distance * 1000) {
            // It's to far away, remove it.
            snapshot.dealers.splice(dealer_offset, 1);
            dealer_offset--;
        }
    }
    
    return snapshot.dealers;
}

/**
 * This event is fired if it comes time to load the dealers
 * but it is found google didn't return a postcode.
 * 
 * We need the postcode to work out if a dealer is PMA or not.
 */
function on_ajax_postcode(po) {
    snapshot.geocode.address_components.push({
        'long_name': po.postcode,
        'short_name': po.postcode,
        'types': [
            'postal_code'
        ]
    });
    
    google_map.append().show();
}

function on_ajax_distance_matrix(elements) {
    
    for (var dealer_offset = 0; dealer_offset < snapshot.dealers.length && dealer_offset < elements.length; dealer_offset++) {
        snapshot.dealers[dealer_offset].distance_matrix = elements[dealer_offset];
        
        // No distance results
        if (elements[dealer_offset].distance == undefined) {
            snapshot.dealers[dealer_offset].distance_matrix.distance = {
                'value': parseFloat(snapshot.dealers[dealer_offset].distance),
                'text': parseFloat(snapshot.dealers[dealer_offset].distance).toFixed(2) + ' km'
            };
            
            snapshot.dealers[dealer_offset].distance_matrix.duration = {
                'value': 0,
                'text': ''
            };
        }
    }
    
	// We always need at least 1 result!
	if (snapshot.dealers.length > 1) {
		snapshot.dealers = remove_dealers_gt_distance($("select[name='radius'] option:selected").val());
	}
	
    snapshot.dealers.sort(function(a, b) {
        return a.distance_matrix.distance.value == a.distance_matrix.distance.value ? 0 : (a.distance_matrix.distance.value > a.distance_matrix.distance.value ? 1 : -1);
    });
    
    // If we don't have a postcode in our geolocation
    if (snapshot.get_geocode_postcode() == null) {

        // Need another check to grab the postal code
        $.ajax({
            url: BASE_URL + 'index.php/api/location/po/suburb/' + snapshot.get_geocode_suburb() + '/state/' + snapshot.get_geocode_state(),
            type: 'GET',
            success: on_ajax_postcode
        });
    }
    else {
        // All good to go, get on with it.
        google_map.append().show();
    }
}

function on_ajax_closest_dealers(dealers) {
    snapshot.dealers = dealers;

    var dealer_locations = [];

    for (var dealer_offset = 0; dealer_offset < snapshot.dealers.length; dealer_offset++) {
        var dealer = snapshot.dealers[dealer_offset];

        dealer_locations.push(new google.maps.LatLng(dealer.latitude, dealer.longitude)); 
    }

    var service = new google.maps.DistanceMatrixService();
    service.getDistanceMatrix({
        origins: [snapshot.geocode.geometry.location],
        destinations: dealer_locations,
        travelMode: google.maps.TravelMode.DRIVING,
        avoidHighways: false,
        avoidTolls: false
    }, function (results, status) {
        if (status == google.maps.DistanceMatrixStatus.OK) {
            on_ajax_distance_matrix(results.rows[0].elements);
        }
    });
}

function on_ajax_geocode(geocode) {
    //snapshot.geocode = geocode;
    $("#address").val(geocode.formatted_address);
    
    google_map.scrub();
    google_map.set_home_marker(new google.maps.LatLng(geocode.geometry.location.lat(), geocode.geometry.location.lng()));
    
    $.ajax({
        url: BASE_URL + 'index.php/api/dealer/near/lat/' + geocode.geometry.location.lat() + '/lng/' + geocode.geometry.location.lng() + '/dealer_type/' + $("input[name='dealer_type']:checked").val() + '/radius/' + $("select[name='radius'] option:selected").val(),
        type: 'GET',
        success: on_ajax_closest_dealers
    });
}

function get_geocode_data_by_address(address) {

	$('#preferred-dealers-wrap, #closest-dealers-wrap').hide();
	$('.no-results').remove();

    //var geocoder = new google.maps.Geocoder();

    //if (geocoder) {
        google_map.geocoder.geocode({'address': address, 'region': 'au'}, function (results, status) {
            if (status == google.maps.GeocoderStatus.OK) {
                
                for (var result_offset = 0; result_offset < results.length; result_offset++) {
                    snapshot.geocode = results[result_offset];
                    
                    if (snapshot.get_geocode_component('country') == 'AU') {
                        snapshot.geocode = results[result_offset];
                        
                        break;
                    }
                }

                on_ajax_geocode(snapshot.geocode);
            }
        });
    //}
}

function get_geocode_data_by_lat_long(latitude, longitude) {

    $('#preferred-dealers-wrap, #closest-dealers-wrap').hide();
    $('.no-results').remove();

    var latlng = new google.maps.LatLng(latitude, longitude);

    google_map.geocoder.geocode({'latLng': latlng}, function (results, status) {
        if (status == google.maps.GeocoderStatus.OK) {
            snapshot.geocode = results[1];

            on_ajax_geocode(snapshot.geocode);
        }
    });
}

function on_ajax_geoip(geoip) {
    currentLat = geoip.latitude;
    currentLong = geoip.longitude;
    get_geocode_data_by_lat_long(geoip.latitude, geoip.longitude);
}

/*
function on_navigator_geolocation_error(error) {
    // Fall back on the GeoIP data
    get_geocode_data_by_lat_long(GEOIP_LATITUDE, GEOIP_LONGITUDE);
}
*/

/*
function on_navigator_geolocation_complete(position) {
    if (position.address != undefined) {
        if (position.address.streetNumber != null && position.address.street != null &&  position.address.city != null &&  position.address.region != null) {
            get_geocode_data_by_address(position.address.streetNumber + ' ' + position.address.street + ' ' + position.address.city + ' ' + position.address.region);
        }
        else {
            get_geocode_data_by_lat_long(position.coords.latitude, position.coords.longitude);
        }
    }
    else {
        get_geocode_data_by_lat_long(position.coords.latitude, position.coords.longitude);
    }
}
*/






function draw_the_map() {
    get_geocode_data_by_address($('#address').val());
    // return false;
}

function location_html_found(position) {
    $('#location-overlay').hide();
    currentLat = position.coords.latitude;
    currentLong = position.coords.longitude;
    get_geocode_data_by_lat_long(position.coords.latitude, position.coords.longitude);
}

function location_html_error(error) {
    $('#location-overlay').hide();
    $('#current_location').hide();
    /*
    $.ajax({
        url: BASE_URL + 'index.php/api/location/geoip',
        type: 'GET',
        success: on_ajax_geoip
    });
    */
}

$(document).ready(function () {

    google_map.scrub();
    google_map.dealer_map_new_bounds = new google.maps.LatLngBounds(
        new google.maps.LatLng(-39.368279,110.551756),
        new google.maps.LatLng(-9.968851,155.463865)
        );
    google_map.show();

    $('#location-wrapper').submit(function() {
		draw_the_map();
		
		return false;
	});
    $('#dealer-types input').change(draw_the_map);
    $('#radius').change(draw_the_map);

    if ( navigator.geolocation ) {
        $('#current_location').show();
        $('#current_location').click(function(){
            if (currentLat && currentLong) {
                get_geocode_data_by_lat_long(currentLat, currentLong);
            }
            else if ( navigator.geolocation ) {
                $('#location-overlay').show();
                navigator.geolocation.getCurrentPosition(location_html_found,location_html_error, {
                    timeout:5000, 
                    maximumAge:100000
                } );
            }
            else {
                location_html_error('null');
            }

            return false;
        });
    }
    else {
        $('#current_location').hide();
    }

    $(function() {
        $("#address").autocomplete({
            source: function(request, response) {
                google_map.geocoder.geocode( {
                    'address': request.term, 
                    'region': 'au'
                }, function(results, status) {
                    response($.map(results, function(item) {
                        google_geocode.geocode = item;
                        
                        if (google_geocode.get_geocode_component('country') == 'AU') {
                            return {
                                label:  item.formatted_address,
                                value: item.formatted_address,
                                latitude: item.geometry.location.lat(),
                                longitude: item.geometry.location.lng(),
                                data: item
                            }
                        }
                        else {
                            return null;
                        }
                    }));
                })
            },
            //This bit is executed upon selection of an address
            select: function(event, ui) {
                snapshot.geocode = ui.item.data;

                on_ajax_geocode(snapshot.geocode);
            },
            autoFocus: true
        });
    });

    
    // @todo move to css
/*
    $("#preferred-dealer-wrapper").hide();
    $('#all').attr('checked', 'checked').change();
    
    $("input[name='dealer_type']").change(function() {
        get_geocode_data_by_address($('#address').val());
        //lookup_dealer_listing($('#address').val(), $("input[name='dealer_type']:checked").val());
    });

    $("select[name='radius']").change(function() {
        get_geocode_data_by_address($('#address').val());
    });

    $(function() {
        $("#address").autocomplete({
            source: function(request, response) {
                google_map.geocoder.geocode( {'address': request.term, 'region': 'au' }, function(results, status) {
                    response($.map(results, function(item) {
                        google_geocode.geocode = item;
                        
                        if (google_geocode.get_geocode_component('country') == 'AU') {
                            return {
                                label:  item.formatted_address,
                                value: item.formatted_address,
                                latitude: item.geometry.location.lat(),
                                longitude: item.geometry.location.lng(),
                                data: item
                            }
                        }
                        else {
                            return null;
                        }
                    }));
                })
            },
            //This bit is executed upon selection of an address
            select: function(event, ui) {
                snapshot.geocode = ui.item.data;

                on_ajax_geocode(snapshot.geocode);
            },
            autoFocus: true
        });
    });
*/

    /* navigator.geolocation.getCurrentPosition(on_navigator_geolocation_complete,on_navigator_geolocation_error); */
});


