function getHTTPObject() {
  if (typeof XMLHttpRequest != "undefined") {
    return new XMLHttpRequest();
  } else if (window.ActiveXObject) {
    var aVersions = [ "MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0","MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp" ,"Microsoft.XMLHttp" ];
    for (var i = 0; i < aVersions.length; i++) {
      try {
        var oXmlHttp = new ActiveXObject(aVersions[i]);
        return oXmlHttp;
      } catch (oError) {
        //Do nothing
      }
    }
  }
  throw new Error("XMLHttp object could not be created.");
}

var httpObject = getHTTPObject();

var tableBlock = 'table';
var tableRow = 'table-row';
var tableCell = 'table-cell';
if (document.all && document.styleSheets[document.styleSheets.length - 1].rules) { tableBlock = 'block'; tableRow = 'block'; tableCell = 'block'; }

function ExchangeLabelControl() { }

ExchangeLabelControl.prototype = new GControl();

ExchangeLabelControl.prototype.initialize = function(map) {
  var container = document.createElement("div");
  container.style.width='100%';
  container.style.textAlign='center';
  var exchangeLabel = document.createElement("div");
  exchangeLabel.id = "exchangeLabel";
  container.appendChild(exchangeLabel);
  map.getContainer().appendChild(container);
  return container;
}

ExchangeLabelControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(0, 7));
}

function ExchangeSelectorControl() { }

ExchangeSelectorControl.prototype = new GControl();

ExchangeSelectorControl.prototype.initialize = function(map) {
  var container = document.createElement("div");
  container.style.width='100%';
  container.style.textAlign='center';
  var mapsInstructions = document.createElement("div");
  mapsInstructions.id = "mapsInstructions";
  mapsInstructions.innerHTML = "<div id='closeme' style='float: right; font-weight: bold; font-size: 2em; margin-right: -0.25em; margin-top: -0.25em; padding-left: 0.25em; padding-right: 0.25em; border: 1px solid #00F;'><a href='javascript: close this' style='text-decoration: none;' onclick='hideInstructions(); return false;'>X</a></div><span style='font-size: 1.2em; font-weight: bold;'>Welcome to TPG's DSLAM coverage maps,</span> kindly powered by Google<br>The blue markers above are exchanges where TPG's ADSL2+ is available. Selecting a marker will show the approximate area covered at that exchange. Selecting a point within an exchange with a TPG DSLAM will return a sample of connections closest to that point.<br>Alternatively you could enter your 'street, suburb' into the search box below, if the search result is close to or in an exchange with a TPG DSLAM then that exchange will be selected and a sample of nearby connections will be returned where possible.";
  container.appendChild(mapsInstructions);
  var exchangeSelector = document.createElement("div");
  exchangeSelector.id = "exchangeSelector";
  container.appendChild(exchangeSelector);
  map.getContainer().appendChild(container);
  return container;
}

ExchangeSelectorControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_BOTTOM_LEFT, new GSize(0, 7));
}

function KeyControl() { }

KeyControl.prototype = new GControl();

