var map;
var object_list;
var move_refresh = 0;
var geocoder = null;
var gmarkers;
var glabels;
var loading = new Object();

// initialize variables
loading['chat'] = 0;
loading['server'] = 0;
loading['positions'] = 0;
loading['locate'] = 0;

/**
 * Global Variables
 *
 */
var gOpenSATS = new OpenSATS();

function OpenSATS() {
  this.runcount = 0;
  this.satelliteMap = new Map();
  this.home = undefined;
  this.paths = new Array();
  this.firstload = true;
  this.names = new Map();

  // Initialize tick timer.
  //var me = this;
  //me.onTimer();
} // OpenSATS

/**
 * OpenSATS::onTimer
 */
OpenSATS.prototype.onTimer = function() {
  this.runcount++;
  var d = new Date();

  changeById('clock', d.toFormattedUTCString());

  // Load any new stations
  if ((this.runcount % 10) == 0 || this.runcount == 1)
    this.getSatellitesFromServer(map);

  if ((this.runcount % 120) == 0)
    this.getPathsFromServer(map);

  // Update all satellite positions
  var keys = this.satelliteMap.getKeys();
  for(var i=0; i < keys.length; i++) {
    var s = this.satelliteMap.get(keys[i]);
    s.incrementPosition();
    if (this.home != undefined) {
      s.plotCompassLine(this.home.getPosition());
      s.changeTrackingLabel(this.home.getPosition());
    } // if
    else
      s.removeCompassLine();
  } // for

  // set the timer
  window.setTimeout('gOpenSATS.onTimer()', 1000);
} // OpenSATS::onTimer

/**
 * OpenSATS::Control
 *
 * Select all text on click.
 *
 */
OpenSATS.prototype.Control = function(id, doACTION) {
  var myImg = document.getElementById(id);
  var path = '/images/opensats/c/';

  if (myImg == null)
    return;

  var menus = {
    "cOPENSATS": new Array("opensats.png", "OpenSATS", "cOPENAPRS:Overlay"),
    "cEDIT":  new Array("edit.png", "Edit", "cEDIT:Overlay"),
    "cTOOLS":  new Array("tools.png", "View", "cTOOLS:Overlay"),
    "cVIEW":  new Array("view.png", "View", "cVIEW:Overlay"),
    "cHELP":  new Array("help.png", "Help", "cHELP:Overlay"),
    "cDONATE":  new Array("donate.png", "Donate")
  };

  var tooltips = {
    "controlCHAT": '<div class="tooltip"><b>Web Chat</b><br /><br />Chat with others users currently on the website.</div>'
  };

  for(var m in menus) {
    if (m == id) {
      if (doACTION == 'over') {
        var mySub = "over/";
        if (tooltips[m] != undefined)
          Tip(tooltips[m], BALLOON, true, ABOVE, true, OFFSETX, 0);

        if (menus[m][2] != undefined)
          showWindow(menus[m][2]);
      } // if
      else if (doACTION == 'on') {
        var mySub = "on/";
        myImg.src = path + mySub + menus[m][0];
      } // if
      else if (doACTION == 'off') {
        var mySub = "off/";
        myImg.src = path + mySub + menus[m][0];
        UnTip();
        if (menus[m][2] != undefined)
          hideWindow(menus[m][2]);
      } // if
      else {
        var mySub = "off/";
        UnTip();
      } // else

      myImg.src = path + mySub + menus[m][0];
    } // if
  } // for

  return void(0);
} // OpenSATS::Control()

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::onLoad
 * Loads google Maps settings for OpenSATS interface.
 * Parameters: n/a
 * Returns: n/a
 */
