
/* File: mapTiles.js
*/
var size;   // Size of array grid in each dimension
var data;   // 2 dimensional array to hold the grid data

var sizeGridX = 6;   // Size of visible grid (table) in each dimension
var sizeGridY = 4;   // Size of visible grid (table) in each dimension

var tileWidth = 125;
var tileHeight = 125;

var markerXOffset = 4;
var markerYOffset = 11;

var offsetGridX = 450;
var offsetGridY = 207;

var zoomLevel = 1;

var needCalibration = true;

var prefixes = new Array(1);
var root1 = "http://ustile.npemap.org.uk/";
var root2 = "http://tile.npemap.org.uk/";
var root = "http://tile.npemap.org.uk/";

prefixes[1] =  "scaled1/";
prefixes[2] =  "scaled3/";
prefixes[3] =  "scaled6/";

var jumpOut = new Array(1);
jumpOut[1] = 3;
jumpOut[2] = 2;
var jumpIn = new Array(1);
jumpIn[2] = 3;
jumpIn[3] = 2;

var zooms = new Array(1);
zooms[1] = 1;
zooms[2] = 3;
zooms[3] = 6;


var screenWidth = YAHOO.util.Dom.getViewportWidth();
var screenHeight = YAHOO.util.Dom.getViewportHeight();
var bottomLeft = new Array();


var markerElement;
var postcodeFormElement;
var mainPageElement;


// Postcode specific helper functions
function box1Keypress(e) {
  var event = YAHOO.util.Event.getEvent(e);
  var key = String.fromCharCode(YAHOO.util.Event.getCharCode(event));
  if (key == ' ') {
    $('postcode2').focus();
    return false;
  } else if (key >= '0' && key <= '9' && this.value.length == 3) {
    this.value = this.value + key;
    $('postcode2').focus();
    YAHOO.util.Event.preventDefault(event);
  }
}


YAHOO.util.Event.addListener('postcode1', 'keypress', box1Keypress );


function showPostcodeWindow(easting, northing, x, y) {
    hideMarkerWindow();

    var easting = trimSixDigits(Math.round(easting));
    var northing = trimSixDigits(Math.round(northing));

    markerElement.style.visibility = 'visible';
    YAHOO.util.Dom.setXY(markerElement, [(x-markerXOffset), (y-markerYOffset)]);
    
    postcodeFormElement.style.display = 'block';
    YAHOO.util.Dom.setXY(postcodeFormElement, [Math.max(0, (x-50)), (y-180) < 0 ? (y+10):(y-180)]);
    
   // Compute lat+long
   var en = new OSRef(easting,northing);
   var latlong = en.toLatLng();
   var lat = Math.round(latlong.lat*10000) / 10000;
   var lng = Math.round(latlong.lng*10000) / 10000;
   

    $('location').innerHTML = easting + ', ' + northing + " (" + lat + ", " + lng + ")";
    $('easting').value = easting;
    $('northing').value = northing;
    $('returnX').value = offsetGridX;
    $('returnY').value = offsetGridY;

    $('postcode1').value = "";
    $('postcode2').value = "";
    $('postcode1').focus();

}


YAHOO.util.Event.addListener('postcode_submit', 'submit', submitPostcodeAjax);

function submitPostcodeAjax(e) {
  var el = $('postcode_submit');
  var data = Form.serialize(el);
  Element.show('status');
  $('status').innerHTML = "<p>Submitting postcode "+ $F('postcode1') + " " + $F('postcode2') + "...</p>";
 new Ajax.Request(el.getAttribute("action"), {
           method:"post",
           postBody:data, 
           onComplete: function(o) {drawExisting(); updateStatus(o);  }
 });
 closePostcodeWindow();
 YAHOO.util.Event.preventDefault(e);
}

var updateStatus = function(o) {
  $('status').innerHTML = o.responseText; 
}



function closePostcodeWindow() {
  postcodeFormElement.style.display = 'none';
  markerElement.style.visibility = 'hidden';
}

