// MEASUREMENTS 

// Use to position clicks relative to canvas
function findoffset(box) {
  var canvas = $(box);
  var offset = canvas.offset();
  var scrolloffset = window.pageYOffset;
  offsetx = offset.left;
  offsety = offset.top - scrolloffset;
}

// Create arrow 
  Raphael.fn.arrow = function(startx,starty,endx,endy,len,angle,color) {
    color = typeof(color) != 'undefined' ? color : "#888";
    
    var theta = Math.atan2((endy-starty),(endx-startx));
    var baseAngleA = theta + angle * Math.PI/180;
    var baseAngleB = theta - angle * Math.PI/180;
    var tipX = endx + len * Math.cos(theta);
    var tipY = endy + len * Math.sin(theta);
    var baseAX = endx - len * Math.cos(baseAngleA);
    var baseAY = endy - len * Math.sin(baseAngleA);
    var baseBX = endx - len * Math.cos(baseAngleB);
    var baseBY = endy - len * Math.sin(baseAngleB);
    var pathData = " M " + tipX      + " " + tipY +
                   " L " + baseAX  + " " + baseAY +
                   " L " + baseBX  + " " + baseBY +
                   " Z ";
    return {
      path: this.path({fill: color, stroke: "none"},pathData),
      type: 'arrow'
    };
  };

// Create connection
Raphael.fn.connection = function (obj1, obj2, line, bg) {
    if (obj1.line && obj1.from && obj1.to) {
        line = obj1;
        obj1 = line.from;
        obj2 = line.to;
    }
    var bb1 = obj1.getBBox();
    var bb2 = obj2.getBBox();
    var p = [{x: bb1.x + bb1.width / 2, y: bb1.y - 1},
        {x: bb1.x + bb1.width / 2, y: bb1.y + bb1.height + 1},
        {x: bb1.x - 1, y: bb1.y + bb1.height / 2},
        {x: bb1.x + bb1.width + 1, y: bb1.y + bb1.height / 2},
        {x: bb2.x + bb2.width / 2, y: bb2.y - 1},
        {x: bb2.x + bb2.width / 2, y: bb2.y + bb2.height + 1},
        {x: bb2.x - 1, y: bb2.y + bb2.height / 2},
        {x: bb2.x + bb2.width + 1, y: bb2.y + bb2.height / 2}];
    var d = {}, dis = [];
    for (var i = 0; i < 4; i++) {
        for (var j = 4; j < 8; j++) {
            var dx = Math.abs(p[i].x - p[j].x),
                dy = Math.abs(p[i].y - p[j].y);
            if ((i == j - 4) || (((i != 3 && j != 6) || p[i].x < p[j].x) && ((i != 2 && j != 7) || p[i].x > p[j].x) && ((i != 0 && j != 5) || p[i].y > p[j].y) && ((i != 1 && j != 4) || p[i].y < p[j].y))) {
                dis.push(dx + dy);
                d[dis[dis.length - 1]] = [i, j];
            }
        }
    }
    if (dis.length == 0) {
        var res = [0, 4];
    } else {
        var res = d[Math.min.apply(Math, dis)];
    }
    if (res == undefined) {
        var res = [0, 4]; // Hack to prevent flying off bug
    }
    var x1 = p[res[0]].x,
        y1 = p[res[0]].y,
        x4 = p[res[1]].x,
        y4 = p[res[1]].y,
        dx = Math.max(Math.abs(x1 - x4) /2 , 10),
        dy = Math.max(Math.abs(y1 - y4) /2 , 10),
        x2 = [x1, x1, x1 - dx, x1 + dx][res[0]].toFixed(3),
        y2 = [y1 - dy, y1 + dy, y1, y1][res[0]].toFixed(3),
        x3 = [0, 0, 0, 0, x4, x4, x4 - dx, x4 + dx][res[1]].toFixed(3),
        y3 = [0, 0, 0, 0, y1 + dy, y1 - dy, y4, y4][res[1]].toFixed(3);
    var path = ["M", x1.toFixed(3), y1.toFixed(3), "C", x2, y2, x3, y3, x4.toFixed(3), y4.toFixed(3)].join(",");
    if (line && line.line) {
        line.bg && line.bg.attr({path: path});
        line.line.attr({path: path});
    } else {
        var color = typeof line == "string" ? line : "#000";
        return {
            bg: bg && bg.split && this.path(path).attr({stroke: bg.split("|")[0], fill: "none", "stroke-width": bg.split("|")[1] || 3}),
            line: this.path(path).attr({stroke: color, fill: "none", "stroke-width": 3 , "stroke-dasharray": "."}),
            from: obj1,
            to: obj2
        };
    }
};