OpenSATS.prototype.onLoad = function() {
  document.body.style.overflow = 'hidden';

  var opts = {
    zoom: 2,
    center: new google.maps.LatLng(38.256973, -122.311685),
    mapTypeId: google.maps.MapTypeId.ROADMAP
  } // opts

  // Center the map on Palo Alto
  map = new google.maps.Map(document.getElementById("mapDiv"), opts);
  //map.addControl(new GSmallMapControl());
  //map.addControl(new GMapTypeControl());
  //map.disableDragging();
  //map.setCenter(new google.maps.LatLng(38.256973, -122.311685), 2);

//  var topLeft = new GControlPosition(G_ANCHOR_TOP_LEFT, new GSize(10,100));
//  var bottomRight = new GControlPosition(G_ANCHOR_BOTTOM_RIGHT, new GSize(0,0));

//  map.addMapType(G_SATELLITE_3D_MAP);
//  map.addMapType(G_PHYSICAL_MAP);
  //map.setMapType(G_HYBRID_MAP);
//  map.addControl(new GLargeMapControl(), topLeft);
//  map.addControl(new GMapTypeControl(), bottomRight);
//  map.disableScrollWheelZoom();
  geocoder = new google.maps.Geocoder();

  var center = map.getCenter();
  navUpdate('navOverlay2', center.lat(), center.lng() );

  object_list = new Array();

  google.maps.event.addListener(map, "mousemove", function(event) {
    var point = event.latLng;
    navUpdate('navOverlay2', point.lat(), point.lng());
  });

  //var daylight = new daylightMap.daylightLayer();
  //daylight.addToMap(map);
  //daylight.addToMapType(G_SATELLITE_MAP);
  //daylight.addToMapType(G_HYBRID_MAP);

  // Pause the map when the info window is open.
  google.maps.event.addListener(map, "infowindowopen", function() {
    pause = document.getElementById("openaprs_form_pause");
    if (pause == null)
      return;

    pause.checked = true;
    changeById('mapSTATUS', 'Paused');
    changeById('topMESSAGE', 'Paused');

    showControl('controlPAUSE', false);
  });

  // Pause the map when the info window is open.
  //google.maps.event.addListener(map, "moveend", function() {
    // Turn off autocenter if user moves the map
    // manually.
  //  if (isChecked('OpenSATS:Form:Autocenter'))
  //    unCheck('OpenSATS:Form:Autocenter');
  //});


  // Unpause the map when the infowindow is closed.
  google.maps.event.addListener(map, "infowindowclose", function() {
    pause = document.getElementById("openaprs_form_pause");
    if (pause == null)
      return;

    changeById('mapSTATUS', 'Resuming');
    changeById('topMESSAGE', 'Resuming');

    pause.checked = false;
    showControl('controlPAUSE', false);
  });

  this.getSatelliteNamesFromServer();
  updateChat();
  updateAd();

  //toggleCONSOLE();
  toggleSTATIONS();

  var loadTips = readCookie("myTips");
  if (loadTips == "yes" || loadTips == "") {
    loadHelp('random:tips');
    windowControl('helpOverlay');
  } // if

  // add logout functions
  onLogout.push(new Function("changeFieldById('aprsMESSAGE:Form:Timestamp', '0'); clearRows('messagingTable')"));
  onLogout.push(new Function("clearRows('viewTable');"));

} // onLoadOpensats

/**
 * getSatelliteNamesFromServer
 *
 * Redraws the current list of stations.
 *
 */
OpenSATS.prototype.getSatelliteNamesFromServer = function() {
  var request = createXMLHttpRequest();
  var pause = document.getElementById("openaprs_form_pause");
  var me = this;

  /**
   * Default Variables
   *
   * Span through the possible field values
   * and set our variable list accordingly.
   *
   */
  var ids = {
    "find": "openaprs_form_find",
    "units": "openaprs_form_units",
    "geocoords": "openaprs_form_geocoords",
    "timezone": "openaprs_form_timezone"
  };

  var dfts = {
    "find": "",
    "units": "imperial",
    "geocoords": "decimal",
    "timezone": "America/Los_angeles"
  };

  var var_list = createURI(document, false, ids, dfts);

  changeById('mapSTATUS', 'Fetching Names');
  changeById('topMESSAGE', 'Fetching Names');
  changeById("locate_status", "<i>fetching names</i>");

  var queryString = "/ajax/opensats/satellites/names.php?hash="
                    + seed
                    + var_list;

  var start_date = new Date();

  request.open("GET", queryString, true);
  request.onreadystatechange = function() {
    var len;

    if (request.readyState == 4) {
      var xmlDoc = request.responseXML;

      // Remove from requestMap.
      requestMap.remove('getSatelliteNamesFromServer');

      var c = me.storeSatelliteNamesFromServer(request);

      var end_date = new Date();
      var diff = parseFloat((end_date.getTime()/1000) - (start_date.getTime()/1000));

      changeById("mapRESULTS", "Results " + c + " names (" + diff.toRound(3) + " seconds)");
      log('Satellite List: Results ' + c + ' names (' + diff.toRound(3) + ' seconds)');

      // We don't want to start our main timer
      // until AFTER we've loaded the satellite
      // names.
      me.onTimer();
    } // if

  } // function()

  request.send(null);
} // OpenSATS::getSatelliteNamesFromServer

/**
 * getSatellitesFromServer
 *
 * Redraws the current list of stations.
 *
 */
