(function() {

  /*
   Google Maps Mobile API
   @author Owain Lewis
   @url www.owainlewis.com
  */

  var MarkerError;
  var _this = this;

  window.Map = {};

  /*
  Custom Map Exception
  */

  MarkerError = function(message) {
    this.name = "MarkerError";
    return this.message = "Could not plot given point on map";
  };

  MarkerError.prototype = Error.prototype;

  /*
   A GMap Object that can be called across functions
  */

  Map.defaultOptions = {
    zoom: 10,
    center: Map.london,
    disableDefaultUI: true,
    zoomControl: true,
    mapTypeId: google.maps.MapTypeId.ROADMAP,
    height: 480
  };

  /*
  Map Direction Service
  */

  Map.directionsService = new google.maps.DirectionsService();

  /*
  Map Directions Render Object
  */

  Map.directionsDisplay = new google.maps.DirectionsRenderer();

  Map.refresh = function() {
    var map;
    map = null;
    return $("#mapDiv").html("");
  };

  Map.updateDistance = function(d) {
    return $('#distance_from_location').html("Walking distance: " + d + " from your current location");
  };

  Map.showAllPubs = function(map) {
    var pubs;
    var _this = this;
    pubs = parser.getAllPubs();
    return _.each(pubs, function(pub, index) {
      if (pub.lat !== "NULL") {
        return Map.addPub(map, pub['lat'], pub['long'], pub['id']);
      }
    });
  };

  /*
  
  @description Return the type of icon we need
  @returns {String} Image Path i.e /images/icon.png
  */

  Map.getPubIcon = function() {
    var icon;
    icon = 'assets/images/pint.png';
    return icon;
  };

  Map.getIcon = function(type) {
    var icon;
    switch (type) {
      case "pub":
        icon = Map.getPubIcon();
        break;
      case "attraction":
        icon = 'assets/images/attraction_icon.png';
        break;
      default:
        icon = "assets/images/default_icon.png";
    }
    return icon;
  };

  Map.addPub = function(map, lat, long, id) {
    var html, info, marker_title, temp;
    marker_title = new google.maps.Marker({
      position: new google.maps.LatLng(lat, long),
      map: map,
      icon: Map.getPubIcon(),
      title: Fullers.Utils.getPubAttr(id, "name")
    });
    html = "<img class='map_image' src=\"assets/pubs/<%= p_img %>\" />\n<h1><%= p_name %></h1>\n<p><%= p_addr %></p>\n<a href=\"<%= p_link %>\">View pub details</a>";
    temp = _.template(html, {
      p_img: Fullers.Utils.getPubAttr(id, "image"),
      p_name: Fullers.Utils.getPubAttr(id, "name"),
      p_addr: Fullers.Utils.getPubAttr(id, "address"),
      p_link: "#/detail/" + id
    });
    info = new google.maps.InfoWindow({
      content: temp
    });
    return google.maps.event.addListener(marker_title, 'click', function() {
      return info.open(map, marker_title);
    });
  };

  Map.addMarker = function(map, lat, long, marker_title, callback, type) {
    marker_title = new google.maps.Marker({
      position: new google.maps.LatLng(lat, long),
      map: map,
      icon: Map.getIcon(type),
      title: marker_title
    });
    if (callback) {
      return google.maps.event.addListener(marker_title, 'click', function() {
        return callback.call(this);
      });
    }
  };

  Map.parseOptions = function(arr) {
    var cons, _results;
    _results = [];
    while (arr.length) {
      _results.push(cons = arr.pop);
    }
    return _results;
  };

  Map.render = function(lat, long) {
    var map;
    if (!arguments.length) {
      map = new google.maps.Map(document.getElementById("mapDiv"), Map.defaultOptions);
      return Map.showAllPubs(map);
    } else {
      return alert(arguments);
    }
  };

  Map.renderDirectionResponse = function(response, status, dist) {
    var map;
    map = new google.maps.Map(document.getElementById("mapDiv"), Map.defaultOptions);
    if (status === google.maps.DirectionsStatus.OK) {
      Map.updateDistance(dist);
      Map.directionsDisplay.setMap(map);
      return Map.directionsDisplay.setDirections(response);
    } else {
      return alert(response + " : " + status);
    }
  };

  /*
    Map.renderDirections - Render directions to a destination (param) from yuor current location 
    @params {dest} The destination you are trying to get directions to. Can be any string i.e "london bridge"
  */

  Map.renderDirections = function(from, dest) {
    var request;
    if (arguments.length !== 2) {
      throw new Error("" + arguments.length + " of 2 required args");
    }
    request = {
      origin: from,
      destination: dest,
      travelMode: google.maps.DirectionsTravelMode.WALKING
    };
    return Map.directionsService.route(request, function(response, status) {
      var distance_from_current_location;
      distance_from_current_location = response.routes[0].legs[0].duration.text;
      return Map.renderDirectionResponse(response, status, distance_from_current_location);
    });
  };

  Map.pubIsNear = function(pub, loc) {
    var distance;
    if (loc != null) {
      distance = Map.distance(loc.lat, loc.long, pub.lat, pub.long, "M");
      if (distance < 0.3) {
        return true;
      } else {
        return false;
      }
    }
  };

  Map.getListHTML = function() {
    var lambda, nearbyPubs, pub, pubs, _i, _len;
    pubs = Fullers.Modules.Parser.getAllPubs();
    nearbyPubs = [];
    for (_i = 0, _len = pubs.length; _i < _len; _i++) {
      pub = pubs[_i];
      if (Map.pubIsNear(pub, Map.pos)) nearbyPubs.push(pub);
    }
    if (nearbyPubs.length > 0) {
      $('#no_pubs').hide();
    } else {
      $('#no_pubs').show();
    }
    lambda = function() {
      var res;
      res = _.map(nearbyPubs, function(p) {
        return "<li><a href='#/detail/" + p.id + "'><img src='assets/pubs/" + p.image + "' /><h2>" + p.name + "<span>" + p.address + "</span></h2></a></li>";
      });
      return res.join('');
    };
    return lambda.call(this);
  };

  Map.renderAsList = function() {
    var map_view_list;
    $("#map_list").show();
    map_view_list = document.getElementById('map_list_view');
    return map_view_list.innerHTML = Map.getListHTML();
  };

  Map.renderSingleLocation = function(lat, long, type) {
    var map;
    map = new google.maps.Map(document.getElementById("mapDiv"), Map.defaultOptions);
    map.setCenter(new google.maps.LatLng(lat, long));
    map.setZoom(16);
    return Map.addMarker(map, lat, long, "The pub", null, type);
  };

  Map.postcodeSearch = function(query, name) {
    var geo, map, opts;
    opts = {
      zoom: 15,
      disableDefaultUI: true,
      zoomControl: true,
      mapTypeId: google.maps.MapTypeId.ROADMAP
    };
    map = new google.maps.Map(document.getElementById("mapDiv"), opts);
    geo = new google.maps.Geocoder();
    Map.addAddress(map, geo, query);
    return Map.showAllPubs(map);
  };

  Map.renderCurrentLocation = function(lat, long, pubs, attractions) {
    var map;
    map = new google.maps.Map(document.getElementById("mapDiv"), Map.defaultOptions);
    map.setCenter(new google.maps.LatLng(lat, long));
    map.setZoom(16);
    Map.addMarker(map, lat, long, "Current Location");
    Map.pos = {
      lat: lat,
      long: long
    };
    return Map.showAllPubs(map);
  };

  Map.addAddress = function(map, geocoder, addr, callback) {
    postcode.setMapPosFromPostcode(addr);
    return geocoder.geocode({
      'address': addr
    }, function(results, status) {
      if (status === google.maps.GeocoderStatus.OK) {
        map.setCenter(results[0].geometry.location);
        if (callback) callback.call(map);
        return new google.maps.Marker({
          map: map,
          icon: 'assets/images/attraction_icon.png',
          position: results[0].geometry.location
        });
      } else {
        alert("Sorry. Geocoder could not find that location");
        return Fullers.renderBaseURL();
      }
    });
  };

  Map.distance = function(lat1, lon1, lat2, lon2, unit) {
    var dist, radlat1, radlat2, radlon1, radlon2, radtheta, theta;
    radlat1 = Math.PI * lat1 / 180;
    radlat2 = Math.PI * lat2 / 180;
    radlon1 = Math.PI * lon1 / 180;
    radlon2 = Math.PI * lon2 / 180;
    theta = lon1 - lon2;
    radtheta = Math.PI * theta / 180;
    dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(radtheta);
    dist = Math.acos(dist);
    dist = dist * 180 / Math.PI;
    dist = dist * 60 * 1.1515;
    if (unit === "K") dist = dist * 1.609344;
    if (unit === "N") dist = dist * 0.8684;
    return dist;
  };

}).call(this);

