// TODO: cleanup objects, make us an object
// TODO: cleanup icon handling
// TODO: cleanup constants
// TODO: use MarkerManager

// constants
var tickPeriod = 500;
var iWidth = 32;
var iHeight = 32;
var anchorX = 6;
var anchorY = 20;
var mapWidth = $('#map').width();
var mapHeight = $('#map').height();
var updatePeriod = 10000;
var MIN_REFERRALS = 200;
var MOST_RECENT = 10;
var SEARCH_LIFETIME = 600000;
var activeIcon = "/images/vm-active.png";
var inactiveIcon = "/images/vm-activeorg.png";
var searchMarkerRadius = 40000;

// Create a map object
var map = new GMap2(document.getElementById("map"));
map.setCenter(new GLatLng(39.809, -98.555), 4);
map.addControl(new GLargeMapControl3D());
map.enableContinuousZoom();
map.disableScrollWheelZoom();

var floater;

var newIcon = new GIcon();
newIcon.image = activeIcon;
newIcon.iconSize = new GSize(iWidth, iHeight);
newIcon.iconAnchor = new GPoint(anchorX, anchorY);
newIcon.infoWindowAnchor = new GPoint(5, 1);
newIcon.vmIconType = 0;
newIcon.shadow = null;
newIcon.printShadow = null;

var oldIcon = new GIcon(newIcon);
oldIcon.image = inactiveIcon;
oldIcon.vmIconType = 1;

var hoverIcon = new GIcon(newIcon);
hoverIcon.image = activeIcon;
hoverIcon.vmIconType = 2;

//noinspection JSUnusedLocalSymbols
function floaterIndex(marker, b) {
  return 100000;
}

//noinspection JSUnusedLocalSymbols
function orderOfCreationIndex(marker, b) {
  return 1;
}

function zoomToMarker() {
  map.panTo(this.vmReferral.marker.getLatLng());
}

// -------------------------------------------------

var currentReferrals = [];
var mostRecentReferralId = 0;
var nextUpdate = 0;

function showFloater() {
  if (floater) map.removeOverlay(floater);
  floater = new GMarker(this.vmReferral.marker.getLatLng(), {icon:hoverIcon,zIndexProcess:floaterIndex});
  map.addOverlay(floater);
  $('div.hover').removeClass("hover");
  $(this).addClass("hover");
}

function hideFloater() {
  map.removeOverlay(floater);
  $(this).removeClass("hover");
  floater = null;
}

function Search(searchData) {
  this.txt = searchData.txt;
  this.lat = searchData.point[0];
  this.lng = searchData.point[1];
  this.point = new GLatLng(this.lat, this.lng);
  this.poly = null;
}

Search.prototype.add = function(animateOverlay) {
  if (animateOverlay) {
    var containerPoint = map.fromLatLngToContainerPixel(this.point);
    var left = containerPoint.x;
    var top = containerPoint.y;

    if (left > 0 && left < mapWidth && top > 0 && top < mapHeight) {
      var zoomText = $('<div class="search">' + this.txt + '</div>');
      zoomText.css({'position': 'absolute', 'top': top, 'left': left, 'opacity': 0.0, 'fontSize': '2px'});
      $('#map').append(zoomText);

      zoomText.animate({
        'opacity': 1.0,
        'fontSize': '12px'
      }, 400, null).animate({
        'dummy': 1
      }, 1000).fadeOut('slow', function() {
        $(zoomText).remove();
      });
    }
  }
};

function Referral(refData) {
  this.refId = refData.refId;
  this.oppId = refData.oppId;
  this.oppTitle = refData.oppTitle;
  this.oppLatitude = refData.oppLatitude;
  this.oppLongitude = refData.oppLongitude;
  this.oppAddress = refData.oppAddress;
  this.refTime = refData.refTime * 1000;
  this.oppDescription = refData.oppDescription;
  this.orgName = refData.orgName;
  this.orgId = refData.orgId;
  this.marker = null;
  this.status = "new";
  this.oldAge = this.refTime + 3600000; // 3600000
  this.recent = true;
  this.point = new GLatLng(this.oppLatitude, this.oppLongitude);
}

Referral.prototype.trim = function(str, chars) {
  if (str && str.length > chars) {
    str = str.substring(0, chars - 3) + "...";
  }

  return str;
};

Referral.prototype.setRecent = function(recent) {
  if (this.recent != recent) {
    this.recent = recent;
    if (this.marker) {
      this.marker.setImage(recent ? activeIcon : inactiveIcon);
    }
  }
};

Referral.prototype.isActive = function(now) {
  now = now || new Date().getTime();
  return this.oldAge > now;
};

Referral.prototype.add = function(animateOverlay, animateDiv) {
  this.addDiv();

  if (animateDiv) {
    for (var i = 0; i < 3; i++) {
      $(this.div).animate({"opacity": "toggle"}, 300).animate({"opacity": "toggle"}, 300);
    }
  }

  if (animateOverlay) {
    var containerPoint = map.fromLatLngToContainerPixel(this.point);
    var mLeft = containerPoint.x - anchorX;
    var mTop = containerPoint.y - anchorY;

    if (mLeft > 0 && mLeft < mapWidth && mTop > 0 && mTop < mapHeight) {
      var randTop = Math.random() * mapHeight;
      var randLeft = Math.random() * mapWidth;

      var zoomImage = $('<img src="' + activeIcon + '">');
      var thisInClosure = this;
      zoomImage.css({'position': 'absolute', 'top': randTop, 'left': randLeft, 'opacity': 0.0, 'width': 100, 'height': 100});
      $('#map').append(zoomImage);
      zoomImage.animate({'top': mTop, 'left': mLeft, 'opacity': 1.0, 'width': iWidth, 'height': iHeight}, 800, null, function() {
        zoomImage.remove();
        thisInClosure.addOverlay();
      });
    }
  } else {
    this.addOverlay();
  }
};