OpenSATS.prototype.getSatellitesFromServer = function(map) {
  var request = createXMLHttpRequest();
  var pause = document.getElementById("openaprs_form_pause");
  var me = this;
  var sw = new Stopwatch();
  var sw2 = new Stopwatch();
  var sw3 = new Stopwatch();

  if (requestMap.isKey('getSatellitesFromServer')) {
    // We already have a request in progress.
    var r = requestMap.get('getSatellitesFromServer');
    if (r.time < (getUnixTime() - 10)) {
      r.request.abort();
      requestMap.remove('getSatellitesFromServer');
      log('Satellites: Connection timed out.');
      changeById('mapSTATUS', 'Timed out');
    } // if
    else {
      changeById('mapSTATUS', 'Please wait');
      return false;
    } // else
  } // if

  if (pause != null && pause.checked == true) {
    changeById('locate_status', 'Paused');
    changeById('mapSTATUS', 'Paused');
    changeById('topMESSAGE', 'Paused');
    return;
  } // if

  if (this.names.length < 1)
    var n = "25544,-1,-2";
  else {
    var n = "";
    var keys = this.names.getKeys();
    for(var i=0; i < keys.length; i++) {
      if (this.names.get(keys[i])) {
        if (n.length > 0)
          n += ",";

        n += keys[i];
      } // if
    } // for
  } // else

  /**
   * Default Variables
   *
   * Span through the possible field values
   * and set our variable list accordingly.
   *
   */
  var ids = {
    "find": "openaprs_form_find",
    "units": "openaprs_form_units",
    "geocoords": "openaprs_form_geocoords",
    "timezone": "openaprs_form_timezone",
    "n": "none"
  };

  var dfts = {
    "find": "",
    "units": "imperial",
    "geocoords": "decimal",
    "timezone": "America/Los_angeles",
    "n": n
  };

  var var_list = createURI(document, false, ids, dfts);

  changeById('mapSTATUS', 'Updating');
  changeById('topMESSAGE', 'Updating');
  changeById("locate_status", "<i>updating</i>");

  var queryString = "/ajax/opensats/satellites/positions.php?hash="
                    + seed
                    + var_list;

  sw.Start();
  sw2.Start();

  var r = new requestObject(request);
  requestMap.add('getSatellitesFromServer', r);

  request.open("GET", queryString, true);
  request.onreadystatechange = function() {
    var len;

    if (request.readyState == 4) {
      var xmlDoc = request.responseXML;

      sw2.Stop();

      // Remove from requestMap.
      requestMap.remove('getSatellitesFromServer');

      sw3.Start();
      var c = me.storeSatellitesFromServer(request);
      sw3.Stop();

      changeById("mapRESULTS", "Results " + c + " satellites ("+sw.Time()+" seconds)");
      log('Satellite: Results ' + c + ' satellites (T:'+sw.Time()+'/X:'+sw2.Time()+'/P:'+sw3.Time()+')');

      // If this is the first time we've tried to get satellites
      // then try and get their paths as well.
      if (me.firstload) {
        me.getPathsFromServer(map);
        me.firstload = false;
      } // if

    } // if

  } // function()

  request.send(null);
} // OpenSATS::getSatellitesFromServer

/**
 * getPathsFromServer
 *
 * Redraws the current list of stations.
 *
 */
