var p_latlng_array = [];

p_latlng_array[0] = new GLatLng(37.97356775986967,23.751282691955566);
p_latlng_array[1] = new GLatLng(37.96741045292136,23.77462863922119);
p_latlng_array[2] = new GLatLng(37.98011356100264,23.75943660736084);
p_latlng_array[3] = new GLatLng(37.98676024997843,23.774542808532715);
p_latlng_array[4] = new GLatLng(37.983648389125854,23.78286838531494);
p_latlng_array[5] = new GLatLng(37.99325414315071,23.790507316589355);
p_latlng_array[6] = new GLatLng(38.000931077344774,23.7868595123291);
p_latlng_array[7] = new GLatLng(38.00326443553524,23.782310485839844);
p_latlng_array[8] = new GLatLng(37.998174913696246,23.778297901153564);
p_latlng_array[9] = new GLatLng(38.00069435569893,23.77490758895874);
p_latlng_array[10] = new GLatLng(37.99831018794891,23.769328594207764);
p_latlng_array[11] = new GLatLng(38.00478615087543,23.76321315765381);
p_latlng_array[12] = new GLatLng(38.008150720458545,23.74490976333618);
p_latlng_array[13] = new GLatLng(38.01876754564554,23.746283054351807);
p_latlng_array[14] = new GLatLng(38.02806445739448,23.752849102020264);
p_latlng_array[15] = new GLatLng(38.03256035877346,23.740575313568115);
p_latlng_array[16] = new GLatLng(38.02735455300635,23.73793601989746);
p_latlng_array[17] = new GLatLng(38.01491320729587,23.719182014465332);
p_latlng_array[18] = new GLatLng(38.00982449404459,23.71772289276123);
p_latlng_array[19] = new GLatLng(37.99629795769223,23.69429111480713);
p_latlng_array[20] = new GLatLng(37.97624027632676,23.676953315734863);
p_latlng_array[21] = new GLatLng(37.97498860351825,23.70471954345703);
p_latlng_array[22] = new GLatLng(37.97241753296282,23.7050199508667);
p_latlng_array[23] = new GLatLng(37.96886524785879,23.699398040771484);
p_latlng_array[24] = new GLatLng(37.96333349027599,23.70826005935669);
p_latlng_array[25] = new GLatLng(37.96365491878729,23.71596336364746);
p_latlng_array[26] = new GLatLng(37.96106653345441,23.72218608856201);
p_latlng_array[27] = new GLatLng(37.95516196668683,23.715040683746338);
p_latlng_array[28] = new GLatLng(37.94945997179703,23.723816871643066);
p_latlng_array[29] = new GLatLng(37.95422294455842,23.73017907142639);
p_latlng_array[30] = new GLatLng(37.957006137369426,23.74817132949829);
p_latlng_array[31] = new GLatLng(37.96167557350534,23.745810985565186);
p_latlng_array[32] = new GLatLng(37.9668352934834,23.754844665527344 );
p_latlng_array[33] = new GLatLng(37.972620515491336,23.750767707824707);
p_latlng_array[34] = new GLatLng(37.97356775986967,23.751282691955566);


