
// Global variables, keeping track of markers and map state
var markers = {};
var mapstate = {};
var inpanel = null;
var filterloaded = {};
var markerSelected = 0;

var controller = '';

// Maps zoom level to detail category
// 0-region, 1-small icons, 2-large icons
var zoomDetail = [0,0,0,0,0,1,1,2,2,2,2,2,2,2,2,2,2,2];
var zoomLines  = [0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1];

var gSort = null;
var gSortDirection = 1;


// Dependencies (must be defined in views):
//   external function setFilters(filters)
//   external function getFilters() -> filters
//   external function onMapChanged()


function mapInit(params) {
  mapstate = params.mapstate;
  controller = params.controller;
  
  if (params.filters) {
    setFilters(params.filters);
  }
  initGMap(mapstate);  
  loadMarkers();
  
  /*
  // Read polylines
  zoomLevel = map.getZoom();
  if (zoomLevel >= 8) {
    new Ajax.Request('/map/get_polylines', {asynchronous:true, evalScripts:true});
  }
  */
  
  GEvent.addListener(map, "click", function(marker, point) {
    if (marker && marker.myid) {
      markerSelect(marker.mytype, marker.myid);
    }
  });

 GEvent.addListener(map, "dragend", function () {
    mapPan();
  });
  
  GEvent.addListener(map, "zoomend", function () {
    mapZoom();
  });

  GEvent.addListener(map, "maptypechanged", function() {
    var maptype = maptypeEnumToString(map.getCurrentMapType());
    mapstate['type'] = maptype;
    new Ajax.Request("/"+controller+"/ajax_mapstate_changed", {asynchronous: true, parameters:flatten({mapstate:mapstate})});
  });
}

