var EARTH_RADIUS_EQUATOR = 6378140.0;
var RADIAN = 180 / Math.PI;
var CLICK_ZOOM = 12;

var map = null;
var adTypes = 2;
var keyVisible = false;

var ads = {};
var customers = {};
var currentCustomer = '';
var campaignAds = {};
var defaultRadius = 0;
var serverDomain = 'http://data.insidemessenger.com/T4/';

var pathToRoot = '';
var markerManager = null;
var managed = true;
var _bookedSuffix = '_Booked';

var tvRegions = ['Anglia', 'Carlton_LWT', 'Central', 'Grampian', 'Granada', 'HTV',
                 'Meridian', 'STV', 'Tyne-Tees', 'Ulster', 'Westcountry', 'Yorkshire', 'London', 'Ireland'];

var baseAdIcon = new GIcon();
baseAdIcon.iconSize         = new GSize(29, 44);
baseAdIcon.iconAnchor       = new GPoint(15, 42);
baseAdIcon.infoWindowAnchor = new GPoint(14, 2);

//var testAdIcon = new GIcon();
//testAdIcon.iconSize         = new GSize(29, 44);
//testAdIcon.iconAnchor       = new GPoint(11, 11);
//testAdIcon.infoWindowAnchor = new GPoint(11, 1);    

if (managed)
{
  // Override some methods of GMarker for compatibility with marker manager
  GMarker.prototype.hide = function ()
  {
    this.hidden = true;
    if (this.getPoint().lat() < 90)
      try {
        this.savePoint = this.getPoint();
        this.setPoint(new GLatLng(90, 0));
      } catch(e) {}
  };
  GMarker.prototype.show = function ()
  {
    this.hidden = false;
    if ((this.getPoint().lat() == 90) &&
        this.savePoint)
      try {
        this.setPoint(this.savePoint);
        this.savePoint = null;
      } catch(e) {}
  };
  GMarker.prototype.isHidden = function ()
  {
    return this.hidden;
  };
}

addEventHandler(window, 'unload', windowUnload);
addEventHandler(window, 'resize', windowResize);

t4Ad = function (xmlNode)
{
  this.row = -1;
  this.locale = null;

  if (xmlNode)
  {
    this.id = parseInt(xmlNode.getAttribute('id'));
    this.lat = parseFloat(xmlNode.getAttribute('lat'));
    this.lon = parseFloat(xmlNode.getAttribute('lng'));
    this.tvRegion = String(xmlNode.getAttribute('tv_region')).replace(/  /g, ' ');

    this.iconImg = pathToRoot + 'images/T4_' + this.type.capitalize() + '_TV_' + this.tvRegion.replace(' and ', '_');
  	this.icon = new GIcon(baseAdIcon, this.iconImg + '.png');
    this.icon.printImage = this.iconImg +'.png';
	this.icon.mozPrintImage = this.iconImg +'.png';

    var options = {icon: this.icon, title: this.getTitle()};
    this.marker = new GMarker(new GLatLng(this.lat, this.lon), options);
    
    if (managed)
    {
      if (!markerManager)
        markerManager = new GMarkerManager(map);

      markerManager.addMarkers([this.marker], 0);
    }
    else
      map.addOverlay(this.marker);

    this.marker.hide();
    
    this.setBooked(campaignAds[this.id]);

    var id = this.id;
    GEvent.addListener(this.marker, 'click', function () {ads[id].showInfoWindow()});
  }
};

t4Ad.prototype.isBooked = function ()
{
  return (this.iconImg.indexOf(_bookedSuffix) > -1);
};

t4Ad.prototype.setBooked = function (newStatus)
{
  if (!newStatus)
    this.iconImg = this.iconImg.replace(_bookedSuffix, '');
  else
    if (this.iconImg.indexOf(_bookedSuffix) == -1)
      this.iconImg = this.iconImg + _bookedSuffix;

  if (!this.marker.isHidden())
  {
    try 
    {
      this.marker.setImage(this.iconImg + '.png');
    } 
    catch (e) 
    {
      this.icon.image = this.iconImg + '.png';
      var options = {icon: this.icon, title: this.getTitle()};
      this.marker = new GMarker(new GLatLng(this.lat, this.lon), options);
      
      if (managed)
        markerManager.addMarker(this.marker, 0);
      else
        map.addOverlay(this.marker);
    }
  
    var sidebarImg = document.getElementById('ad_img_' + this.id);
    if (sidebarImg)
      sidebarImg.src = this.iconImg + '.png';
  }
};