function POIManager(gmap,srvURL) {
  this.id = POIManager.instancesIdx++;
  POIManager.instances[this.id] = this;
  this.poiList = {};            //Holds a list of all displayed pois, indexed per poi id
  this.poiLayerIdToPOIId = {};  //For each layer id, holds the list of poi ids shown for this layer
  this.poiMap = {};             //Keeps a unique id per POI, determined by layerId, lat and lng (single point per coordinate)
  this.poiMapIdCount = 1;       //Used to assign temporary unique ids for each individual POI
  this.rectPerLayer = {};       //For each layer, holds the rectangle which is being displayed right now
  this.invocationQueue = [];
  this.map = gmap;
  this.serverURL = srvURL;
  this.that = this;
  this.layerIcons = {};
  this.coa_poly = new GPolygon(p_latlng_array);

  this.init = function() {
    this.poiList = {};
    this.poiLayerIdToPOIId = {};
    this.poiMap = {};
    this.poiMapIdCount = 1;
    this.rectPerLayer = {};
  }

  this.setLayerIcon = function(layerid, gi) {    
    this.layerIcons[layerid] = gi;    
  }
  
  this.getPOIId = function(poi) {
    if (this.poiMap[poi.layerId]===undefined) this.poiMap[poi.layerId] = {};
    if (this.poiMap[poi.layerId][poi.lat]===undefined) this.poiMap[poi.layerId][poi.lat] = {};
    var t = this.poiMap[poi.layerId][poi.lat][poi.lng];    
    if (t== undefined) return -1;    
    return t;
  }

  this.addPOI = function(poi) {
    var id = this.poiMapIdCount++;
    if (this.poiMap[poi.layerId]===undefined) poiMap[this.poi.layerId] = {};
    if (this.poiMap[poi.layerId][poi.lat]===undefined) this.poiMap[poi.layerId][poi.lat] = {};
    this.poiMap[poi.layerId][poi.lat][poi.lng] = id;
    poi.id = id;
    if (this.poiLayerIdToPOIId[poi.layerId]===undefined) this.poiLayerIdToPOIId[poi.layerId] = {};
    this.poiLayerIdToPOIId[poi.layerId][id] = 1;
    this.poiList[id] = poi;
    return id;
  }

  this.removePOI = function(id) {
    var t = this.poiList[id];
    if (this.poiList[id]!==undefined) {
      delete this.poiList[id];
      delete this.poiMap[t.layerId][t.lat][t.lng];
      delete this.poiLayerIdToPOIId[t.layerId][id];
    }
  }

  this.getPOIHtml = function(poiid) {
    var st = '';
    var poi = this.poiList[poiid];
//    var catid = poiLayerIdToCategoryId[poi.layerId];    
//    var cat = poiCategories[catid];
//    st += '<b>'+cat+': '+poiCategoryLayerInfo[cat][poi.layerId].layerName+'</b><br />';

    st += poi.attr.NAME_GQ+'<br />';
    var phone = poi.attr.POI_PHONE_GQ;
    if (phone>0.01) st += Math.round(phone)+'<br />';
    
    return st;
  }

  this.filterDisabledLayers = function(layerids) {
    var t = [];
    for (var i = 0; i < layerids.length; i++) {
      if (this.rectPerLayer[layerids[i]]!==undefined) t.push(layerids[i]);
    }    
    return t;
  }

  this.processPOIData = function(poiData,layerids,gbounds) {    
    for (var i in poiData.poiList) {
      poi = poiData.poiList[i];      
      var poi_latlng = new GLatLng(poi.lat,poi.lng);
      if (poly_contains_poi(poi_latlng,this.coa_poly)){
      //if(this.coa_poly.getBounds().containsLatLng(poi_latlng)){	
	var id = this.getPOIId(poi);      
	if (id<0) {
	  id = this.addPOI(poi);
	  if (this.rectPerLayer[poi.layerId]===undefined) continue;
	      var marker = new GMarker(new GLatLng(poi.lat,poi.lng), this.layerIcons[poi.layerId]);
	      marker.poiId = id;	    	    
	      marker.bindInfoWindowHtml(this.getPOIHtml(id));
	      markersOnMap.push({'lat':poi.lat,'lng':poi.lng,'name':poi.attr.NAME_GQ});
	      this.map.addOverlay(marker);	      
	      poi.marker = marker;
	    }	  
      }      
    }
    
    if (poiData.remaining>0) {
      //_retrieveExtraPOIs(poiData.sessionid,undefined,gbounds);
      var entry = {'sessionid':poiData.sessionid, 'layerids':layerids, 'gbounds':gbounds};
      this.invocationQueue.push(entry);
    }
    this.processInvocationQueue();
  }

  this.removePOIsByLayer = function(layerids) {
    for (var j in layerids) {
    	delete this.rectPerLayer[layerids[j]];
    	var poiids = this.poiLayerIdToPOIId[layerids[j]];
    	if (poiids!==undefined) {
    		for (var i in poiids) {
    			if (this.poiList[i].marker!==undefined) this.map.removeOverlay(this.poiList[i].marker);
    			this.removePOI(this.poiList[i].id);
    		}
    	}
    }
  }

  this.retrieveExtraPOIs = function(sessionid,layerids,gbounds) {    
    if (layerids.length==0) return;
    var queryData = {};
    queryData.sessionid = sessionid;
    queryData.count = POIManager.MAX_POI_COUNT;    
    if (sessionid==0) {
      queryData.layerids = layerids.join(',');
      queryData.sw_lat = gbounds.southwest.lat;
      queryData.sw_lng = gbounds.southwest.lng;
      queryData.ne_lat = gbounds.northeast.lat;
      queryData.ne_lng = gbounds.northeast.lng;      
    }
    RemoteAjax.call({
      url: this.serverURL+'/getSessionPoiList.jsp',
      data: queryData,
      instance: this,
      extra: {'layerids':layerids, 'gbounds': gbounds},
      success: 'retrieveExtraPOIs_success'
    });
  }

  this.retrieveExtraPOIs_success = function(data,extra) {    
    this.processPOIData(data,extra.layerids,extra.gbounds);
  }

  this.getPOIs = function(layerids,gbounds) {
    var i,j,k,m;

    //First we split the layer ids into groups having the same
    //prefetched rectangle lists
    var layerGroups = [];
    for (i = 0; i < layerids.length; i++) {
      var found = false;
      for (j = 0; j < layerGroups.length; j++) {
        var f = false;
        for (k = 0; k < layerGroups[j].length; k++) {
          if (layerGroups[j][k]==layerids[i]) {
            f = true;
            break;
          }
        }
        if (f) {
          found = true;
          break;
        } else {
          var r1 = this.rectPerLayer[layerids[i]];
          var r2 = this.rectPerLayer[layerGroups[j][0]];
          if (r1===undefined) {
            if (r2===undefined) {
              layerGroups[j].push(layerids[i]);
              found = true;
              break;
            }
          } else {
            if (r2!==undefined) {
              if (compareRectangles(r1,r2)) {
                layerGroups[j].push(layerids[i]);
                found = true;
                break;
              }
            }
          }
        }
      }
      if (!found) {
        //We need to add a new group
        layerGroups.push([layerids[i]]);
      }
    }

    //alert(toJSONString(layerGroups));

    //Each group will have the rectangle calculations done separately
    for (i = 0; i<layerGroups.length; i++) {
      var lid = layerGroups[i][0];
      var t = [gbounds];
      if (this.rectPerLayer[lid]!==undefined) {
        t = getRectangleDiff(this.rectPerLayer[lid],gbounds);
      }
      for (j = 0; j<t.length; j++) {
        var entry = {'sessionid':0, 'layerids':layerGroups[i], 'gbounds':t[j]};
        this.invocationQueue.push(entry);
      }
      for (j = 0; j<layerGroups[i].length; j++) {
        this.rectPerLayer[layerGroups[i][j]] = gbounds;
      }
    }

    //We start the processing of the invocation queue...
    this.processInvocationQueue();
  }

  this.processInvocationQueue = function() {
    if (this.invocationQueue.length>0) {
      var t = this.invocationQueue.shift();
      this.retrieveExtraPOIs(t.sessionid,this.filterDisabledLayers(t.layerids),t.gbounds);
    }
  }

  this.getPOIById = function(id) {
    return this.poiList[id];
  }

  this.getDisplayedLayersArray = function() {
    var t = [];
    for (var i in this.rectPerLayer) {
      t.push(i);
    }
    return t;
  }

  this.mapUpdated = function() {
    var bounds = this.map.getBounds();
    this.getPOIs(this.getDisplayedLayersArray(),
          {'southwest':{'lat':bounds.getSouthWest().lat(), 'lng':bounds.getSouthWest().lng()},
           'northeast':{'lat':bounds.getNorthEast().lat(), 'lng':bounds.getNorthEast().lng()}});
  }
}

