/**
 * Author: Akshay Bhurtun
 * Date: 05 June 2008
 *
 * Layer used as a container for POIs
 *
 * $Id: ClientPOILayer.js,v 1.11 2009/02/23 05:55:12 vpulla Exp $
 */

qxp.OO.defineClass("ia.layer.ClientPOILayer",com.ptvag.webcomponent.map.layer.Layer,
function(vectorLayer_) 
{
   com.ptvag.webcomponent.map.layer.Layer.call(this);
   
   var cName = "[ia.layer.ClientPOILayer] ";   
   var vectorLayer = vectorLayer_;
   var layerName = null;
   var customLayerManager = new CustomLayerManager(this);
   
   var self = this;
   self.layerName = layerName;
   
   var poiCategories = new Array();
   poiCategories[0] = new POICategory("default");
   
   var routes = new Array();
   
   var cursor_mouseDown="url(./img/close_hand.cur), move";
   var cursor_mouseMove="url(./img/close_hand.cur), move";
   var cursor_mouseUp="url(./img/open_hand.cur), move";

   /*========================= PUBLIC FUNCTIONS =============================*/
   
   self.getCustomLayerManager = function getCustomLayerManager()
   {
      return customLayerManager;
   }  
   
   self.removePOIByPOIid=function removePOIByPOIid(poiid)
   {
      var fnName = cName + "removePOIByPOIid() ";
      var categoryIndex = null;
      var poiIndex = null;
      for(var i=0; i<poiCategories.length; i++)
      {
         var pois = poiCategories[i].getPOIs();
         
         for(var j=0; j<pois.length; j++)
         {
            if(pois[j].$("poiid") == poiid)
            {
               categoryIndex = i;
               poiIndex=j;
               log.debug(fnName, "Found a match!!");
               break;
            }
         }
      }
      
      if(categoryIndex != null && poiIndex != null)
      {
         var selectedCategory = poiCategories[categoryIndex];
         var poisArray = selectedCategory.getPOIs();
         
         log.debug(fnName, "Number of pois [" + poisArray.length + "]");
         log.debug(fnName, "categoryIndex [" + categoryIndex + "]");
         log.debug(fnName, "poiIndex [" + poiIndex + "]");
         poisArray[poiIndex].clearVectorElements(vectorLayer);
         
         var newArray = new Array();
         newArray = poisArray.slice(0, poiIndex);
         var lastIndex = poisArray.length;
         
         if(poiIndex == poisArray.length-1)
            --lastIndex;
         newArray = newArray.concat(poisArray.slice(poiIndex+1, lastIndex));
         selectedCategory.setPOIs(newArray);
         
         this.drawRoute(selectedCategory.getCategoryId());
         
         log.debug(fnName, "Number of pois After[" + selectedCategory.getPOIs().length + "]");
      }
   };
   
   
   /**
    * Function to hide all of the POI that belong to a particular category 
    * with id categoryId
    * @param categoryId - if null all of the POIs will be hidden
    */
   self.hidePOIsByCategory=function hidePOIsByCategory(categoryId)
   {
      var fnName = cName + "hidePOIsByCategory()";
      
      var pois = new Array();
      if(categoryId == null)
      {
         for(var i=0; i<poiCategories.length; i++)
         {
            pois = pois.concat(poiCategories[i].getPOIs());
         }
      }
      else
      {
         var category = getCategory(categoryId);
         if(category != null)
            pois = category.getPOIs();
      }
         
      if(pois == null)
      {
         log.warn(fnName, "failed to retrieve POICategory with id [" + categoryId + "]");
         return;
      }
      else
      {
         log.debug(fnName, "Number of pois [" + pois.length + "]");
      }
      
      for(var i=0; i<pois.length; i++)
      {
         pois[i].clearVectorElements(vectorLayer);
      }
   };
   
   /**
    * Plot all the POI belonging to a particular category onto the map.
    * 
    * If the categoryId is "null" all of the pois from all of the categories 
    * will be returned and plotted.
    *
    * @param categoryId - the pois from the category to be plotted onto the map
    *                     if null, plot all of the points in all of the 
    *                     categories 
    */
   self.plotPOIs=function plotPOIs(categoryId)
   {
      var fnName = cName + "plotPOIs()";
      var pois = new Array();
   
      if(categoryId == null)
      {
         for(var i=0; i<poiCategories.length; i++)
         {
            pois = pois.concat(poiCategories[i].getPOIs());
         }
      }
      else
      {
         var category = getCategory(categoryId);
         if(category != null)
            pois = category.getPOIs();
      }
         
      if(pois == null)
      {
         log.warn(fnName, "failed to retrieve POICategory with id [" + categoryId + "]");
         return;
      }
   
      var poiToPlot = null;
      
      // lets sort the POIs based on index      
      pois = pois.sort(_sortByIndex);
      for(var i=0; i<pois.length; i++)
      {
         pois[i].render(vectorLayer);
      }
   }
   
   /**
    * Sort comparator function. Sort everything in descrending order of index 
    * @param a - ClientPOI
    * @param b - ClientPOI
    * @return 1 - if a < b
    *         0 - if a = b
    *        -1 - if a > b
    */ 
   
   function _sortByIndex(a, b)
   {
      var index_a = a.getPOI().index;
      var index_b = b.getPOI().index;
      if(index_a < index_b)
         return 1;
      else if(index_a == index_b)
         return 0
      else
         return -1;
   }
   
   /**
    * Function to return all of the POIs within this layer
    */
   self.getAllPOIs=function getAllPOIs(categoryId)
   {
      var fnName = cName + "getAllPOIs()";
      var pois = new Array();
   
      for(var i=0; i<poiCategories.length; i++)
      {
         if(categoryId == null)
            pois = pois.concat(poiCategories[i].getPOIs());
         else if (poiCategories[i].getCategoryId() == categoryId)
            return poiCategories[i].getPOIs();
      }
      
      return pois;
   }
   
   /**
    * Add a new route to the layer. if the route with the same id already exists,
    * it will be replaced.
    */
   self.addRoute=function addRoute(route)
   {
      if(route != null)
      {
         for(var i=0; i<routes.length; i++)
         {
            if(routes[i].getRouteId() == route.getRouteId())
            {
               routes[i] = route;
               return;
            }
         }
         routes[routes.length] = route;
      }
   };
   
   /**
    * Add a POI. This function looks for the category attribute attached to the 
    * poi object passed in as the parameter.
    *
    * @param poi - Stringified object representing a POI i.e. {id:..,longitude:..,...}
    * @return ClientPOI
    */
   self.addPOI=function addPOI(poi)
   {
      var fnName = cName + "addPOI()";  
      
      if(poi.categoryId != null && poi.categoryId.length != 0)
      {
         var currentCategory = getCategory(poi.categoryId);
         
         if(currentCategory == null)
         {
            log.debug(fnName, "Creating new category [" + poi.categoryId + "]");
            currentCategory = new POICategory(poi.categoryId);
            poiCategories[poiCategories.length] = currentCategory;
         }
      }
      else
      {
         log.debug(fnName, "using fallback category [default]");
         currentCategory = poiCategories[0];
      }
      var currentPOI = new ClientPOI(poi);
      return currentCategory.addPOI(currentPOI);
   };
   
   self.getCategoryById=getCategory;
   
   /**
    * get a specific Category based on an id
    */
   function getCategory(categoryId)
   {
      var fnName = cName + "getCategory() ";
      for(var i=0; i<poiCategories.length; i++)
      {
         if(poiCategories[i].getCategoryId() == categoryId)
         {
            log.debug(fnName, "found category with id [" + categoryId + "]");
            return poiCategories[i];
         }
      }
      
      log.warn(fnName, "failed to retrieve category with id [" + categoryId + "]");
      return null;
   };
   
   
   /**
    * Function to retrieve a route by its id
    */
   this.getRouteById=function getRouteById(routeId)
   {
      var fnName = cName + "getRouteById() ";
      if(routeId == null)
         return null;
      for(var i=0; i<routes.length; i++)
      {
         if(routes[i].getRouteId() == routeId)
            return routes[i];
      } 
      return null;
   };
   
   /**
    * Function to get a POI JSObject with index "index" the index is used as an 
    * id for the POIs on the same page.
    */
   this.getPOIByIndex=function getPOIByIndex(index)
   {
      var fnName = cName + "getPOIByIndex()";
      for(var i=0; i<poiCategories.length; i++)
      {
         var pois = poiCategories[i].getPOIs();
         
         for(var j=0; j<pois.length; j++)
         {
            if(pois[j].$("index") == index)
            {
               log.debug(fnName, "Found a match!!");
               return pois[j];
            }
         }
      }
   };
   
   /**
    * Function to get a POI by POIID
    * @param poiid - the poiid of the POI to be retrieved
    */
   this.getPOIByPoiId=function getPOIByPoiId(index)
   {
      var fnName = cName + "getPOIByIndex()";
      for(var i=0; i<poiCategories.length; i++)
      {
         var pois = poiCategories[i].getPOIs();
         
         for(var j=0; j<pois.length; j++)
         {
            if(pois[j].$("poiid") == index)
            {
               log.debug(fnName, "Found a match!!");
               return pois[j];
            }
         }
      }
   };
   
   /*======================== ROUTING FEATURE ================================*/
   
   /**
    * Function to add a poi to a particular route. The poi is added to the route
    * with the routeId specified in the poi object
    *
    * @param poi - stringiified object of the form {routeId:..,poiid:...,...}
    * @deprecated
    */
   this._addRoutePOI=function _addRoutePOI(poi)
   {
      var fnName = cName + "addRoutePOI() ";
      
      if(poi.x == null || poi.x == 0 || poi.y == null || poi.y == 0)
      {
         var smartCoord = ptvWrapper.getSmartCoordinate(poi);
         poi.x = smartCoord.x;
         poi.y = smartCoord.y;
      }
      
      var routeId = poi.routeId;
      if(routeId == null || routeId.length == 0)
      {
         log.warn(fnName, "routeId missing from POI, will not be added as a way point!");
         return;
      }
      var currentPOI = new ClientPOI(poi);
      var currentRoute = null;
      
      log.debug(fnName, "looking for route with id [" + routeId + "]");
      
      for(var i=0; i<routes.length; i++)
      {
         if(routes[i].getRouteId() == routeId)
         {
            currentRoute = routes[i];
            break;
         }
      }
      if(currentRoute == null)
      {
         currentRoute = new Route(routeId, this);
         routes[routes.length] = currentRoute;
      }
      log.debug(fnName, "Added POI to route [" + routeId + "]");
      return currentRoute.addRoutePOI(currentPOI);
   };
   
   
   /**
    * Function to draw a route based on the routeId
    *
    * @param routeId - route with the specified id that will be rendered on the
    *                  map
    * @param recenter - whether to recenter on the route or not
    */
   this.drawRoute=function drawRoute(routeId, recenter)
   {
      var fnName = cName + "drawRoute()";
      
      log.debug(fnName, "Number of routes available [" + routes.length + "]");
      log.debug(fnName, "looking for route with routeId [" + routeId + "]");
      var coordsToRecenterOn = new Array();
      
      var currentRoute = self.getRouteById(routeId);
      
      if(typeof(preRouteProcessing) == "function")
      {
         preRouteProcessing(routes, currentRoute);
      }
      for(var i=0; i<routes.length; i++)
      {
         log.debug(fnName, "current route id [" + routes[i].getRouteId() + "]");
         
         // if we want to draw all of the routes
         if(routeId == null)
         {
            log.debug(fnName, "Drawing allof the routes");
            routes[i].drawRoute(vectorLayer, false);
         }
         // if we want to draw only 1 route in particular
         if(routeId == routes[i].getRouteId())
         {
            log.debug(fnName, "Drawing route with id [" + routeId + "]");
            routes[i].drawRoute(vectorLayer, recenter);
            break;
         }
      }
      
      if(typeof(postRouteProcessing) == "function")
      {
         postRouteProcessing(routes, currentRoute);
      }
   };
   
   /**
    * Method to remove a poi from a route
    * @param routeId - the id of the route from where the POI will be removed
    * @param poiid - the id of the clientPOI that will be removed from the route
    *                specified
    */
   this.removePOIFromRoute=function removePOIFromRoute(routeId, poiid)
   {
      var fnName = cName + "removePOIFromRoute() ";
      var route = null;
      log.debug(fnName, "removing POI [" + poiid + "] from route [" + routeId + "]");
      for(var i=0; i<routes.length; i++)
      {
         if(routes[i].getRouteId() == routeId)
         {
            route = routes[i];
            break;
         }
      }
      
      if(route == null)
      {
         log.warn(fnName, "unable to find route with id [" + routeId + "]");
         return;
      }
      
      route.removePOI(poiid);
   };
   
   /*========================= ACCESSOR FUNCTIONS ============================*/
   
   this.getCategories=function getCategories()
   {
      return poiCategories;
   };
   
   this.getRoutes=function getRoutes()
   {
      return routes;
   };
   
   this.setMouseDown=function setMouseDown(cursorMouseDown)
   {
      if(cursorMouseDown != null && cursorMouseDown.length > 0)
         cursor_mouseDown=cursorMouseDown;
   };
   
   this.setMouseMove=function setMouseMove(cursorMouseMove)
   {
      if(cursorMouseMove != null && cursorMouseMove.length > 0)
         cursor_mouseMove=cursorMouseMove;
   };
   
   this.setMouseUp=function setMouseUp(cursorMouseUp)
   {
      if(cursorMouseUp != null && cursorMouseUp.length > 0)
         cursor_mouseUp=cursorMouseUp;
   };
   
   
   /*========================== EVENT HANDLERS ===============================*/
    var editRoute = null;
    var routePOIIndex = -1;
    var routeClientPOI = null;
    
    this.clearEditRoute=function clearEditRoute()
    {
       if(routeClientPOI != null)
         routeClientPOI.getPOI().moving=false;
       editRoute = null;
       routePOIIndex = -1;
       routeClientPOI = null;
    }; 
    
    this.setEditRoute=function setEditRoute(routePOI)
    {
      var fnName = cName + "setEditRoute() ";
      
      if(routePOI.getPOI().hoverTimerHandler != null)
         clearTimeout(routePOI.getPOI().hoverTimerHandler);
         
      editRoute = self.getRouteById(routePOI.$("routeId"));
      
      for(var i=0; i<editRoute.getRouteElements().length; i++)
      {
         if(editRoute.getRouteElements()[i].poiid == routePOI.$("poiid"))
         {
            routeClientPOI = routePOI; 
            routePOIIndex = i;
            break;
         }
      }
    };
    
    this.onMouseDown = function(evt) 
    {
      var fnName = cName + "onMouseDown() ";
      if(editRoute != null)
      {
         editRoute.setLastValidRouteElements(editRoute.getRouteElements());
         map.setCursor(cursor_mouseDown);
         routeClientPOI.getPOI().moving = true;
         this.setEnabled(true);
         
         // clearing the vector will cause an exitHover handler to be triggered
         // which will clear the route being modified. so we use a flag above
         // "moving" so that we know that we are about to move this POI.
         if(routeClientPOI != null)
            routeClientPOI.clearVectorElements(vectorLayer);
         
         var result = editRoute.getPolyPaint().onMouseDown(evt, routePOIIndex);
         return result;
      }
      
      if(routes != null && routes.length > 0 )
      {
         map.setCursor(cursor_mouseDown);
         this.setEnabled(true);
         for(var i=0; i<routes.length; i++)
         {
            var result = routes[i].getPolyPaint().onMouseDown(evt);
            if(result)
            {
               routes[i].setLastValidRouteElements(routes[i].getRouteElements());
               editRoute = routes[i];
               editRoute.removeDragPoints();
               
               return result;
            }
         }
      }
      return false
    }
    
    this.onMouseMove = function(evt) 
    {
      var fnName = cName + "onMouseMove() ";
      if(editRoute != null)
      {
         if(routeClientPOI == null)
            map.setCursor(cursor_mouseMove);
         else if(routeClientPOI != null && routeClientPOI.getPOI().moving)
            map.setCursor(cursor_mouseMove);
         var result = editRoute.getPolyPaint().onMouseMove(evt);
         if(result)
            return true;
      }
      this.setEnabled(false);
      self.clearEditRoute();
      return true;
    }
    
    this.onMouseUp = function(evt, moving) 
    {
      
      this.setEnabled(false);
      if(routes != null && routes.length > 0 && editRoute != null)
      {
         map.setCursor(cursor_mouseUp);
         var result = editRoute.getPolyPaint().onMouseUp(evt);
         
         var coords = map.translateMouseCoords(evt); //translate mouse pixel coords
         var geoCoords = ptvWrapper.getRealCoordinate(coords);
         geoCoords.longitude = geoCoords.x;
         geoCoords.latitude = geoCoords.y;
         
         var routeElements = editRoute.getRouteElements();
         
         var pointInMotion = evt.pointInMotion;
         
         if(pointInMotion == null)
            return false;
         
         routeElements[pointInMotion].longitude = geoCoords.longitude;
         routeElements[pointInMotion].latitude = geoCoords.latitude;
         
         if(routeElements[pointInMotion].type == null || 
            (routeElements[pointInMotion].type != "START" && 
            routeElements[pointInMotion].type != "VIA" &&
            routeElements[pointInMotion].type != "END" )) 
            routeElements[pointInMotion].type = "NEW_VIA";
         
         var oldRoutePOIs = editRoute.removeAllRoutePOIs();
         editRoute.setLastValidRoutePOIs(oldRoutePOIs);
         var count = routeElements.length;
         
         var elemCounter = 0;
         for(var i=0; i<count; i++)
         {
            if(routeElements[i].type != null && 
               (routeElements[i].type == "START" ||
                routeElements[i].type == "VIA" ||
                routeElements[i].type == "NEW_VIA" ||
                routeElements[i].type == "END"))
            {
               var poiRef = null;
               if(routeElements[i].type != "NEW_VIA")
               {
                  poiRef = oldRoutePOIs[elemCounter];
                  ++elemCounter;
               }
               if(poiRef == null && routeElements[i].type == "NEW_VIA")
               {
                  //poiRef = new ClientPOI(MapUtils.getDefaultClientPOI());
                  var stringPOI = editRoute.getDefaultVIAPOI();
                  if(stringPOI == null)
                     stringPOI = MapUtils.getDefaultClientPOI();
                  stringPOI.poiid="";  
                  
                  poiRef = new ClientPOI(stringPOI);
                  poiRef.getPOI().type = "VIA";
                  poiRef.getPOI().fill=true;
               }
               
               if(poiRef == null)
                  continue;
                  
               /*poiRef.getPOI().drawPriority=5;
               poiRef.getPOI().label="";
               poiRef.getPOI().radius=5;
               poiRef.getPOI().hideTT = false;
               poiRef.getPOI().disableTTOnHover=true;*/
               poiRef.getPOI().longitude = routeElements[i].longitude;
               poiRef.getPOI().latitude = routeElements[i].latitude;
               poiRef.getPOI().x = routeElements[i].x;
               poiRef.getPOI().y = routeElements[i].y;
               poiRef = editRoute.addRoutePOI(poiRef);
            }
         }
         editRoute.drawRoute(null, false);
         setTimeout("map.setCursor(\"default\")", 1000);
         editRoute = null;
         return result;
      }
      return false;
    }
    
    this.getVectorLayer=function getVectorLayer()
    {
       return vectorLayer;
    }
});




