/**
 * 
 * All content on this website (including text, images, source
 * code and any other original works), unless otherwise noted,
 * is licensed under a Creative Commons License.
 * 
 * http://creativecommons.org/licenses/by-nc-sa/2.5/
 * 
 * Copyright (C) 2004-2009 Open-Xchange, Inc.
 * Mail: info@open-xchange.com 
 * 
 * @author Matthias Biggeleben <matthias.biggeleben@open-xchange.com>
 * @ignore
 */

// DEVELOPMENT IN PROGRESS // SUBJECT TO PERMANENT CHANGE!

/*jslint white: true, browser: true, devel: true, evil: true, forin: true, undef: true, eqeqeq: true, immed: true */

/*global jQuery */

(function ($) {
    
    var Draggable = function (node, options) {
        
        // vars
        var helper = null, fast = null;
        var offset = { top: 0, left: 0 };
        var delta = { top: 0, left: 0 };
        var origin = { top: 0, left: 0 };
        var dropzone = null;
        
        // defaults
        var o = $.extend({
            helper: "clone",
            zIndex: 65000,
            revert: true,
            opacity: 1,
            shadow: false,
            over: function (flag, helper) {
                helper.css("backgroundColor", flag ? "#a6c37d" : "white");
            },
            out: function (helper) {
                helper.css("backgroundColor", "white");
            },
            scope: {}
        }, options || {});
        
        // set scope
        o.hover = $.proxy(o.hover, node);
        
        var remove = function () {
            if (helper !== null) {
                helper.remove();
                helper = null;
                fast = null;
            }
        };
        var revert = function () {
            if (o.revert === true) {
                helper.empty().css({
                    MozBoxShadow: "",
                    border: "1px solid #ccc"
                }).animate(
                    { top: offset.top + "px", left: offset.left + "px" },
                    500,
                    remove
                );
            } else {
                remove();
            }
        };
        
        // event handlers
        var move = function (e) {
            // use fast access
            fast.top = (e.pageY + delta.top) + "px";
            fast.left = (e.pageX + delta.left) + "px";
        };
        var hover = function (e) {
            switch (e.type) {
            case "mouseover":
                var zone = $(this).data("dropzone"), accept = zone.accept(o.scope);
                o.over(accept, helper);
                dropzone = accept ? zone : null;
                break;
            case "mouseout":
                dropzone = null;
                o.out(helper);
                break;
            }
        };
        var drag = function (e) {
            if (Math.abs(e.pageX - origin.left) < 20 && Math.abs(e.pageY - origin.top) < 20) {
                return;
            }
            // unbind
            $(document).unbind("mousemove", drag);
            // create helper
            if (o.helper === "clone") {
                // get offset
                offset = node.offset();
                // get delta
                delta = { top: 5, left: 10 };
                // create clone
                var clone = node.clone(false).css({
                    position: "static",
                    top: "",
                    left: "",
                    right: "",
                    bottom: "",
                    margin: 0
                });
                var css = {
                    position: "absolute", 
                    top: (e.pageY - delta.top) + "px",
                    left: (e.pageX - delta.left) + "px",
                    width: node.width() + "px",
                    height: node.height() + "px",
                    zIndex: o.zIndex,
                    backgroundColor: "white",
                    opacity: o.opacity
                };
                if (o.shadow === true) {
                    css.MozBoxShadow = "2px 2px 20px 3px #000";
                }
                helper = $("<div/>").css(css).append(clone).appendTo(document.body);
                fast = helper[0].style;
            }
            // activate dropzones
            $(".dropzone").bind("mouseover mouseout", hover);
            // bind
            $(document).bind("mousemove", move);
        };
        var stop = function (e) {
            // unbind handlers
            $(".dropzone").unbind("mouseover mouseout", hover);
            $(document).unbind("mousemove", move);
            $(document).unbind("mousemove", drag);
            $(document).unbind("mouseup", stop);
            // revert?
            if (helper !== null) {
                if (dropzone === null) {
                    o.out(helper);
                    revert();
                } else {
                    remove();
                    dropzone.drop(o.scope);
                }
            }
        };
        var start = function (e) {
            // remember origin
            origin = { top: e.pageY, left: e.pageX };
            // bind events
            $(document).bind("mousemove", drag);
            $(document).bind("mouseup", stop);
        };

        // disable
        this.disable = function () {
            stop();
            node.unbind("mousedown", start);
            return this;
        };
        
        // enable
        this.enable = function () {
            node.bind("mousedown", start);
            return this;
        };
    };
    
    $.fn.draggable = function (options) {
        
        return this.each(function () {
            // vars
            var node = $(this), instance = node.data("draggable");
            // action?
            if (typeof options === "string") {
                if (instance) {
                    switch (options) {
                    case "destroy":
                        instance.disable();
                        node.removeData("draggable");
                        break;
                    case "disable":
                        instance.disable();
                        break;
                    case "enable":
                        instance.enable();
                        break;
                    }
                }
            } else {
                // has instance?
                if (instance) {
                    node.draggable("destroy");
                }
                // new instance
                node.data("draggable", new Draggable(node, options).enable());
            }
        });
    };
    
    var Dropzone = function (node, options) {
        
        // defaults
        var o = $.extend({
            accept: function () {
                return true;
            },
            drop: function (scope) {
                console.log("Drop!", scope);
            }
        }, options || {});
        
        this.accept = function (scope) {
            return o.accept(scope);
        };
        
        this.drop = function (scope) {
            o.drop(scope);
        };
        
        // disable
        this.disable = function () {
            node.removeClass("dropzone");
            return this;
        };
        
        // enable
        this.enable = function () {
            node.addClass("dropzone");
            return this;
        };
    };
    
    $.fn.dropzone = function (options) {
        
        return this.each(function () {
            // vars
            var node = $(this), instance = node.data("dropzone");
            // action?
            if (typeof options === "string") {
                if (instance) {
                    switch (options) {
                    case "destroy":
                        instance.disable();
                        node.removeData("dropzone");
                        break;
                    case "disable":
                        instance.disable();
                        break;
                    case "enable":
                        instance.enable();
                        break;
                    }
                }
            } else {
                // has instance?
                if (instance) {
                    node.dropzone("destroy");
                }
                // new instance
                node.data("dropzone", new Dropzone(node, options).enable());
            }
        });
    };
    
}(jQuery));