function showMarkerWindow(x,y, postcode, easting, northing, source, id) {
  closePostcodeWindow();
   // Compute lat+long
   var en = new OSRef(easting,northing);
   var latlong = en.toLatLng();
   var lat = Math.round(latlong.lat*10000) / 10000;
   var lng = Math.round(latlong.lng*10000) / 10000;

   // Display
   $('location_detail').innerHTML = easting + ", "+northing;
   $('latlong_detail').innerHTML = lat + ", " + lng;
   $('postcode_detail').innerHTML = postcode;
   $('postcode_id_detail').value= id; 
   $('reason_email').value= ''; 
   $('reason').value= ''; 
   $('source_detail').innerHTML = ((source == 0) ? 'this site' : '<a href="http://www.freethepostcode.org/">freethepostcode.org</a>');
   $('postcode_detail_window').style.display = 'block';
   $('bad').style.display = '';
   $('report_form').style.display = 'none';
   YAHOO.util.Dom.setXY('postcode_detail_window', [Math.max(0, (x-50)), (y-100) < 0 ? (y+10):(y-100)]);
}

function hideMarkerWindow() {
   $('postcode_detail_window').style.display = 'none';
}


// MAP METHODS --------------------------------------------

function mapClick(e) {
    e = YAHOO.util.Event.getEvent(e);
    var img = YAHOO.util.Event.getTarget(e);
    var x = YAHOO.util.Event.getPageX(e);
    var y = YAHOO.util.Event.getPageY(e);
    var imgPos = YAHOO.util.Dom.getXY(img);
    var tileX = x - imgPos[0];
    var tileY = y - imgPos[1];
    // Tiles are eee/nnn.jpg
    var tile = img.src.substring( img.src.lastIndexOf("/") - 3 );
    var baseEasting = tile.substring(0, tile.indexOf("/"))-0;
    var baseNorthing = tile.substring(tile.indexOf("/") + 1, tile.indexOf("."))-0;
    var tileXratio =  tileX/img.offsetWidth;
    var tileYratio = 1 -(tileY/img.offsetHeight);
    if (zoomLevel != 1) {
      // Zoom in.
      gotoLocation(Math.round((baseEasting -0 + tileXratio) * zooms[zoomLevel]), 
			             Math.round((baseNorthing -0 + tileYratio) *  zooms[zoomLevel]),
									  zoomLevel - 1);
    } else {
    
      showPostcodeWindow(((baseEasting  + tileXratio)*1000), ((baseNorthing +tileYratio)*1000), x, y); 

    }
  }

YAHOO.util.Event.addListener('map', 'click', mapClick);



function zoomOut() {
	if(zoomLevel == (prefixes.length-1)) {
    location.href="allmaps.html";
		return;
	}
	tidyUp();

  gotoLocation(offsetGridX * zooms[zoomLevel], offsetGridY * zooms[zoomLevel], zoomLevel + 1);
}

function tidyUp() {
  removeMarkers();
}

function zoomIn() {
	if(zoomLevel == 1) {
		return;
	}

  gotoLocation(offsetGridX * zooms[zoomLevel], offsetGridY * zooms[zoomLevel], zoomLevel - 1);
}

function fixZoomButton() {
  if(zoomLevel == 1) {
    Element.hide('zoomin_enabled');
    Element.show('zoomin_disabled');
    Element.show('showHideMarkers');
	} else {
    Element.show('zoomin_enabled');
    Element.hide('zoomin_disabled');
    Element.hide('showHideMarkers');
  }
}

function doResize() {
  screenWidth = YAHOO.util.Dom.getViewportWidth();
  screenHeight = YAHOO.util.Dom.getViewportHeight();
  drawTable();
  refreshGrid();
}

function drawTable() {
  sizeGridX = Math.floor(((screenWidth -210) / tileWidth));
  sizeGridY = Math.floor(((screenHeight -130) / tileHeight));
  var map = $('map');
  map.innerHTML = '';
  for(var y=sizeGridY; y>=1; y--) {
    for(var x=1; x<=sizeGridX; x++) {
			map.appendChild(createIMG(tileWidth, tileHeight, 'element'+x+'.'+y));
     }
		 map.appendChild(document.createElement('br')); 
  }
  
  $('map').style.width = (sizeGridX * tileWidth) + "px" ;
}

