///////////////////////////////
//	Author : colm
///////////////////////////////
/////
// 23 / 8 updated to pull stuff in and out of the database  
/////
/////
// 29 / 8 updated to draw a dotted line between point a and b 
//        which disappears when the arc is finished.      
/////

/**********************************************
Arc TOOL
***********************************************/
ArcTool.prototype = new DrawingTool(); 
ArcTool.prototype.constructor = ArcTool;
ArcTool.superclass = DrawingTool.prototype;

function ArcTool(){
  this.actionState="click0";
	this.radius = 0;
	this.large_flag = 0;
	this.sweep = 0;
	this.ax = 0;
	this.ay = 0;
	this.bx = 0;
	this.by = 0;
	this.cx = 0;
	this.cy = 0;
	this.axis_rot = 0;
}

ArcTool.prototype.initTool = function(){ 
  if (debugLevel >= 20) {
    debug("ARCTOOL : init");
  }	
  useCanvas();
  eventCatcher.addEventListener( "mouseup", this, false );
  window.document.getElementById("drawers").style.visibility = "visible";
}

// an extra state is added here as the mose button is pressed 3 times in total
// to generate an arc.

ArcTool.prototype.mouseup = function(evt){
  evt = (evt) ? evt : ((window.event) ? window.event : "");
  
  if (debugLevel >= 20)
  debug("ARCTOOL : mouseupped:"+this.actionState+":");
  switch (this.actionState){
  case "click0":						// starts off the line.
    this.startLine(evt);
    break;
  case "click1":
    this.endLine(evt);			// finishes the line and starts the arc
    this.startArc(evt);
    break;
  case "click2":
    this.endArc(evt);				// all finished lets go home.
    break;
  default:
    alert("Unknown line state:"+this.actionState+":");
    break;
  }
}

ArcTool.prototype.mousemove = function( evt ){
  evt = (evt) ? evt : ((window.event) ? window.event : "");
  if (this.actionState == "click1"){
    this.bx=getX(evt);
    this.by=getY(evt);
 		this.tempLine.update(this.ax, this.ay, this.bx, this.by, false);   // updating line.
  }
  else if (this.actionState =="click2"){
    this.cx=getX(evt);
    this.cy=getY(evt);
    this.myArc.update(this.cx, this.cy);
  }
}

ArcTool.prototype.startLine = function(evt) {
  if (debugLevel >= 20)
  debug("ARCTOOL : startline");
  evt = (evt) ? evt : ((window.event) ? window.event : "");
  this.ax=getX(evt);
  this.ay=getY(evt);
  this.bx = this.ax;
  this.by = this.ay;
  this.actionState = "click1"
  //in
	this.tempLine = new Line(this.ax, this.ay, this.bx, this.by , "on", true);
	this.tempLine.tempLine();

  eventCatcher.addEventListener("mousemove", this, false);
}

ArcTool.prototype.endLine = function(evt) {
  if (debugLevel >= 20)
  debug("ARCTOOL : endLine");
}

ArcTool.prototype.startArc = function(evt) {
	this.myArc = new Arc(this.ax, this.ay, this.bx, this.by, this.cx, this.cy, this.radius, this.sweep, this.large_flag, this.axis_rot, true);
  this.actionState="click2";
}


ArcTool.prototype.endArc = function(evt) {
	if (debugLevel >= 20)
	  debug("ARCTOOL : endArc");
	this.tempLine.destructor();
	this.tempLine = null; 	
  eventCatcher.removeEventListener("mousemove", this, false);
  this.actionState="click0";
}


ArcTool.prototype.deactivate = function(){
	if (this.actionState == "click1"){
		this.tempLine.destructor();
		delete this.tempLine;
		eventCatcher.removeEventListener("mousemove", this, false);
		this.actionState = "click0";
	}	
  else if (this.actionState == "click2"){
    this.myArc.destructor();
    delete this.myArc;
		this.tempLine.destructor();
		delete this.tempLine;
 		eventCatcher.removeEventListener("mousemove", this, false);
  	this.actionState = "click0";
	}
  eventCatcher.removeEventListener("mouseup", this, false);
  window.document.getElementById("drawers").style.visibility = "hidden";
}



//////////////////////////////////////////////////////////////////
// All functions below are for reconstructing an arc out of adata
// pulled out of a database.
//////////////////////////////////////////////////////////////////


