/* <copyright>
This file contains proprietary software owned by Motorola Mobility, Inc.<br/>
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.<br/>
(c) Copyright 2011 Motorola Mobility, Inc.  All Rights Reserved.
</copyright> */

var Montage = require("montage/core/core").Montage,
    viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils,
    vecUtils = require("js/helper-classes/3D/vec-utils").VecUtils,
    toolHandleModule = require("js/stage/tool-handle"),
    ElementsMediator = require("js/mediators/element-mediator").ElementMediator,
    DrawingToolBase = require("js/tools/drawing-tool-base").DrawingToolBase,
    Keyboard = require("js/mediators/keyboard-mediator").Keyboard,
    ModifierToolBase = require("js/tools/modifier-tool-base").ModifierToolBase;

var SelectionTool = exports.SelectionTool = Montage.create(ModifierToolBase, {
    drawingFeedback: { value: { mode: "Draw2D", type: "" } },

    _canOperateOnStage: { value: true},
    _isSelecting: {value: false, writable:true},
    _shiftMove: { value: 10},

    _showTransformHandles: { value: false, enumerable: true },

    _handleToolOptionsChange : {
        value: function (event) {
            this._showTransformHandles = event.detail.inTransformMode;
            this.DrawHandles();
        }
    },

    startDraw: {
        value: function(event) {
            if(!this.application.ninja.selectedElements.length)
            {
                this._isSelecting = true;
                this._canSnap = false;
            }
            else
            {
                this._canSnap = true;
            }

            this.isDrawing = true;
            this.application.ninja.stage.showSelectionBounds = false;

            if(this._canSnap)
            {
                this.initializeSnapping(event);
            }
            else
            {
                this.drawWithoutSnapping(event);
            }
        }
    },

    drawSelectionMarquee: {
        value: function(event) {
            var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas,
                                                        new WebKitPoint(event.pageX, event.pageY));

            if(this._isSpace) {
                this._currentDX = point.x - this._currentX;
                this._currentDY = point.y - this._currentY;

                this.downPoint.x += this._currentDX;
                this.downPoint.y += this._currentDY;
                this.currentX += this._currentDX;
                this.currentY += this._currentDY;

                DrawingToolBase.draw2DRectangle(this.downPoint.x,this.downPoint.y,this.currentX - this.downPoint.x,this.currentY - this.downPoint.y);
            } else {
                this._currentX = point.x;
                this._currentY = point.y;

                DrawingToolBase.draw2DRectangle(this.downPoint.x,this.downPoint.y,point.x - this.downPoint.x,point.y - this.downPoint.y);
            }
        }
    },

    HandleMouseMove: {
        value: function(event) {
            if(this._escape) {
                this._escape = false;
                this.isDrawing = true;
            }

            if(this._isSelecting) {
                // Draw the Selection Marquee
                this.drawSelectionMarquee(event);
            }
            else
            {
                if(this.isDrawing) {
                    this._hasDraw = true;   // Flag for position of element
                    this.doDraw(event);
                } else {
                    this._showFeedbackOnMouseMove(event);
    //                if(this._canSnap)
    //                {
    //                    this.doSnap(event);
    //                }
                }

                this.DrawHandles(this._delta);
                if(this._canSnap && this._isDrawing)
                {
                    this.application.ninja.stage.stageDeps.snapManager.drawLastHit();
                }
            }
        }
    },

    HandleLeftButtonUp: {
        value: function(event) {
            var selectedItems,
                point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas, new WebKitPoint(event.pageX, event.pageY));

            this.isDrawing = false;
            this.application.ninja.stage.showSelectionBounds = true;
            if(this._escape) {
                this._escape = false;
                this._isSelecting = false;
                return;
            }


            if(this._isSelecting) {
                this._isSelecting = false;

                // Don't do the marque selection if the mouse has not moved
                if(this.downPoint.x != point.x && this.downPoint.y != point.y) {
                    var box = [];
                    selectedItems = [];

                    box[0] = this.downPoint.x;
					box[1] = this.downPoint.y;
					box[2] = point.x;
					box[3] = point.y;

                    //selectionManagerModule.selectionManager.marqueeSelection(box);
                    var childNodes = this.application.ninja.currentDocument.documentRoot.childNodes;
                    childNodes = Array.prototype.slice.call(childNodes, 0);
                    childNodes.forEach(function(item) {
                        if(item.nodeType == 1 && SelectionTool._complicatedCollisionDetection(item, box)) {
                            selectedItems.push(item);
                        }
                    });

                    this.application.ninja.selectionController.selectElements(selectedItems);

                }

                this.endDraw(event);
                return;
            }



            if(this._hasDraw)
            {
                if(this._activateOriginHandle)
                {
                    this._setTransformOrigin(true);
                }
                else if ( ((this.downPoint.x - point.x) !== 0) ||
                            ((this.downPoint.y - point.y) !== 0) )
                {
                    this._updateTargets(true);
                }

                this._hasDraw = false;
            }
            if(this._handleMode !== null)
            {
                this._handleMode = null;
                this._delta = null;
                this.DrawHandles();
            }

            this.endDraw(event);
        }
    },

    /**
     * Double click handler
     *
     * Sets the currentSelectionContainer to the current selected element. If no elements are selected set the
     * currentSelectionContainer to the userDocument div.
     */
    HandleDoubleClick: {
        value: function(event) {
            if(this.application.ninja.selectedElements.length > 0) {
                this.application.ninja.currentSelectedContainer = this.application.ninja.selectedElements[0]._element;
            } else {
                this.application.ninja.currentSelectedContainer = this.application.ninja.currentDocument.documentRoot;
            }
        }
    },

    HandleKeyPress: {
        value: function(event){
            var inc;

            if (!(event.target instanceof HTMLInputElement)) {
                if(this.application.ninja.selectedElements.length !== 0) {
                    inc  = (event.shiftKey) ? this._shiftMove : 1;

                    switch(event.keyCode) {
                        case Keyboard.LEFT:
                            var newLeft = [];
                            var leftArr = this.application.ninja.selectedElements.map(function(item) {
                                newLeft.push( (parseFloat(ElementsMediator.getProperty(item._element, "left")) - inc) + "px"  );
                                return ElementsMediator.getProperty(item._element, "left");
                            });

                            ElementsMediator.setProperty(this.application.ninja.selectedElements, "left", newLeft , "Change", "selectionTool", leftArr);
                            break;
                        case Keyboard.UP:
                            var newTop = [];
                            var topArr = this.application.ninja.selectedElements.map(function(item) {
                                newTop.push( (parseFloat(ElementsMediator.getProperty(item._element, "top")) - inc) + "px"  );
                                return ElementsMediator.getProperty(item._element, "top");
                            });

                            ElementsMediator.setProperty(this.application.ninja.selectedElements, "top", newTop , "Change", "selectionTool", topArr);
                            break;
                        case Keyboard.RIGHT:
                            var newLeft = [];
                            var leftArr = this.application.ninja.selectedElements.map(function(item) {
                                newLeft.push( (parseFloat(ElementsMediator.getProperty(item._element, "left")) + inc) + "px"  );
                                return ElementsMediator.getProperty(item._element, "left");
                            });

                            ElementsMediator.setProperty(this.application.ninja.selectedElements, "left", newLeft , "Change", "selectionTool", leftArr);
                            break;
                        case Keyboard.DOWN:
                            var newTop = [];
                            var topArr = this.application.ninja.selectedElements.map(function(item) {
                                newTop.push( (parseFloat(ElementsMediator.getProperty(item._element, "top")) + inc) + "px"  );
                                return ElementsMediator.getProperty(item._element, "top");
                            });

                            ElementsMediator.setProperty(this.application.ninja.selectedElements, "top", newTop , "Change", "selectionTool", topArr);
                            break;
                        default:
                            return false;
                            break;
                    }


                } else {
                    // Try and capture the delete key so that the browser doesn't attempt an unwelcome history action.
                    if (event.keyCode == Keyboard.BACKSPACE) {
                        event.stopImmediatePropagation();
                        event.preventDefault();
                    }
                }
            }
            // console.log("Unhandled key press:", event.keyCode);

        }
    },

    _updateTargets: {
        value: function(addToUndoStack) {
            var newLeft = [],
                newTop = [],
                newWidth = [],
                newHeight = [],
                previousLeft = [],
                previousTop = [],
                previousWidth = [],
                previousHeight = [];
            var len = this.application.ninja.selectedElements.length;
            this._targets = [];
            for(var i = 0; i < len; i++)
            {
                var elt = this.application.ninja.selectedElements[i]._element;

                var curMat = viewUtils.getMatrixFromElement(elt);
                var curMatInv = glmat4.inverse(curMat, []);

                this._targets.push({elt:elt, mat:curMat, matInv:curMatInv});
                if(addToUndoStack)
                {
                    var previousMat = this._undoArray[i].mat.slice(0);
                    var prevX = this._undoArray[i]._x;
                    var prevY = this._undoArray[i]._y;
                    var prevW = this._undoArray[i]._w;
                    var prevH = this._undoArray[i]._h;
                    var _x = parseFloat(ElementsMediator.getProperty(elt, "left")) + curMat[12] - previousMat[12];
                    var _y = parseFloat(ElementsMediator.getProperty(elt, "top")) + curMat[13] - previousMat[13];
                    var _w = parseFloat(ElementsMediator.getProperty(elt, "width"));
                    var _h = parseFloat(ElementsMediator.getProperty(elt, "height"));

                    previousLeft.push(prevX + "px");
                    previousTop.push(prevY + "px");
                    previousWidth.push(prevW + "px");
                    previousHeight.push(prevH + "px");
                    newLeft.push(_x + "px");
                    newTop.push(_y + "px");
                    newWidth.push(_w + "px");
                    newHeight.push(_h + "px");

                    viewUtils.setMatrixForElement(elt, previousMat);
                }
            }
            if(addToUndoStack)
            {
                ElementsMediator.setProperties(this.application.ninja.selectedElements,
                                                { "left": newLeft, "top": newTop, "width": newWidth, "height": newHeight },
                                                "Change",
                                                "selectionTool",
                                                { "left" : previousLeft, "top" : previousTop, "width": previousWidth, "height": previousHeight}
                                              );
            }
            // Save previous value for undo/redo
            this._undoArray = [];
            for(i = 0, len = this._targets.length; i < len; i++)
            {
                var item = this._targets[i];
                var _x = parseFloat(ElementsMediator.getProperty(item.elt, "left"));
                var _y = parseFloat(ElementsMediator.getProperty(item.elt, "top"));
                var _w = parseFloat(ElementsMediator.getProperty(item.elt, "width"));
                var _h = parseFloat(ElementsMediator.getProperty(item.elt, "height"));
                var _mat = viewUtils.getMatrixFromElement(item.elt);
                this._undoArray.push({_x:_x, _y:_y, _w:_w, _h:_h, mat:_mat});
            }

        }
    },

    _moveElements: {
		value: function (transMat) {
			var len = this._targets.length,
				i,
				item,
				elt,
				curMat;

			var matInv = glmat4.inverse(this._startMat, []);
			var nMat = glmat4.multiply(transMat, this._startMat, [] );
			var qMat = glmat4.multiply(matInv, nMat, []);

            this._startMat = nMat;

			for(i = 0; i < len; i++)
			{
				item = this._targets[i];
				elt = item.elt;
				curMat = item.mat;

//                curMat = curMat.multiply(qMat);
				glmat4.multiply(curMat, qMat, curMat);

				viewUtils.setMatrixForElement( elt, curMat, true);

                this._targets[i].mat = curMat;
			}
            NJevent("elementChanging", {type : "Changing", redraw: false});
		}
	},

    //-------------------------------------------------------------------------
    //Routines to modify the selected objects
    modifyElements : {
        value : function(data, event)
        {
            var delta,
                deltaH,
                deltaW,
                deltaL,
                deltaT;
            if(this._handleMode !== null)
            {
                // 0  7  6
                // 1     5
                // 2  3  4
                switch(this._handleMode)
                {
                    case 0:
                        // Resize North-West
                        delta = ~~(data.pt1[0] - data.pt0[0]);
                        deltaW = this._undoArray.map(function(item) { return item._w + delta + "px"});
                        deltaL = this._undoArray.map(function(item) { return item._x + delta + "px"});
                        delta = ~~(data.pt1[1] - data.pt0[1]);
                        deltaH = this._undoArray.map(function(item) { return item._h - delta + "px"});
                        deltaT = this._undoArray.map(function(item) { return item._y + delta + "px"});
                        ElementsMediator.setProperties(this.application.ninja.selectedElements,
                                                        { "left": deltaL, "top": deltaT, "width": deltaW, "height": deltaH }, "Changing", "SelectionTool" );
                        break;
                    case 1:
                        // Resize West
                        delta = ~~(data.pt1[0] - data.pt0[0]);
                        deltaW = this._undoArray.map(function(item) { return item._w - delta + "px"});
                        deltaL = this._undoArray.map(function(item) { return item._x + delta + "px"});
                        ElementsMediator.setProperties(this.application.ninja.selectedElements,
                                                        { "left": deltaL, "width": deltaW }, "Changing", "SelectionTool" );
                        break;
                    case 2:
                        // Resize South-West
                        delta = ~~(data.pt1[0] - data.pt0[0]);
                        deltaW = this._undoArray.map(function(item) { return item._w - delta + "px"});
                        deltaL = this._undoArray.map(function(item) { return item._x + delta + "px"});
                        delta = ~~(data.pt1[1] - data.pt0[1]);
                        deltaH = this._undoArray.map(function(item) { return item._h + delta + "px"});
                        ElementsMediator.setProperties(this.application.ninja.selectedElements,
                                                        { "left": deltaL, "width": deltaW, "height": deltaH }, "Changing", "SelectionTool" );
                        break;
                    case 3:
                        // Resize South
                        delta = ~~(data.pt1[1] - data.pt0[1]);
                        deltaH = this._undoArray.map(function(item) { return item._h + delta + "px"});
                        ElementsMediator.setProperty(this.application.ninja.selectedElements, "height", deltaH, "Changing", "SelectionTool" );
                        break;
                    case 4:
                        // Resize South-East
                        delta = ~~(data.pt1[0] - data.pt0[0]);
                        deltaW = this._undoArray.map(function(item) { return item._w + delta + "px"});
                        delta = ~~(data.pt1[1] - data.pt0[1]);
                        deltaH = this._undoArray.map(function(item) { return item._h + delta + "px"});
                        ElementsMediator.setProperties(this.application.ninja.selectedElements, { "width": deltaW, "height": deltaH }, "Changing", "SelectionTool" );
                        break;
                    case 5:
                        // Resize East
                        delta = ~~(data.pt1[0] - data.pt0[0]);
                        deltaW = this._undoArray.map(function(item) { return item._w + delta + "px"});
                        ElementsMediator.setProperty(this.application.ninja.selectedElements, "width", deltaW, "Changing", "SelectionTool" );
                        break;
                    case 6:
                        // Resize North-East
                        delta = ~~(data.pt1[0] - data.pt0[0]);
                        deltaW = this._undoArray.map(function(item) { return item._w + delta + "px"});
                        delta = ~~(data.pt1[1] - data.pt0[1]);
                        deltaH = this._undoArray.map(function(item) { return item._h - delta + "px"});
                        deltaT = this._undoArray.map(function(item) { return item._y + delta + "px"});
                        ElementsMediator.setProperties(this.application.ninja.selectedElements,
                                                        { "top": deltaT, "width": deltaW, "height": deltaH }, "Changing", "SelectionTool" );
                        break;
                    case 7:
                        // Resize North
                        delta = ~~(data.pt1[1] - data.pt0[1]);
                        deltaH = this._undoArray.map(function(item) { return item._h - delta + "px"});
                        deltaT = this._undoArray.map(function(item) { return item._y + delta + "px"});
                        ElementsMediator.setProperties(this.application.ninja.selectedElements,
                                                        { "top": deltaT, "height": deltaH }, "Changing", "SelectionTool" );
                        break;
                    default:
                        break;
                }

                this._delta = delta;
            }
            else
            {
                // form the translation vector and post translate the matrix by it.
                delta = vecUtils.vecSubtract( 3, data.pt1, data.pt0 );
                var transMat = Matrix.Translation( delta );
                this._moveElements(transMat);
            }
        }
    },

    updateUsingSnappingData: {
        value: function(event) {
            var data;

            if(this._handleMode === null)
            {
                this.getUpdatedSnapPoint(event);
                if (this._mouseDownHitRec && this._mouseUpHitRec)
                {
                    data = this.getMousePoints();
                    if(data)
                    {
                        this.modifyElements(data, event);
                    }
                }
            }
            else
            {
                var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas,
                                                                new WebKitPoint(event.pageX, event.pageY));
                var do3DSnap = false;
                do3DSnap = event.ctrlKey || event.metaKey;

                this.mouseUpHitRec = DrawingToolBase.getUpdatedSnapPoint(point.x, point.y, do3DSnap, this.mouseDownHitRec);
                if (this._mouseDownHitRec && this._mouseUpHitRec)
                {
                    data = this.getDrawingData(event);
                    if(data)
                    {
                        this.modifyElements({pt0:data.mouseDownPos, pt1:data.mouseUpPos}, event);
                    }
                }
            }
        }
    },

    /*
 	 *  The parameterization is based on the position of the
 	 *  snap point in pre-transformed element screen space
 	 */
 	parameterizeSnap:
 	{
 		value: function( hitRec )
 		{
 			var paramPt = [0,0,0];
             var elt = this._getObjectBeingTracked(hitRec);
 			if (elt)
 			{
                this.clickedObject = elt;
                if(this._handleMode === null)
                {
                    var worldPt = hitRec.calculateStageWorldPoint();
                    MathUtils.makeDimension4( worldPt );
                    var mat = viewUtils.getObjToStageWorldMatrix( elt, true );
                    if(mat)
                    {
                        var invMat = glmat4.inverse(mat, []);
                        var scrPt = MathUtils.transformHomogeneousPoint( worldPt, invMat );
                        scrPt = MathUtils.applyHomogeneousCoordinate( scrPt );

                        var bounds = viewUtils.getElementViewBounds3D( elt );
                        var x0 = bounds[0][0],  x1 = bounds[3][0],
                            y0 = bounds[0][1],  y1 = bounds[1][1];
                        var dx = x1 - x0,   dy = y1 - y0;
                        var u = 0, v = 0;
                        if (MathUtils.fpSign(dx) != 0)
                            u = (scrPt[0] - x0) / dx;
                        if (MathUtils.fpSign(dy) != 0)
                            v = (scrPt[1] - y0) / dy;

                        paramPt[0] = u;
                        paramPt[1] = v;
                        paramPt[2] = scrPt[2];
                    }
                }
                else
                {
                    // 0  7  6
                    // 1     5
                    // 2  3  4
                    switch(this._handleMode)
                    {
                        case 0:
                            paramPt = [0,0,0];
                            break;
                        case 1:
                            paramPt = [0,0.5,0];
                            break;
                        case 2:
                            paramPt = [0,1,0];
                            break;
                        case 3:
                            paramPt = [0.5,1,0];
                            break;
                        case 4:
                            paramPt = [1,1,0];
                            break;
                        case 5:
                            paramPt = [1,0.5,0];
                            break;
                        case 6:
                            paramPt = [1,0,0];
                            break;
                        case 7:
                            paramPt = [0.5,0,0];
                            break;
                    }
                }
 			}

 			return paramPt;
 		}
 	},

    /**
     * This function is for specifying custom feedback routine
     * upon mouse over.
     * For example, the drawing tools will add a glow when mousing
     * over existing canvas elements to signal to the user that
     * the drawing operation will act on the targeted canvas.
     */
    _showFeedbackOnMouseMove : {
        value: function (event) {
            if(this._target && this._handles)
            {
                var len = this._handles.length;
                var i = 0,
                    toolHandle,
                    c,
                    point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas,
                                                            new WebKitPoint(event.pageX, event.pageY));
                for (i=0; i<len; i++)
                {
                    toolHandle = this._handles[i];
                    c = toolHandle.collidesWithPoint(point.x, point.y);
                    if(c)
                    {
                        this.application.ninja.stage.drawingCanvas.style.cursor = toolHandle._cursor;
                        this._handleMode = i;
                        return;
                    }
                }
            }

            this._handleMode = null;
   //            this.application.ninja.stage.drawingCanvas.style.cursor = this._cursor;
            this.application.ninja.stage.drawingCanvas.style.cursor = "auto";
        }
    },

    // TODO - This tool-specific customization should be somewhere else
    _initializeToolHandles: {
        value: function() {
            this.application.ninja.stage.stageDeps.snapManager.enableSnapAlign( false );
            this.application.ninja.stage.stageDeps.snapManager.enableElementSnap( false );
            this.application.ninja.stage.stageDeps.snapManager.enableGridSnap( false );
        }
    },

    // Should be an array of handles for each tool.
    // The array should contain ToolHandle objects that define
    // dimensions, cursor, functionality
    // For example, the Selection Tool holds the 8 resize handles in this order because this
    // is the order we retrieve a rectangle's points using viewUtils:
    // 0  7  6
    // 1     5
    // 2  3  4
    // Draw handles.  For now, we are setting up the selection/transform tool's handles in this base class
    // But it should probably be moved to the selection tool
    DrawHandles: {
        value: function (delta) {
            this.application.ninja.stage.clearDrawingCanvas();

            var item = this._target;
            if(!item || !this._showTransformHandles)
            {
                return;
            }

            if(!this._handles)
            {
                this._handles = [];

                // NorthWest
                var nw = toolHandleModule.ToolHandle.create();
                nw.init("NW-resize");
                this._handles.push(nw);

                // West
                var w = toolHandleModule.ToolHandle.create();
                w.init("W-resize");
                this._handles.push(w);

                // SouthWest
                var sw = toolHandleModule.ToolHandle.create();
                sw.init("SW-resize");
                this._handles.push(sw);

                // South
                var s = toolHandleModule.ToolHandle.create();
                s.init("S-resize");
                this._handles.push(s);

                // SouthEast
                var se = toolHandleModule.ToolHandle.create();
                se.init("SE-resize");
                this._handles.push(se);

                // East
                var e = toolHandleModule.ToolHandle.create();
                e.init("E-resize");
                this._handles.push(e);

                // NorthEast
                var ne = toolHandleModule.ToolHandle.create();
                ne.init("NE-resize");
                this._handles.push(ne);

                // North
                var n = toolHandleModule.ToolHandle.create();
                n.init("N-resize");
                this._handles.push(n);

            }


            viewUtils.setViewportObj( item );
            var bounds3D = viewUtils.getElementViewBounds3D( item );

            var zoomFactor = 1;
            var viewPort = this.application.ninja.stage._viewport;
            if (viewPort.style && viewPort.style.zoom)
            {
                zoomFactor = Number(viewPort.style.zoom);
            }
            var tmpMat = viewUtils.getLocalToGlobalMatrix( item );
            for (var j=0;  j<4;  j++)
            {
                var localPt = bounds3D[j];
                var tmpPt = viewUtils.localToGlobal2(localPt, tmpMat);

                if(zoomFactor !== 1)
                {
                    tmpPt = vecUtils.vecScale(3, tmpPt, zoomFactor);

                    tmpPt[0] += this.application.ninja.stage._scrollLeft*(zoomFactor - 1);
                    tmpPt[1] += this.application.ninja.stage._scrollTop*(zoomFactor - 1);
                }
                bounds3D[j] = tmpPt;
            }

            // Draw tool handles
            var context = this.application.ninja.stage.drawingContext;
            context.beginPath();

            // NW
            var x = bounds3D[0][0];
            var y = bounds3D[0][1];
            context.moveTo(x, y);
            this._handles[0].draw(x, y);

            var left = x;
            var top = y;

            if(delta)
            {
                context.font = "10px sans-serif";
                context.textAlign = "right";

                context.fillText("( " + (left - this.application.ninja.stage.userContentLeft) + " , " +
                                       (top - this.application.ninja.stage.userContentTop) + " )", x-10, y-4);
            }

            // W
            var pt = MathUtils.interpolateLine3D(bounds3D[0], bounds3D[1], 0.5);
            x = pt[0];
            y = pt[1];
            context.moveTo( x, y );
            this._handles[1].draw(x, y);

            // SW
            x = bounds3D[1][0];
            y = bounds3D[1][1];
            context.moveTo( x, y );
            this._handles[2].draw(x, y);

            // S
            pt = MathUtils.interpolateLine3D(bounds3D[1], bounds3D[2], 0.5);
            x = pt[0];
            y = pt[1];
            context.moveTo( x, y );
            this._handles[3].draw(x, y);

            // SE
            x = bounds3D[2][0];
            y = bounds3D[2][1];
            context.moveTo( x, y );
            this._handles[4].draw(x, y);

            if(delta)
            {
                context.fillText("H: " + (y - top), x+38, y - 4);
                context.fillText("W: " + (x - left), x-5, y + 12);
            }

            // E
            pt = MathUtils.interpolateLine3D(bounds3D[2], bounds3D[3], 0.5);
            x = pt[0];
            y = pt[1];
            context.moveTo( x, y );
            this._handles[5].draw(x, y);

            // NW
            x = bounds3D[3][0];
            y = bounds3D[3][1];
            context.moveTo( x, y );
            this._handles[6].draw(x, y);

            // N
            pt = MathUtils.interpolateLine3D(bounds3D[0], bounds3D[3], 0.5);
            x = pt[0];
            y = pt[1];
            context.moveTo( x, y );
            this._handles[7].draw(x, y);

            context.closePath();
        }
    },

    // TODO : Use the new element mediator to get element offsets
    _complicatedCollisionDetection:
	{
        value: function(elt, box)
		{
            var left, top, width, height;

            left = box[0];
			width = box[2] - left;
			if (width < 0)
			{
				left = box[2];
				width = -width;
			}
            top = box[1];
			height = box[3] - top;
			if (height < 0)
			{
				top = box[3];
				height = -height;
			}

            var rtnVal = MathUtils.rectsOverlap( [left,top], width, height,  elt );

            return rtnVal;
        }
    },

    // TODO : Use the new element mediator to get element offsets
    _simpleCollisionDetection: {
        value: function(ele, box){
            var left1, left2, right1, right2, top1, top2, bottom1, bottom2;

            left1 = ele.offsetLeft;
            left2 = box[0];
            right1 = ele.offsetLeft + ele.offsetWidth;
            right2 = box[2];
            top1 = ele.offsetTop;
            top2 = box[1];
            bottom1 = ele.offsetTop + ele.offsetHeight;
            bottom2 = box[3];

            if (bottom1 < top2) return false;
            if (top1 > bottom2) return false;
            if (right1 < left2) return false;
            if (left1 > right2) return false;

            return true;
        }
    }

});