OpenSATS.prototype.getPathsFromServer = function(map) {
  var request = createXMLHttpRequest();
  var me = this;
  var sw = new Stopwatch();
  var sw2 = new Stopwatch();
  var sw3 = new Stopwatch();

  if (requestMap.isKey('getPathsFromServer')) {
    // We already have a request in progress.
    var r = requestMap.get('getPathsFromServer');
    if (r.time < (getUnixTime() - 10)) {
      r.request.abort();
      requestMap.remove('getPathsFromServer');
      log('Satellite Paths: Connection timed out.');
      changeById('mapSTATUS', 'Timed out');
    } // if
    else {
      changeById('mapSTATUS', 'Please wait');
      return false;
    } // else
  } // if

/*
  if (pause != null && pause.checked == true) {
    changeById('locate_status', 'Paused');
    changeById('mapSTATUS', 'Paused');
    changeById('topMESSAGE', 'Paused');
    return;
  } // if
*/

  // Find all satellites that we're currently tracking.
  var keys = this.satelliteMap.getKeys();
  var n = "";
  for(var i=0; i < keys.length; i++) {
    var s = this.satelliteMap.get(keys[i]);
    if (s.isTracking == true) {
      if (keys.length > 0)
        n += ",";

      n += s.number;
    } // if
  } // for

  if (n.length == 0) {
    // clear the map markers and draw the new ones
    for(var i=0; i < this.paths.length; i++)
      this.paths[i].setMap(null);

    return;
  } // if

  /**
   * Default Variables
   *
   * Span through the possible field values
   * and set our variable list accordingly.
   *
   */
  var ids = {
    "find": "openaprs_form_find",
    "units": "openaprs_form_units",
    "geocoords": "openaprs_form_geocoords",
    "timezone": "openaprs_form_timezone",
    "n": "blah"
  };

  var dfts = {
    "find": "",
    "units": "imperial",
    "geocoords": "decimal",
    "timezone": "America/Los_angeles",
    "n": n
  };

  var var_list = createURI(document, false, ids, dfts);

  changeById('mapSTATUS', 'Updating Paths');
  changeById('topMESSAGE', 'Updating Paths');
  changeById("locate_status", "<i>updating Paths</i>");

  var queryString = "/ajax/opensats/satellites/paths.php?hash="
                    + seed
                    + var_list;

  sw.Start();
  sw2.Start();

  var r = new requestObject(request);
  requestMap.add('getPathsFromServer', r);

  request.open("GET", queryString, true);
  request.onreadystatechange = function() {
    var len;

    if (request.readyState == 4) {
      var xmlDoc = request.responseXML;

      sw2.Stop();

      // Remove from requestMap.
      requestMap.remove('getPathsFromServer');

      sw3.Start();
      var c = me.storePathsFromServer(request);
      sw3.Stop();

      changeById("mapRESULTS", "Results " + c + " paths ("+sw.Time()+" seconds)");
      log('Paths: Results ' + c + ' paths (T:'+sw.Time()+'/X:'+sw2.Time()+'/P:'+sw3.Time()+')');

    } // if

  } // function()

  request.send(null);
} // OpenSATS::getPathsFromServer

OpenSATS.prototype.storeSatellitesFromServer = function(xmlDoc) {
  var new_object_list = [];
  var station_list = "<table class=\"station_table\">";
  var numSatellites = 0;
  var numbers = new Array();
  var i;

  if (xmlDoc == null)
    return;

  var parseMe = xmlDoc.responseText.split('\n');
  var wasHome = false;

  // Main large loop
  for(i=0; i < parseMe.length; i++) {
    // Skip broken lines or comments
    if (parseMe[i].length < 1 ||
        parseMe[i].substr(0, 1) == "#")
      continue;

    var v = new Vars();

    v.Parse(parseMe[i]);

    // BEGIN: PROCESS LOCATIONS
    if (v.getField("TY") == "L") {
      var longitude = parseFloat(v.getField("lo"), 6);
      var latitude = parseFloat(v.getField("la"), 6);

      if (this.home != undefined) {
        this.home.setMap(null);
        this.home = undefined;
      } // if

      wasHome = true;

      // Draw the marker on the map only if it isn't in the station list
      var img = v.getField("img");

      var icon = new google.maps.MarkerImage(
        img,				// url
        new google.maps.Size(22, 22),	// size
        new google.maps.Point(0, 0),	// origin
        new google.maps.Point(11, 11),	// anchor
        new google.maps.Size(22, 22)	// scaledSize
      );

      var marker = new MarkerWithLabel({
        position: new google.maps.LatLng(latitude, longitude),
        icon: icon,
        labelContent: v.getField("nm"),
        labelClass: "labels",
        labelAnchor: new google.maps.Point(11, -11)
      });

//createStationAJAX(longitude, latitude, v.getField("nm"), "/", img, v.getField("inf"));

//FIXME
//      var label = new ELabel(new google.maps.LatLng(latitude, longitude), v.getField("nm"), "labels", new GSize(-18, +60), 90);
//      createLabel(marker, label);
//      label.hide();

      this.home = marker;

      new_object_list.push(marker);
      //new_object_list.push(label);
    } // if
    // END: PROCESS LOCATIONS

    // BEGIN: PROCESS SATELLITES
    if (v.getField("TY") == "PA") {
      var marker = this.addSatellite(v, new_object_list);
      this.addSatellitePositions(v, new_object_list);
      //this.addSatellitePath(v, new_object_list);
      //this.addSatelliteGroundCircle(v, new_object_list);
      //this.addSatelliteCompassLine(marker, v, new_object_list);
      numbers.push(v.getField("num"));

      numSatellites++;
    } // if
    // END: PROCESS SATELLITES

  } // for

  changeById("locate_status", "<i>" + numSatellites + " stations displayed</i>");
  changeById("mapSTATUS", "Idle");
  changeById('topMESSAGE', 'Idle');

  //if (numSatellites == 1)
  //  changeById("googleEarthLink", '[<a href="http://www.openaprs.net/ajax/google_earth/satellites/query.php?find='+retData[0]["name"]+'">Google Earth: ' + retData[0]["name"].toUpperCase() + '</a>]');
  //else
  //  changeById("googleEarthLink", '[<a href="http://www.openaprs.net/ajax/google_earth/satellites/query.php">Google Earth: Satellites</a>]');


  // clear the map markers and draw the new ones
  //map.clearOverlays();

  // Reset home marker.
  if (!wasHome && this.home != undefined) {
    this.home.setMap(null);
    this.home = undefined;
  } // if

  for(var k = 0; k < new_object_list.length; k++)
    new_object_list[k].setMap(map);

  object_list = new_object_list;

  // Now we need to remove any satellites that weren't found in
  // the most recent update.  This seems like it is inefficient,
  // perhaps there is a beter way?
  var keys = this.satelliteMap.getKeys();
  for(var i=0; i < keys.length; i++) {
    var needToKeep = false;
    for(var j=0; j < numbers.length && !needToKeep; j++) {
      if (keys[i] == numbers[j])
        needToKeep = true;
    } // for

    if (!needToKeep) {
      this.removeSatellite(keys[i]);
      log('Removed satellite number ' + keys[i]);
    } // if
  } // for

  return numSatellites;
} // OpenSATS::storeSatellitesFromServer