t4Ad.prototype.show = function ()
{
  this.marker.show();
  this.showRadius();

  if (fields.ad_list && (this.row == -1))
    this.makeRow();
};

t4Ad.prototype.hide = function ()
{
  this.marker.closeInfoWindow();
  this.marker.hide();
  
  this.hideRadius();

  if (fields.ad_list && (this.row > -1))
  {
    fields.ad_list.deleteRow(this.row);
    for (var i in ads) 
      if (ads[i].row > this.row)
        ads[i].row--;
    this.row = -1;
  }
};

t4Ad.prototype.makeRow = function ()
{
  this.row = fields.ad_list.rows.length;
  var newRow = fields.ad_list.insertRow(-1);
  newRow.id = 'ad_row_' + this.id;

  var newCell = newRow.insertCell(-1);
  var newHTML = '<img id="ad_img_' + this.id + '" width="15" height="22" src="' + this.iconImg + '.png" />';
  newCell.innerHTML = newHTML;

  newCell = newRow.insertCell(-1);
  newCell.innerHTML = this.getRowContent();
};

t4Ad.prototype.rowClick = function ()
{
  map.setCenter(new GLatLng(this.lat, this.lon));
  if (map.getZoom() < CLICK_ZOOM)
    map.setZoom(CLICK_ZOOM);

  setTimeout('ads[' + this.id + '].showInfoWindow()', 100);
};

t4Ad.prototype.showInfoWindow = function ()
{
  if (this.marker)
  {
    var content = 
      '<div class="popup">' + 
        this.getInfoWindowContent() + 
        '<label id="label_radius" for="radius">Show radius:</label> ' +
        '<select id="radius">';
    for (var r = 0; r <= 500; r += 50)
    {
      content = content + '<option value="' + r + '"';
      if (this.locale &&
          (this.locale.radius == r))
        content = content + ' selected="selected"';
      content = content + '>' + r + '</option>';
    }
    content = content + 
        '</select> ' +
        '<span id="radius_units">metres</span> ' +
        '<input id="apply_radius" type="submit" value="Apply" onclick="ads[' + this.id + '].showRadius(parseInt(valueOfField(document.getElementById(\'radius\')))); return false" /> ' +
        '<input id="clear_radius" type="submit" value="Clear" onclick="ads[' + this.id + '].hideRadius(); return false" />' +
      '</div>';

    this.marker.openInfoWindowHtml(content);
  }
};

t4Ad.prototype.hideRadius = function ()
{
  if (this.locale)
  {
    map.removeOverlay(this.locale);
    this.locale = null;
  }
};

t4Ad.prototype.showRadius = function (newRadius)
{
  if (isNaN(newRadius))
    newRadius = null;

  if (newRadius)
  {
    if (this.locale)
      this.hideRadius();
  }
  else
    if (!this.locale)
      newRadius = defaultRadius;

  if (newRadius)
  {
    this.locale = filledCircle(new GLatLng(this.lat, this.lon), newRadius, '#000000', 0.2);
    this.locale.radius = newRadius;
    map.addOverlay(this.locale);
  }
};


t4AdGate = function (xmlNode)
{
//  this.iconImg = pathToRoot + 'images/gate';
//  this.icon = new GIcon(baseAdIcon, this.iconImg + '.png');
//  this.icon.printImage = this.icon.mozPrintImage = this.iconImg + '.gif';

  this.type = 'gate';
  this.station   = xmlNode.getAttribute('station');
  this.trainLine = xmlNode.getAttribute('train_line');

  t4Ad.call(this, xmlNode);
};
t4AdGate.inheritsFrom(t4Ad);

t4AdGate.prototype.getTitle = function ()
{
  return this.station;
};

t4AdGate.prototype.getRowContent = function ()
{
  var content = '<a href="#" onclick="ads[' + this.id + '].rowClick(); return false">' + 
               this.station + ' (' + this.trainLine + ' line)</a>';
  return content;
};

t4AdGate.prototype.getInfoWindowContent = function ()
{
  var content = '<h3>Station: ' + this.station + '</h3>' +
                '<p>Type: Ad Gate</p>' +
                '<p>Train Line: ' + this.trainLine + '</p>' +
                '<p>TV Region: ' + this.tvRegion + '</p>';
  return content;
};