KeyControl.prototype.initialize = function(map) {
  var container = document.createElement("div");
  var key = document.createElement("div");
  key.id = "exchangeKey";
  var keyHTML = "<table>";
  keyHTML += "<tr class='yellow'><td><table cellspacing='0'>";
  keyHTML += "<tr><td colspan='2' onMouseOver='this.style.backgroundColor=\"#FF0\";' onMouseOut='this.style.backgroundColor=\"#FF8\";'>";
  keyHTML += "<a href='javascript: Frequently Asked Questions' onClick='showFAQ(\"faqs\"); return false; ' style='text-decoration: none;'>DSLAM Coverage F.A.Q.</a>";
  keyHTML += "</td></tr></table></td></tr><tr class='grey'><td><table cellspacing='0'>";
  keyHTML += "<tr><td colspan='2'>Possible cable distance<br>from the TPG dslam \"<img src='/maps/images/marker_cyan.png' height='15px'>\"</td></tr>";
  keyHTML += "<tr><td class='conType'>Protocol&nbsp;</td><td class='avgSpeed'>Average Sync</td></tr></table></td></tr>"; 
  keyHTML += "<tr id='zoneRed' class='red'><td id='zrih'><table cellspacing='0'><tr><td>Up to 1.5km</td></tr></table></td></tr>";
  keyHTML += "<tr id='zoneYellow' class='yellow'><td id='zyih'><table cellspacing='0'><tr><td>1.5km to 3km</td></tr></table></td></tr>";
  keyHTML += "<tr id='zoneGreen' class='green'><td id='zgih'><table cellspacing='0'><tr><td>3km to 4.5km</td></tr></table></td></tr>";
  keyHTML += "<tr id='zoneBlue' class='blue'><td id='zbih'><table cellspacing='0'><tr><td>Over 4.5km</td></tr></table></td></tr>";
  keyHTML += "<tr id='subExchange' class='magenta'><td><table cellspacing='0'><tr><td>Sub-Exchange</td></tr></table></td></tr>";
  keyHTML += "<tr class='grey'><td><table cellspacing='0'><tr><td>These zones should not be<br>viewed as accurate<br>Your mileage may vary.</td></tr></table></td></tr>";
  keyHTML += "</table>";
  key.innerHTML = keyHTML;
  //key.style.visibility = 'hidden';
  //key.style.display = 'none';
  container.appendChild(key);
  map.getContainer().appendChild(container);
  return container;
}

KeyControl.prototype.getDefaultPosition = function() {
  return new GControlPosition(G_ANCHOR_TOP_RIGHT, new GSize(5, 32));
}

var map = null;              
var geocorder = null;        
var exchlist = new Object();
var markers = new Object();
var boundaries = new Object();
var activeExch = null;
var selectedExch = '';
var lastExch = null;
var tmpExch = null;
var labelBuffer = null;
var geoXml = null;
var myTileLayer = null;
var tt = {};
var lsc;

var defaultZoom = 14;
var userMarker = null;

var showEverywhere = 0;

function hideInstructions() {
  document.getElementById('mapsInstructions').style.visibility = 'hidden';
  document.getElementById('mapsInstructions').style.display = 'none';
}

function hideZone(zone) {
  document.getElementById(zone).style.visibility = 'hidden';
  document.getElementById(zone).style.display = 'none';
}

function showZone(zone) {
  document.getElementById(zone).style.visibility = 'visible';
  document.getElementById(zone).style.display = tableRow;
}

function lookupExch(exch) {
  var re = new RegExp('[A-Z][A-Z][A-Z][A-Z]', 'i');
  if (!arguments[1] && exch.match(re)) { hideInstructions(); }
  if (exch == activeExch) {
    centerMarker(exch);
  } else if (httpObject) {
    if (activeExch != "GUESS") {
      clearUserMarker(); 
    }
    selectedExch = '';
    labelBuffer = null;
    if (arguments[1]) { exch += "&virgin=true"; }
    httpObject.abort();
    httpObject.onreadystatechange = handleLookupResponse;
    httpObject.open("GET", "getexchs.php?exch="+exch);
    httpObject.send(null);
  }
}

function handleLookupResponse() {
  if (httpObject.readyState == 4 && httpObject.status == 200) {
    for (var b in boundaries) {
      map.removeOverlay(boundaries[b]);
    }
//alert(httpObject.responseText);
//document.getElementById('debug').innerHTML = httpObject.responseText;
    eval(httpObject.responseText);
    pageRefresh();
  }
}

function pageRefresh() {
  for (var m in markers) {
    if ((markers[m] != null) && !(exchlist[m]) && (m != activeExch) && m.match(/^[A-Z]{4}$/)) {
      clearMarker(m);
      markers[m] = null;
    }
  }
  for (var e in exchlist) {
    if (!markers[e]) {
      if (exchlist[e].latitude && (exchlist[e].visible || showEverywhere)) {  
        var gp = new GLatLng(exchlist[e].latitude, exchlist[e].longitude);
        str = "<strong>" + e + "</strong>" + "<br/>" + exchlist[e].name +"<br/>" + exchlist[e].address;
        createMarker(gp, e, str, exchlist[e].status);
      }
    }
    if (e == activeExch) {
      centerMarker(e);
    }
    if (e == tmpExch && activeExch == 'ZZZZ') {
      activeExch = tmpExch;
    }
  }
  if (exchlist[activeExch] && exchlist[activeExch].status == "cyan") {
    selectedExch = activeExch;
  } else {
    selectedExch = '';
  }
}