OpenSATS.prototype.storePathsFromServer = function(xmlDoc) {
  var new_object_list = [];
  var station_list = "<table class=\"station_table\">";
  var numSatellites = 0;
  var i;

  if (xmlDoc == null)
    return;

  var parseMe = xmlDoc.responseText.split('\n');
  var wasHome = false;

  // Main large loop
  for(i=0; i < parseMe.length; i++) {
    // Skip broken lines or comments
    if (parseMe[i].length < 1 ||
        parseMe[i].substr(0, 1) == "#")
      continue;

    var v = new Vars();

    v.Parse(parseMe[i]);

    // BEGIN: PROCESS SATELLITE PATHS
    if (v.getField("TY") == "PA") {
      //var marker = this.addSatellite(v, new_object_list);
      //this.addSatellitePositions(v, new_object_list);
      this.addSatellitePath(v, new_object_list);
      //this.addSatelliteGroundCircle(v, new_object_list);
      //this.addSatelliteCompassLine(marker, v, new_object_list);

      numSatellites++;
    } // if
    // END: PROCESS SATELLITES

  } // for

  //changeById("locate_status", "<i>" + numSatellites + " paths displayed</i>");
  changeById("mapSTATUS", "Idle");
  changeById('topMESSAGE', 'Idle');

  // clear the map markers and draw the new ones
  for(var i=0; i < this.paths.length; i++)
    this.paths[i].setMap(null);

  for(var k = 0; k < new_object_list.length; k++)
    new_object_list[k].setMap(map);

  this.paths = new_object_list;

  return numSatellites;
} // OpenSATS::storePathsFromServer

OpenSATS.prototype.storeSatelliteNamesFromServer = function(xmlDoc) {
  var numRows = 0;
  var i;

  if (xmlDoc == null)
    return;

  clearRows('satelliteNamesTable');

  var parseMe = xmlDoc.responseText.split('\n');

  // Main large loop
  for(i=0; i < parseMe.length; i++) {
    // Skip broken lines or comments
    if (parseMe[i].length < 1 ||
        parseMe[i].substr(0, 1) == "#")
      continue;

    var v = new Vars();

    v.Parse(parseMe[i]);

    // BEGIN: PROCESS SATELLITE PATHS
    if (v.getField("TY") == "NM") {
      this.addSatelliteName(v);
      numRows++;
    } // if
    // END: PROCESS SATELLITES

  } // for

  //changeById("locate_status", "<i>" + numSatellites + " paths displayed</i>");
  changeById("mapSTATUS", "Idle");
  changeById('topMESSAGE', 'Idle');

  return numRows;
} // OpenSATS::storeSatelliteNamesFromServer

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::addSatellite
 * Adds a new satellite to the map.
 * Parameters:
 *   v: Special Vars's type record with satellite information.
 *   o: Object list to add satellite to.
 * Returns: n/a
 */