function createIMG(width, height, id) {
  var img = document.createElement('img');
	img.width = width;
	img.height = height;
	img.id = id;
	return img;
}


function initializePage() {
		markerElement = $('marker');
		postcodeFormElement = $('postcode_form');
    mainPageElement = $('main_page');

    updateShowMarkers();
    parseQueryString();
    fixZoomButton();

    doResize();
}

function reload_page() {
    parseQueryString();
    fixZoomButton();
    refreshGrid();
}
  

function parseQueryString() {
  var hash = location.href.lastIndexOf('#');
	var query = location.href.lastIndexOf("?")
  var params = '';
  if (hash != -1) {
    params = location.href.substring(hash+1);
  }
  else if (query != -1) {
    params = location.href.substring(query+1);
  }
  if (params.length > 0) {
    urlterms=params.split(",")
    offsetGridX = urlterms[0]-0 ; 
    offsetGridY = urlterms[1]-0 ; 

    if(urlterms.length > 2) {
      zoomLevel = urlterms[2]-0 ;
    }
	}
}

function gotoLocation(easting, northing, zoom) {
  offsetGridX = Math.round(easting / zooms[zoom]); 
  offsetGridY = Math.round(northing/ zooms[zoom]); 
  zoomLevel = zoom;
  fixZoomButton();
  refreshGrid();
}


// Need to use substring for IE, and it doesn't take negative numbers.
function trimNumber(string) {
  str = '000' + string
	return str.substring(str.length -3)
}

function trimSixDigits(string) {
  str = '000000' + string
	return str.substring(str.length -6)
}

function refreshGrid() {
  closePostcodeWindow();
  hideMarkerWindow();

	for(var x=1; x<=sizeGridX; x++) {
		for(var y=1; y<=sizeGridY; y++) {
            tileX = x+offsetGridX-Math.round(sizeGridX/2);
            tileY = y+offsetGridY-Math.round(sizeGridY/2);
            $('element' + x + '.' + y).src = tileURL(tileX, tileY);
        }
    }
  minEasting = (offsetGridX-Math.round(sizeGridX/2))+1;
  minNorthing= (offsetGridY-Math.round(sizeGridY/2))+1;
  maxEasting = minEasting + sizeGridX;
  maxNorthing= minNorthing + sizeGridY;

  if (zoomLevel == 1) {
		drawExisting();
	}
	updatePermalink();
}

function tileURL(tileX, tileY) {
	  //var root = (tileX % 2) == 0 ? root1 : root2;
		return root + prefixes[zoomLevel]+trimNumber(tileX)+'/'+ trimNumber(tileY) + '.jpg';
}

function drawExisting() {
	if (shouldWeShowMarkers()) {
		var url = "../../cgi/get-postcodes.fcgi";
		var params = "mineasting=" + minEasting + "000&maxeasting="  + maxEasting + "000&minnorthing=" + minNorthing + "000&maxnorthing=" + maxNorthing+"000";
		
		removeMarkers();
    $('spinner').innerHTML = "<p>Loading....</p>";
		needCalibration = true;
		
    var myAjax = new Ajax.Request(url, {
        method: 'get',
        parameters: params,
        onComplete: successHandler,
        onFailure: failHander
    });
        
  }
}
var successHandler = function(o){ 
  eval(o.responseText);  
}

var failHander = function(o) {
  // Don't do anything
  $('spinner').innerHTML = '<p class="error">Problem showing existing data.</p>';
}

function findMarkerOffsets() {
  newMarker = document.createElement('div');
  newMarker.style.position = 'absolute';
  mainPageElement.appendChild(newMarker);

  topLeft = YAHOO.util.Dom.getXY('element1.' + sizeGridY);
  var bottom = topLeft[1] + (tileHeight*sizeGridY);
 
  YAHOO.util.Dom.setXY(newMarker, [topLeft[0] - markerXOffset, bottom - markerYOffset]);
  

  markerLeft = parseInt(newMarker.style.left);
  markerTop= parseInt(newMarker.style.top);
  mainPageElement.removeChild(newMarker);
	needCalibration = false;
}