function createMarker(point, id, str, status) {
  var image = "http://www.tpg.com.au/maps/images/marker_" + status + ".png" 
  
  if (markers[id]) {
    clearMarker(id);
  }
 
  var icon = new GIcon();
  icon.image = image;
  icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
  icon.iconSize = new GSize(12, 20);
  icon.shadowSize = new GSize(22, 20);
  icon.iconAnchor = new GPoint(6,20);
  icon.infoWindowAnchor = new GPoint(5, 1);
  
  var marker = new GMarker(point, icon);
  GEvent.addListener(marker, "click", function() { clearUserMarker(); if (exchlist[id]) { lookupExch(id); if (lastExch) { map.removeOverlay(myTagTileLayer); } lastExch = null; } });
  GEvent.addListener(marker, "mouseover", function() { if (exchlist[id]) { showLabel(id); if ((!activeExch || (showEverywhere && id != activeExch)) && id != lastExch) { if (lastExch) { map.removeOverlay(myTagTileLayer); } lastExch = id; map.addOverlay(myTagTileLayer); } } });
  GEvent.addListener(marker, "mouseout", function() { if (labelBuffer) { showLabel(labelBuffer); } });
  markers[id] = new Object();
  markers[id]['m'] = marker;
  markers[id]['s'] = str;
  map.addOverlay(marker);
}

function centerMarker(name) {
  if (ex = markers[name]) {
    var bounds = map.getBounds();
    var southWest = bounds.getSouthWest();
    var northEast = bounds.getNorthEast();

    if (map.getZoom() > 12 && 
       ((ex['m'].getPoint().lat() > southWest.lat()) && (ex['m'].getPoint().lat() < northEast.lat()) && 
        (ex['m'].getPoint().lng() > southWest.lng()) && (ex['m'].getPoint().lng() < northEast.lng()))) {
       map.panTo(ex['m'].getPoint());
       //map.setCenter(ex['m'].getPoint());
    } else {
       map.setCenter(ex['m'].getPoint(), defaultZoom);
    }       
  }
}

function clearMarker(exch) {
  if (m = markers[exch]) {
    map.removeOverlay(m['m']);
  }
}