Referral.prototype.addOverlay = function() {
  this.marker = new GMarker(this.point, {icon: this.recent ? newIcon : oldIcon, zIndexProcess: orderOfCreationIndex, title: this.oppTitle});
  this.marker.vmReferral = this;
  map.addOverlay(this.marker);
};

Referral.prototype.addDiv = function() {
  var row = $(this.getHtml());

  this.div = row.get(0);
  this.div.vmReferral = this;
  $('#referrals').prepend(row);

  $(row).click(zoomToMarker);
  $(row).hover(showFloater, hideFloater);
};

Referral.prototype.getHtml = function() {
  return '<div class="referral"><p>'
    + '<strong>' + this.timeOfReferral()
    + '<br><a href="/search/opp' + this.oppId + '.jsp" target="blank">' + this.trim(this.oppTitle, 30) + '</a></strong>'
    + '<br><a href="/search/org' + this.orgId + '.jsp" target="blank">' + this.trim(this.orgName, 30) + '</a>'
    + '<br>' + this.trim(this.oppAddress, 30)
    + '</p></div>';
};

Referral.prototype.remove = function() {
  this.marker.vmReferral = null;
  map.removeOverlay(this.marker);

  this.div.vmReferral = null;
  $(this.div).remove();
};

Referral.prototype.timeOfReferral = function() {
  date = new Date(this.refTime);

  var h = date.getHours();
  var m = date.getMinutes();
  var s = date.getSeconds();

  var a = "AM";
  if (h >= 12) {
    a = "PM";
    h = h - 12;
  }

  if (h == 0) {
    h = 12;
  }

  if (m < 10) {
    m = "0" + m;
  }

  if (s < 10) {
    s = "0" + s;
  }

  return "" + h + ":" + m + ":" + s + " " + a;
};

//noinspection JSUnusedLocalSymbols
function loadData(data, status) {
  if (data.refTotal) {
    $('#refTotal').text(data.refTotal);
  }

  if (data.refAvg) {
    $('#refAvg').text(data.refAvg);
  }

  if (data.visitors) {
    $('#visitors').text(data.visitors);
  }

  var firstLoad = mostRecentReferralId == 0;
  if (!firstLoad) {
    var searches = data.searches;

    if (searches && searches.length) {
      var searchTimeout = (updatePeriod / searches.length);

      for (var sIndex in searches) {
        var search = new Search(searches[sIndex]);
        setTimeout(function(s){return function() {s.add(true);};}(search), sIndex * searchTimeout);
      }
    }
  }

  var timeout = 0;
  var referrals = data.referrals;
  if (referrals && referrals.length) {
    var now = new Date().getTime();
    var refRecent = 0;

    for (var rIndex in referrals) {
      var referral = new Referral(referrals[rIndex]);
      referral.recent = rIndex > (referrals.length - MOST_RECENT);

      if (firstLoad && rIndex < (data.referrals.length - MIN_REFERRALS) && !referral.isActive(now)) {
        continue;
      }

      if (referral.refId > mostRecentReferralId) {
        currentReferrals.push(referral);

        if (firstLoad) {
          setTimeout(function(r){return function() {r.add(true, false);};}(referral), timeout);
          timeout += 50;
          if (referral.isActive(now)) {
            $('#refRecent').text(++refRecent);
          }
        } else {
          referral.add(true);
        }

        mostRecentReferralId = referral.refId;
      }
    }
  }

  nextUpdate = new Date().getTime() + updatePeriod + timeout + (timeout == 0 ? 0 : 5000); // need extra time for init
}

//noinspection JSUnusedLocalSymbols
function loadError(req, status, error) {
  nextUpdate = new Date().getTime() + updatePeriod;
}

/**
 * Work backwards through referrals from newest to oldest:
 * 1. make sure the MOST_RECENT referrals are highlighted
 * 2. make sure that we have at least MIN_REFERRALS
 */
function updateReferrals(now) {
  var newReferrals = [];
  var refRecent = 0;

  for (var index = currentReferrals.length - 1; index >= 0; index--) {
    var referral = currentReferrals[index];

    if (referral.isActive(now) || newReferrals.length < MIN_REFERRALS) {
      if (referral.isActive(now)) {
        refRecent++;
      }

      referral.setRecent(newReferrals.push(referral) < MOST_RECENT);
    } else {
      referral.remove();
    }
  }

  currentReferrals = newReferrals.reverse();
  $('#refRecent').text(refRecent);
}

function tick() {
  var now = new Date().getTime();
  $('#refresh').text(((nextUpdate - now) / 1000).toFixed(0));

  try {
    if (nextUpdate != "..." && now > nextUpdate) {
      nextUpdate = "...";
      $.ajax({type: "POST", url: "/livemap", data: {since: mostRecentReferralId}, dataType: "json", success: loadData, error: loadError});

      // update our referral info after requesting
      updateReferrals(now);
    }
  } catch (e) {
    // ignore exception
  }

  setTimeout(tick, tickPeriod);
}

GEvent.addListener(map, "tilesloaded", tick);

