﻿////////////////////////////////////////////////////////////////////////////
// Copyright 2009 Ingenios Ltd.
// http://ingenios.co.uk
////////////////////////////////////////////////////////////////////////////

google.load("maps", "2", {"other_params":"sensor=false"});
google.load("search", "1");

var _geocoder;
var _lsearchctrl;
var _callbk_createmap;
var _callbk_click;

function maps_init(callbk_createmap, callbk_click) {
  _callbk_createmap = callbk_createmap;
  _callbk_click = callbk_click;

  _geocoder = new google.maps.ClientGeocoder();
  _geocoder.setBaseCountryCode('uk');
  _lsearchctrl = new google.search.LocalSearch();
  //FAILS/map.addControl(_lsearchctrl);

  google.setOnLoadCallback(maps_init_afterload);
}

function maps_init_afterload() {
  if (google.maps.BrowserIsCompatible()) {
    var map;

    if (_callbk_createmap) {
      map = _callbk_createmap();

      if (_callbk_click) {
        google.maps.Event.addListener(map, "click", action_mapclick);
      }
    }
  }
}

function lookup_addr(searchaddr, callbk_geo) {
  if (!searchaddr) {
    alert("Please enter a postcode, address or town.");
  } else {
    //OLD/addr = fix_if_postcode(addr);
    //OLD/_geocoder.getLatLng(addr, function(latlng) { action_geo(addr, callbk_geo, latlng); });
    //OLD/_geocoder.getLocations(addr, function(latlng) { action_geo(addr, callbk_geo, latlng); });
    _lsearchctrl.setSearchCompleteCallback(null,
            function() { action_localsearch(searchaddr, callbk_geo, _lsearchctrl.results); });
    _lsearchctrl.execute(searchaddr + ", UK");
  }
}

function lookup_latlng(searchlatlng, callbk_revgeo) {
  _geocoder.getLocations(searchlatlng,
          function(resp) { action_reversegeo(searchlatlng, callbk_revgeo, resp); });
}


function action_mapclick(overlay, latlng, overlaylatlng) {
  if (latlng != null) {
    _callbk_click(latlng);
  }
}

function action_reversegeo(searchlatlng, callbk_revgeo, response) {
  if (!response || response.Status.code != 200 || response.Placemark.length == 0) {
    callbk_revgeo(searchlatlng, null);
  } else {
    //' Orig LatLng    => response.name 
    //' LatLng         => place.Point.coordinates[0],  place.Point.coordinates[1]
    //' Status Code    => response.Status.code
    //' Status Request => response.Status.request
    //' Address        => place.address
    //' Accuracy       => place.AddressDetails.Accuracy
    //' Country Code   => place.AddressDetails.Country.CountryNameCode

    //place = response.Placemark[0];
    //point = create_latlng(place.Point.coordinates[1],place.Point.coordinates[0]);
    callbk_revgeo(searchlatlng, response.Placemark[0]);
  }
}

//OLD/function action_geo(searchaddr, callbk_geo, latlng) {
//OLD/  if (!latlng) {
//OLD/    alert("Could not find '" + searchaddr + "'.");
//OLD/  } else {
//OLD/    callbk_geo(searchaddr, latlng);
//OLD/  }
//OLD/}

function action_localsearch(searchaddr, callbk_geo, results) {
  var hit = find_first(results, function(result){return result.country=='GB'});
  if (!hit) {
    alert("Could not find '" + searchaddr + "'.");
  } else {
    callbk_geo(searchaddr, create_latlng(hit.lat, hit.lng));
  }
}

// -------------- directions functions ---------------

var _ishandling_directionscomplete = false;
var _callbk_directionscomplete = null;

function action_directionscomplete() {
  if (_callbk_directionscomplete) {
    _callbk_directionscomplete();
    _callbk_directionscomplete = null;
  }
}
//function action_directionsload() {
//}
//function action_directionserror() {
//}

function display_directions(gdir, llfrom, llto, fncomplete) {
  if (!_ishandling_directionscomplete) {
    google.maps.Event.addListener(gdir, "addoverlay", action_directionscomplete);
    //google.maps.Event.addListener(gdir, "load", action_directionsload);
    //google.maps.Event.addListener(gdir, "error", action_directionserror);
    google.maps.Event.addListener(gdir, "error", action_directionscomplete);
    _ishandling_directionscomplete = true;
  }

  _callbk_directionscomplete = fncomplete;
  gdir.loadFromWaypoints( [ llfrom.lat() + "," + llfrom.lng(),
                            llto.lat() + "," + llto.lng() ] );
}

// -------------- map util functions ---------------

function create_latlng(lat,lng) {
  // NB.Google maps has a nasty bug..
  //    if 'lat' is passed in as a string, 'lat()' returns a number (GOOD)
  //    if 'lng' is passed in as a string, 'lng()' returns a string!! (BAD!!)
  return new google.maps.LatLng(parseFloat(lat), parseFloat(lng));
  //(not as browser independent)
  //return new google.maps.LatLng(Number(lat), Number(lng));
}

function boundsbegin(latlng) {
  var bnds = new google.maps.LatLngBounds(latlng,latlng);
  boundsextend(bnds,latlng);
  return bnds;
}

function boundsextend(bnds, latlng) {
  var r = 0.10;  //sweet spot 0.03 to 0.10
  bnds.extend(create_latlng(latlng.lat() + r, latlng.lng() + r));
  bnds.extend(create_latlng(latlng.lat() - r, latlng.lng() - r));
}

function toMiles(metres) {
  return metres / 1609.334;
}

function dist_calc(lat1, lon1, lat2, lon2) {
  var R = 6378137;
  var d = Math.sin(toRad(lat1))*Math.sin(toRad(lat2)) +
          Math.cos(toRad(lat1))*Math.cos(toRad(lat2))*Math.cos(toRad(lon2-lon1));
  // work around buggy javascript math...
  // (sometimes d calculates to 1.0000000000000002, which is
  //  outside the  -1 <= x <= 1  range required for acos() )
  d = (d > 1.0)? 1.0 : d;
  d = (d < -1.0)? -1.0 : d;
  return R * Math.acos(d);
}

// ------------- other util functions ---------------

function fix_if_postcode(addr) {
  // if postcode with no space, insert space at proper position.
  // geocoder needs this (but localsearch doesn't).
  var i = addr.length - 3;
  var reg = /^([a-z]\d|[a-z]\d\d|[a-z]\d[a-z]|[a-z][a-z]\d|[a-z][a-z]\d\d|[a-z][a-z]\d[a-z])\d[a-z][a-z]$/i;
  return reg.test(addr)? addr.substring(0,i)+' '+addr.substring(i) : addr;
}