ArcTool.prototype.intersectCircleLine = function(c, r, a1, a2) {
    var result = new Array();
    var a  = (a2.x - a1.x) * (a2.x - a1.x) +
             (a2.y - a1.y) * (a2.y - a1.y);
    var b  = 2 * ( (a2.x - a1.x) * (a1.x - c.x) +
                   (a2.y - a1.y) * (a1.y - c.y)   );
    var cc = c.x*c.x + c.y*c.y + a1.x*a1.x + a1.y*a1.y -
             2 * (c.x * a1.x + c.y * a1.y) - r*r;
    var deter = b*b - 4*a*cc;

    if ( deter < 0 ) {
        debug("Outside");
    } else if ( deter == 0 ) {
        debug("Tangent");
        // NOTE: should calculate this point
    } else {
        var e  = Math.sqrt(deter);
        var u1 = ( -b + e ) / ( 2*a );
        var u2 = ( -b - e ) / ( 2*a );

        if ( (u1 < 0 || u1 > 1) && (u2 < 0 || u2 > 1) ) {
            if ( (u1 < 0 && u2 < 0) || (u1 > 1 && u2 > 1) ) {
                debug("L Outside");
            } else {
                debug("L Inside");
								result.push( a1.lerp(a2, u1) );
								result.push( a1.lerp(a2, u2) );
            }
        } else {
            // debug("L Intersection");

            if ( 0 <= u1 && u1 <= 1)
                result.push( a1.lerp(a2, u1) );

            if ( 0 <= u2 && u2 <= 1)
                result.push( a1.lerp(a2, u2) );
        }
    }
    return result;
};


///////////////////////////////////////////////////////
//this tries to generate a third point on the circles
//circumference. If large_arc == 1 then the third point 
// has to be between the other two points.
// if its 1 then it has to be outside the
// two points.
///////////////////////////////////////////////////////
ArcTool.prototype.calcThirdPt = function( cntr ){
	var minx = (this.ax < this.bx) ? this.ax : this.bx;
	var maxx = (this.ax > this.bx) ? this.ax : this.bx;
	var miny = (this.ay < this.by) ? this.ay : this.by;
	var maxy = (this.ay > this.by) ? this.ay : this.by;
	var tempx = cntr.x + this.radius;
	var tempy = cntr.y + this.radius;
	var i = 0;
	var flag = 0;

	while (flag == 0){	
	
		var rad = i * (3.14 / 180);
		var x = tempx * Math.cos(rad) - tempy * Math.sin(rad); 
		var y = tempy * Math.cos(rad) + tempx * Math.sin(rad); 
		var other = new Point2D(x, y);
		
		var res = this.intersectCircleLine(cntr, this.radius, cntr, other );
		if (this.large_flag == 0){
			if (maxx == minx){
				if(cntr.x < minx){
					if ((res[0].y > miny) && (res[0].y < maxy) && (res[0].x > minx)){
						this.cx = res[0].x;
						this.cy = res[0].y;
						flag = 1;
					}
				}
				if(cntr.x > minx){
					if ((res[0].y > miny) && (res[0].y < maxy) && (res[0].x < minx)){
						this.cx = res[0].x;
						this.cy = res[0].y;
						flag = 1;
					}
				}
			}
			if(maxy == miny){
				if(cntr.y < miny){
					if ((res[0].x > minx) && (res[0].x < maxx) && (res[0].y > miny)){
						this.cx = res[0].x;
						this.cy = res[0].y;
						flag = 1;
					}
				}				
				if(cntr.y > miny){
					if ((res[0].x > minx) && (res[0].x < maxx) && (res[0].y < miny)){
						this.cx = res[0].x;
						this.cy = res[0].y;
						flag = 1;
					}
				}			
			}
			else {	
		 		if ((res[0].x > minx) && (res[0].x < maxx)){
					if ((res[0].y > miny) && (res[0].y < maxy)){
						this.cx = res[0].x;
						this.cy = res[0].y;
						flag = 1;
					}
				}
			}
		}
		else if (this.large_flag == 1){
			if ((res[0].x < minx) || (res[0].x > maxx) || (res[0].y< miny) || (res[0].y > maxy)) {
				this.cx = res[0].x;
				this.cy = res[0].y;
				flag = 1;
			}
		}
		i++;
		if (i > 359){ // ensure the loop isn't endless if something extraordinary occurs.
			debug ("loop broken.");
			break;
		}
	} 
}