function showLabel(id) {
  if (document.getElementById('exchangeLabel')) {
    if (!labelBuffer) { labelBuffer = id; }
    if (!id) { id = labelBuffer; }
    var exchangeHTML = ""; var exchangeState = ""; var exchangeIcon = "";
    if (exchlist[id]) {
      if (exchlist[id].status == "cyan") {
        exchangeState = "active";
        exchangeIcon = "<a href='http://www.tpg.com.au/products_services/adsl2plus_pricing.php'><img src='/maps/images/logo_adsl2enabled.gif' style='border: 0;'></a>";
      } else if (exchlist[id].status == "yellow") {
        exchangeState = "soon";
        exchangeIcon = "<img src='/maps/images/logo_comingsoon.gif'>";
      } else {
        exchangeState = "inactive";
      }
      exchangeHTML = "<div align='center'>";
      exchangeHTML += "<table id='" + exchangeState + "Exchange'>";
      exchangeHTML += "<tr>";
      if (exchangeIcon) { exchangeHTML += "<td>" + exchangeIcon + "</td>"; }
      exchangeHTML += "<td id='" + exchangeState + "Label' class='TitleLabel'>" + exchlist[id].name + ' (' + id + ')' + "</td></tr>";
      exchangeHTML += "<tr><td id='" + exchangeState + "Address' " + (exchangeIcon ? "colspan='2'" : "") + ">" + exchlist[id].address + "</td></tr></table>";
      exchangeHTML += "</div>";
    } else {
      if (id == 'ACT') {
        exchangeState = "Australia Capital Territory";
        document.getElementById('ACT').style.display = 'inline';
        document.getElementById('ACT').style.visibility = 'visible';
      } else {
        document.getElementById('ACT').style.display = 'none';
        document.getElementById('ACT').style.visibility = 'hidden';
      }
      if (id == 'NSW') {
        exchangeState = "New South Wales";
        document.getElementById('NSW').style.display = 'inline';
        document.getElementById('NSW').style.visibility = 'visible';
      } else {
        document.getElementById('NSW').style.display = 'none';
        document.getElementById('NSW').style.visibility = 'hidden';
      }
      if (id == 'QLD') {
        exchangeState = "Queensland";
        document.getElementById('QLD').style.display = 'inline';
        document.getElementById('QLD').style.visibility = 'visible';
      } else {
        document.getElementById('QLD').style.display = 'none';
        document.getElementById('QLD').style.visibility = 'hidden';
      }
      if (id == 'SA') {
        exchangeState = "South Australia";
        document.getElementById('SA').style.display = 'inline';
        document.getElementById('SA').style.visibility = 'visible';
      } else {
        document.getElementById('SA').style.display = 'none';
        document.getElementById('SA').style.visibility = 'hidden';
      }
      if (id == 'VIC') {
        exchangeState = "Victoria";
        document.getElementById('VIC').style.display = 'inline';
        document.getElementById('VIC').style.visibility = 'visible';
      } else {
        document.getElementById('VIC').style.display = 'none';
        document.getElementById('VIC').style.visibility = 'hidden';
      }
      if (id == 'WA') {
        exchangeState = "Western Australia";
        document.getElementById('WA').style.display = 'inline';
        document.getElementById('WA').style.visibility = 'visible';
      } else {
        document.getElementById('WA').style.display = 'none';
        document.getElementById('WA').style.visibility = 'hidden';
      }
      exchangeHTML = "<div align='center'>";
      exchangeHTML += "<table id='stateExchange'>";
      exchangeHTML += "<tr><td id='stateLabel' class='TitleLabel'>" + exchangeState + "</td></tr></table></div>";
    }
    document.getElementById('exchangeLabel').innerHTML = exchangeHTML;
  }
}

var searchMarker;
var searchMarkerHTML;

function extendMarker(marker, html, result) {
  
  //alert(marker.getLatLng().lat() + ', ' + marker.getLatLng().lng());
  hideInstructions();
  lastResponse = '';
  activeExch = "GUESS";
  searchMarker = marker;
  drawCircles(marker.getLatLng());
  if (httpUserObject) {
    httpUserObject.abort();
    httpUserObject.onreadystatechange = handleSearchResponse;
    httpUserObject.open("GET", "getclosest.php?latitude="+marker.getLatLng().lat()+"&longitude="+marker.getLatLng().lng()+"&exch=GUESS");
    httpUserObject.send(null);
  }
  var innerHTML = html.innerHTML;
  var re = new RegExp('\n', 'i');
  while (innerHTML.match(re)) {
    innerHTML = innerHTML.replace(re, "");
  }
  //innerHTML = innerHTML.replace(new RegExp('<[^>]*gs-directions.*(<[^>]*gs-watermark)', 'mi'), "$1");
  //innerHTML = innerHTML.replace(new RegExp('<[^>]*gs-directions.*', 'mi'), "");
  innerHTML = innerHTML.replace(new RegExp('<[^>]*gs-directions.*', 'i'), "");
  html.innerHTML = innerHTML;
  var re = new RegExp('<a[^>]*>[^<]*<\/a>', 'mi');
  while (innerHTML.match(re)) {
    innerHTML = innerHTML.replace(re, "");
  }
  searchMarkerHTML = innerHTML;
  html.innerHTML = searchMarkerHTML + '<br><span style="font-size: 1.2em;">' + lastResponse + '</span>';
  return html;
}

function handleSearchResponse() {
  if (httpUserObject.readyState == 4 && httpUserObject.status == 200) {
    var re = new RegExp('\(([A-Z][A-Z][A-Z][A-Z])\)[^12]', 'm');
    if (regMatch = httpUserObject.responseText.match(re)) { lookupExch(regMatch[1], 'firsttime'); }
    searchMarker.openInfoWindowHtml("<span style='font-size: 0.75em;'>" + searchMarkerHTML + "</span><br>" + httpUserObject.responseText);
    lastResponse = httpUserObject.responseText;
  }
}

