Daedalus.Gadget = OpenLayers.Class.create();
Daedalus.Gadget.prototype = 
    OpenLayers.Class.inherit( Daedalus.Base, {

    /**
     * @type OpenLayers.Events
     */
    events: null,
    
    /**
     * @type {Element}
     */
    div: null,
    
    /**
     * @type Array of Daedalus.Icon
     */
    icons: null,
    
    /**
     * @type Daedalus.Icon
     */
    dragging: null,
    
    /**
     * @type {Object}
     */
    dragOffset: null,

    /**
     * @type OpenLayers.Map
     */
    map: null,

    /**
     * @type OpenLayers.Layer
     */
    flags: null,

    /**
     * @constructor
     * 
     * @param {Element} div
     */
    initialize: function(div) {
        this.displayClass = this.CLASS_NAME.replace(".", "");
        this.div          = div;
        this.events       = new OpenLayers.Events(
            this, this.div, null
        );
        this.icons        = [];
        
        this.installHandlers();
    },

    getIconFromEvent: function(evt) {
        var node = OpenLayers.Event.element(evt);

        /** TODO: We need a better way to do this. */
        for (var i = 0; i < this.icons.length; i++) {
            var icon = this.icons[i];
            if (icon.imageDiv.id == node.id) {
                return icon;
            }
            if (icon.imageDiv.firstChild.id == node.id) {
                return icon;
            }
        }
        return null;
    },
    
    endDrag: function() {
        if (this.dragging) {
            var d = this.dragging;
            this.dragging = null;
            var parent = d.imageDiv.parentNode;
            parent.removeChild(d.imageDiv);
            d.destroy();
        }
    },

    setFlags: function(flags) {
        this.flags = flags;
    },
    
    getMousePosition: function(evt) {
        var mouse_x   = Event.pointerX(evt);
        var mouse_y   = Event.pointerY(evt);
        var mouse_pos = new OpenLayers.Pixel(mouse_x, mouse_y);
        return mouse_pos;
    },

    handlers: {
        mouseover: function(evt) {
            // TODO: Only really need to decode the event here and stash
            // the active icon. 
            var icon = this.getIconFromEvent(evt);
            if (icon) {
                icon.setCursor('pointer');
                //icon.setCursor('hand');
            }
            return true;
        },
        
        mouseout: function(evt) {
            var icon = this.getIconFromEvent(evt);
            if (icon) {
                icon.setCursor('');
            }
            return true;
        },
        
        mousedown: function(evt) {
            var icon = this.getIconFromEvent(evt);
            if (icon) {
                //icon.setCursor('move');
                this.endDrag();
                this.dragging = icon.clone();

                var mouse_pos = this.getMousePosition(evt);
                var icon_pos  = Position.cumulativeOffset(icon.imageDiv);
                this.dragOffset = {
                    x: mouse_pos.x - icon_pos[0],
                    y: mouse_pos.y - icon_pos[1]
                };
                var px = new OpenLayers.Pixel(icon_pos[0], icon_pos[1]);
                this.dragging.moveTo(px);
                this.div.appendChild(this.dragging.imageDiv);

                OpenLayers.Event.stop(evt);
                return false;
            }
            return true;
        },

        mouseup: function(evt) {
            if (this.dragging) {
                if (this.map) {
                    var mouse_pos = this.getMousePosition(evt);
                    var div_pos   = Position.cumulativeOffset(this.div);
                    var rel_pos   = new OpenLayers.Pixel(
                        mouse_pos.x - div_pos[0], 
                        mouse_pos.y - div_pos[1]
                    );
                    var px        = this.map.getLayerPxFromViewPortPx(rel_pos);
                    var lonlat    = this.map.getLonLatFromLayerPx(px);
                    var bounds    = this.map.getExtent();
                    var on_screen = bounds.containsLonLat(lonlat);

                    if (on_screen) {
                        // Create the flag. From now on it's the map's
                        // responsibility
                        var spec = {
                            id:          OpenLayers.Util.createUniqueID("flag_"),
                            icontype_id: this.dragging.type,
                            name:        'mark',
                            e:           lonlat.lon,
                            n:           lonlat.lat
                        };
                        var flag = this.flags.updateFlag(spec);
                        this.signal('markerCreate', flag);
                    }
                }
                this.endDrag();
                return false;
            }
            
            return true;
        },
        
        mousemove: function(evt) {
            if (this.dragging) {
                var mouse_pos = this.getMousePosition(evt);
                var px = new OpenLayers.Pixel(
                    mouse_pos.x - this.dragOffset.x,
                    mouse_pos.y - this.dragOffset.y
                );
                this.dragging.moveTo(px);
                OpenLayers.Event.stop(evt);
                return false;
            }

            return true;
        }
    },

    installHandlers: function() {
        for (var h in this.handlers) {
            this.events.register(h, this, this.handlers[h]);
        }
    },

    /**
     * 
     */
    destroy: function () {
        if (this.events) {
            this.events.destroy();
        }
        for (var i = 0; i < this.icons.length; i++) {
            this.icons[i].destroy();
        }
        this.icons    = null;
        this.div      = null;
        this.dragging = null;
        this.map      = null;
        this.flags    = null;
    },
    
    addIcon: function(icon) {
        this.icons.push(icon);
    },
    
    setMap: function(map) {
        this.map = map;
    },
    
    getMap: function() {
        return this.map;
    },
    
    /** @final @type String */
    CLASS_NAME: "Daedalus.Gadget"
});