ArcTool.prototype.intersectCircleCircle = function(c1, r1, c2, r2) {
   var result = new Array();
    
    // Determine minimum and maximum radii where circles can intersect
    var r_max = r1 + r2;
    var r_min = Math.abs(r1 - r2);
    
   // Determine actual distance between circle circles
    var c_dist = c1.distanceFrom( c2 );
    var a = (r1*r1 - r2*r2 + c_dist*c_dist) / ( 2*c_dist );
    var h = Math.sqrt(r1*r1 - a*a);
    var p = c1.lerp(c2, a/c_dist);
    var b = h / c_dist;
				
    result.push( new Point2D(
    	p.x - b * (c2.y - c1.y),
      p.y + b * (c2.x - c1.x)));
    result.push( new Point2D(
      p.x + b * (c2.y - c1.y),
      p.y - b * (c2.x - c1.x)));
    
	return result;
};

//////////////////////////////////////
// the intersectCircleCircle function generates two
// possible centres for the arc based on the two points
// and the radius. The rest of this function
// tries to figure out which centre is the valid one - based on the 
// sweep flag.
//////////////////////////////////////


ArcTool.prototype.calculateCentre = function(  ){
	var c1 = new Point2D(this.ax, this.ay);
	var c2 = new Point2D(this.bx, this.by);

	var centre = this.intersectCircleCircle(c1,this.radius,c2,this.radius);

	var r = 0;
	if ((this.large_flag == 0)	&& (this.sweep == 0))
		r = 1;
	else if ((this.large_flag == 0) && (this.sweep == 1))
		r = 0;
	else if ((this.large_flag == 1) && (this.sweep == 0))
		r = 0;				
	else if ((this.large_flag == 1) && (this.sweep == 1))
		r = 1;				
		
	var a = 0;
	if ((this.ax < this.bx) && (this.ay <= this.by))
		a = 1;
	else if ((this.ax < this.bx) && (this.ay > this.by))
		a = 2;
	else if ((this.ax >= this.bx) && (this.ay <= this.by))
		a = 3;
	else if ((this.ax >= this.bx) && (this.ay > this.by))
		a = 4;
	
	var c = 0;
	if (centre[0].y <= centre[1].y)
		c = 0;
	else 
		c = 1;	
		
	// debug (" a  r c : " + a + " " + r + " " + c);	
	
	if ((a == 1) || (a == 2)){     
		if (r == 0){
			if (c == 0)
				var cntr = centre[1];
			else
				var cntr = centre[0];  
		}		
		else if (r == 1){	
			if (c == 0)
				var cntr = centre[0];
			else
				var cntr = centre[1];  
		}			
	}	
	else if ((a == 3) || (a == 4)){		
		if (r == 0){
			if (c == 1)
				var cntr = centre[1];
			else
				var cntr = centre[0];
			}		
		else if (r == 1){	
			if (c == 1)
				var cntr = centre[0];			
			else
				var cntr = centre[1];
		}			
	}	
	return cntr;
}

// parses the path string retrieved from the database
// into its constituent parts for reconstruction into 
// handles.
ArcTool.prototype.parsePath = function( path ){
 	var str_arr = new Array();
 	var l_index = 0;
	for (var i =0; i < path.length; i++){
		if(path.charAt(i) == " "){
			str_arr.push(path.substring(l_index,  i));
			l_index = i;	
		} 	 	
	}
	str_arr.push(path.substring(l_index, path.length));
	var ind = str_arr[1].indexOf("A");
	this.ay = Number(str_arr[1].substring(0, ind));
	this.radius = Number(str_arr[2]);
	this.ax = Number(str_arr[0].substring(1, str_arr[0].length -1));	
	this.bx = Number(str_arr[str_arr.length - 2]);
	this.by = Number(str_arr[str_arr.length - 1]);
	this.sweep = Number(str_arr[str_arr.length - 3]);
	this.large_flag = Number(str_arr[str_arr.length - 4].charAt(1));  
}


ArcTool.prototype.copyconstructor = function( svgNode ){
	var path = svgNode.getAttribute("d");
	// debug ("path : " + path);
	this.parsePath(path);
	var cntre = this.calculateCentre();
	this.calcThirdPt(cntre);
  this.myArc = new Arc(this.ax, this.ay, this.bx, this.by, this.cx, this.cy, this.radius, this.sweep, this.large_flag, this.axis_rot, false);
	this.myArc.copyconstructor( svgNode );
  return this.myArc;
}

var arcTool = new ArcTool();
