/**
 * A layer for interactively painting a route polygon on the map.
 * This is a custom layer created by PTV and modified to fit in the current
 * framework to allow multiple routes to be modified
 * 
 * $Id: PolyPaintLayer.js,v 1.7 2009/02/23 05:55:12 vpulla Exp $
 */
 
qxp.OO.defineClass("com.ptvag.polypaint.PolyPaintLayer",
com.ptvag.webcomponent.map.layer.Layer,
function() 
{
   com.ptvag.webcomponent.map.layer.Layer.call(this);
    
   var self = this;
   var vector = com.ptvag.webcomponent.map.vector;
   var clazz = this.constructor;
    
   var mPolyPoints = [];
   var mStationPoints = [];
    
   var mMode = clazz.MODE_OFF;
    
   var mPointInMotion = -1;
   var mOutlinePoints = new Array();
    
   var mHandlerMethod = null;
    
   var movingVIAMarkerImg=null;
    
   self.setMovingVIAMarkerImg = function setMovingVIAMarkerImg(movingVIAMarkerImg_)
   {
      movingVIAMarkerImg = movingVIAMarkerImg_;
   };
    
   self.getMovingVIAMarkerImg = function getMovingVIAMarkerImg()
   {
     return movingVIAMarkerImg;
   };
    
   self.setPolyPoints = function(polyPoints) 
   {
      removePoly();
    	mPolyPoints = polyPoints;
      //startPaintMode();
      mMode = clazz.MODE_PAINT;
      renderPoly();    
      mMode = clazz.MODE_MODIFY;
   };
    
   self.setStationCoordinates = function(stationCoordinates) 
   { // array of coordinate-objects
    
      var newMStationPoints = []; 
    	
    	var stationCoordinatesCount = stationCoordinates.length;
      for (var i = 0; i < stationCoordinatesCount; ++i) 
      {
         geoCoords = stationCoordinates[i];
	      var smartCoords = com.ptvag.webcomponent.map.CoordUtil.geoDecimal2SmartUnit(geoCoords); 
         newMStationPoints.push(smartCoords);
      }
      mStationPoints = newMStationPoints;
   };
    
   self.setChangePointHandler = function (handlerMethod) 
   {
      mHandlerMethod = handlerMethod;
   }
   
   /**
    * Removes the polygon from the map.
    */
   var removePoly = function removePoly() 
   {
      var theMap = map;
      var vectorLayer = theMap.getLayer("vector");
        
      var polyPointCount = mPolyPoints.length;
      for (var i = 0; i < polyPointCount; ++i) 
      {
         vectorLayer.hideElement("paintedPoly-inner-circle-" + i);
         vectorLayer.hideElement("paintedPoly-outer-circle-" + i);
      }
        
        
      // vectorLayer.hideElement("paintedPoly");
      vectorLayer.hideElement("paintedPolyOutline");
   };
    
    
   var findAdjoiningStations = function() 
   {
	   var outlinePoints = new Array();
      dragPolyPoint = mPolyPoints[mPointInMotion];
        
      if (dragPolyPoint.type!="START") 
      {
         var preI=1;
	      currentPoint = mPolyPoints[mPointInMotion-preI];
	      previousStationfound = false;

	      while (!previousStationfound) 
         {
            if (currentPoint.type!="INFO") 
            {
	        	  previousStationfound = true;
	        	  outlinePoints.push(currentPoint);
	        	}
	        	preI++;
	        	currentPoint = mPolyPoints[mPointInMotion-preI];
	        	
         }
      }
        
      // insert drag point:
     outlinePoints.push(dragPolyPoint);
        
     if (dragPolyPoint.type!="END") 
     {
	     var nextJ=1;
	     currentPoint = mPolyPoints[mPointInMotion+nextJ];
	     nextStationfound = false;
	                
         while (!nextStationfound) 
         {
            if (currentPoint.type!="INFO") 
            {
               nextStationfound = true;
               outlinePoints.push(currentPoint);
	        	}
            nextJ++;
            currentPoint = mPolyPoints[mPointInMotion+nextJ];
         }
      }       
      return outlinePoints;   	
   }
    
   /**
    * Renders the polygon on the map.
    */
   var renderPoly = function renderPoly() 
   {
      if(mPolyPoints == null)
         return;
      // first, check if there are any points
      var polyPointCount = mPolyPoints.length;
      if (polyPointCount == 0) 
         return;

      // retrieve the map and the vector layer
      var theMap = map;
      var vectorLayer = theMap.getLayer("vector");

      // draw the polygon itself
      /*var polygon =
            new map.vector.Poly("rgba(0, 255, 0, 0.8)", mPolyPoints, null,
                                "paintedPoly");
      vectorLayer.addElement(polygon);*/
        
        
      /*if (mMode == clazz.MODE_MODIFY) 
      {
         // draw a black outline
        
         if (mPointInMotion != -1 && mOutlinePoints.length!=0) 
         {
            // mOutlinePoints = findAdjoiningStations();
		      var outline =
		            new vector.Line("rgba(0, 0, 255, 0.4)", 1, mOutlinePoints, null,
		                                "paintedPolyOutline");
            vectorLayer.addElement(outline);  
		                		
        	}      	
        	
      }*/
        
   
      // draw circles at the corners of the polygon
      if (mMode == clazz.MODE_PAINT || mMode == clazz.MODE_MODIFY) 
      {
         var circleRadius = self.getCircleRadius();
         var outerCircle;
         var innerCircle;
         var circleInnerCol;
         var circleOuterCol;
         var drawingPriority;
         var polyPoint;
            
         for (var j = 0; j < polyPointCount; j++) 
         {
            polyPoint = mPolyPoints[j];
            
            if (mMode == clazz.MODE_PAINT) 
            {
               if (polyPoint.type!="INFO") 
               {
               	circleInnerCol = "rgba(0, 255, 255, 0)";
               	circleOuterCol = "rgba(0, 0, 0, 0)";  
               	drawingPriority = 100;             		
               }
               else 
               {
               	circleInnerCol = "rgba(0, 127, 255, 1)";
               	circleOuterCol = "rgba(0, 0, 0, 1)";
               	drawingPriority = null;
               }
            
               /*outerCircle =
                  new vector.Circle(polyPoint.x, polyPoint.y,
                                        circleOuterCol,
                                        circleRadius*2, drawingPriority,
                                        "paintedPoly-outer-circle-" + j);
               vectorLayer.addElement(outerCircle);
              
               innerCircle =
                  new vector.Circle(polyPoint.x, polyPoint.y,
                                        circleInnerCol,
                                        (circleRadius - 1)*2, drawingPriority,
                                        "paintedPoly-inner-circle-" + j);
               vectorLayer.addElement(innerCircle);*/
            } 
            else if (mMode == clazz.MODE_MODIFY) 
            {
               if (polyPoint.type!="INFO") 
               {
                  circleActiveCol = "rgba(0, 255, 255, 0.8)";
	               circleInactiveCol = "rgba(0, 255, 255, 0.8)";               		
             	}
             	else 
               {
             	   circleActiveCol = "rgba(0, 127, 255, 0.8)";
             	   circleInactiveCol = "rgba(0, 127, 255, 0.8)";
               }
                	
               if(mPointInMotion == j)
               {
                  /*innerCircle =
                  new vector.Circle(polyPoint.x, polyPoint.y,
                                        (mPointInMotion == j ?
                                         circleActiveCol :
                                         circleInactiveCol),
                                        5*2, null,
                                        "paintedPoly-inner-circle-" + j);*/
                                      
                  var imageMarker = new vector.ImageMarker2();
                  imageMarker.setX(polyPoint.x);
                  imageMarker.setY(polyPoint.y);
                  
                  if(movingVIAMarkerImg == null)
                     imageMarker.setUrl(conf_defaultVIAImage);
                  else
                     imageMarker.setUrl(movingVIAMarkerImg);
                  //imageMarker.setUrl(conf_defaultVIAImage);
                  imageMarker.setId("paintedPoly-inner-circle-" + j);
                  vectorLayer.addElement(imageMarker);
                  
               }
            }
         }
      }
   };
    
    
   /**
    * Determines whether the given coordinates are near a polygon point.
    * 
    * @param   coords {Map}        the coordinates.
    * 
    * @return  {int}               -1 if no polygon point is near the given
    *                              coordinates. Otherwise, the index of the
    *                              nearest point.
    */
   var polyPointAtCoords = function(coords) 
   {
      var theMap = map;
      var zoom = theMap.getVisibleZoom();
        
      var absoluteCoords = com.ptvag.webcomponent.map.CoordUtil.smartUnit2Pixel(coords, zoom);
      var circleRadius = self.getCircleRadius();
      var circleRadiusSquared = circleRadius*circleRadius;
      var minDistSquared = 0;
      var retVal = -1;
      var polyPointCount = mPolyPoints.length;
      for (var i = 0; i < polyPointCount; ++i) 
      {
         var absolutePointCoords = 
               com.ptvag.webcomponent.map.CoordUtil.smartUnit2Pixel(mPolyPoints[i], zoom);
         var distX = absoluteCoords.x - absolutePointCoords.x;
         var distY = absoluteCoords.y - absolutePointCoords.y;
         var distSquared = distX*distX + distY*distY;
         if (distSquared <= circleRadiusSquared) 
         {
            if (retVal == -1 || distSquared < minDistSquared) 
            {
               retVal = i;
               minDistSquared = distSquared;
            }
         }
      }
      return retVal;
   };
    
    
   // overridden
   // (returning false means that lower layers will receive the event)
   self.onMouseDown = function(evt, routeElemIndex) 
   {
      if (mMode == clazz.MODE_OFF) 
         return false;

      var theMap = map;
      var coords = theMap.translateMouseCoords(evt);
      if (coords == null)
         return false;   // event is beyond the map boundary, don't handle it

      if (mMode == clazz.MODE_PAINT) 
      {
         removePoly();
         if (polyPointAtCoords(coords) == 0) 
         {
            mMode = clazz.MODE_MODIFY;
         } 
         else 
         {
            mPolyPoints.push(coords);
         }
         renderPoly();
      }
      else if (mMode == clazz.MODE_MODIFY) 
      {
         var pointAtCoords = routeElemIndex;
         if(pointAtCoords == null)
            pointAtCoords = polyPointAtCoords(coords);
         if (pointAtCoords == -1) 
         {
            return false;
         }
         else 
         {
            mPointInMotion = pointAtCoords;
            mOutlinePoints = findAdjoiningStations();
            removePoly();
            renderPoly();
         }
      }

      return true;
   };
    
    
   // overridden
   self.onMouseMove = function(evt) 
   {
      if (mPointInMotion == -1) 
      {
         return false;
      }

      var theMap = map;
      var coords = theMap.translateMouseCoords(evt);
      if (coords == null) 
      {
         mPointInMotion = -1;
         return true;
      }
        
      removePoly();
      mPolyPoints[mPointInMotion].x = coords.x;
      mPolyPoints[mPointInMotion].y = coords.y;        
      renderPoly();
      return true;
   };
    
    
   // overridden
   self.onMouseUp = function(evt) 
   {
      if (mPointInMotion == -1) 
      {
         return false;
      }
      //evt.pointInMotion = mPolyPoints[mPointInMotion];
      evt.pointInMotion = mPointInMotion;
        
      if (mHandlerMethod != null) 
      {
         mHandlerMethod(evt);
      }
        
      mPointInMotion = -1;
        
      return true;
   };
    
    
   /**
    * Activates the poly paint mode.
    */
   /*
   self.startPaintMode = function() 
   {
      mMode = clazz.MODE_PAINT;
   };
   */
    
   /**
    * Clears the polygon and the array of poly points.
    */
   self.clearPoly = function() 
   {
      removePoly();
      mPolyPoints = [];
   };
    
    
   /**
    * Returns the array of poly points.
    */
   self.getPolyPoints = function() 
   {
      return mPolyPoints;
   };
    
});

qxp.Class.MODE_OFF = 0;
qxp.Class.MODE_PAINT = 1;
qxp.Class.MODE_MODIFY = 2;

qxp.OO.addProperty({ name:"circleRadius", type:qxp.constant.Type.NUMBER,
                    allowNull:false, defaultValue:10 });