t4AdBarrier = function (xmlNode)
{
//  this.iconImg = pathToRoot + 'images/barrier';
//  this.icon = new GIcon(baseAdIcon, this.iconImg + '.png');
//  this.icon.printImage = this.icon.mozPrintImage = this.iconImg + '.gif';

  this.type = 'barrier';
  this.town     = xmlNode.getAttribute('town');
  this.carPark  = xmlNode.getAttribute('car_park');

  t4Ad.call(this, xmlNode);
};
t4AdBarrier.inheritsFrom(t4Ad);

t4AdBarrier.prototype.getTitle = function ()
{
  return this.town + ': ' + this.carPark;
};

t4AdBarrier.prototype.getRowContent = function ()
{
  var content = '<a href="#" onclick="ads[' + this.id + '].rowClick(); return false">' + 
                this.town + ' (' + this.carPark + ')</a>';
  return content;
};

t4AdBarrier.prototype.getInfoWindowContent = function ()
{
  var content = '<h3>Town: ' + this.town + '</h3>' +
                '<p>Type: Ad Barrier</p>' +
                '<p>Car Park: ' + this.carPark + '</p>' +
                '<p>TV Region: ' + this.tvRegion + '</p>';
  return content;
};



function showCustomer(name)
{
  var i;

  if ((name != '') &&
      (name == currentCustomer))
    return;

  if (customers[currentCustomer])
  {
    for (i = 0; i < customers[currentCustomer].length; i++)
      customers[currentCustomer][i].hide();
  }

  currentCustomer = name;

  if (name == '')
  {
    if ((typeof afterCustomerChange) == 'function')
      afterCustomerChange(name);
  }
  else
  {
    if (customers[name])
    {
      for (i = 0; i < customers[name].length; i++)
        customers[name][i].show();

      if ((typeof afterCustomerChange) == 'function')
        afterCustomerChange(name);
    }
    else
    {
      customers[name] = [];
      GDownloadUrl(pathToRoot + 'customers/' + name + '.xml?sid='+Math.random(), function (response) {receiveCustomer(name, response)});
    }
  }
};

function receiveCustomer(name, response)
{
  var xmlDoc = GXml.parse(response);

  var width  = parseInt(xmlDoc.documentElement.getAttribute('icon_width'));
  var height = parseInt(xmlDoc.documentElement.getAttribute('icon_height'));
  customers[name].icon = new GIcon(null, pathToRoot + 'customers/images/' + name + '.png');
  customers[name].icon.iconSize         = new GSize(width, height);
  customers[name].icon.iconAnchor       = new GPoint(Math.round(width / 2), Math.round(height / 2));
  customers[name].icon.infoWindowAnchor = new GPoint(Math.round(width / 2), 1);    

  var customerNodes = xmlDoc.documentElement.getElementsByTagName('marker');
  for (var n = 0; n < customerNodes.length; n++)
    customers[name][n] = new customerLocation(name, n, customerNodes[n]);

  if ((typeof afterCustomerChange) == 'function')
    afterCustomerChange(name);
};

customerLocation = function (type, index, xmlNode)
{
  this.type = type;
  this.id   = index;

  this.name = xmlNode.getAttribute('location_name');
  this.lat  = parseFloat(xmlNode.getAttribute('lat'));
  this.lon  = parseFloat(xmlNode.getAttribute('lng'));
  this.address = xmlNode.getAttribute('address');
  this.town    = xmlNode.getAttribute('town');
  this.phone   = xmlNode.getAttribute('tel');

  var options = {icon: customers[type].icon, title: this.name};
  this.marker = new GMarker(new GLatLng(this.lat, this.lon), options);
  map.addOverlay(this.marker);
  GEvent.addListener(this.marker, 'click', function () {customers[type][index].showInfoWindow()});
  
  if (fields.customer_list)
    this.makeRow();
};

customerLocation.prototype.show = function ()
{
  this.marker.show();

  if (fields.customer_list && (this.row == -1))
    this.makeRow();
};

customerLocation.prototype.hide = function ()
{
  this.marker.hide();

  if (fields.customer_list && (this.row > -1))
  {
    fields.customer_list.deleteRow(this.row);
    for (var i = 0; i < customers[this.type].length; i++) 
      if (customers[this.type][i].row > this.row)
        customers[this.type][i].row--;
    this.row = -1;
  }
};