function completeMarkers() {
	$('spinner').innerHTML = "&nbsp;";
}


var markers = new Array();
var nextMarker = 0;

function removeMarkers() {
  var pageElement = $('main_page');
  for(var i=0; i<nextMarker; i=i+1) {
    markers[i].style.visibility = 'hidden';
  }
  markerElement.style.visibility = 'hidden';
  nextMarker = 0;
}

var markerColours = new Array(1);
markerColours[0] = "../images/green-marker.gif";
markerColours[1] = "../images/blue-marker.gif";


function addMarker(postcode, easting, northing, others ) {
  // Others is an array for us to put extra stuff in

  var newMarker;
  var id = others[0];
  var source = others[1];

  if (needCalibration) findMarkerOffsets();

  if (nextMarker < markers.length) {
    newMarker = markers[nextMarker]; 
  	var img=newMarker.firstChild;
    newMarker.style.visibility = 'visible';
  }
  else {
    newMarker = document.createElement('div');
  	var img=document.createElement('img');
    newMarker.appendChild(img);
    newMarker.className = 'postcode_marker';
    markers[markers.length] = newMarker;
    mainPageElement.appendChild(newMarker);
  }
  img.title = postcode;
  img.src = markerColours[source]; 

  nextMarker = nextMarker + 1;


  var x = ((easting / 1000) - minEasting) * tileWidth;
  var y = ((northing / 1000) - minNorthing) * tileHeight;
  
  newMarker.onclick = function(e) { 
    e = YAHOO.util.Event.getEvent(e);
    var x = YAHOO.util.Event.getPageX(e);
    var y = YAHOO.util.Event.getPageY(e);
    showMarkerWindow(x,y, postcode, easting, northing, source, id); 
  };

//  YAHOO.util.Dom.setXY(newMarker, [bottomLeft[0]+x-markerXOffset, bottom- (y+markerYOffset)]);
  setMarkerXY(newMarker, x, y);
}

function setMarkerXY(marker, x, y) {
  marker.style.left = Math.round(markerLeft + x) + 'px' ;
  marker.style.top = Math.round(markerTop - y) + 'px';
  
}


function updatePermalink() {
	$("permalink").href = "#" + getLink();
  location.href = '#'+getLink();
}

function getZoomOneLink() {
  return (offsetGridX * zooms[zoomLevel]) + "," + 
         (offsetGridY * zooms[zoomLevel]) + "," + 1;
}
function getLink() {
  return offsetGridX + "," + offsetGridY + "," + zoomLevel;
}


function updateGrid(theDirection) {
    if ( theDirection == 'right' ) {
        offsetGridX ++;
    }
    else if ( theDirection == 'left' ) {
        if ( offsetGridX > 0 )
            offsetGridX --;
    }
    else if ( theDirection == 'up' ) {
      offsetGridY ++;
    }
    else if ( theDirection == 'down' ) {
        if ( offsetGridY > 0 )
            offsetGridY --;
    }
    else if ( theDirection == 'upleft' ) {
      offsetGridY ++;
      if ( offsetGridX > 0 )
          offsetGridX --;
    }
    else if ( theDirection == 'upright' ) {
      offsetGridY ++;
      offsetGridX ++; 
    }
    else if ( theDirection == 'downleft' ) {
      if ( offsetGridY > 0 )
        offsetGridY --; 
      if ( offsetGridX > 0 )
          offsetGridX --;
    }
    else if ( theDirection == 'downright' ) {
      if ( offsetGridY > 0 )
        offsetGridY --; 
      offsetGridX ++; 
    }

	refreshGrid();
}


