// Polyline with arrows
//
// Bill Chadwick May 2008
//
// Free for any use
//
// Modified for HH400 Maps; does not draw the polyline
// draws two "chevrons" with a off-white semi-transparent background
//
// Constructor params exactly as GPolyline then 
// 1) arrow spacing in pixels, 
// 2) arrow head length in pixels
// 3) arrow colour
// 4) arrow thickness in pixels
// 5) arrow opacity

function BDCCArrowedPolyline(points, color, weight, opacity, opts, gapPx, headLength, headColor, headWeight, headOpacity, idx) {	
    
    this.gapPx = gapPx;
    this.points = points;
    this.color = color;
    this.weight = weight;
    this.opacity = opacity;
    this.headLength = headLength;
    this.headColor = headColor;
    this.headWeight = headWeight;
    this.headOpacity = headOpacity;
    this.opts = opts;
    this.heads = new Array();
    this.line = null;
    this.idx = idx;

}
BDCCArrowedPolyline.prototype = new GOverlay();


BDCCArrowedPolyline.prototype.initialize = function(map) {

    this.map = map;   
    this.prj = map.getCurrentMapType().getProjection();
    var rdrw = GEvent.callback(this,this.recalc );
  	this.lstnMoveEnd = GEvent.addListener(map,"zoomend",function(){rdrw ();});
  	this.lstnType = GEvent.addListener(map,"maptypechanged",function(){rdrw ();});

  	this.recalc();//first draw
}

BDCCArrowedPolyline.prototype.remove = function() {

    try{
        if (this.line)
            this.map.removeOverlay(this.line);
        for(var i=0; i<this.heads.length; i++)
            this.map.removeOverlay(this.heads[i]); 
    }
    catch(ex)
    {
    }
}

BDCCArrowedPolyline.prototype.redraw = function(force) {
    return;//do nothing, the GPolyline line and heads draw themselves
}


BDCCArrowedPolyline.prototype.copy = function(map) {
    return new BDCCArrowedPolyline(this.points,this.color,this.weight,this.opacity,this.opts,this.gapPx, this.headLength, this.headColor, this.headWeight, this.headOpacity);
}


BDCCArrowedPolyline.prototype.recalc = function() {
		
	if (arrow_vis[this.idx] && arrow_vis[this.idx] == 'hidden') { return false; }

   var zoom = this.map.getZoom();

   this.remove();

   //the main polyline
   //this.line = new GPolyline(this.points,this.color,this.weight,this.opacity,this.opts);
   //this.map.addOverlay(this.line);

   // the arrow heads
   this.heads = new Array();

   var p1 = this.prj.fromLatLngToPixel(this.points[0],  zoom);//first point
   var p2;//next point
   var dx;
   var dy;
   var sl;//segment length
   var theta;//segment angle
   var ta;//distance along segment for placing arrows
      
   for (var i=1; i<this.points.length; i++){
  
   	showLoadingStatus('Voyage Arrows');
     
      p2 = this.prj.fromLatLngToPixel(this.points[i],  zoom)
      dx = p2.x-p1.x;
      dy = p2.y-p1.y;
      sl = Math.sqrt((dx*dx)+(dy*dy)); 
      theta = Math.atan2(-dy,dx);
      
      j=1;
      
	if(this.gapPx == 0){
		//just put one arrow at the end of the line
        	this.addHead(p2.x,p2.y,theta,zoom);
	}
	else if(this.gapPx == 1) {
		//just put one arrow in the middle of the line
        	var x = p1.x + ((sl/2) * Math.cos(theta)); 
        	var y = p1.y - ((sl/2) * Math.sin(theta));
        	this.addHead(x,y,theta,zoom);        
	}
	else{
      	//iterate along the line segment placing arrow markers
      	//don't put an arrow within gapPx of the beginning or end of the segment 

	      ta = this.gapPx;
      	while(ta < sl){
        	var x = p1.x + (ta * Math.cos(theta)); 
        	var y = p1.y - (ta * Math.sin(theta));
        	//this.addHead(x,y,theta,zoom);
        	ta += this.gapPx;  
      	}  
      
        	//line too short, put one arrow in its middle
      	if(ta > this.gapPx){
        		var x = p1.x + ((sl/2) * Math.cos(theta)); 
        		var y = p1.y - ((sl/2) * Math.sin(theta));
        		var x1 = p1.x + (((sl+16)/2) * Math.cos(theta)); 
        		var y1 = p1.y - (((sl+16)/2) * Math.sin(theta));
        		var x2 = p1.x + (((sl+32)/2) * Math.cos(theta)); 
        		var y2 = p1.y - (((sl+32)/2) * Math.sin(theta));
        		this.addHead(x,y,theta,zoom,2);
        		this.addHead(x1,y1,theta,zoom,2);
        		//this.addHead(x2,y2,theta,zoom,1);
      	}
	}
      
      p1 = p2;  
      
   }
   setTimeout(function() {hideLoadingStatus()},2500);
}

BDCCArrowedPolyline.prototype.addHead = function(x,y,theta,zoom,offset) {

    //add an arrow head at the specified point
    var t = theta + (Math.PI/4) ;
    if(t > Math.PI)
        t -= 2*Math.PI;
    var t2 = theta - (Math.PI/4) ;
    if(t2 <= (-Math.PI))
        t2 += 2*Math.PI;
    var pts = new Array();
    var x1 = x-Math.cos(t)*(this.headLength-offset);
    var y1 = y+Math.sin(t)*(this.headLength-offset);
    var x2 = x-Math.cos(t2)*(this.headLength-offset);
    var y2 = y+Math.sin(t2)*(this.headLength-offset);
    pts.push(this.prj.fromPixelToLatLng(new GPoint(x1,y1), zoom));
    pts.push(this.prj.fromPixelToLatLng(new GPoint(x,y), zoom));    
    pts.push(this.prj.fromPixelToLatLng(new GPoint(x2,y2), zoom));
   
   /*
   In order to improve performance, the polylines utilize an polyline encoding class;
   This adds to the download overhead (by including script), but greatly
   improves performance, especially in Internet Explorer
   */
   
    //Add thick white lines for arrows
    //this.heads.push(new GPolyline(pts,'#FFFFED',(this.headWeight * 2),0.4,this.opts));
    this.heads.push(new GPolyline.fromEncoded(polylineEncoder.dpEncodeToJSON(pts,'#FFFFED',(this.headWeight * 2),0.4)));
    this.map.addOverlay(this.heads[this.heads.length-1]);
    
    //this.heads.push(new GPolyline(pts,this.headColor,this.headWeight,this.headOpacity,this.opts));
    this.heads.push(new GPolyline.fromEncoded(polylineEncoder.dpEncodeToJSON(pts,this.headColor,this.headWeight,this.headOpacity)));
    this.map.addOverlay(this.heads[this.heads.length-1]);
    
}

