// Global variables

var qiblaLat = 21.42252;
var qiblaLng = 39.82621;
 
var geocoder = null;
var map = null;
var centerMarker = null;

function load(startAddr, startLat, startLng, startZoom) {

 if ( !GBrowserIsCompatible()) {
   alert("I am sorry. But Browser not supported" );
   return;
 }
 
  if (!startAddr) startAddr = '';
  if (!startLat) startLat = 37.7752;
  if (!startLng) startLng = -122.4192;
  if (!startZoom) startZoom = 15;
 
map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(37.4419, -122.1419), 13);
map.enableInfoWindow();
geocoder = new GClientGeocoder();
        
var home = new GLatLng(startLat, startLng);

map.addControl(new GLargeMapControl());
map.addControl(new GMapTypeControl());
map.addControl(new GScaleControl());
map.setCenter(home, startZoom);
     
var icon = new GIcon(null, 'images/crosshair.gif');
  icon.iconSize = new GSize(17, 17);
  icon.iconAnchor = new GPoint(8, 8);
  centerMarker = new GMarker(home, {icon: icon, clickable: false});

  GEvent.addListener(map, 'move', mapDraw);
  document.getElementById('address').value = startAddr;
  leaveAddressField();
  mapDraw();
  
}

// update map 
function mapDraw()
{
  var center = map.getCenter();
  var lng = center.lng();
  var lat = center.lat();
  
  var qiblaDir = calcQiblah(lat, lng, qiblaLat, qiblaLng);

  map.clearOverlays();
  centerMarker.setPoint(center);
  map.addOverlay(centerMarker);

  var line = getLine(lat, lng, qiblaDir);
  map.addOverlay(line); 
  
  updateCompassImage( qiblaDir );
}

function updateCompassImage( qiblaDir )
{
  document.getElementById( "compassImage").src = "images/compassPointer.png?angle=" + qiblaDir;
}


function calcQiblah(lat1, lon1, lat2, lon2) {
  var dLon = (lon2-lon1).toRad();
  var dPhi = Math.log(Math.tan(lat2.toRad()/2+Math.PI/4)/Math.tan(lat1.toRad()/2+Math.PI/4));
  if (Math.abs(dLon) > Math.PI) dLon = dLon>0 ? -(2*Math.PI-dLon) : (2*Math.PI+dLon);
  
  return Math.atan2(dLon, dPhi).toBrng();
}

function getLine(lat, lng, angle)
{
  var factor = 8;
  var zoom = map.getZoom();
  var dLng = factor/ Math.pow(2, zoom- 7);
  if (zoom < 7) dLng = factor;

  dLng = dLng* Math.sin(dtr(angle));

  var from = new GPoint(lng, lat);
  var lat2 = getLat(lat, angle, dLng)
  var to = new GPoint(lng+ dLng, lat2);
  if (Math.abs(dLng) > Math.abs(lng- qiblaLng))
    to = new GPoint(qiblaLng, qiblaLat);

  var line = new GPolyline([ from, to ], '#FF0000', 4);
  return line;
}

// Misc Function
var addrEmptyMsg = "Enter Address OR Zip code";

function leaveAddressField()
{
  var address = document.getElementById('address');

  if (address.value == '' || address.value == addrEmptyMsg)
  {
    address.style.color = '#999999';
    address.value = addrEmptyMsg;
  }
}

function addressFieldFocus()
{
  var address = document.getElementById('address');

  address.style.color = '#000000';
  if (address.value == addrEmptyMsg)
    address.value = '';
}



//-------------------------- Geocoder Functions -----------------------


// browse address
function browseAddress() 
{
  var address = document.getElementById('address').value;
  if (address == '' || address == addrEmptyMsg)
  {
    alert(addrEmptyMsg);
    return;
  }
  geocoder.getLocations(address, showAddressOnMap);
  return false;
}


// show address on map
function showAddressOnMap(response) 
{
  if (!response || response.Status.code != 200) 
    alert('Address not found. Please try again');
  else 
  {
    place = response.Placemark[0];
    point = new GLatLng(place.Point.coordinates[1], place.Point.coordinates[0]);
    map.setCenter(point, 8+ place.AddressDetails.Accuracy);
    marker = new GMarker(point);
    map.addOverlay(marker);
    marker.openInfoWindowHtml(place.address);
  }
}

//-------------------------- Angle Unit Conversion -----------------------


// degree to radian
function dtr(d)
{
    return (d* Math.PI)/ 180.0;
}

// radian to degree
function rtd(r)
{
    return (r* 180.0)/ Math.PI;
}


// find lat2 for a given direction
function getLat(lat1, angle, dLng) 
{
  return rtd(getLatRad(dtr(lat1), dtr(angle), dtr(dLng)));
}

function getLatRad(lat1, angle, dLng) 
{
  return Math.atan((Math.sin(dLng)+ Math.tan(angle)* Math.sin(lat1)* Math.cos(dLng))/ (Math.tan(angle)* Math.cos(lat1)));
}


/////////// Extension functions

Number.prototype.toRad = function() {  // convert degrees to radians
  return this * Math.PI / 180;
}

Number.prototype.toDeg = function() {  // convert radians to degrees (signed)
  return this * 180 / Math.PI;
}

Number.prototype.toBrng = function() {  // convert radians to degrees (as bearing: 0...360)
  return (this.toDeg()+360) % 360;
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */

// extend Number object with methods for presenting bearings & lat/longs

Number.prototype.toDMS = function() {  // convert numeric degrees to deg/min/sec
  var d = Math.abs(this);  // (unsigned result ready for appending compass dir'n)
  d += 1/7200;  // add ½ second for rounding
  var deg = Math.floor(d);
  var min = Math.floor((d-deg)*60);
  var sec = Math.floor((d-deg-min/60)*3600);
  // add leading zeros if required
  if (deg<100) deg = '0' + deg; if (deg<10) deg = '0' + deg;
  if (min<10) min = '0' + min;
  if (sec<10) sec = '0' + sec;
  return deg + '\u00B0' + min + '\u2032' + sec + '\u2033';
}

Number.prototype.toLat = function() {  // convert numeric degrees to deg/min/sec latitude
  return this.toDMS().slice(1) + (this<0 ? 'S' : 'N');  // knock off initial '0' for lat!
}

Number.prototype.toLon = function() {  // convert numeric degrees to deg/min/sec longitude
  return this.toDMS() + (this>0 ? 'E' : 'W');
}

Number.prototype.toPrecision = function(fig) {  // override toPrecision method with one which displays 
  if (this == 0) return 0;                      // trailing zeros in place of exponential notation
  var scale = Math.ceil(Math.log(this)*Math.LOG10E);
  var mult = Math.pow(10, fig-scale);
  return Math.round(this*mult)/mult;
}