function find() {
  var where = $('where').value;
  if (where.length > 0) {
     request = 'http://ws.geonames.org/searchJSON?name=' +  encodeURIComponent(where)  + '&callback=getLocation&country=GB&fclass=P&style=SHORT';
    aObj = new JSONscriptRequest(request);
    // Build the script tag
    aObj.buildScriptTag();
    // Execute (add) the script tag
    aObj.addScriptTag();
  }
  return false;
}
// this function will be called by our JSON callback
function getLocation(jData) {
  if (jData == null) {
    // There was a problem parsing search results
    return;
  }

  var geonames = jData.geonames;
  if (geonames.length > 0) {
    if (geonames.length == 1) {
      var name = geonames[0];
      gotoLatLong(name.lat, name.lng, 1);
    } else {
      var popup = showGeonamesPopup();
      for(var i=0; i<geonames.length; i=i+1) {
        appendLink($('geonames_results'), geonames[i]);
      }
    }
    $('where').value = '';
  }
  else {
    alert("Sorry, can't find that location"); 
  }
}

function hideGeonamesPopup() {
 var popup = $('geonames_results_window'); 
 popup.style.display = 'none';
}

function showGeonamesPopup() {
 var popup = $('geonames_results_window'); 
 popup.style.display = 'block';
 $('geonames_results').innerHTML = '';
 
}

function appendLink(popup, loc) {
 var link = document.createElement("A");
 link.onclick = function () { gotoLatLong(loc.lat, loc.lng, 1); hideGeonamesPopup(); return false; };
 link.href = '#';
 link.innerHTML = loc.name ;
 popup.appendChild(link);
 var span = document.createElement("SPAN");
 span.className = "loc";
 formatLatLong(span, loc.lat, loc.lng);
 popup.appendChild(span);
 popup.appendChild(document.createElement("BR"));
}

function formatLatLong(parent, lat, lng) {
  var text = " N " + formatDeg(lat) + " " ;
  if (lng < 0) { text += "W ";} else { text += "E ";}
  text += formatDeg(Math.abs(lng));
  parent.appendChild(document.createTextNode(text));
}

function formatDeg(num) {
  var text = (Math.floor(num * 10)/10) + "\u00B0 ";
  return text; 
}

function gotoLatLong(lat, lng, zoom) {
    var ll = new LatLng(lat,lng);
    ll.WGS84ToOSGB36();
    var en = ll.toOSRef();
    var easting = Math.round(en.easting/1000);
    var northing = Math.round(en.northing/1000);
    gotoLocation(easting, northing, zoom);
}

function showReportForm() {
  $('report_form').style.display = 'block';
  $('bad').style.display = 'none';
  return false;
}

YAHOO.util.Event.addListener('bad', 'click', showReportForm);

function handleArrowKeys(e) {
  var event = YAHOO.util.Event.getEvent(e);
  switch (event.keyCode) {
      case 37:
          updateGrid('left');
          break;    
      case 38:
          updateGrid('up');
          break;    
      case 39:
          updateGrid('right');
          break;    
      case 40:
          updateGrid('down');
          break;    
   }
}


function shouldWeShowMarkers() {
	if (readCookie('hideMarkers')) {
		return false;
	}
	return true;
}

function setMarkersHidden() {
  createCookie("hideMarkers", 'true', 30);
	removeMarkers();
	updateShowMarkers();
}

function unsetMarkersHidden() {
  eraseCookie("hideMarkers");
	drawExisting();
	updateShowMarkers();
}

function updateShowMarkers() {
  if (shouldWeShowMarkers()) {
    $('setMarkers').style.display = ''; 
    $('unsetMarkers').style.display = 'none'; 
	} else {
    $('setMarkers').style.display = 'none'; 
    $('unsetMarkers').style.display = ''; 
	}
}


function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}

function readCookie(name) {
	var nameEQ = name + "=";
	var ca = document.cookie.split(';');
	for(var i=0;i < ca.length;i++) {
		var c = ca[i];
		while (c.charAt(0)==' ') c = c.substring(1,c.length);
		if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length,c.length);
	}
	return null;
}

function eraseCookie(name) {
	createCookie(name,"",-1);
}