OpenSATS.prototype.addSatellite = function(v, o) {
  var latitude = parseFloat(v.getField("la"), 6);
  var longitude = parseFloat(v.getField("lo"), 6);
  var k = v.getField("num");
  var ct = parseInt(v.getField("ct"));

  if (this.satelliteMap.isKey(k)) {
    // Already in the satellite objectMap.
    // Re just want to sync the time index.
    var s = this.satelliteMap.get(k);
    s.syncIndex(ct, v.getField("img"));

    return undefined;
  } // if

  // Draw the marker on the map only if it isn't in the station list
  var img = "http://www.opensats.net/images/icons/satellite/small/" + v.getField("img");
  var marker = this.createSatelliteMarker(latitude, longitude, img, v.getField("num"));

  //var label = new ELabel(new google.maps.LatLng(latitude, longitude), v.getField("nm"), "labels", new GSize(-18, +60), 90);
  //createLabel(marker, label);
  //label.hide();

  // Add this satellite to the map.
  var sat = new Satellite(k, ct, marker, v.getField("nm"), v.getField("img"));

  // Only enable the compass line or ground circle if we're in tracking mode
  // for this satellite.
  if (v.isName("TRK") && v.getField("TRK") == "Y") {
//    sat.enableCompassLine();
//    sat.enableGroundCircle();
  } // if

  this.satelliteMap.add(k, sat);

  //if (k == "25544") {
  //  sat.enableTracking();
  //  this.boldSatelliteName(k);
  //} // if

  // Set star next to satellite in the satellite list.
  this.linkSatelliteName(k);

  o.push(marker);
  //o.push(label);

  return marker;
} // OpenSATS::addSatellite

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::removeSatellite
 * Adds a new satellite to the map.
 * Parameters:
 *   k		: Satellite number to remove.
 * Returns: n/a
 */
OpenSATS.prototype.removeSatellite = function(k) {
  if (!this.satelliteMap.isKey(k))
    return false;

  // Set star next to satellite in the satellite list.
  // We shouldn't unstar the satellite since it may
  // be a temporary outage.
  //this.unstarSatelliteName(k);
  this.unboldSatelliteName(k);
  this.unlinkSatelliteName(k);

  var s = this.satelliteMap.get(k);

  var refreshPaths = s.isTracking;

  s.remove();
  this.satelliteMap.remove(k);

  if (refreshPaths)
    this.getPathsFromServer(map);

  return true;
} // OpenSATS::removeSatellite

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::addSatellitePositions
 * Adds a new set of future positions to satellite storage.
 * Parameters:
 *   v: Special Vars's type record with satellite information.
 *   o: Object list to add satellite to.
 * Returns: n/a
 */
OpenSATS.prototype.addSatellitePositions = function(v, o) {
  var num_rows = 0;

  if (!v.isName("PA") || !v.isName("NUM"))
    return 0;

  // Get the satellite number (record key).
  var k = v.getField("NUM");

  if (!this.satelliteMap.isKey(k))
    // Satellite wasn't stored in database.
    return 0;

  // Get satellite record.
  var s = this.satelliteMap.get(k);

  var parseMe = v.getField("PA").split('\n');

  for (var i=0; i < parseMe.length; i++) {
    var v2 = new Vars();
    v2.Parse(parseMe[i]);

    if (!v2.isName("ct"))
      continue;

    var t = parseInt(v2.getField("ct"));
    var lat = parseFloat(v2.getField("la"), 6);
    var lng = parseFloat(v2.getField("lo"), 6);
    var point = new google.maps.LatLng(lat, lng);

    s.addPosition(t, point, v2);

    num_rows++;
  } // for

  return num_rows;
} // OpenSATS::addSatellitePositions

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::addSatellitePath
 * Adds a new satellite to the map.
 * Parameters:
 *   v: Special Vars's type record with satellite information.
 *   o: Object list to add satellite to.
 * Returns: n/a
 */
OpenSATS.prototype.addSatellitePath = function(v, o) {
  if (!v.isName("PA")) return;

  var parseMe = v.getField("PA").split('\n');
  var points = new Array();

  for (var i=0; i < parseMe.length; i++) {
    var v2 = new Vars();

    v2.Parse(parseMe[i]);

    // Skip bad lines
    if (!v2.isName("la")) continue;

    var longitude = parseFloat(v2.getField("lo"), 6);
    var latitude = parseFloat(v2.getField("la"), 6);
    var currColor = seqColor(i, parseMe.length);

    if (currColor != lastColor && points.length > 1) {
      var polyline = new google.maps.Polyline({
        path: points,
        strokeColor: lastColor,
        strokeWeight: 2,
        strokeOpacity: .5
      });

      o.push(polyline);

      points = new Array();
      points.push(lpoint);
    } // if

    var lpoint = new google.maps.LatLng(latitude, longitude);
    points.push(lpoint);

    var lastColor = currColor;
  } // for

  if (points.length > 1) {
    var polyline = new google.maps.Polyline({
      path: points,
      strokeColor: lastColor,
      strokeWeight: 2,
      strokeOpacity: .5
    });
    o.push(polyline);
  } // if

  return;
} // OpenSATS::addSatellitePath

