// enhance MDVMap core
// NOTE: mdvMap.js must be included first

var MDVEvent_DRAGGABLEMARKER_ONRELEASE = MDVEventID++;

MDVMap.prototype.createDraggableMarker = function (options) {
    
    if (options && options.imgSrc) {
        return MDVMarkerDraggable(this, options);
    }
    else {
        return null;
    }
};

//       pseudo constructor for draggable marker.
//       
//       returns          the enhanced marker object.
//       arguments       a reference to the mdvMap instance, and an object literal containing
//                            - members imgSrc, coords, factor (all mandatory)  for instantiation of MDVMarker
//                            - members markerSequence, func, drawLayer (optional) if connecting polylines are to be updated.
//                              if markerSequence is present, func and drawLayer are mandatory as well.
//                              markerSequence contains an array of object literals containing at least members markerId, x, y
//                              func takes a function reference to the polyline drawing method
//                              drawLayer a reference to the polyline layer

var MDVMarkerDraggable = function (mdvMap, options) {

    var markerSequence = options.markerSequence || null;
    var func = options.func || null;
    var drawLayer = options.drawLayer || null;
    
    // mandatory arguments missing
    if (!options.coords || !options.factor || !options.imgSrc) {
        return null;
    }
    
    // setup the enhanced marker object that eventually gets returned 
    var draggable = new MDVMarker(mdvMap, options.coords, options.imgSrc, options.factor);
    
    draggable.dragging                          = false;
    draggable.mapName                           = draggable.mdvMap.config.get('mapName');
    draggable.posViewport                       = mdvLib.getElementPosition(mdvMap.viewport);
	draggable.img.className 					= 'MDVDraggableMarker'
    
    // make options available when the changed object is returned upon mouseup 
    draggable.options                           = options;
    
    // we got a marker sequence to perform manipulations of connecting polylines,
    // so prepare the draggable object
    if (mdvLib.typeOf(markerSequence) === 'array') {
        draggable.markerSequence                = markerSequence;
        draggable.currentMarkerFromSequence     = null;
        draggable.currentMarkerIdx              = null;
        
    }
    
    draggable.img.onclick = function (e) {

        var evt = e || window.event;
        
        this.cancelEvent(evt);
        return false;        
    
    }.bind(draggable);

    draggable.img.onmousedown = function (e) {
        
        var i, evt = e || window.event;
        
        this.applyEventBlockLayer(true);
        
        //prevent tt from interfering with our dd operation
        if (this.toolTip) {
            this.preventTooltip();
         }
        
        this.dragging = true;
        this.img.style.cursor = 'move';
        
        if (this.markerSequence) {
            // get correct marker from marker sequence
            // for later polyline manipulation
            for (i=0; i<this.markerSequence.length; i+=1) {
                if (this.markerSequence[i].markerId === this.id) {
                    this.currentMarkerFromSequence = this.markerSequence[i];
                    this.currentMarkerIdx = i;
                    break;
                }
            }
        }
        
        this.cancelEvent(evt);
        return false;
        
    }.bind(draggable);

    draggable.img.onmouseup = function (e) {
        
        var mousePos, mouseCoords, evt = e || window.event;

        this.dragging = false;
        this.img.style.cursor = 'default';
       
       if (this.toolTip) {
            mousePos = mdvLib.getMousePosition(evt);
            mouseCoords = this.toMapCoords(mousePos);
            //update marker, so that bound tt shows at the correct position
            this.setCoords(mouseCoords);
        }
        
        // reset currentMarker
        this.currentMarkerFromSequence = null;
        
        window.setTimeout(function() {
        		this.applyEventBlockLayer(false); 
        		this.mdvMap.events.triggerEvent(MDVEvent_DRAGGABLEMARKER_ONRELEASE, 'MDVMarker has been released.', this);
        	}.bind(this), 500);
        
    }.bind(draggable);
    
    draggable.updatePosition = function (e) {
       
       var mousePos, mapPos, evt = e || window.event;
       
       if (this.dragging !== true) {
            return;
       }   
       
        this.cancelEvent(evt);
        
        //prevent tt from interfering with our dd operation
        // calling preventToolTip only onmousedown is not enough
        if (this.toolTip) {
            this.preventTooltip();
         }
        
        mousePos = mdvLib.getMousePosition(evt);
        mapPos = this.toMapPx(mousePos);
   
        this.img.style.top = mapPos.y - Math.floor(this.img.height/2) + 'px';
        this.img.style.left = mapPos.x - Math.floor(this.img.width/2) + 'px';
        
        if (this.currentMarkerFromSequence) {
            this.updateConnectedPolylines(this.toMapCoords(mousePos));
        }   
        return false;
    };
    
    draggable.updateConnectedPolylines = function (mapCoords) {
        
        var _draw = function () {

            var start, end, poly, i=1;
            
            if (typeof func !== 'function') {
                throw {
                    name: 'MDVMarkerDraggable',
                    message: 'no function reference for\ndrawing of polylines provided.'
                }
            }        
            
            if (!drawLayer) {
                throw {
                    name: 'MDVMarkerDraggable',
                    message: 'no draw layer for\ndrawing of polylines provided.'
                }
            }
            
            while (this.markerSequence[i]) {	
                start = this.markerSequence[i-1].x + ',' + this.markerSequence[i-1].y;
                end = this.markerSequence[i].x + ',' + this.markerSequence[i].y;
                poly = func.apply(this, [start, end]);
                drawLayer.addPolyline(poly);
                i += 1;
        	}
        }.bind(this);
        
        //remove all lines before updating
        // use try catch, as drawLayer might not have been passed in.
        // we'll catch the error a few lines furhter down.
        try {
            drawLayer.removeAllPolylines();
        } catch (e) {
            
        }
        //update current marker position... 
        this.currentMarkerFromSequence.x = mapCoords.x;
        this.currentMarkerFromSequence.y = mapCoords.y;

        // ... and redraw all segments
        try {    
            _draw();
        } catch(e) {
            alert('ERROR in: ' + e.name + '\n\nMESSAGE:\n' + e.message);
        }
    };
    
    draggable.toMapCoords = function (mousePos) {
        
        var posX = mousePos.left - this.posViewport.left;
        var posY = mousePos.top - this.posViewport.top;
        var mouseCoords = this.mdvMap.getCoordinates({x: posX, y: posY});
        
        return mouseCoords;
    };
    
    draggable.toMapPx = function (mousePos) {
        return this.mdvMap.getPoint(this.toMapCoords(mousePos));
    };
    
    draggable.cancelEvent = function(evt) {
        
        evt.cancelBubble = true;
        evt.returnValue = false;

        if (evt.stopPropagation) {
            evt.stopPropagation();
        }    
        if (evt.preventDefault) {
            evt.preventDefault();
        }    
     	return false;
    };
    
    draggable.applyEventBlockLayer = function (bool) {
    	
    	var div;
    	
		if (bool === false) {
			// remove old eventBlockLayer
			if (this.mdvMap.eventBlockLayer) {
				this.mdvMap.eventBlockLayer.style.display = 'none';
				this.mdvMap.eventBlockLayer.oncontextmenu = null;
 				this.mdvMap.eventBlockLayer.onmouseover = null;
				this.mdvMap.eventBlockLayer.onmouseup = null;
				this.mdvMap.viewport.removeChild(this.mdvMap.eventBlockLayer);
				this.mdvMap.eventBlockLayer = null;
			}
			return;
		}
		
		div = document.createElement('div');
		div.id = 'eventBlockLayer';
	    div.oncontextmenu = function(e) {
	        return false;    
        };
         
        div.onmouseover = function (e) {
        	document.body.style.cursor = 'move';
        };
        // marker img does not get the mouseup event in firefox
        // although stacking via zIndex seems alright... so work around it. 
        div.onmouseup = function(e) {
        	document.body.style.cursor = 'default';
        	this.img.onmouseup(e);	
        }.bind(this);
		
		//store a reference...		
		this.mdvMap.eventBlockLayer = div;
		
		//... and append it to the viewport
		this.mdvMap.viewport.appendChild(div);
		
		mdvLib.style([div], {
			width: this.mdvMap.viewport.style.width,
			height: this.mdvMap.viewport.style.height,
			position: 'absolute',
			left: 0,
			top: 0,
			zIndex: (this.layer && this.layer.zIndex-1) || 40,
			backgroundColor: '#000',
			opacity: .1,
			filter: 'alpha(opacity=10)'
		});	
		
   };
    
    draggable.preventTooltip = function () {
        
        //tt might be open...
        if (this.toolTip.isVisible()) {
            this.toolTip.hide();
        }
        //...or in the timer queue
        this.toolTip.cancelDisplay();
    };
    
    attachEventListener(window.document, 'mousemove', function(e) {draggable.updatePosition(e)}.bind(draggable), null);    
    attachEventListener(window, 'resize', function(e) {
                                            this.posViewport = mdvLib.getElementPosition(this.mdvMap.viewport);
                                        }.bind(draggable), null);
    
    return draggable;
};







