/**
 * Route Class to model a route. This class keep tracks of the different pois 
 * that define a route.
 *
 * @author Akshay Bhurtun
 *
 * $Id: Route.js,v 1.14 2009/07/20 07:24:20 abhurtun Exp $ 
 */

function Route(routeId_, containerLayer_)
{
   var cName = "[Route] ";
   var routeId = routeId_;
   
   var routeColor = "rgba(0,0,255,0.8)";
   var routeWidth = 3;
   var routeHoverRadius = -1;
   var routeHoverBorder = 2;
   var routeHoverColor = "white";
   var routeHoverBorderColor = "red";
   var routeHoverImage = null;
   
   
   var routeElements = new Array();
   var lastValidRouteElements=new Array();
   var routeCoordinates = new Array();
   var currentRoute = null;
   var line = null;
   var routePOIs = new Array();
   var lastValidRoutePOIs = new Array();
   var routeDetail = "";
   var routeOptimization ="";
   var useToll=false;
   var vectorLayer = null;
   var self = this;
   var containerLayer = containerLayer_;
   var currentMap = map;
   var corridorSearchDistance=1000.0;
   
   var distance;
   var time;
   var rpcCall=false;
   var lazyLoad = false;
   
   var defaultVIAPOI=null;
   
   var hoverCursor="url(./img/open_hand.cur), move";
   self.postRouteRenderedFn=null;
   self.preRouteRenderedFn=null;
   var poiCounter = 0;
   
   var polyPaint = new com.ptvag.polypaint.PolyPaintLayer();
   
   //var ptvLayers = new Array();
   
   var customLayerManager = new CustomLayerManager(containerLayer_);
   
   
   self.getRouteHoverRadius=function getRouteHoverRadius()
   {
      return routeHoverRadius;
   };
   
   self.setRouteHoverRadius=function setRouteHoverRadius(_routeHoverRadius)
   {
      routeHoverRadius = _routeHoverRadius;
   };
   
   self.getRouteHoverBorder=function getRouteHoverBorder()
   {
      return routeHoverBorder;
   };
   
   self.setRouteHoverBorder=function setRouteHoverBorder(_routeHoverBorder)
   {
      routeHoverBorder = _routeHoverBorder;
   };
   
   self.getRouteHoverColor=function getRouteHoverColor()
   {
      return routeHoverColor;
   };
   
   self.setRouteHoverColor=function setRouteHoverColor(_routeHoverColor)
   {
      routeHoverColor = _routeHoverColor;
   };
   
   self.getRouteHoverBorderColor=function getRouteHoverBorderColor()
   {
      return routeHoverBorderColor;
   };
   
   self.setRouteHoverBorderColor=function setRouteHoverBorderColor(_routeHoverBorderColor)
   {
      routeHoverBorderColor = _routeHoverBorderColor;
   };
   
   self.getRouteHoverImage=function getRouteHoverImage()
   {
      return routeHoverImage;
   };
   
   self.setRouteHoverImage=function setRouteHoverImage(_routeHoverImage)
   {
      routeHoverImage = _routeHoverImage;
   };
   
   
   
   
   self.addLayer = function addLayer(ptvLayerType, ptvLayerDescription, ptvLayerAttNames, defaultPOI, drawPOIByDefault, layerHandlerFn, maxResults)
   {
      customLayerManager.addLayer(ptvLayerType, ptvLayerDescription, ptvLayerAttNames, defaultPOI, drawPOIByDefault, layerHandlerFn, maxResults);
   }
   
   
   self.setLazyLoad=function setLazyLoad(lazyLoad_)
   {
      lazyLoad = lazyLoad_;
   };
   
   self.isLazyLoad=function isLazyLoad()
   {
      return lazyLoad;
   };
   
   self.isRpcCall=function isRpcCall()
   {
      return rpcCall;
   };
   
   self.setRpcCall=function setRpcCall(rpcCall_)
   {
      rpcCall = rpcCall_;
   };
   
   self.getCurrentRoute=function getCurrentRoute()
   {
      return currentRoute;
   };
   
   self.getLine=function getLine()
   {
      return line;
   };
   
   self.setLine=function setLine(line_)
   {
      line=line_;
   };
   
   self.setLastValidRoutePOIs=function setLastValidRoutePOIs(validPOIs)
   {
      lastValidRoutePOIs=validPOIs;
   };
   
   self.getLastValidRoutePOIs=function getLastValidRoutePOIs()
   {
      return lastValidRoutePOIs;
   };
   
   self.setLastValidRouteElements=function setLastValidRouteElements(routeElems)
   {
      log.debug("setLastValidRouteElements ", "settinglast... [" + routeElements.length + "]");
      lastValidRouteElements=new Array();
      
      for(var i=0; i<routeElems.length; i++)
      {
         lastValidRouteElements[i] = {};
         var error = false;
         try
         {
            lastValidRouteElements[i] = eval(uneval(routeElems[i]));
         }
         catch(e)
         {
            error = true;
         }
         
         if(error)
         {
            for(var prop in routeElems[i])
            {
               eval("lastValidRouteElements[" + i + "]." + prop + "= routeElems[" + i + "]." + prop);
            }
         }
      }
   }; 
   
   self.getLastValidRouteElements=function getLastValidRouteElements()
   {
      return lastValidRouteElements;
   };
   
   self.getDistance=function getDistance()
   {
      return distance;
   };
   
   self.setDistance=function setDistance(distance_)
   {
      distance=distance_;
   };
   
   self.getTime=function getTime()
   {
      return time;
   };
   
   self.setTime=function setTime(time_)
   {
      time=time_;
   };
   
   
   self.setPreRouteRenderedFn=function setPreRouteRenderedFn(preRouteRenderedFn_)
   {
      self.preRouteRenderedFn = preRouteRenderedFn_;
   };
   
   self.setPostRouteRenderedFn=function setPostRouteRenderedFn(postRouteRenderedFn_)
   {
      self.postRouteRenderedFn = postRouteRenderedFn_;
   };
   
   self.getHoverCursor=function getHoverCursor()
   {
      return hoverCursor;
   };
   
   self.setHoverCursor=function setHoverCursor(hoverCursor_)
   {
      hoverCursor = hoverCursor_;
   };
   
   self.setMovingVIAMarkerImg=function setMovingVIAMarkerImg(movingVIAMarkerImg)
   {
      polyPaint.setMovingVIAMarkerImg(movingVIAMarkerImg);
   };
   
   self.setDefaultVIAPOI=function setDefaultVIAPOI(defaultVIAPOI_)
   {
      defaultVIAPOI = defaultVIAPOI_;
   };
   
   self.setCorridorSearchDistance=function setCorridorSearchDistance(distance)
   {
      corridorSearchDistance = distance;
   };
   
   self.getCorridorSearchDistance=function getCorridorSearchDistance()
   {
      return corridorSearchDistance;
   };
   
   /**
    * A cloned version needs to be rturned so that the same object is not 
    * referenced internally for multiple VIAs
    */
   self.getDefaultVIAPOI=function getDefaultVIAPOI()
   {
      var clonedVIA = {};
      
      for(var attr in defaultVIAPOI)
      {
         eval("clonedVIA." + attr + "=defaultVIAPOI." + attr);
      }
      return clonedVIA;
   };      
   
   self.getRouteWidth=function getRouteWidth()
   {
      return routeWidth;
   };
   
   self.setRouteWidth=function setRouteWidth(routeWidth_)
   {
      routeWidth = routeWidth_;
   };
   
   self.setRouteDetail=function setRouteDetail(routeDetail_)
   {
      routeDetail = routeDetail_;
   };
   
   self.setRouteOptimization=function setRouteOptimization(routeOptimization_)
   {
      routeOptimization = routeOptimization_;
   };
   
   self.setUseToll=function setUseToll(useToll_)
   {
      useToll = useToll_;
   };
   
   self.getRoutePOIs=function getRoutePOIs()
   {
      return routePOIs;
   };
   
   self.setRoutePOIs=function setRoutePOIs(routePOIs_)
   {
      routePOIs = routePOIs_;
   };
   
   self.removeAllRoutePOIs=function removeAllRoutePOIs()
   {
      var tempRoutePOIs = routePOIs;
      routePOIs = new Array();
      return tempRoutePOIs;
   };
   
   self.getPolyPaint=function getPolyPaint()
   {
      return polyPaint;
   };
   
   
   self.getRouteId=function getRouteId()
   {
      return routeId;
   };
   
   
   
   self.setRouteId=self.setId=function setRouteId(routeId_)
   {
      routeId= routeId;
   };
   
   
   self.setRouteCoordinates=function setRouteCoordinates(routeCoordinates_)
   {
      routeCoordinates = routeCoordinates_; 
      line = new com.ptvag.webcomponent.map.vector.Line();
      line.setCoordinates(routeCoordinates);
      line.setPriority(-1);
      
   };
   
   self.addRouteCoordinate=function addRouteCoordinate(coordinate)
   {
      routeCoordinates[routeCoordinates.length] = coordinate; 
   };
   
   
   this.getRouteColor=function getRouteColor()
   {
      return routeColor;
   };
   
   this.setRouteColor=function setRouteColor(routeColor_)
   {
      routeColor = routeColor_;
   };
   
   this.removeAllRouteCoordinates=function removeAllRouteCoordinates()
   {
      routeCoordinates = new Array();
      if(currentRoute != null)
      {
         vectorLayer.removeElement(currentRoute);
         currentRoute = null;
         line = null;
      }
   };
   
   this.getRouteElements=function getRouteElements()
   {
      return routeElements;
   };
   
   this.setRouteElements=function setRouteElements(routeElements_)
   {
      routeElements = routeElements_;   
   };
   
   this.getRouteCoordinates=function getRouteCoordinates()
   {
      return routeCoordinates;
   };
   /**
    * Add a routePOI (clientPOI object)
    * @param poi - of type clientPOI
    */
   self.addRoutePOI=function addRoutePOI(poi)
   {
      var fnName = cName + "addRoutePOI() ";
      var poiid = poi.$("poiid");
      poi.getPOI().routeId = routeId;
      
      log.info(fnName, "poiid [" + poi.getPOI().poiid + "] $ [" + poi.$("poiid") + "]");
      
      // check if this poi is already in the list, if it does, remove it
      if(poiid != null && (""+poiid).length > 0)
      {
         for(var i=0; i<routePOIs.length; i++)
         {
            if(routePOIs[i] != null && poiid == routePOIs[i].$("poiid"))
            {
               log.warn(fnName, "POI with poiid [" + poiid + "] already exists, replacing with new POI");
               
               routePOIs[i].clearVectorElements(vectorLayer);
               poi.copyVariables(routePOIs[i]);
               routePOIs[i].setStringifiedPOI(poi.getPOI());
               return routePOIs[i];
            }
         }
      }
      else
      {
         poiid = "ROUTEPOI_" + poiCounter;
         poi.setVariable("poiid", "\"" + poiid + "\"");
      }
      
      // set the routeColor
      if(poi.$("routeColor") != null && poi.$("routeColor").length > 0)
         routeColor = poi.$("routeColor");
      
      if(poi.getPOI().routeWidth != null)
         routeWidth = poi.getPOI().routeWidth;
      
      /*if(routePOIs.length > 1)
      {
         routePOIs[routePOIs.length] = poi;
      }
      else*/
      routePOIs[routePOIs.length] = poi;
      
      poiCounter = poiCounter+1;
      return poi;
   };
   
   /**
    * @deprecated
    */
   function parsePOIViewSets(poiViewSetElems)
   {
      var fnName = cName + "parsePOIViewSet() ";
      
      for(var i=0; i<poiViewSetElems.length; i++)
      {
         var poiViewSet = poiViewSetElems[i];
         var poiType = poiViewSetElems[i].getElementsByTagName("poiType")[0].lastChild.data;
         //log.debug(fnName, "poiType [" + poiType + "]");
         
         var poiViews =  poiViewSetElems[i].getElementsByTagName("poiViews")[0].getElementsByTagName("POIView");
         var attributes = poiViewSetElems[i].getElementsByTagName("POIAttribute");
         var attributeNames = new Array();
         
         for(var j=0; j<attributes.length; j++)
         {
            attributeNames[attributeNames.length] = attributes[j].getElementsByTagName("name")[0].lastChild.data;
         }
         for(var j=0; j<poiViews.length; j++)
         {
            var poiid = poiViews[j].getElementsByTagName("poiID")[0].lastChild.data;
            
            var ptvLayer = customLayerManager.getLayerByType(poiType);
            var defaultLayerPOI = ptvLayer.defaultPOI;
            
            var poi = {};
      
            for(var attr in defaultLayerPOI)
            {
               eval("poi." + attr + "=defaultLayerPOI." + attr);
            }
            
            poi.poiid = poiid;
            
            var summary = "";
            var valueTags = poiViews[j].getElementsByTagName("value");
            var ptvAttributes = {};
            for(var k=0; k<valueTags.length; k++)
            {
               var valueData = valueTags[k].lastChild.data;
               var elementClass = poiType + "_" + attributeNames[k];
               summary += "<div class='" + elementClass +"'><span class='ptvAttributeName'>" + attributeNames[k] + ":</span>" + valueData + "</div>";
               eval("ptvAttributes." + attributeNames[k] + "=\"" + valueData + "\";"); 
            }
            poi.ptvAttributes = ptvAttributes;
            poi.summary = summary;
            poi.categoryId = ptvLayer.ptvLayerDescription;
            poi.hideTT=false;
            poi.longitude = parseInt(poiViews[j].getElementsByTagName("longitude")[0].lastChild.data)/conf_smartUnitToGeoFactor;
            poi.latitude = parseInt(poiViews[j].getElementsByTagName("latitude")[0].lastChild.data)/conf_smartUnitToGeoFactor;
            
            var clientPOI = containerLayer.addPOI(poi);
            if(ptvLayer.layerHandlerFn != null)
            {
               if(typeof(ptvLayer.layerHandlerFn) == "function")
                  ptvLayer.layerHandlerFn(clientPOI);
               else if(typeof(ptvLayer.layerHandlerFn) == "string")
                  eval(ptvLayer.layerHandlerFn);
            }
            if(ptvLayer.drawPOIByDefault)
               clientPOI.render(vectorLayer);          
         }
      } 
   }
   
   self.renderRoute=function renderRoute(show, recenter)
   {
      if(show)
      {
         if(currentRoute == null)
         {
            if(line == null)
               return;
            line.setPixelSize(routeWidth);
            line.setColor(routeColor);
            currentRoute = vectorLayer.addElement(line);
         }
      }
      else   
      {
         if(currentRoute != null)
         {
            vectorLayer.removeElement(currentRoute);
            currentRoute = null;
         }
      }
      
      if(recenter == null || recenter == true)
      {
         currentMap.setViewToPoints(routeElements, false, false);
         currentMap.setResetRect(currentMap.getRect());
      }
   }
   
   /**
    * fire preroute rendered handler
    */
   self.firePreRouteRenderedHandler=function firePreRouteRenderedHandler()
   {
      if(self.preRouteRenderedFn != null)
      {
         if(typeof(self.preRouteRenderedFn) == "function")
         {
            var result = self.preRouteRenderedFn(this);
            if(result != null && result != 0)
               return result; 
         }
         else if(typeof(self.preRouteRenderedFn) == "string")
            eval(self.preRouteRenderedFn);
      }
      return 0;
   }
   
   /**
    * Fire post route rendered handler
    */
   self.firePostRouteRenderedHandler=function firePostRouteRenderedHandler()
   {
      if(self.postRouteRenderedFn != null)
      {
         if(typeof(self.postRouteRenderedFn) == "function")
            self.postRouteRenderedFn(this);
         else if(typeof(self.postRouteRenderedFn) == "string")
            eval(self.postRouteRenderedFn);
      }
   }
   
   /**
    * Function to be invoked when receiving response from routing interface
    * @param document - the xml document containing all the data regarding the 
    *                   route generated
    * @param recenter_ - whether to recenter on a route or not
    */
   self.displayRouteFromXML=function displayRouteFromXML(documentXML, recenter_, renderLine)
   {
      var fnName = cName + "displayRouteFromXML() ";
      var iaptvMap = documentXML.getElementsByTagName("IAPTV")[0];
      var routing = iaptvMap.getElementsByTagName("routing")[0];
      var routingCoords = routing.getElementsByTagName("routeCoords")[0].getElementsByTagName("Coordinate");
      distance = XMLUtils.getChildNodesByTagName(routing, "distance")[0].lastChild.data;
      time = XMLUtils.getChildNodesByTagName(routing, "time")[0].lastChild.data;
      var routingElems = routing.getElementsByTagName("routeElements")[0].getElementsByTagName("RouteElement");
      log.debug(fnName, "Number of points [" + routingCoords.length + "]");
      var counter = 0;
      
      if(routingCoords == null || routingCoords.length == 0)
      {
         MapUtils.processError(100);
         
         if(renderLine != null && renderLine == true)
         {
            // reset the POIs
            routePOIs = lastValidRoutePOIs;
            routeElements = lastValidRouteElements;
            
            //polyPaint.clear();
            polyPaint.setPolyPoints(routeElements);
            
            for(var i=0; i<routePOIs.length; i++)
            {
               routePOIs[i].render(vectorLayer);
            }
            self.setDragPoints();
         }
         MapUtils.toggleInfoLayer(false);
         
         return;
      }
      else
      {
         // reset all of the coordinates to be used for drawing
         this.removeAllRouteCoordinates();
         var buffer = "";
         for(var i=0; i<routingCoords.length; i++)
         {
            var longitude = parseFloat(routingCoords[i].getElementsByTagName("longitude")[0].lastChild.data)/conf_smartUnitToGeoFactor;
            var latitude = parseFloat(routingCoords[i].getElementsByTagName("latitude")[0].lastChild.data)/conf_smartUnitToGeoFactor;           
            var temp = {longitude:longitude,latitude:latitude};
            var routeCoord = ptvWrapper.getSmartCoordinate(temp);
            this.addRouteCoordinate(routeCoord);
            
            buffer += routeCoord.x + "," + routeCoord.y;
            if(i < routingCoords.length -1)
               buffer += ",";
         }
         
         log.debug(fnName, "buffer: " + buffer);
         
         /*if(currentRoute != null)
         {
            vectorLayer.removeElement(currentRoute);
            currentRoute = null;
         }*/
         
         line = new com.ptvag.webcomponent.map.vector.Line();
         line.setCoordinates(buffer.split(","));
      }
      
      self.removeAllRouteElements();
      
      
      var preHandlerResult = self.firePreRouteRenderedHandler();
      if(preHandlerResult != 0)
         return;
      customLayerManager.clearLayers();
      
      for(var i=0; i<routingElems.length; i++)
      {
         var coordinate = XMLUtils.getChildNodesByTagName(routingElems[i], "coordinate")[0];
         var type = routingElems[i].getElementsByTagName("type")[0].getElementsByTagName("name")[0].lastChild.data;
         var longitude = parseFloat(coordinate.getElementsByTagName("longitude")[0].lastChild.data)/conf_smartUnitToGeoFactor;
         var latitude = parseFloat(coordinate.getElementsByTagName("latitude")[0].lastChild.data)/conf_smartUnitToGeoFactor;
         var smartCoord = ptvWrapper.getSmartCoordinate({longitude:longitude,latitude:latitude});  
         
         var attachedPOIs = XMLUtils.getChildNodesByTagName(routingElems[i].getElementsByTagName("attached")[0], "POIViewSet");
         parsePOIViewSets(attachedPOIs);
         //if(attachedPOIs != null)
         //   log.debug(fnName, "Parsing POIViewSet [" + attachedPOIs.length + "]");
         
         if(type == "START"  || type == "END" || type == "VIA")
         {
            smartCoord.poiid=routePOIs[counter].$("poiid");
            routePOIs[counter].getPOI().type = type;
            routePOIs[counter].getPOI().index = "" + counter;
            routePOIs[counter].clearVectorElements(vectorLayer, true);
            routePOIs[counter].getPOI().longitude = longitude;
            routePOIs[counter].getPOI().latitude = latitude;
            routePOIs[counter].getPOI().x = smartCoord.x;
            routePOIs[counter].getPOI().y = smartCoord.y;
            if(renderLine)
               routePOIs[counter].render(vectorLayer);
            
            if(conf_enablerouting)
            {
               routePOIs[counter].getPOI().hoverHandler=function(routePOI)
                                                   {
                                                      containerLayer.setEditRoute(routePOI);
                                                      self.removeDragPoints();
                                                      // if the tooltip is shown, do nothing
                                                      if(routePOI.getMarkerToolTip().getId() != null)
                                                         return;
                                                      containerLayer.setEnabled(true);
                                                      log.debug("hoverhandler", "hoverHandler fired");
                                                      routePOI.getPOI().hoverTimerHandler = setTimeout("var tempLayer=map.getLayer(\"" + containerLayer.layerName + "\");" + 
                                                                                                       "tempLayer.setEnabled(false);" +
                                                                                                       "log.debug('viahover', 'ok!!')", 
                                                                                                       2000);
                                                   };
               routePOIs[counter].getPOI().exitHoverHandler=function(routePOI)
                                                   {
                                                      // if the tooltip is up, dont do anything
                                                      if(routePOI.getMarkerToolTip().getId() != null)
                                                         return;
                                                      if(routePOI.getPOI().moving == null || routePOI.getPOI().moving == false)
                                                      {
                                                         containerLayer.clearEditRoute();
                                                         self.setDragPoints();   
                                                      }
                                                      if(routePOI.getPOI().hoverTimerHandler != null)
                                                         clearTimeout(routePOI.getPOI().hoverTimerHandler);
                                                      
                                                   };
               routePOIs[counter].getPOI().clickHandler=function(routePOI)
                                                   {
                                                      if(routePOI.getPOI().hoverTimerHandler != null)
                                                         clearTimeout(routePOI.getPOI().hoverTimerHandler);
                                                   };
               if(routePOIs[counter].getPOI().useRoutingInfo == null)
               {
                  routePOIs[counter].getPOI().useRoutingInfo=true;
                  if(routePOIs[counter].getPOI().routingInfo == null)
                     routePOIs[counter].getPOI().routingInfo= "<a style=\"cursor:pointer\" onmouseover=\"map.getLayer('" + containerLayer.layerName + "').getRouteById('" + routeId + "').removeDragPoints()\" onmouseout=\"map.getLayer('" + containerLayer.layerName + "').getRouteById('" + routeId + "').setDragPoints()\" onclick=\"map.getLayer('" + containerLayer.layerName + "').getRouteById('" + routeId + "').removePOI('" + routePOIs[counter].$("poiid") + "');\">Remove</a>";
               }
               routePOIs[counter].getPOI().disableTTOnHover=true;
            }
            ++counter;
         }
         
         smartCoord.type = type;
         smartCoord.longitude = longitude;
         smartCoord.latitude = latitude;
         
         if(conf_enablerouting)
         {
            self.renderHoverDragPointAt(smartCoord);
         }         
         routeElements[routeElements.length] = smartCoord;
      }
      
      if(renderLine)
         self.renderRoute(true);
      
      //polyPaint.removePoly();
      polyPaint.setPolyPoints(routeElements);

      if(recenter_)
      {
         currentMap.setViewToPoints(routeElements, false, false);
         currentMap.setResetRect(currentMap.getRect());
      }
      
      self.firePostRouteRenderedHandler();      
      setTimeout("MapUtils.toggleInfoLayer(false)", 200);
   };
   
   self.removeDragPoints=function removeDragPoints()
   {
      var fnName = "removeDragPoints() ";
      log.debug(fnName, "removing dragpoints ...");
      for(var i=0; i<routeElements.length; i++)
      {
         vectorLayer.removeElement(routeElements[i].hoverDragId);
      }
   }
   
   self.renderHoverDragPointAt = function renderHoverDragPointAt(smartCoord)
   {
      var hoverArea = new com.ptvag.webcomponent.map.vector.HoverArea(smartCoord.x, smartCoord.y);
      hoverArea.setTolerance(10);
      
      var hoverDragId = vectorLayer.addElement(hoverArea);
      smartCoord.hoverDragId = hoverDragId;
      hoverArea.setHoverHandler(function()
                                { 
                                   currentMap.setCursor(hoverCursor);
                                   containerLayer.setEnabled(true);
                                   
                                   if(routeHoverImage == null)
                                   {
                                      if(routeHoverRadius == -1)
                                         routeHoverRadius = routeWidth;
                                      
                                      var outerCircle =
                                       new com.ptvag.webcomponent.map.vector.Circle(smartCoord.x, smartCoord.y,
                                                             routeHoverBorderColor,
                                                             routeHoverRadius+(routeHoverBorder*2), 0,
                                                             routeId + "_currentOuterCircle");
                                       vectorLayer.addElement(outerCircle);
                                       
                                       var innerCircle =
                                       new com.ptvag.webcomponent.map.vector.Circle(smartCoord.x, smartCoord.y,
                                                             routeHoverColor,
                                                             routeHoverRadius, 0,
                                                             routeId + "_currentInnerCircle");
                                       vectorLayer.addElement(innerCircle);
                                    }
                                    else
                                    {
                                       var hoverImage = new com.ptvag.webcomponent.map.vector.ImageMarker2(smartCoord.x, smartCoord.y, routeHoverImage, 34, 0, routeId + "_hoverImageId");
                                       vectorLayer.addElement(hoverImage);
                                    }
                                });
      hoverArea.setUnhoverHandler(function()
                                  { 
                                    currentMap.setCursor("default");
                                  });
   }
   
   self.setDragPoints = function setDragPoints()
   {
      var fnName = cName + "setDragPoints() ";
      log.debug(fnName, "resetting drag points ..."); 
      for(var i=0; i<routeElements.length; i++)
      {
         self.renderHoverDragPointAt(routeElements[i]);
      }
   }
   
   self.removeAllRouteElements=function removeAllRouteElements()
   {
      self.removeDragPoints();
      routeElements = new Array();
      vectorLayer.removeElement(routeId + "_currentInnerCircle");
      vectorLayer.removeElement(routeId + "_currentOuterCircle");
      vectorLayer.removeElement(routeId + "_hoverImageId");
   };
   
   /**
    * remove the following vectors
    * - hover areas for route elements
    * - line displaying the actual route
    * - all of the route POIS (START,VIA,END)
    */
   self.removeAllRoutePOIsVector=function removeAllRoutePOIsVector()
   {
      self.removeAllRouteElements();
      if(currentRoute != null)
      {
         vectorLayer.removeElement(currentRoute);
         currentRoute = null;
         line = null;
      }
      
      for(var i=0; i<routePOIs.length; i++)
      {
         routePOIs[i].clearVectorElements(vectorLayer, true);
      }
      
   }
   
   
   /**
    * Function to render a route on a map.
    * @param vectorLayer_ - the layer on which to draw this route.
    * @recenter_ - whether to recenter the map on the route or not?
    */
   
   self.drawRoute=function drawRoute(vectorLayer_, recenter_, renderLine, toggleInfoLayer)
   {
      var fnName = cName + "drawRoute()";
      
      if(vectorLayer_ != null)
         vectorLayer = vectorLayer_;
         
      if(vectorLayer == null)
      {
         log.warn(fnName, "Vector layer for drawing not specified aborting...");
         return;
      }
      
      log.debug(fnName, "Number of routePois [" + routePOIs.length + "]");
      if(routePOIs.length < 2)
         return;
      
      var httpRequest = null;
      
      // only initialise this when doing normal ajax call
      if(!rpcCall)
      {
         httpRequest = ConnectionUtils.getXmlHttpObject();
         httpRequest.onreadystatechange = 
         function()
         {
            if(httpRequest != null && httpRequest.readyState == 4)
            {
               if (httpRequest.status == 200)
               {
                  var response = httpRequest.responseText;
                  var responseXML = null;
                  if(window.ActiveXObject)
                  {
                     responseXML = new ActiveXObject("Microsoft.XMLDOM");
                     responseXML.loadXML(httpRequest.responseText);
                  }
                  else
                  {
                     responseXML = httpRequest.responseXML;
                  }
                  if(renderLine == null)
                     renderLine = true;
                  self.displayRouteFromXML(responseXML, recenter_, renderLine);
                  
               }
               else
               {
                  if(log)
                     log.warn("There was a problem with the request. http status [" + httpRequest.status + "]");
               }
               httpRequest=null;
            }
         }
      }
      try
      {
         var buffer = "routeId=" + routeId +
                      "&corridorSearchDistance=" + corridorSearchDistance +
                      "&routeOptimization=" + routeOptimization +
                      "&lazyLoad=" + lazyLoad +
                      "&useToll=" + useToll + "&points=";
                      
         var startingLon = null;
         var startingLat = null;
         
         for(var i=0; i<routePOIs.length; i++)
         {
            buffer += routePOIs[i].$("longitude") + "," + routePOIs[i].$("latitude");
            if(i < routePOIs.length-1)
               buffer += ":"; 
            
            var prefixLon = (""+routePOIs[i].$("longitude")).split(".")[0];
            var prefixLat = (""+routePOIs[i].$("latitude")).split(".")[0];
            var longDistance = false;
            
            if(startingLon == null)
               startingLon = prefixLon;
               
            var deltaLon = parseInt(startingLon) - parseInt(prefixLon);
            if(deltaLon >= 20 || deltaLon <= -20)
               longDistance = true;
               
            if(startingLat == null)
               startingLat = prefixLat;
            var deltaLat = parseInt(startingLat) - parseInt(prefixLat); 
            if(deltaLat >= 20 || deltaLat <= -20)
               longDistance = true;
         }
         if(longDistance)
            buffer += "&routeDetail=STANDARD";
         else
            buffer += "&routeDetail=" + routeDetail;
         
         // set Layers
         buffer += customLayerManager.getLayersAsURLParams();
         if(toggleInfoLayer == null || toggleInfoLayer == true)
            MapUtils.toggleInfoLayer(true);

         if(!rpcCall)
         {
            httpRequest.open('GET', conf_routingServlet + "?" + buffer, true);
            httpRequest.setRequestHeader("charset", "UTF-8");
            httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
            httpRequest.send(null);
         }
         else
            self.rpcCallRoutingServlet(buffer, recenter_, renderLine);
      }
      catch(e)
      {
         log.fatal(fnName, "Exception when sending request " + e);
      }
   }
   
   self.rpcCallRoutingServlet = function rpcCallRoutingServlet(parameters, recenterOnRoute, renderLine)
   {
      if(renderLine == null)
         renderLine = true;
      var scriptId = "ROUTINGRPC_" + routeId;
      var scriptSrc = conf_routingServlet + "?" +  parameters + 
                  "&scriptId=" + scriptId +
                  "&rpcCall=true&containerLayerName=" + containerLayer.layerName +
                  "&renderLine=" + renderLine +
                  "&recenterOnRoute=" + recenterOnRoute;
      ConnectionUtils.invokeServerViaRPC(scriptId, scriptSrc);
   }
   
   /**
    * Function to remove a poi from a route
    * @param poiid - the id of the POI to be removed
    */
   self.removePOI=function removePOI(poiid)
   {
      var fnName = cName + "removePOI() ";
      
      var poiIndex = -1;
      for(var i=0; i<routePOIs.length; i++)
      {
         if(routePOIs[i].$("poiid") == poiid)
         {
            poiIndex = i;
            break;
         }
      }
      log.debug(fnName, "poiIndex [" + poiIndex + "]");
      if(poiIndex >= 0)
      {
         var newArray = new Array();
         
         routePOIs[poiIndex].clearVectorElements(vectorLayer);
         
         if(currentRoute != null)
         {
            vectorLayer.removeElement(currentRoute)
            currentRoute = null;
         }
         
         newArray = routePOIs.slice(0, poiIndex);
         var lastIndex = routePOIs.length;
         
         if(poiIndex == routePOIs.length-1)
            --lastIndex;
         newArray = newArray.concat(routePOIs.slice(poiIndex+1, lastIndex));
         routePOIs = newArray;
         
         this.drawRoute(null, false);
      }
   };
   
   /**
    * method to be invoked by RPC call to populate the route elements
    */
   self.rpc_populateRouteElements=function rpc_populateRouteElements(ptvRouteElements, renderLine)
   {
      var counter = 0;
      for(var i=0; i<ptvRouteElements.length; i++)
      {
         var type = ptvRouteElements[i].type;
         var smartCoord = ptvWrapper.getSmartCoordinate(ptvRouteElements[i]);  
         
         if(type == "START"  || type == "END" || type == "VIA")
         {
            smartCoord.poiid=routePOIs[counter].$("poiid");
            routePOIs[counter].getPOI().type = type;
            routePOIs[counter].getPOI().index = "" + counter;
            routePOIs[counter].clearVectorElements(vectorLayer, true);
            routePOIs[counter].getPOI().longitude = ptvRouteElements[i].longitude;
            routePOIs[counter].getPOI().latitude = ptvRouteElements[i].latitude;
            
            routePOIs[counter].getPOI().x = smartCoord.x;
            routePOIs[counter].getPOI().y = smartCoord.y;
            if(renderLine)
            {
               routePOIs[counter].render(vectorLayer);
            }
            
            if(conf_enablerouting)
            {
               routePOIs[counter].getPOI().hoverHandler=function(routePOI)
                                                   {
                                                      containerLayer.setEditRoute(routePOI);
                                                      self.removeDragPoints();
                                                      // if the tooltip is shown, do nothing
                                                      if(routePOI.getMarkerToolTip().getId() != null)
                                                         return;
                                                      containerLayer.setEnabled(true);
                                                      log.debug("hoverhandler", "hoverHandler fired");
                                                      routePOI.getPOI().hoverTimerHandler = setTimeout("var tempLayer=map.getLayer(\"" + containerLayer.layerName + "\");" + 
                                                                                                       "tempLayer.setEnabled(false);" +
                                                                                                       "log.debug('viahover', 'ok!!')", 
                                                                                                       2000);
                                                   };
               routePOIs[counter].getPOI().exitHoverHandler=function(routePOI)
                                                   {
                                                      // if the tooltip is up, dont do anything
                                                      if(routePOI.getMarkerToolTip().getId() != null)
                                                         return;
                                                      if(routePOI.getPOI().moving == null || routePOI.getPOI().moving == false)
                                                      {
                                                         containerLayer.clearEditRoute();
                                                         self.setDragPoints();   
                                                      }
                                                      if(routePOI.getPOI().hoverTimerHandler != null)
                                                         clearTimeout(routePOI.getPOI().hoverTimerHandler);
                                                      
                                                   };
               routePOIs[counter].getPOI().clickHandler=function(routePOI)
                                                   {
                                                      if(routePOI.getPOI().hoverTimerHandler != null)
                                                         clearTimeout(routePOI.getPOI().hoverTimerHandler);
                                                   };
               if(routePOIs[counter].getPOI().useRoutingInfo == null)
               {
                  routePOIs[counter].getPOI().useRoutingInfo=true;
                  if(routePOIs[counter].getPOI().routingInfo == null)
                     routePOIs[counter].getPOI().routingInfo= "<a style=\"cursor:pointer\" onmouseover=\"map.getLayer('" + containerLayer.layerName + "').getRouteById('" + routeId + "').removeDragPoints()\" onmouseout=\"map.getLayer('" + containerLayer.layerName + "').getRouteById('" + routeId + "').setDragPoints()\" onclick=\"map.getLayer('" + containerLayer.layerName + "').getRouteById('" + routeId + "').removePOI('" + routePOIs[counter].$("poiid") + "');\">Remove</a>";
               }
               routePOIs[counter].getPOI().disableTTOnHover=true;
            }
            ++counter;
         }
         
         smartCoord.type = type;
         smartCoord.longitude = ptvRouteElements[i].longitude;
         smartCoord.latitude = ptvRouteElements[i].latitude;
         
         if(conf_enablerouting)
         {
            self.renderHoverDragPointAt(smartCoord);
         }         
         routeElements[routeElements.length] = smartCoord;
      }
      polyPaint.setPolyPoints(routeElements);
      
   }; 
   
   /**
    * Populate the various server POIs
    */
   self.rpc_populateLayers=function rpc_populateLayers(serverPOIViews)
   {
      customLayerManager.populateLayers(serverPOIViews);
   };
};