/**
 * Move a flag with a drag.
 * 
 * @class
 * @requires OpenLayers/Control.js
 * @requires OpenLayers/Handler/Drag.js
 * @requires OpenLayers/Handler/Flag.js
 */
Daedalus.DragFlag = OpenLayers.Class.create();
Daedalus.DragFlag.prototype = 
  OpenLayers.Class.inherit(Daedalus.Base, OpenLayers.Control, {

    /**
     * Define this function if you want to know about each move of a flag.
     * The function should expect to receive two arguments: the flag that
     * is being dragged and the pixel location of the mouse.
     * @param {OpenLayers.Flag.Vector} flag
     * @param {OpenLayers.Pixel}
     */
    onDrag: function(flag, pixel) {},

    /**
     * @type OpenLayers.Layer.Vector
     * @private
     */
    layer: null,
    
    /**
     * @type OpenLayers.Flag.Vector
     * @private
     */
    flag: null,

    /**
     * @type OpenLayers.Handler.Drag
     * @private
     */
    dragHandler: null,

    /**
     * The functions that are sent to the drag handler for callback
     * @type Object
     */
    dragCallbacks: {},

    /**
     * @type OpenLayers.Handler.Flag
     * @private
     */
    flagHandler: null,

    /**
     * The functions that are sent to the flag handler for callback
     * @type Object
     */
    flagCallbacks: {},
    
    /**
     * @type OpenLayers.Pixel
     * @private    
     */
    lastPixel: null,

    /**
     * @param {OpenLayers.Layer.Vector} layer
     * @param {Object} options
     */
    initialize: function(layer, options) {
        OpenLayers.Control.prototype.initialize.apply(this, [options]);
        this.layer = layer;
        this.dragCallbacks = OpenLayers.Util.extend(
            {
                down: this.downFlag,
                move: this.moveFlag,
                up:   this.upFlag,
                out:  this.cancel
            },
            this.dragCallbacks
        );
        
        this.dragHandler = new OpenLayers.Handler.Drag(
            this, this.dragCallbacks
        );

        this.flagCallbacks = OpenLayers.Util.extend(
            {
                over: this.overFlag,
                out:  this.outFlag
            }, 
            this.flagCallbacks
        );

        this.flagHandler = new OpenLayers.Handler.Feature(
            this, this.layer, this.flagCallbacks, {}
        );
    },
    
    /**
     * Take care of things that are not handled in superclass
     */
    destroy: function() {
        this.layer = null;
        this.dragHandler.destroy();
        this.flagHandler.destroy();
        OpenLayers.Control.prototype.destroy.apply(this, []);
    },

    /**
     * Activate the control and the flag handler
     * 
     * @type Boolean
     * @return Successfully activated the control and flag handler
     */
    activate: function() {
        return (this.flagHandler.activate() &&
                OpenLayers.Control.prototype.activate.apply(this, arguments));
    },

    /**
     * Deactivate the control and all handlers
     * 
     * @type Boolean
     * @return Successfully deactivated the control
     */
    deactivate: function() {
        // the return from the handlers is unimportant in this case
        this.dragHandler.deactivate();
        this.flagHandler.deactivate();
        return OpenLayers.Control.prototype.deactivate.apply(this, arguments);
    },

    /**
     * Called when the flag handler detects a mouse-over on a flag.
     * This activates the drag handler.
     * 
     * @param {OpenLayers.Flag.Vector} flag
     */
    overFlag: function(flag) {
        if (this.dragHandler.dragging) {
            if (this.flag == flag) {
                this.over = true;
            }
            else {
                this.over = false;
            }
        }
        else {
            this.flag = flag;
            this.dragHandler.activate();
            this.over = true;
            // TBD replace with CSS classes
            //this.map.div.style.cursor = 'move';
            this.map.div.style.cursor = 'pointer';
        }
    },

    /**
     * Called when the drag handler detects a mouse-down.
     * 
     * @param {OpenLayers.Pixel} pixel
     */
    downFlag: function(pixel) {
        this.dragHandler.dragging = true;
        this.lastPixel = pixel;
        if (this.over) {
            this.dragHandler.dragging = true;
            this.lastPixel = pixel;
            this.signal('dragStart', this.flag);
        }
    },

    /**
     * Called when the drag handler detects a mouse-move.  Also calls the
     * optional onDrag method.
     * 
     * @param {OpenLayers.Pixel} pixel
     */
    moveFlag: function(pixel) {
        this.flag.move(pixel.x - this.lastPixel.x, 
                       pixel.y - this.lastPixel.y);
        this.layer.drawMarker(this.flag);
        this.lastPixel = pixel;
        this.onDrag(this.flag, pixel);
    },

    /**
     * Called when the drag handler detects a mouse-up.
     * 
     * @param {OpenLayers.Pixel} pixel
     */
    upFlag: function(pixel) {
        this.dragHandler.dragging = false;
        if (this.over) {
            this.signal('dragEnd', this.flag);
        }
        else {
            this.dragHandler.deactivate();
            this.flag = null;
            this.map.div.style.cursor = "default";
        }
    },

    /**
     * Called when the flag handler detects a mouse-out on a flag.
     * 
     * @param {OpenLayers.Flag.Vector} flag
     */
    outFlag: function(flag) {
        if (!this.dragHandler.dragging) {
            this.over = false;
            this.dragHandler.deactivate();
            // TBD replace with CSS classes
            this.map.div.style.cursor = "default";
        } else {
            if (this.flag == flag) {
                this.over = false;
            }
        }
    },
    
    /**
     * Called when the drag handler detects a mouse-out (from the map viewport)
     */
    cancel: function() {
        this.dragHandler.deactivate();
        this.over = false;
    },

    /**
     * Set the map property for the control and all handlers.
     * 
     * @param {OpenLayers.Map} map
     */
    setMap: function(map) {
        this.dragHandler.setMap(map);
        this.flagHandler.setMap(map);
        OpenLayers.Control.prototype.setMap.apply(this, arguments);
    },

    /** @final @type String */
    CLASS_NAME: "Daedalus.DragFlag"
});