customerLocation.prototype.makeRow = function ()
{
  this.row = fields.customer_list.rows.length;
  var newRow = fields.customer_list.insertRow(-1);
  newRow.id = 'customer_row_' + this.id;

  var newCell = newRow.insertCell(-1);
  var content = '<a href="#" onclick="customers[\'' + this.type + '\'][' + this.id + '].showInfoWindow(); return false">' + 
                this.name + '</a>';
  newCell.innerHTML = content;
};

customerLocation.prototype.showInfoWindow = function ()
{
  if (this.marker)
  {
    var content = '<div class="popup">' + 
                    '<h3>' + this.type + '</h3>' +
                    '<p>' + this.name + '</p>';
    if (this.address)
      content = content + '<p>' + this.address + '</p>';
    if (this.town)
      content = content + '<p>' + this.town + '</p>';

    content = content + '</div>';

    this.marker.openInfoWindowHtml(content);
  }
};

function calcLatLon(lat, lon, distance, bearing) 
{
  /* Find coordinates the given distance (in meters) and bearing from the given coordinates.
   *
   *  Lat, lon, and bearing in degrees. Distance in meters.
   *
   * Thanks to http://www.nearby.org.uk/project-kml.php?source=1
   */

  with (Math)
  {
    var b = bearing / RADIAN;
    lon = lon / RADIAN;
    lat = lat / RADIAN;
    var e = 0.08181922;
        
    var R = EARTH_RADIUS_EQUATOR * (1 - e * e) / pow( (1 - e*e * pow(sin(lat),2)), 1.5);    
    var psi = distance/R;
    var phi = PI/2 - lat;
    var arccos = cos(psi) * cos(phi) + sin(psi) * sin(phi) * cos(b);
    var latA = (PI/2 - acos(arccos)) * RADIAN;
    
    var arcsin = sin(b) * sin(psi) / sin(phi);
    var lonA = (lon - asin(arcsin)) * RADIAN;
  }

  return [latA, lonA];
};

function filledCircle(center, radius, color, opacity)
{
  /* Returns a filled, semitransparent circle on the map.
   *
   *  center: GLatLng
   *  radius: in meters
   */

  var circlePoints = [];
  var radiusCoords;
  for (var a = 0; a < 361; a += 5) 
  {
    radiusCoords = calcLatLon(center.lat(), center.lng(), radius, a);
    circlePoints.push(new GLatLng(radiusCoords[0], radiusCoords[1]));
  }

  return new GPolygon(circlePoints, color, 1, Math.min(1, 2 * opacity), color, opacity);
};

function windowUnload()
{
  for (var a in ads)
  { 
    ads[a].icon   = null;
    ads[a].marker = null;
  }
  ads = null;
  
  GUnload();
};

function windowResize()
{
  var newHeight = (windowHeight() - getTop(fields.ad_list_area)) + 'px';
  fields.ad_list_area.style.height = newHeight;
  if (fields.customer_list_area)
    fields.customer_list_area.style.height = newHeight;

  newHeight = (windowHeight() - getTop(fields.map)) + 'px';
  fields.map.style.height = newHeight;

  fields.map.style.width = fields.sidebar.style.left = (windowWidth() - 401) + 'px';

  if (map != null)
    map.checkResize();
};

function receiveAds(response)
{
  var xmlDoc = GXml.parse(response);
  var adNodes = xmlDoc.documentElement.getElementsByTagName('marker');
  var id;
  var type = false;
  for (var n = 0; n < adNodes.length; n++)
  {
    if (!type)
    {
      type = adNodes[n].getAttribute('type');
      if (type)
        type = type.toLowerCase().replace('ad ', '');
    }

    id = adNodes[n].getAttribute('id');
    if (type == 'gate')
      ads[id] = new t4AdGate(adNodes[n]);
    else
      ads[id] = new t4AdBarrier(adNodes[n]);
  }
  
  type += 's';
  var element = document.getElementById('show_' + type);
  if (element)
    element.disabled = false;
  element = document.getElementById('label_' + type);
  if (element)
  {
    element.style.color = '';
    element.innerHTML = element.innerHTML.replace('(loading)', '');
  }
  
  adTypes--;
  if (adTypes == 0)
  {
    if ((typeof filterAds) == 'function')
      filterAds();
    if ((typeof setCustomer) == 'function')
      setCustomer();

    if (managed)
      markerManager.refresh();
  }
};

function toggleKey()
{
  keyVisible = !keyVisible;
  refreshKey();
};

