﻿// Namespace declaration ...
if (!window.RHPConsulting)
    window.RHPConsulting = {};

// object, constructor ...    
RHPConsulting.SilverlightDragDropExtender = function()
{
    this._elementToDrag = null;
    this._elementToTriggerDrag = null;
    // variables used when dragging ...
    this._flagDragging = false;
    this._beginDragX = null;
    this._beginDragY = null;
    this._originalOpacity = null;
    this._opacity = 1;
    this._limitToContainer = false;
    // arrays used for storing handlers ...
    this._dragDropStartedHandlers = new Array();
    this._dragDropCompleteHandlers = new Array();
    this._draggingHandlers = new Array();
   
}
RHPConsulting.SilverlightDragDropExtender.prototype = {

    // Events ...
    addEventListener : function(eventName, handler) {
        var handlers = this._get_EventArrayReference(eventName);
        handlers.push(handler);        
    },
    removeEventListener : function(eventName, handler) {
        var handlers  = this._get_EventArrayReference(eventName)
        for(var index in handlers) {
            if(handlers[index] == handler) {
                handlers.splice(index,1);
            }
        } 
    },
    // Events - Private Methods ...
    _raiseEvent : function(eventName, sender, args, ext) {
        var handlers = this._get_EventArrayReference(eventName);
        for(var index in handlers) { handlers[index](sender,args,ext); }  
    },
    // Events - Private Properties ...
    _get_EventArrayReference : function(eventName) {
        var handlers = null;
        switch (eventName)
        {
            case "DragDropComplete" :   handlers = this._dragDropcompleteHandlers;   break;
            case "DragDropStarting" :   handlers = this._dragDropStartedHandlers;    break;
            case "Dragging"         :   handlers = this._draggingHandlers;           break;
        }
        return handlers;
    },

    // Properties ...
    set_LimitToContainer : function(value) {
        this._limitToContainer = value;
    },
    get_LimitToContainer : function(value) {
        return this._limitToContainer;
    },
    set_Opacity :function(value) {
        this._opacity = value;
    },
    get_Opacity : function(value) {
        return this._opacity;
    },
    get_Version : function() {
        return "1.0.0.0";
    },
    get_Trademark : function() {
        return "RHPConsulting.NET";
    },
    get_Author : function() {
        return "Roberto Hernández-Pou";
    },

    // Public Methods ...    
    RootCanvasCoordinates : function(userInterfaceElement) {
        var coordinates = {};
        coordinates.Top = userInterfaceElement["Canvas.Top"];
        coordinates.Left = userInterfaceElement["Canvas.Left"];
        
        if (userInterfaceElement.GetParent() != null)
        {  

            // do recursive ...
            var coordinates1 = this.RootCanvasCoordinates(userInterfaceElement.GetParent());
            
            // set values ...
            coordinates.Top  += coordinates1.Top;
            coordinates.Left += coordinates1.Left;
        
        }
        
        return coordinates;
        
    },
    Initialize : function(elementToDrag, elementToTriggerDrag, container) {
        this._elementToDrag = elementToDrag;
        this._elementToTriggerDrag = elementToTriggerDrag;
        
        // associate events ...
        this._elementToTriggerDrag.addEventListener("MouseLeftButtonDown"   , Silverlight.createDelegate(this, this._frameworkElementLeftButtonDown));
        this._elementToTriggerDrag.addEventListener("MouseLeftButtonUp"     , Silverlight.createDelegate(this, this._frameworkElementLeftButtonUp));
        this._elementToTriggerDrag.addEventListener("MouseMove"             , Silverlight.createDelegate(this, this._frameworkElementDrag));
        this._elementToTriggerDrag.addEventListener("MouseLeave"            , Silverlight.createDelegate(this, this._frameworkElementMouseLeave));
        
    },
    
    // Private Methods ...
    _frameworkElementMouseLeave : function(sender,args) {
        if (this._draggingFlag == true)
            this.FrameworkElementLeftButtonUp(this._elementToDrag,args,this);
    },
    _frameworkElementLeftButtonDown : function(sender, args) {
        // enable flag to signal dragging has begun ...
        this._dragginFlag = true;
        // save original opacity ...
        this._originalOpacity = this._elementToDrag.opacity;
        // save original mouse position ...
        this._beginDragX = args.getPosition(null).X;
        this._beginDragY = args.getPosition(null).Y;
        // set new opacitiy ...
        this._elementToDrag.opacity = this._opacity;
        // capture mouseevents ...
        sender.captureMouse();
        // fire events ...
        this._raiseEvent("DragDropStarting",this._elementToDrag,args,this);
    },
    _frameworkElementLeftButtonUp : function(sender, args) {
        // set dragging flag (false)
        this._dragginFlag = false;
        // set original opacity ...
        this._elementToDrag.opacity = this._originalOpacity;
        // release mouse ...
        sender.releaseMouseCapture();
        // fire events ...
        this._raiseEvent("DragDropComplete",this._elementToDrag,args, this);
    },
    _frameworkElementDrag : function(sender, args) {
        if (this._dragginFlag == true)
        {
            var positionX = args.getPosition(null).X;
            var positionY = args.getPosition(null).Y;    
              
              if (this._beginDragX != -1 && this._beginDragY != -1) {
              
                var newPositionX = this._elementToDrag["Canvas.Left"] + positionX - this._beginDragX;
                var newPositionY = this._elementToDrag["Canvas.Top"]  + positionY - this._beginDragY;
              
                // validate coordinates ...
                if (this._validatePosition(newPositionX,newPositionY) == false)  {
                    this._frameworkElementLeftButtonUp(sender,args,this); 
                    return;
                }
                
                this._elementToDrag["Canvas.Left"] = newPositionX;
                this._elementToDrag["Canvas.Top"]  = newPositionY;
                
                this._beginDragX = positionX;
                this._beginDragY = positionY;
             
                // build customargument with correct position ...
                var customArgs = {};
                customArgs.MouseX = positionX;
                customArgs.MouseY = positionY;
                customArgs.Top = this._elementToDrag["Canvas.Top"];
                customArgs.Left = this._elementToDrag["Canvas.Left"];
              
                // fire events ...
                this._raiseEvent("Dragging",this._elementToDrag,customArgs,this);
              }
              
        }
    },
    _validatePosition : function(positionX, positionY) {
        
        // initialize parent boundaries ...
        containerWidth   = this._elementToDrag.GetParent().Width;
        containerHeight  = this._elementToDrag.GetParent().Height;
        containerTop     = 0;
        containerLeft    = 0;
    
        if (this._limitToContainer != true) {
            // Get RealBoundaries ...
            var boundariesXY = this._hostBoundariesXY(this._elementToDrag);
            // initialize container boundaries ...
            var containerWidth   = this._elementToDrag.GetHost().content.ActualWidth;
            var containerHeight  = this._elementToDrag.GetHost().content.ActualHeight;
            var containerTop     = boundariesXY.Top;
            var containerLeft    = boundariesXY.Left;
        }
    
        // out of position (left, top)
        if (positionX <= containerLeft || positionY <= containerTop)
            return false;

        // out of canvas   (right, bottom)
        if (positionX >= (containerWidth + containerLeft - this._elementToDrag.Width) || positionY >= (containerHeight + containerTop - this._elementToDrag.Height))
            return false;
       
        // all rules passed ...
        return true;
        
    },
    _hostBoundariesXY : function(userInterfaceElement) {
        var boundaries = {};
        boundaries.Top  = 0;
        boundaries.Left = 0;
        
        if(userInterfaceElement.GetParent() != null) 
        {  
        
            // get parent top, left 
            boundaries.Top  = -userInterfaceElement.GetParent()["Canvas.Top"];
            boundaries.Left = -userInterfaceElement.GetParent()["Canvas.Left"];    
        
            // do recursive ...
            var boundaries1 = this._hostBoundariesXY(userInterfaceElement.GetParent());
            
            // set values ...
            boundaries.Top  -= Math.abs(boundaries1.Top);   
            boundaries.Left -= Math.abs(boundaries1.Left); 
        }
        
        return boundaries;
    }
}
 
// Delegates ...	
if (!window.Silverlight) 
	window.Silverlight = {};

Silverlight.createDelegate = function(instance, method) {
	return function() {
        return method.apply(instance, arguments);
    }
}