POIManager.MAX_POI_COUNT = 50;
POIManager.instances = {};
POIManager.instancesIdx = 0;

//from rectangles.js

function compareRectangles(r1,r2) {
  return (  (Number(r1.southwest.lat)==Number(r2.southwest.lat))
          &&(Number(r1.southwest.lng)==Number(r2.southwest.lng))
          &&(Number(r1.northeast.lat)==Number(r2.northeast.lat))
          &&(Number(r1.northeast.lng)==Number(r2.northeast.lng)));
}

function getRectangleDiff(r1,r2) {
  var r2_northwest = {'lat':r2.southwest.lat,'lng':r2.northeast.lng};
  var r2_southeast = {'lat':r2.northeast.lat,'lng':r2.southwest.lng};
  if (containsPoint(r1,r2.southwest)) {
    if (containsPoint(r1,r2.northeast)) {
      //alert('Case 000,010,000');
      return [];
    } else {
      if (containsPoint(r1,r2_northwest)) {
        //alert('Case 000,001,000');
        return [{'southwest':{'lat':r1.northeast.lat, 'lng':r2.southwest.lng}, 'northeast':r2.northeast}];
      } else {
        if (containsPoint(r1,r2_southeast)) {
          //alert('Case 010,000,000');
          return [{'southwest':{'lat':r2.southwest.lat, 'lng':r1.northeast.lng}, 'northeast':r2.northeast}];
        } else {
          //alert('Case 001,000,000');
          return [
            {'southwest':{'lat':r2.southwest.lat, 'lng':r1.northeast.lng}, 'northeast':r2.northeast},
            {'southwest':{'lat':r1.northeast.lat, 'lng':r2.southwest.lng}, 'northeast':{'lat':r2.northeast.lat, 'lng':r1.northeast.lng}}
          ];
        }
      }
    }
  } else {
    if (containsPoint(r1,r2.northeast)) {
      if (containsPoint(r1,r2_southeast)) {
        //alert('Case 000,100,000');
        return [{'southwest':r2.southwest, 'northeast':{'lat':r1.southwest.lat, 'lng':r2.northeast.lng}}];
      } else {
        if (containsPoint(r1,r2_northwest)) {
          //alert('Case 000,000,010');
          return [{'southwest':r2.southwest, 'northeast':{'lat':r2.northeast.lat, 'lng':r1.southwest.lng}}];
        } else {
          //alert('Case 000,000,100');
          return [
            {'southwest':r2.southwest, 'northeast':{'lat':r2.northeast.lat, 'lng':r1.southwest.lng}},
            {'southwest':{'lat':r2.southwest.lat, 'lng':r1.southwest.lng}, 'northeast':{'lat':r1.southwest.lat, 'lng':r2.northeast.lng}}
          ];
        }
      }
    } else {
      if (containsPoint(r1,r2_northwest)) {
        //alert('Case 000,000,001');
        return [
          {'southwest':r2.southwest, 'northeast':{'lat':r2.northeast.lat, 'lng':r1.southwest.lng}},
          {'southwest':{'lat':r1.northeast.lat, 'lng':r1.southwest.lng}, 'northeast':r2.northeast}
        ];
      } else {
        if (containsPoint(r1,r2_southeast)) {
          //alert('Case 100,000,000');
          //alert(toJSONString(r1)+'\n\n'+toJSONString(r2));
          return [
            {'southwest':r2.southwest, 'northeast':{'lat':r1.southwest.lat, 'lng':r1.northeast.lng}},
            {'southwest':{'lat':r2.southwest.lat, 'lng':r1.northeast.lng}, 'northeast':r2.northeast}
          ];
        } else {
          if (containsPoint(r2,r1.southwest)) {
            //alert('Case 111,101,111');
            //r1 is entirely contained within r2
            return [
              {'southwest':r2.southwest, 'northeast':{'lat':r1.southwest.lat, 'lng':r2.northeast.lng}},
              {'southwest':{'lat':r1.northeast.lat, 'lng':r2.southwest.lng}, 'northeast':r2.northeast},
              {'southwest':{'lat':r1.southwest.lat, 'lng':r1.northeast.lng}, 'northeast':{'lat':r1.northeast.lat, 'lng':r2.northeast.lng}},
              {'southwest':{'lat':r1.southwest.lat, 'lng':r2.southwest.lng}, 'northeast':{'lat':r1.northeast.lat, 'lng':r1.southwest.lng}}
            ];
          } else {
            //r1 and r2 are disjoint
            //alert('Case 000,000,000');
            return [r2];
          }
        }
      }
    }
  }
}