OpenSATS.prototype.addCompassListener = function(marker, label, polyline) {
  google.maps.event.addListener(marker, "mouseover", function() {
    label.show();
    polyline.show();
  });

  google.maps.event.addListener(marker, "mouseout", function() {
    label.hide();
    polyline.hide();
  });
} // OpenSATS::addCompassListener

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::createSatelliteMarker
 * Change satellite tracking to num specified.
 * Parameters:
 *   lat		: Latitude to create marker at.
 *   lng		: Longitude to create marker at.
 *   img		: Image to use for marker.
 *   num		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.createSatelliteMarker = function(lat, lng, img, num) {
  var icon;
  var point;
  var marker;
  var me = this;

  // Create our "tiny" marker icon
  var point = new google.maps.LatLng(lat, lng);
  var icon = new google.maps.MarkerImage(
    img,				// url
    new google.maps.Size(22, 22),	// size
    new google.maps.Point(0, 0),	// origin
    new google.maps.Point(11, 11),	// anchor
    new google.maps.Size(22, 22)	// scaledSize
  );

//  icon.image = img;
//  icon.shadow = "http://www.openaprs.net/images/icons/shadow.png";
//  icon.iconSize = new GSize(22, 22);
//  icon.shadowSize = new GSize(22, 20);
//  icon.iconAnchor = new GPoint(11, 11);
//  icon.infoWindowAnchor = new GPoint(15, 13);

  var marker = new MarkerWithLabel({
    position: point,
    icon: icon,
    labelClass: 'satLabel',
    labelAnchor: new google.maps.Point(22, -22),
    labelVisible: false
  });

  google.maps.event.addListener(marker, "click", function() {
    changeById('mapSTATUS', 'Tracking ' + num);
    me.changeSatelliteTracking(num);
  });

  return marker;
} // createSatelliteAJAX

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::changeSatelliteTracking
 * Change satellite tracking to num specified.
 * Parameters:
 *   num		: Satellite number to start tracking.
 * Returns: n/a
 */
OpenSATS.prototype.changeSatelliteTracking = function(num) {
  // Update all satellite positions
  var keys = this.satelliteMap.getKeys();
  var wasFound = false;

  changeById('OpenSATS:Names:Error', '');

  for(var i=0; i < keys.length; i++) {
    s = this.satelliteMap.get(keys[i]);
    if (keys[i] == num) {
      s.enableTracking();
      this.boldSatelliteName(keys[i]);
      wasFound = true;
      map.setCenter(s.marker.getPosition());
    } // if
    else {
      s.disableTracking();
      this.unboldSatelliteName(keys[i]);
    } // else
  } // for

  if (!wasFound)
    changeById('OpenSATS:Names:Error', 'Not being displayed.');

  this.getPathsFromServer(map);

  return;
} // OpenSATS::changeSatelliteTracking

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::addSatelliteName
 * Adds a new satellite name to stored list.
 * Parameters:
 *   v: Special Vars's type record with satellite information.
 * Returns: n/a
 */