function currentTileSet(x,y,z) {
  var w = (x + y) % 4;
  return "http://mt" + w + ".tpg.com.au/maps/tiles/"+activeExch+"/"+activeExch+"_"+z+"_"+x+"_"+y+".png";
}

function currentTagTileSet(x,y,z) {
  var w = (x + y) % 4;
  return "http://mt" + w + ".tpg.com.au/maps/tiles/"+lastExch+"/"+lastExch+"_"+z+"_"+x+"_"+y+".png";
}

var faqs = [];

function showFAQ(faq) {
  if (!faqs[faq]) {
    faqs[faq] = true;
  } else {
    faqs[faq] = !faqs[faq];
  }
  if (faqs[faq]) {
    document.getElementById(faq).style.visibility = 'visible';
    document.getElementById(faq).style.display = 'block';
    if (faq == "faqs") { map.disableScrollWheelZoom(); }
  } else {
    document.getElementById(faq).style.visibility = 'hidden';
    document.getElementById(faq).style.display = 'none';
    if (faq == "faqs") { map.enableScrollWheelZoom(); }
  }
}

var httpUserObject = getHTTPObject();
var lastResponse = null;

function addUserMarkers() {
  GEvent.addListener(map, "click", function(overlay, point) {
    hideInstructions();
    if (point && selectedExch) {
      if (userMarker == null) {
        userMarker = createUserMarker(point, "red");
        map.addOverlay(userMarker);
        GEvent.addListener(userMarker, 'click', function() { userMarker.openInfoWindowHtml(lastResponse); });
        drawCircles(point);
      } else {
        userMarker.setPoint(point);
        drawCircles(point);
      }
      if (httpUserObject) {
        httpUserObject.abort();
        httpUserObject.onreadystatechange = handleUserResponse;
        httpUserObject.open("GET", "getclosest.php?latitude="+point.y+"&longitude="+point.x+"&exch="+selectedExch);
        httpUserObject.send(null);
      }
    }
  });
}

function handleUserResponse() {
  if (httpUserObject.readyState == 4 && httpUserObject.status == 200) {
    userMarker.openInfoWindowHtml(httpUserObject.responseText);
    lastResponse = httpUserObject.responseText;
  }
}

function createUserMarker(point, status) {
  var image = "http://www.tpg.com.au/maps/images/marker_" + status + ".png" 
  
  var icon = new GIcon();
  icon.image = image;
  icon.shadow = "http://labs.google.com/ridefinder/images/mm_20_shadow.png";
  icon.iconSize = new GSize(12, 20);
  icon.shadowSize = new GSize(22, 20);
  icon.iconAnchor = new GPoint(6,20);
  icon.infoWindowAnchor = new GPoint(5, 1);
  
  return new GMarker(point, icon);
}

var circles = [];

function clearUserMarker() {
  if (userMarker) { userMarker.closeInfoWindow(); map.removeOverlay(userMarker); userMarker = null; }
  if (circles[1]) { map.removeOverlay(circles[1]); }
  if (circles[2]) { map.removeOverlay(circles[2]); }
  if (circles[5]) { map.removeOverlay(circles[5]); }
  if (circles[10]) { map.removeOverlay(circles[10]); }
}

function drawCircles(center) {
  drawCircle(center, 0.1, 30);
  drawCircle(center, 0.2, 30);
  drawCircle(center, 0.5, 40);
  drawCircle(center, 1.0, 60);
}

function drawCircle(center, radius, nodes) {   // Esa 2006
  //calculating km/degree
  var latConv = center.distanceFrom(new GLatLng(center.lat()+0.1, center.lng()))/100;
  var lngConv = center.distanceFrom(new GLatLng(center.lat(), center.lng()+0.1))/100;

  var points = [];
  var step = parseInt(360/nodes) || 10;
  for (var i = 0; i <= 360; i += step) {
    var pint = new GLatLng(center.lat() + (radius/latConv * Math.cos(i * Math.PI/180)), center.lng() + (radius/lngConv * Math.sin(i * Math.PI/180)));
    points.push(pint);
  }
  if (circles[radius*10]) { map.removeOverlay(circles[radius*10]); }
  circles[radius*10] = new GPolyline(points,"#0000ff",2);
  map.addOverlay(circles[radius*10]);
}