// icons are defined here statically in order to save space
// in the return value from ajax_get_markers
var icons = {
  bplay1: {url: '/images/small/bplay.png', w:12, h:20, ix:6, iy:6, ax:6, ay:6},
  rplay1: {url: '/images/small/rplay.png', w:12, h:20, ix:6, iy:6, ax:6, ay:6},
  yplay1: {url: '/images/small/yplay.png', w:12, h:20, ix:6, iy:6, ax:6, ay:6},
  gplay1: {url: '/images/small/gplay.png', w:12, h:20, ix:6, iy:6, ax:6, ay:6},
  dplay1: {url: '/images/small/dplay.png', w:12, h:20, ix:6, iy:6, ax:6, ay:6},
  bplay2: {url: '/images/large/bplay.png', w:34, h:34, ix:17, iy:17, ax:17, ay:17},
  rplay2: {url: '/images/large/rplay.png', w:34, h:34, ix:17, iy:17, ax:17, ay:17},
  yplay2: {url: '/images/large/yplay.png', w:34, h:34, ix:17, iy:17, ax:17, ay:17},
  gplay2: {url: '/images/large/gplay.png', w:34, h:34, ix:17, iy:17, ax:17, ay:17},
  dplay2: {url: '/images/large/dplay.png', w:34, h:34, ix:17, iy:17, ax:17, ay:17},
  r1: {url: '/images/small/r.png', w:12, h:20, ix:6, iy:6, ax:6, ay:20},
  y1: {url: '/images/small/y.png', w:12, h:20, ix:6, iy:6, ax:6, ay:20},
  g1: {url: '/images/small/g.png', w:12, h:20, ix:6, iy:6, ax:6, ay:20},
  d1: {url: '/images/small/d.png', w:12, h:20, ix:6, iy:6, ax:6, ay:20},
  b1: {url: '/images/small/b.png', w:12, h:20, ix:6, iy:6, ax:6, ay:20},
  r2: {url: '/images/large/r.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  rII2: {url: '/images/large/rII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  rIII2: {url: '/images/large/rIII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  rIV2: {url: '/images/large/rIV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  rV2: {url: '/images/large/rV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  y2: {url: '/images/large/y.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  yII2: {url: '/images/large/yII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  yIII2: {url: '/images/large/yIII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  yIV2: {url: '/images/large/yIV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  yV2: {url: '/images/large/yV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  g2: {url: '/images/large/g.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  gII2: {url: '/images/large/gII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  gIII2: {url: '/images/large/gIII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  gIV2: {url: '/images/large/gIV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  gV2: {url: '/images/large/gV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  d2: {url: '/images/large/d.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  dII2: {url: '/images/large/dII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  dIII2: {url: '/images/large/dIII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  dIV2: {url: '/images/large/dIV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  dV2: {url: '/images/large/dV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  b2: {url: '/images/large/b.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  bII2: {url: '/images/large/bII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  bIII2: {url: '/images/large/bIII.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  bIV2: {url: '/images/large/bIV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  bV2: {url: '/images/large/bV.png', w:20, h:34, ix:10, iy:10, ax:10, ay:34},
  G: {url: '/images/gauge.png', w:8, h:8, ix:4, iy:4, ax:4, ay:4},
  H: {url: '/images/hotspring.png', w:8, h:8, ix:4, iy:4, ax:4, ay:4}
};


function createIcon(iname) {
  var icon = new GIcon();
  if (typeof(iname) == 'string') {
    var idata = icons[iname];
  } else {
    var idata = iname;
  }
  icon.image = idata.url;
  icon.iconSize = new GSize(idata.w, idata.h);
  icon.iconAnchor = new GPoint(idata.ax, idata.ay);
  icon.infoWindowAnchor = new GPoint(idata.ix, idata.iy);
  return icon;
}


function mapPan() {
  var oldmapstate = mapstate;
  if (mapstate.detail > 0) {
    updateNewBounds();
  } else {
    mapstate = getMapstate();
    new Ajax.Request("/"+controller+"/ajax_mapstate_changed", {
      asynchronous: true,
      parameters:flatten({mapstate:mapstate})
    });
  }
  if (onMapChanged) {
    onMapChanged(mapstate, oldmapstate);
  }
}


function mapZoom() {
  var oldmapstate = mapstate;
  zoom = map.getZoom();
  if (zoomDetail[zoom] != zoomDetail[mapstate.zoom]) {
    // New zoom detail level => reload markers
    loadMarkers();
  } else {
    // Same zoom detail- get more points and update side panel etc.
    if (zoom < mapstate.zoom) {
      updateNewBounds();
    } else {
      updateCache();      
      updatePanel();
      
      mapstate = getMapstate();
      new Ajax.Request("/"+controller+"/ajax_mapstate_changed", {
        asynchronous: true,
        parameters:flatten({mapstate:mapstate})
      });
    }
  }

  // Callback to javascript in _filter (allows graying out some options etc)
  if (onMapChanged) {
    onMapChanged(mapstate, oldmapstate);
  }
}

// Called when a filter checkbox is changed
// onFilterChange('grade', '#{grade}', $F('filter[#{grade}]')

function onFilterChange(mtype, category, item, onoff)  {
  filters = getFilters();
  if (onoff == "1") {
    // Checkbox on: get the markers from cache or load them
    if (filterloaded[mtype][category][item] == "1") {
      // All the markers are in cache, show them
      for (var id in markers[mtype]) {
        setMarker(mtype, id, filters);
      }
    } else {
      // Get markers
      ajaxGetMarkers(
          flatten({mapstate:mapstate,filters:filters}),
          function () { updatePanel(); filtersloaded[mtype][category][item] = "1"});
      return;
    }
  } else {
    // Checkbox off: Remove the markers from map
    for (var id in markers[mtype]) {
      if (markers[mtype][id].filter[category] == item) {
        hideMarker(mtype, id);
      }
    }
  }
  updatePanel();
}


// Called when checkbox relating to mtype filter is changed
function onMarkerTypeChange(mtype) {
  if ($F('mtype-' + mtype) == 1) {
    // TODO check to see if the markers are in cache (filterloaded)
    // TODO combine with onFilterChange?
    var filters = getFilters();
    var f = {};
    f[mtype] = filters[mtype];

    var params = flatten({mapstate:mapstate, filters:f});
    ajaxGetMarkers(params, function () { if (mtype == inpanel) {updatePanel();} });
  } else {
    // Delete all the markers for 'mtype'
    for (var id in markers[mtype]) {
      hideMarker(mtype, id);
    }
    markers[mtype] = {};
    if (mtype == inpanel) {
      updatePanel();
    }
  }
}

// Get all markers for the current mapstate
function loadMarkers() {
  mapstate = getMapstate();
  filterloaded = getFilters();
  
  // Delete current markers
  if (markers) {
    for (var mtype in markers) {
      for (var id in markers[mtype]) {
        if (markers[mtype][id].visible) {
          // Remove overlay
          map.removeOverlay(markers[mtype][id].marker);
        }
      }
    }
  }
  markers = {};
  
  $('panelmain').update("<img src='/images/progress.gif'> Loading...")

  // Load new markers
  var detail = zoomDetail[map.getZoom()]; 
  new Ajax.Request("/" + controller + "/ajax_get_markers", {
    method: 'get',
    parameters: flatten({mapstate:mapstate, filters:filterloaded}),
    onSuccess: function(transport) {
      if (detail != zoomDetail[map.getZoom()]) {
        // Ignore it-- we have changed detail level since the request
        return;
      }
      markers = eval( "(" + transport.responseText + ")" );
      inpanel = markers.inpanel;
      markers.inpanel = null;
      
      // Loop through the markers returned by the server
      for (var mtype in markers) {
        for (var id in markers[mtype]) {
          // Create a marker for this item
          // TODO only create it if it complies to filter state
          initMarker(mtype, id);
        }
      }
      updatePanel();
      onMapChanged(mapstate, null);
    }
  });
}

function ajaxGetMarkers(params, postFunction) {
  // Get new markers
  var detail = zoomDetail[map.getZoom()];
  new Ajax.Request("/" + controller + "/ajax_get_markers", {
    method: 'get',
    parameters: params,
    onSuccess: function(transport) {
      if (detail != zoomDetail[map.getZoom()]) {
        // Ignore markers if zoom level has changed in the meantime
        return;
      }
      var newmarkers = eval( "(" + transport.responseText + ")" );
      newmarkers.inpanel = null;
      
      // Add the new markers
      for (var mtype in newmarkers) {
        if (!markers[mtype]) {
          markers[mtype] = {};
        }
        for (var id in newmarkers[mtype]) {
          // Create a marker if it doesnt exist already
          if (!(markers[mtype]  && markers[mtype][id])) {
            markers[mtype][id] = newmarkers[mtype][id];
          }
         initMarker(mtype, id);
        }
      }

      if (postFunction) {
        postFunction();
      }
      
      // TODO Remove some markers from cache if there are too many
    }
  });
}


function filterTest(markfilter, filters) {
  for (var f in markfilter) {
    if (markfilter[f] != '' && filters[f][markfilter[f]] != '1') {
      return false;
    }
  }
  return true;
}


function setMarker(mtype, id, filters) {
  var mark = markers[mtype][id];
  var point = new GLatLng(mark.lat, mark.lng);
  if (map.getBounds().contains(point) && filterTest(mark.filter, filters[mtype])) {
    initMarker(mtype, id);
  } else {
    hideMarker(mtype, id);
  }
}


function updateCache() {
  filters = getFilters();

  // Show/Hide markers
  for (var mtype in markers) {
    for (var id in markers[mtype]) {
      setMarker(mtype, id, filters);
    }
  }
}


function updateNewBounds() {
  updateCache();
  
  var oldmapstate = mapstate;
  mapstate = getMapstate();
  filterloaded = getFilters();
  
  var params = flatten({mapstate:mapstate, old:oldmapstate, filters:filterloaded})
  ajaxGetMarkers(params, updatePanel);
}




// This function prepares markers[mtype][id] by creating an icon, setting some variables and making it visible
function initMarker(mtype, id) {
  if (markers[mtype][id].visible)
    return;
  
  var item = markers[mtype][id];

//TODO Check that it complies to filters
//  for (var f in item.filter) {
//    var checkbox = 'filter[' + item.filter[f] + ']';
//    if ($(checkbox) && $F(checkbox) != 1) {
//      return;
//    }
//  }
  
  var icon = createIcon(item.icon);
  
  var point = new GLatLng(item.lat, item.lng);
  var marker = new GMarker(point, {icon:icon, title:item.tooltip});
  marker.myid = id;
  marker.mytype = mtype;
  markers[mtype][id].marker = marker;
  markers[mtype][id].visible = true;
  map.addOverlay(marker);
}

function hideMarker(mtype, id) {
  if (markers[mtype][id].visible) {
    map.removeOverlay(markers[mtype][id].marker);
    markers[mtype][id].marker = null;
    markers[mtype][id].visible = false;
  }
}

// Update gVisible and return list of ids of rivers that are visible
function getMarkersVisible() {
  var bounds = map.getBounds();
  var markersVisible = Array()
  for (var id in markers[inpanel]) {
    if (markers[inpanel][id].visible)
      markersVisible.push(id);
  }
  return markersVisible;
}

// New view selected
function mapGoto(lat, lng, zoom)  {
  // Recenter/zoom map
  map.setCenter(new GLatLng(lat, lng), zoom);

  // It seems like the necessary events are not fired to load the
  // markers so we do it manually.
  loadMarkers();
}

// Highlights a marker on the map
// (it was either selected in the sidebar or clicked on by user)
function markerSelect(mtype,id) {
  // Open info window for the selected item
  marker = markers[mtype][id]
  if (marker.infowindow) {
    marker.marker.openInfoWindowHtml(marker.infowindow);
  } else {
    // Infowindow is null, load with ajax
    marker.marker.openInfoWindowHtml("<div id='infowindow'><img src='/images/progress.gif'> Loading...</div>");
    new Ajax.Request('/map/ajax_infowindow', {
      parameters: {mtype:mtype, id:id},
      onSuccess: function (transport) {
        // Replace the infowindow with the contents we just received
        marker.infowindow = transport.responseText;
        marker.marker.openInfoWindowHtml(marker.infowindow);
      }
    });
  }
  
  // Highlight the entry in the panel
  if (mtype == inpanel) {
    if (markerSelected && $('panelitem-' + markerSelected)) {
      $('panelitem-' + markerSelected).removeClassName('selected');
    }
    if ($('panelitem-' + id)) {
      $('panelitem-' + id).addClassName('selected');
    } else {
      // TODO Marker is on different page than is currently shown
      //toPageID(id);
    }
    markerSelected = id;
  }
  
  // openInfoWindow may pan the map- not sure why it doesnt fire event
  // mapPan();   when uncommented this forces reload of the panellist which overrides the selected item! TODO!
}

function updatePanel() {
  updatePanel(null);
}

function toPage(offset) {
  updatePanel(offset);
}


function updatePanel(offset) {
  var show = getMarkersVisible();
  var params = flatten({
      mapstate: mapstate,
      filters: getFilters(),
      show: show.join(','),
      sort: gSort,
      direction: gSortDirection
    });
  if (offset) {
    params.offset = offset;
  }
  
  // Update sidepanel
  new Ajax.Request("/" + controller + "/ajax_update_panel", {
    method: 'get',
    parameters: params,
    evalScript: true
  });
}

function sortPanel(parameter) {
  if (gSort == parameter) {
    gSortDirection = 1 - gSortDirection;
  } else {
    gSort = parameter;
    gSortDirection = 1;
  }
  updatePanel();
}


// Belongs to trip controller
function showUser(id) {
  // Add/replace user into paneltab and select that tab
}