OpenSATS.prototype.addSatelliteName = function(v) {
  var n = v.getField("nm");
  var k = v.getField("num");
  var cellArray = [];

  // Only add once.
  if (this.names.isKey(k))
    return;

  var aCell = new cellStruct;
  aCell.text = '<a href="javascript:void(0)" onMouseOut="UnTip()" onMouseOver="showBalloon(\'Display '+n+'\', \'Click here to display '+n+' on the map.  Satellites with stars next to them will be displayed on the next update in roughly 10 seconds.  You may only display 6 satellites on the map at a time, click here again to remove.\')" onClick="gOpenSATS.toggleSatelliteName(\''+k+'\')"><img id="OpenSATS:Image:'+k+'" src="/images/windows/offline.png" width="12" height="12" border="0" /></a>';
  cellArray.push(aCell);

  var aCell = new cellStruct;
  aCell.text = '<span id="OpenSATS:Names:Link:'+k+'" style="display:none;"><a id="OpenSATS:Href:'+k+'" href="javascript:void(0)" onMouseOut="UnTip()" onMouseOver="showBalloon(\'Track '+n+'\', \'Click here to track '+n+' on the map.\')" onClick="gOpenSATS.changeSatelliteTracking(\'' + v.getField("num") + '\')">' + v.getField("nm") + '</a></span><span id="OpenSATS:Names:Nolink:'+k+'" style="color:#C0C0C0"><i>'+n+'</i></span>';
  cellArray.push(aCell);

  addRow2('stationsTable', cellArray.reverse());

  this.names.add(k, false);

  if (k == "25544" || k == "-1" || k == "-2")
    this.toggleSatelliteName(k);

  return;
} // OpenSATS::addSatelliteName

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::toggleSatelliteName
 * Adds a new satellite name to stored list.
 * Parameters:
 *   n		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.toggleSatelliteName = function(n) {
  changeById('OpenSATS:Names:Error', '');

  if (!this.names.isKey(n))
    return false;

  var nm = this.names.get(n);

  if (nm == false) {
    if (this.numSatelliteNamesOn() > 5) {
      changeById('OpenSATS:Names:Error', 'Too many to track.');
      return false;
    } // if

    this.names.remove(n);
    this.names.add(n, true);
    this.starSatelliteName(n);
  } // if
  else {
    this.names.remove(n);
    this.names.add(n, false);
    this.unstarSatelliteName(n);
  } // else

  return true;
} // OpenSATS::toggleSatelliteName

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::numSatelliteNamesOn
 * Adds a new satellite name to stored list.
 * Parameters:
 *   n		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.numSatelliteNamesOn = function() {
  var keys = this.names.getKeys();
  var numOn = 0;

  for(var i=0; i < keys.length; i++) {
    if (this.names.get(keys[i]) == true)
      numOn++;
  } // for

  return numOn;
} // OpenSATS::numSatelliteNamesOn

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::boldSatelliteName
 * Adds a new satellite name to stored list.
 * Parameters:
 *   n		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.boldSatelliteName = function(n) {
  if (!this.satelliteMap.isKey(n))
    return false;

  var s = this.satelliteMap.get(n);
  
  var href = '<b>' + s.name + '</b>';
  changeById('OpenSATS:Href:'+n, href);

  return true;
} // OpenSATS::boldSatelliteName

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::unboldSatelliteName
 * Adds a new satellite name to stored list.
 * Parameters:
 *   n		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.unboldSatelliteName = function(n) {
  if (!this.satelliteMap.isKey(n))
    return false;

  var s = this.satelliteMap.get(n);
  
  var href = s.name;
  changeById('OpenSATS:Href:'+n, href);

  return true;
} // OpenSATS::unboldSatelliteName

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::linkSatelliteName
 * Adds a new satellite name to stored list.
 * Parameters:
 *   n		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.linkSatelliteName = function(n) {
  if (!this.names.isKey(n))
    return false;

  showWindow('OpenSATS:Names:Link:'+n);
  hideWindow('OpenSATS:Names:Nolink:'+n);

  return true;
} // OpenSATS::linkSatelliteName

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::unlinkSatelliteName
 * Adds a new satellite name to stored list.
 * Parameters:
 *   n		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.unlinkSatelliteName = function(n) {
  if (!this.names.isKey(n))
    return false;

  hideWindow('OpenSATS:Names:Link:'+n);
  showWindow('OpenSATS:Names:Nolink:'+n);

  return true;
} // OpenSATS::unlinkSatelliteName

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::starSatelliteName
 * Adds a new satellite name to stored list.
 * Parameters:
 *   n		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.starSatelliteName = function(n) {
  if (!this.names.isKey(n))
    return false;

  changeImageById('OpenSATS:Image:'+n, '/images/stars/yellow.png');

  changeById('OpenSATS:Names:Number', this.numSatelliteNamesOn());

  return true;
} // OpenSATS::starSatelliteName

/* ----------------------------------------------------------------------------
 * Name: OpenSATS::unstarSatelliteName
 * Adds a new satellite name to stored list.
 * Parameters:
 *   n		: Satellite number.
 * Returns: n/a
 */
OpenSATS.prototype.unstarSatelliteName = function(n) {
  if (!this.names.isKey(n))
    return false;

  changeImageById('OpenSATS:Image:'+n, '/images/windows/offline.png');

  changeById('OpenSATS:Names:Number', this.numSatelliteNamesOn());

  return true;
} // OpenSATS::unstarSatelliteName