function containsPoint(r1,p1) {
  var t1 = {'lat':Number(p1.lat), 'lng':Number(p1.lng)};
  return ((Number(r1.southwest.lat)<=t1.lat)
          &&(Number(r1.southwest.lng)<=t1.lng)
          &&(Number(r1.northeast.lat)>t1.lat)
          &&(Number(r1.northeast.lng)>t1.lng));
}

function poly_contains_poi(latLng,polygon){
   var bounds = polygon.getBounds();
    
    if(!bounds.containsLatLng(latLng)) {
        return false;
    }
    
    var numPoints = polygon.getVertexCount();
    var inPoly = false;
    var i;
    var j = numPoints-1;
    
    for(var i=0; i < numPoints; i++) { 
        var vertex1 = polygon.getVertex(i);
        var vertex2 = polygon.getVertex(j);
        
        if (vertex1.lng() < latLng.lng() && vertex2.lng() >= latLng.lng() || vertex2.lng() < latLng.lng() && vertex1.lng() >= latLng.lng())  {
            if (vertex1.lat() + (latLng.lng() - vertex1.lng()) / (vertex2.lng() - vertex1.lng()) * (vertex2.lat() - vertex1.lat()) < latLng.lat()) {
                inPoly = !inPoly;
            }
        }
        
        j = i;
    }    
    return inPoly;
}

  

