/* <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,
    drawUtils = require("js/helper-classes/3D/draw-utils").DrawUtils,
    vecUtils = require("js/helper-classes/3D/vec-utils").VecUtils,
    viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils,
    snapManager = require("js/helper-classes/3D/snap-manager").SnapManager,
    Keyboard = require("js/mediators/keyboard-mediator").Keyboard;
    toolBase = require("js/tools/ToolBase").toolBase;

exports.PanTool = Montage.create(toolBase,
{
	_localPt :{value: [0,0] , writable:true},
	_worldPt :{value: [0,0] , writable:true},
	_globalPt :{value: [0,0] , writable:true},
	_globalToUCWorld :{value: [] , writable:true},
	_lastGPt :{value: [0,0], writable:true},
	_lastY :{value: 0, writable:true},

    Configure: {
        value: function ( doActivate )
		{
			if (doActivate)
			{
				NJevent("enableStageMove");
				this.eventManager.addEventListener( "toolDoubleClick", this, false);
				this.application.ninja.stage.canvas.addEventListener("mousewheel", this, false);
				this.activate();
			}
			else
			{
				NJevent("disableStageMove");
                this.eventManager.removeEventListener( "toolDoubleClick", this, false);
				this.application.ninja.stage.canvas.removeEventListener("mousewheel", this, false);
				this.deactivate();
			}
        }
    },

    HandleLeftButtonDown: {
        value : function ( event ) {
            this._isDrawing = true;
			this.isDrawing = true;
 
				this.mouseDown( event );
       }
    },

    HandleMouseMove:
	{
        value : function (event)
		{
			this.mouseMove( event );
		}
	},

    HandleLeftButtonUp:
	{
        value : function ( event )
		{
            //if(this._isDrawing)
			{
				// do one final mouse move to update the scrollbars
				this.mouseUp( event );
               
			    this.application.ninja.stage.clearDrawingCanvas();
                this._hasDraw = false;
                this._isDrawing = false;
                this.isDrawing = false;
            }
        }
    },

    HandleKeyPress: {
        value: function(event) {
            if(event.altKey)
			{
                this._altKeyDown = true;
            }
			else if (event.shiftKey)
			{
				if (!this._shiftKeyDown)
				{
						this._shiftKeyDown = true;
						this._shiftPt = this._lastGPt.slice();
				}
			}
        }
    },

    HandleKeyUp: {
        value: function(event) {
            if(event.keyCode === Keyboard.ALT)
			{
                this._altKeyDown = false;
            }
			else if (event.keyCode === Keyboard.SHIFT)
			{
				this._shiftKeyDown = false;
			}
        }
    },

    handleToolDoubleClick:
	{
        value: function ()
		{
			var uc = this.application.ninja.currentDocument.documentRoot;
			//var uc = documentManagerModule.DocumentManager.activeDocument
			var ucMat = viewUtils.getMatrixFromElement(uc);

			var noTrans = ucMat.slice();
			noTrans[12] = 0;  noTrans[13] = 0;  noTrans[14] = 0;
			var ucMatInv = glmat4.inverse( ucMat, [] );
			var deltaMat = glmat4.multiply( noTrans, ucMatInv, [] );

            this.application.ninja.stage.centerStage();

			this.applyDeltaMat( deltaMat );
        }
    },

    handleMousewheel :
	{
        value:function(event)
		{
			var zoom = this.application.ninja.documentBar.zoomFactor/100.0;
			if (!zoom)  zoom = 1.0;

			var delta = 0;
			if (event.wheelDelta)
				delta = 10*event.wheelDelta/120;
			//console.log( "delta: " + delta );

            this.application.ninja.stage._iframeContainer.scrollLeft += delta;
            this.application.ninja.stage._scrollLeft += delta;

			delta *= zoom;
           
			var uc = this.application.ninja.currentDocument.documentRoot;
			var ucMat = viewUtils.getMatrixFromElement(uc);
			var offset = viewUtils.getElementOffset( uc );
			//console.log( "uc offset: " + offset[0] );

			var localToGlobalMat = viewUtils.getLocalToGlobalMatrix( uc );
			var globalToLocalMat = glmat4.inverse( localToGlobalMat, []);

			var w = uc.offsetWidth,
				h = uc.offsetHeight;
			if(uc.width)
				w = uc.width;
			if(uc.height)
				h = uc.height;
			var localPt = [ w/2,  h/2, 0];
			var globalPt = MathUtils.transformAndDivideHomogeneousPoint( localPt,  localToGlobalMat );
			this.doMouseDown( { x:globalPt[0],  y:globalPt[1] } );

			globalPt[0] += delta;
			this._isDrawing = true;
			this.doMouseMove( { x:globalPt[0],  y:globalPt[1] } );
			this._isDrawing = false;
        }
    },


	/////////////////////////////////////////////////////////////////////
	// Simple tool API
	activate:
	{
		value: function()
		{
			//console.log( "PanTool.activate" );
		}
	},

	deactivate:
	{
		value: function()
		{
			//console.log( "PanTool.deactivate" );
		}
	},

	mouseDown:
	{
		value: function( event )
		{
			//console.log( "PanTool.mouseDown" );
			if (!this.application.ninja.currentDocument)  return;

            var point = webkitConvertPointFromPageToNode(this.application.ninja.stage.canvas,
                                                        new WebKitPoint(event.pageX, event.pageY));
			this.doMouseDown( point );
		}
	},
			

	doMouseDown:
	{
		value: function( point )
		{
			//var tmpPt, tmpPt2, tmpPt3, tmpPt4, tmpMat, tmpMat2;	// DEBUG. (see use of these points below)
			var hitRec = snapManager.snap( point.x, point.y, true );
			if (hitRec)
			{
				//console.log( "hit: " + hitRec.getElement().id );
				var globalPt = [point.x, point.y];
				var elt = hitRec.getElement();
				if (elt)
				{
					// get the userContent object (stage) and its matrix
					var userContent = this.application.ninja.currentDocument.documentRoot;
					var ucMat = viewUtils.getMatrixFromElement(userContent);

					var localToGlobalMat = viewUtils.getLocalToGlobalMatrix( elt );
					var globalToLocalMat = glmat4.inverse( localToGlobalMat, []);

					if (elt != userContent)
						this._localPt = hitRec.calculateElementPreTransformScreenPoint();
					else
					{
						var localPt = hitRec.calculateElementWorldPoint();
						viewUtils.pushViewportObj( userContent );
						var cop = viewUtils.getCenterOfProjection();
						this._localPt = [cop[0] + localPt[0],  cop[1] + localPt[1],  localPt[2]];
						viewUtils.popViewportObj();
					}
					this._globalPt = MathUtils.transformAndDivideHomogeneousPoint( this._localPt,  localToGlobalMat );
					var tmpLocal   = MathUtils.transformAndDivideHomogeneousPoint( this._globalPt, globalToLocalMat );

					this._lastGPt = this._globalPt.slice();
					this._shiftPt = this._lastGPt.slice();
					this._lastY = this._lastGPt[1];

					// set up the matrices we will be needing
					var eltToStageWorldMat = glmat4.multiply( ucMat, viewUtils.getObjToStageWorldMatrix(elt, true), []);
					this._worldPt = MathUtils.transformAndDivideHomogeneousPoint( this._localPt,  eltToStageWorldMat );
//					console.log( "screenPt: " + globalPt );
//					console.log( "_worldPt: " + this._worldPt );
//					console.log( "_localPt: " + this._localPt );
//					console.log( "_globalPt: " + this._globalPt );
//					console.log( "hit localPt: " + hitRec.calculateElementPreTransformScreenPoint() );

					// get a matrix from user content world space to the screen
					viewUtils.pushViewportObj( userContent );
					var cop = viewUtils.getCenterOfProjection();
					var pDist = viewUtils.getPerspectiveDistFromElement(userContent);
					var projMat = glmat4.scale(Matrix.I(4), [pDist,pDist,pDist], []);
					projMat[11] = -1;
					projMat[15] = 1400;
					var v2s = Matrix.Translation([cop[0], cop[1], 0]);
					var ucWorldToGlobal = glmat4.multiply( v2s, projMat, [] );
					var offset = viewUtils.getElementOffset( userContent );
					var offMat = Matrix.Translation([offset[0], offset[1], 0]);
					glmat4.multiply( offMat, ucWorldToGlobal, ucWorldToGlobal );
					this._globalToUCWorld = glmat4.inverse(ucWorldToGlobal, []);
					viewUtils.popViewportObj();

					/*
					tmpPt = MathUtils.transformAndDivideHomogeneousPoint( this._globalPt, this._globalToUCWorld );	// DEBUG - tmpPt should equal this._worldPt
					tmpPt2 = MathUtils.transformAndDivideHomogeneousPoint( this._worldPt, ucWorldToGlobal );	// DEBUG - tmpPt2 should equal globalPt
					tmpPt3 = viewUtils.localToGlobal( this._localPt,  elt );
					tmpPt4 = MathUtils.transformAndDivideHomogeneousPoint( tmpPt3, this._globalToUCWorld );
					tmpMat = glmat4.multiply(ucWorldToGlobal,  eltToStageWorldMat, []);
					tmpMat2 = viewUtils.getLocalToGlobalMatrix( elt );
					*/
				}
			}
		}
	},

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

		}
	},

	doMouseMove:
	{
		value: function( point )
		{
			if (this._isDrawing)
			{
				// get the global screen point
				var gPt = [point.x, point.y, this._globalPt[2]];
				if (this._altKeyDown)
				{
					var dy = 5*(point.y - this._lastY);
					this._globalPt[2] += dy;
					gPt = [this._lastGPt[0], this._lastGPt[1], this._globalPt[2]];
				}
				else if (this._shiftKeyDown)
				{
					var dx = Math.abs( this._shiftPt[0] - gPt[0] ),
						dy = Math.abs( this._shiftPt[1] - gPt[1] );

					if (dx >= dy)
						gPt[1] = this._shiftPt[1];
					else
						gPt[0] = this._shiftPt[0];
				}

				// update the scrollbars
				var deltaGPt = VecUtils.vecSubtract(2, gPt, this._lastGPt);
				this._lastGPt = gPt.slice();
				this._lastY = point.y;

				var oldLeft = this.application.ninja.stage._iframeContainer.scrollLeft,
					oldTop  = this.application.ninja.stage._iframeContainer.scrollTop;
				this.application.ninja.stage._iframeContainer.scrollLeft -= deltaGPt[0];
				this.application.ninja.stage._iframeContainer.scrollTop  -= deltaGPt[1];
				deltaGPt[0] = oldLeft - this.application.ninja.stage._iframeContainer.scrollLeft;
				deltaGPt[1] = oldTop  - this.application.ninja.stage._iframeContainer.scrollTop;

				gPt[0] -= deltaGPt[0];
				gPt[1] -= deltaGPt[1];

				this.updateGlobalToUCWorldMatrix();

				var wPt = MathUtils.transformAndDivideHomogeneousPoint( gPt, this._globalToUCWorld );
				var delta = vecUtils.vecSubtract( 3, wPt, this._worldPt );
				
				if (!this._altKeyDown)
					delta[2] = 0;
				var transMat = Matrix.Translation( delta );
				this._worldPt = wPt;

				// update everything
				this.applyDeltaMat( transMat );
			}
		}
	},

	mouseUp:
	{
		value: function( event )
		{
			//console.log( "PanTool.mouseUp" );
			this.application.ninja.stage.updatedStage = true;
		}
	},

	applyDeltaMat:
	{
		value: function( transMat )
		{
			// update the user content matrix
			var uc = this.application.ninja.currentDocument.documentRoot;
			var ucMat = viewUtils.getMatrixFromElement(uc);
			var newUCMat = glmat4.multiply( transMat, ucMat, [] );
			viewUtils.setMatrixForElement( uc, newUCMat );

			// redraw everything
			this.application.ninja.stage.updatedStage = true;
		}
	},

	updateGlobalToUCWorldMatrix:
	{
		value: function()
		{
			// get the userContent object
			var userContent = this.application.ninja.currentDocument.documentRoot;

			// get a matrix from user content world space to the screen
			viewUtils.pushViewportObj( userContent );
			var cop = viewUtils.getCenterOfProjection();
			var pDist = viewUtils.getPerspectiveDistFromElement(userContent);
			var projMat = glmat4.scale(Matrix.I(4), [pDist,pDist,pDist], []);
			projMat[11] = -1;
			projMat[15] = 1400;
			var v2s = Matrix.Translation([cop[0], cop[1], 0]);
			var ucWorldToGlobal = glmat4.multiply( v2s, projMat, [] );
			var offset = viewUtils.getElementOffset( userContent );
			var offMat = Matrix.Translation([offset[0], offset[1], 0]);
			glmat4.multiply( offMat, ucWorldToGlobal, ucWorldToGlobal );
			this._globalToUCWorld = glmat4.inverse(ucWorldToGlobal, []);
			viewUtils.popViewportObj();
		}
	}
}
);