// the curve we are drawing, if any
var curve = null;
// the last point that was added to the curve, if any
var previous = null;
// the dot (point or handle) that is being edited currently, if any
var editing = null;

// a dot is either a point or a handle
function dot(x, y, size, type) {
    var dot = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    $(dot).attr("cx", x + "px").attr("cy", y + "px");
    $(dot).attr("r", size/2 + "px");
    dot.setAttribute("class", type);
    $(dot).mousedown(function(event) {
            event.stopPropagation();
            editing = dot;
            dot.setAttribute("class", dot.getAttribute("class") + " editing");
        });
    $(dot).mouseup(function(event) {
            editing = null;
            var p = dot.getAttribute("class").indexOf(" editing");
            if (p >= 0) dot.setAttribute("class", dot.getAttribute("class").substring(0, p));
        });
    return dot;
}

function createPoint(x, y) {
    return dot(x, y, 10, "point");
}

function createHandle(point) {
    var handle = dot(point.cx.baseVal.value, point.cy.baseVal.value, 6, "handle");
    handle.point = point;
    return handle;
}

function startCurve(point) {
    curve = document.createElementNS("http://www.w3.org/2000/svg", "path");
    curve.setAttribute("class", "stroke");
    var x = point.cx.baseVal.value;
    var y = point.cy.baseVal.value;

    curve.points = new Array();
    curve.points[0] = point;
    $(curve).attr("d", serializePoints(curve.points));

    $("#canvas").prepend(curve);
}

function extendCurve(point) {
    var x = point.cx.baseVal.value;
    var y = point.cy.baseVal.value;
    var ax = previous.handle2.cx.baseVal.value;
    var ay = previous.handle2.cy.baseVal.value;
    var bx = point.handle1.cx.baseVal.value;
    var by = point.handle1.cy.baseVal.value;

    // link the point to the curve, and remember its position in the curve
    point.curve = curve;
    point.curveIndex = curve.points.length;
    curve.points.push(point);

    // add the point to the curve
    $(curve).attr("d", serializePoints(curve.points));
}

function serializePoints(points) {
    var s = "M";
    $(points).each(function(i) {
            if (i>0) s += this.handle1.cx.baseVal.value + "," + this.handle1.cy.baseVal.value + " ";
            s += this.cx.baseVal.value + "," + this.cy.baseVal.value + " ";
            if (i<points.length-1) {
                s += "C";
                s += this.handle2.cx.baseVal.value + "," + this.handle2.cy.baseVal.value + " ";
            }
        });
    return s;
}

function closeCurve() {
    $(curve).attr("d", $(curve).attr("d") + " Z");
    curve = null;
    previous = null;
}

function endCurve() {
    $(curve).attr("d", $(curve).attr("d"));
    curve = null;
    previous = null;
}

function startDragging(x, y) {
    addPoint(x, y);
}

function drag(x, y) {
    if (editing) dragDot(editing, x, y);
}

function stopDragging() {
    editing = null;
}

function addPoint(x, y) {
    var point = createPoint(x, y);
    addHandles(point);
    previous = point;
    editing = point.handle2;
    $("#canvas").append(point);
}

function addHandles(point) {
    var x = point.cx.baseVal.value;
    var y = point.cy.baseVal.value;

    point.handle1 = createHandle(point);
    point.handle2 = createHandle(point);

    point.handle1.linkedHandle = point.handle2;
    point.handle2.linkedHandle = point.handle1;

    point.handle1.line = document.createElementNS("http://www.w3.org/2000/svg", "path");
    point.handle2.line = document.createElementNS("http://www.w3.org/2000/svg", "path");

    $(point.handle1.line).attr("d", "M"+x+","+y+" L"+x+","+y);
    $(point.handle2.line).attr("d", "M"+x+","+y+" L"+x+","+y);

    point.handle1.line.setAttribute("class", "handleLine");
    point.handle2.line.setAttribute("class", "handleLine");

    if (!curve) {
        startCurve(point);
    } else {
        extendCurve(point);
    }

    $("#canvas").append(point.handle1.line);
    $("#canvas").append(point.handle2.line);
    $("#canvas").append(point.handle1);
    $("#canvas").append(point.handle2);
}

function moveDot(dot, x, y) {

    // move the dot itself
    $(dot).attr("cx", x + "px");
    $(dot).attr("cy", y + "px");

    // move associated lines
    if (dot.line) {
        $(dot.line).attr("d", "M"+x+","+y+" L"+dot.point.cx.baseVal.value+","+dot.point.cy.baseVal.value);
    }
}

function dragDot(dot, x, y) {

    var cx = dot.cx.baseVal.value;
    var cy = dot.cy.baseVal.value;

    var dx = x - cx;
    var dy = y - cy;

    moveDot(dot, x, y);

    // move associated handles
    if (dot.handle1) {
        var hx = dot.handle1.cx.baseVal.value+dx;
        var hy = dot.handle1.cy.baseVal.value+dy;
        moveDot(dot.handle1, hx, hy);
    }
    if (dot.handle2) {
        var hx = dot.handle2.cx.baseVal.value+dx;
        var hy = dot.handle2.cy.baseVal.value+dy;
        moveDot(dot.handle2, hx, hy);
    }
    if (dot.linkedHandle) {
        var hx = dot.linkedHandle.cx.baseVal.value-dx;
        var hy = dot.linkedHandle.cy.baseVal.value-dy;
        moveDot(dot.linkedHandle, hx, hy);
    }

    // move curve
    $(curve).attr("d", serializePoints(curve.points));
}

$(document).ready(function() {
    $(document).mousedown(function(event) {
            startDragging(event.clientX, event.clientY);
        });
    $(document).mousemove(function(event) {
            drag(event.clientX, event.clientY);
        });
    $(document).mouseup(function(event) {
            stopDragging();
        });
    $(document).keypress(function(event) {
            if (event.keyCode == 27) endCurve();
            if (event.keyCode == 13) closeCurve();
        });
});

