$(function() {
    
    var startPath = $(".fragment-path").val();
    
    var PATHCOLOR = "#ff00ff",
        SELECTEDCOLOR = "#ffff00",
        HANDLESIZE = 6;
    
    var jqs = $(".cutout-canvas"),
        offset = jqs.offset(),
        paper = new Raphael(jqs[0]),
        closed = false,
        rectangleMode = false,
        closeTimeout,
        points = [];
    
    paper.rect(0, 0, paper.width, paper.height)
        .attr({
            stroke: "none",
            fill: "#fff",
            "fill-opacity": .01
        })
        .click(clickAddPoint)
        .drag(
            function(dx, dy, mx, my) {
                
                if (dx*dx+dy*dy < 4) {
                    return;
                }
                
                if (!pathDragging) {
                    clearTimeout(closeTimeout);
                    closed = true;
                    resetPoints();
                    for (var i = 0; i < 4; i++) {
                        addPoint(mx - offset.left, my - offset.top)
                    }
                    redrawPath();
                    pathDragging = true;
                    rectangleMode = true;
                }
                
                var x = mx - offset.left,
                    y = my - offset.top;
                points[1].x = points[2].x = x;
                points[2].y = points[3].y = y;
                redrawPath();
            },
            function(mx, my) {
                pathDragging = false;
            },
            function() {
                setTimeout(function() {
                    pointDragging = false;
                },0);
            }
        );
        
    function resetPoints() {
    	rectangleMode = false;
        points.forEach(function(p) {
           p.handle.remove(); 
        });
        points = [];
    }
    
    function addPoint(x, y) {
        
        var dragdeltax, dragdeltay, pointDragging,
            point = {
                x: Math.floor(x),
                y: Math.floor(y)
            }
        
        var pointsWithSameX = [], pointsWithSameY = [];
        
        var pointrect = paper.rect(0, 0, HANDLESIZE, HANDLESIZE)
            .attr({
                stroke: PATHCOLOR,
                fill: PATHCOLOR,
                "fill-opacity": .3
            })
            .hover(shapeMouseOver, shapeMouseOut)
            .drag(
                function(dx, dy) {
                    pointDragging = true;
                    point.x = dx + dragdeltax;
                    point.y = dy + dragdeltay;
                    if (rectangleMode) {
                    	pointsWithSameX.forEach(function(p) {
                    		p.x = point.x;
                    	});
                    	pointsWithSameY.forEach(function(p) {
                    		p.y = point.y;
                    	});
                    }
                    redrawPath();
                },
                function() {
                    dragdeltax = point.x;
                    dragdeltay = point.y;
                    if (rectangleMode) {
                    	pointsWithSameX = points.filter(function(p) {
                    		return p !== point && p.x === point.x;
                    	});
                    	pointsWithSameY = points.filter(function(p) {
                    		return p !== point && p.y === point.y;
                    	});
                    }
                },
                function() {
                    setTimeout(function() {
                        pointDragging = false;
                        shapeMouseOut(pointrect);
                    },0);
                }
            )
            .click(function() {
                if (pointDragging) {
                    return;
                }
                this.remove();
                points = points.filter(function(p) {
                    return p != point;
                });
                redrawPath();
            });
        
        point.handle = pointrect;
            
        points.push(point);
        
    }
    
    function clickAddPoint(e, mx, my) {
        
        if (pathDragging) {
            return;
        }
        
        if (rectangleMode) {
        	resetPoints();
        }
        
        clearTimeout(closeTimeout);
        closed = false;
        
        addPoint(mx - offset.left, my - offset.top);
        
        redrawPath();
        
        closeTimeout = setTimeout(function() {
            closed = true;
            redrawPath();
        }, 1000)

    }
    
    function shapeMouseOver() {
        points.forEach(function(point) {
            if (point.handle !== this) {
                point.handle.attr({
                    stroke: PATHCOLOR,
                    fill: PATHCOLOR
                });
            }
        });
        if (this !== path) {
            path.attr({
                stroke: PATHCOLOR,
                fill: PATHCOLOR
            });
        }
        this.attr({
            stroke: SELECTEDCOLOR,
            fill: SELECTEDCOLOR
        });
    }
    
    function shapeMouseOut() {
        if (pathDragging || !this || !this.attr) {
            return;
        }
        this.attr({
            stroke: PATHCOLOR,
            fill: PATHCOLOR
        });
    }
    
    function redrawPath() {
        var d = "M"
            + points.map(function(p) { return p.x + " " + p.y }).join("L")
            + (closed ? "Z" : "");
        path.attr({
            path: d
        });
        points.forEach(function(point) {
            point.handle.attr({
                x: point.x - HANDLESIZE / 2,
                y: point.y - HANDLESIZE / 2
            });
        });
        var transd = "M"
            + points.map(function(p) { return (p.x / paper.width).toString().replace(/(\.\d{4})\d*/,"$1") + " " + (p.y / paper.height).toString().replace(/(\.\d{4})\d*/,"$1") }).join("L")
            + "Z";
        $(".fragment-path").val(transd).change();
    }
    
    var dragdeltax, dragdeltay, pathDragging;
    
    var path = paper.path()
        .attr({
            stroke: PATHCOLOR,
            fill: PATHCOLOR,
            "fill-opacity": .1
        })
        .click(clickAddPoint)
        .hover(shapeMouseOver, shapeMouseOut)
        .drag(
            function(dx, dy) {
                pathDragging = true;
                points.forEach(function(point) {
                    point.x += dx - dragdeltax;
                    point.y += dy - dragdeltay;
                });
                dragdeltax = dx;
                dragdeltay = dy;
                redrawPath();
            },
            function() {
                dragdeltax = 0;
                dragdeltay = 0;
            },
            function() {
                setTimeout(function() {
                    pathDragging = false;
                    shapeMouseOut(path);
                },0);
            }
        );
    
    $(".clear-fragment").click(function() {
        resetPoints();
        redrawPath();
        return false;
    });
    
    function revertPath() {
        startPath.split(/\s*[A-Z]\s*/).forEach(function(coords) {
            xy = coords.split(/[\s,]/);
            if (xy.length === 2) {
                addPoint(paper.width * parseFloat(xy[0]), paper.height * parseFloat(xy[1]));
            }
        });
        
        if (points.length) {
            closed = true;
        }
        
        if (
        	points.length === 4
        	&& points[0].x === points[3].x
        	&& points[0].y === points[1].y
    		&& points[1].x === points[2].x
            && points[2].y === points[3].y
  		) {
          	rectangleMode = true;
		}
        
        redrawPath();
    }
    
    revertPath();
    
    $(".reset-fragment").click(function() {
        resetPoints();
        revertPath();
        return false;
    })

});