window.onload = function () {

  // SHAPE SELECTION

  // Select a shape
	isSelected = 'false';  // dumb javascript thinks 0 == false
  var selectShape = function (selected) {
    isSelected = selected;
    shapes[selected].animate({"fill-opacity":0.8},500);
    kc.focus();
  };
  var deselectShape = function (selected) {
    isSelected = 'false';
    shapes[selected].animate({"fill-opacity":0.2},140);
  };

  var isSelectedMem = false;
  var clicker = function () {
    // Click on a shape
	  if (isSelected !== 'false' && isSelected !== this.id) {
		  // Create new connection if another shape selected
		  newConn(isSelected,this.id,'#a33');
      isSelectedMem = isSelected;
      deselectShape(this.id);
      selectShape(isSelectedMem);
		  this.toFront();
	  } else if (isSelected === this.id) {
		  // Deselect shape if second click on current shape
		  deselectShape(this.id);
	  } else if (wasDragged == true) {
		  deselectShape(this.id);
    } else {
		  // Select shape if first click on current shape and no shapes selected
		  selectShape(this.id);
		  this.toFront();
	  }
  };
 
  var isDrag = false;
  var clicked = false;

  var dragger = function (e) {
    // Drag shape along
    this.dx = e.clientX;
    this.dy = e.clientY;
    isDrag = this;
    this.animate({"fill-opacity": 1}, 500);
    e.preventDefault && e.preventDefault();
  };


  // OBJECT MODIFICATIONS

  shapeSize = []; 

  var enlargeShape = function () {
    // Enlarge Shape
    newSize = thisSize * 1.2;
    shapes[isSelected].scale(newSize,newSize);
    for (var i = connections.length; i--;) {
      r.connection(connections[i]);
    }
    shapeSize[isSelected] = newSize;
  };

  var shrinkShape = function () {
    // Shrink Shape
    newSize = thisSize * 0.8;
    shapes[isSelected].scale(newSize,newSize);
    for (var i = connections.length; i--;) {
      r.connection(connections[i]);
    }
    shapeSize[isSelected] = newSize;
  };

  var deleteShape = function () {
    shapes[isSelected].remove();
    for (i = 0, ii = connMatrix.length; i < ii; i++) {
      if (connMatrix[isSelected][i] !== undefined) {
        thisConn = connMatrix[isSelected][i];
		    connections[thisConn].line.remove();
        connMatrix[isSelected][i] = connMatrix[i][isSelected] = undefined;
      }
    }
    isSelected = 'false';
  };

  // *** Color-changing stuff goes here



  // OBJECT GENERATORS

  var r = Raphael("holder", 960, 640);

  var connections = [];
  var connMatrix = [];
  var newConn = function (first, second, color) {
	  if (connMatrix[first][second] == undefined) {
      // Create new connection
      connID = shapes.length;
      shapes[connID] = connections.push(r.connection(shapes[first], shapes[second], color ));
		  connMatrix[first][second] = connections.length - 1;
		  connMatrix[second][first] = connections.length - 1;
		  connMatrix[connID]=[];
	  } else {
      // Remove existing connection
		  thisConn = connMatrix[first][second];
		  connections[thisConn].line.remove();
		  connMatrix[first][second] = null;
		  connMatrix[second][first] = null;
	  }
  };
    
  var shapes = [];
  var newShape = function (i) {
    // Create a new shape
    var color = Raphael.getColor();
    shapes[i].attr({fill: color, stroke: color, "fill-opacity": 0.2, "stroke-width": 2});
    shapes[i].node.style.cursor = "move";
    shapes[i].mousedown(dragger);
    shapes[i].click(clicker);
    connMatrix[i]=[];
    shapeSize[i] = 1;
  };

  /* Create initial setup */
    shapes = [  r.ellipse(650, 500, 70, 70),
                r.ellipse(240, 355, 40, 25),
                r.rect(455, 100, 45, 45,3)
             ];
  for (var i = 0, ii = shapes.length; i < ii; i++) {
  	newShape(i);
  }

  newConn(1,2,'#6c6');
  newConn(0,1,'#6c6'); 

 
  // GLOBAL EVENTS 

  var wasDragged = false;
  var xpos = ypos = offsetx = offsety = 0;
  r.canvas.onmousedown = function (e) {
    e = e || window.event;
    wasDragged = false;
    if (!(isDrag)) {
		  if (isSelected === 'false') {
        // Create a new shape if background clicked and no shapes selected
        findoffset("#holder");
        //xpos = Math.round((e.clientX - offsetx)/75)*75;
        //ypos = Math.round((e.clientY - offsety)/75)*75;
        xpos = e.clientX - offsetx;
        ypos = e.clientY - offsety;
			  shapes.push(r.ellipse(xpos, ypos, 40, 35));
			  newShape(shapes.length-1);
		  } else {
        // Deselects shape if background clicked
		  	deselectShape(isSelected);
		  }
	  }
  };

  r.canvas.onmousemove = function (e) {
    wasDragged = true;
    e = e || window.event;
    if (isDrag) {
      isDrag.translate(e.clientX - isDrag.dx, e.clientY - isDrag.dy);
      for (i = 0, ii = connMatrix[isDrag.id].length; i < ii; i++) {
        if (connMatrix[isDrag.id][i] !== undefined) {
          thisConn = connMatrix[isDrag.id][i];
          r.connection(connections[thisConn]);
        }
      }
      /* for (var i = connections.length; i--;) {
        r.connection(connections[i]);
      } */
      r.safari();
      isDrag.dx = e.clientX;
      isDrag.dy = e.clientY;
    }
  };
    
  r.canvas.onmouseup = function () {
    // isDrag && isDrag.animate({"fill-opacity": 0}, 500);
    isDrag = false;
    kc.focus(); // Keeps keypress detection from failing
  };


  var kc = document.getElementById('keycatcher');

  kc.onkeyup = function (e) {
    // Keypress Events
    var key = this.value.substring(this.value.length -1 );
    this.value = "";
    if (isSelected !== 'false') {
      thisSize = shapeSize[isSelected];
      if (key == "k") {
        enlargeShape();
      } else if (key == "j") {
        shrinkShape();
      } else if (key == "d") {
        deleteShape();
      }
    }
    return false;
  };

};
