/* <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> */

/* Base class for the 3D translate tools
Subclass TranslateObject3DTool will translate the object that was clicked.
*/
var Montage = require("montage/core/core").Montage,
    ModifierToolBase = require("js/tools/modifier-tool-base").ModifierToolBase,
    toolHandleModule = require("js/stage/tool-handle"),
    viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils,
    vecUtils = require("js/helper-classes/3D/vec-utils").VecUtils,
    drawUtils = require("js/helper-classes/3D/draw-utils").DrawUtils,
    ElementsMediator = require("js/mediators/element-mediator").ElementMediator;

exports.Translate3DToolBase = Montage.create(ModifierToolBase,
{
	_inLocalMode: { value: true, enumerable: true },
	_clickedOnStage: { value: false },

	HandleDoubleClick : {
	   value : function()
	   {
	   }
	},

    modifyElements : {
		value : function(data, event)
        {
            //console.log( "modifyElements, data: " + data.pt0 + " => " + data.pt1 );

            // form the translation vector and post translate the matrix by it.
            var delta = vecUtils.vecSubtract( 3, data.pt1, data.pt0 );
            if(this._handleMode !== null)
            {
                switch(this._handleMode)
                {
                    case 0:
                        delta[1] = 0;
                        delta[2] = 0;
                        break;
                    case 1:
                        delta[0] = 0;
                        delta[2] = 0;
                        break;
                    case 2:
                        delta[0] = 0;
                        delta[1] = 0;
                        break;
                }
                if( (this.application.ninja.selectedElements.length > 1) && this._clickedOnStage )
                {
                    this._delta = ~~(delta[this._handleMode]);
                }
                else
                {
                    this._delta += ~~(delta[this._handleMode]);
                }

            }
            else
            {
                if(this._mode === 1)
                {
                    delta[2] = delta[1];
                    delta[0] = 0;
                    delta[1] = 0;
                }
                this._delta = delta.slice(0);
            }

            var transMat = Matrix.Translation( delta );

            //console.log( "Translate: " + delta );
            if(this._inLocalMode && (this._targets.length === 1) )
            {
                this._translateLocally(transMat);
            }
            else
            {
                this._translateGlobally(transMat);
            }
        }
	},


	Reset : {
		value : function()
		{
            var item,
                mat,
                dist,
                newStyles = [],
                previousStyles = [],
                len = this.application.ninja.selectedElements.length;
            for(var i = 0; i < len; i++)
            {
                // Reset to the identity matrix but retain the rotation values
                item = this.application.ninja.selectedElements[i];
                mat = ElementsMediator.getMatrix(item);
                mat[12] = 0;
                mat[13] = 0;
                mat[14] = 0;

                dist = ElementsMediator.getPerspectiveDist(item);

                var previousStyleStr = {dist:dist, mat:item.mat};

                var newStyleStr = {dist:dist, mat:mat};

                previousStyles.push(previousStyleStr);
                newStyles.push(newStyleStr);
            }

            ElementsMediator.set3DProperties(this.application.ninja.selectedElements,
                                            newStyles,
                                            "Change",
                                            "translateTool",
                                            previousStyles
                                          );

			this.isDrawing = false;
            this.endDraw(event);


            // Need to force stage to draw immediately so the new selection center is calculated
            this.application.ninja.stage.draw();
            // And captureSelectionDrawn to draw the transform handles
            this.captureSelectionDrawn(null);
		}
	},

	// We will only translate single elements locally
	_translateLocally: {
		value: function (transMat) {
            //console.log( "_translateLocally, startMat: " + this._startMat );
            //console.log( "_translateLocally, transMat: " + transMat );
            //console.log( "_translateLocally, startMat: " + this._startMat + ", transMat: " + transMat );
			var mat = glmat4.multiply(this._startMat, transMat, []);
			viewUtils.setMatrixForElement( this._target, mat, true );
			if(this._mode !== 1)
			{
				this._startMat = mat;
			}
		}
	},

	_translateGlobally: {
		value: function (transMat) {
            //console.log( "_translateGlobally, startMat: " + this._startMat + ", transMat: " + transMat );
            //console.log( "_translateGlobally, transMat: " + transMat );
			var len = this._targets.length,
				i = 0,
				item,
				elt,
				curMat = viewUtils.getMatrixFromElement( this._target ),
                matInv = glmat4.inverse(this._startMat, []),
                nMat = glmat4.multiply(transMat, this._startMat, [] ),
			    qMat = glmat4.multiply(matInv, nMat, []);
           
            if (this._mode === 1)
            { 
                var curInv = glmat4.inverse( curMat, [] );
                transMat = glmat4.multiply( nMat, curInv, [] );
            }

			var shouldUpdateStartMat = true;

			if(this._clickedOnStage)
			{
				shouldUpdateStartMat = false;
			}
			else if(this._mode !== 1)
			{
				this._startMat = nMat;
			}

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

//				glmat4.multiply(curMat, qMat, curMat);
//
//				viewUtils.setMatrixForElement( elt, curMat, true);
                curMat[12] += transMat[12];
                curMat[13] += transMat[13];
                curMat[14] += transMat[14];
                viewUtils.setMatrixForElement( elt, curMat, true);

				if(shouldUpdateStartMat)
				{
                    //console.log(  "\t\tshouldUpdateStartMat" );
					this._targets[i].mat = curMat;
				}
			}
		}
	},

    _updateTargets: {
		value: function(addToUndoStack) {
//            console.log( "_updateTargets" );
            var newStyles = [],
                previousStyles = [],
			    len = this.application.ninja.selectedElements.length;
			this._targets = [];
			for(var i = 0; i < len; i++)
			{
				var elt = this.application.ninja.selectedElements[i];

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

				this._targets.push({elt:elt, mat:curMat, matInv:curMatInv});
                if(addToUndoStack)
                {
                    var previousStyleStr = {dist:this._undoArray[i].dist, mat:MathUtils.scientificToDecimal(this._undoArray[i].mat.slice(0), 5)};

                    var newStyleStr = {dist:viewUtils.getPerspectiveDistFromElement(elt), mat:MathUtils.scientificToDecimal(curMat, 5)};

                    previousStyles.push(previousStyleStr);
                    newStyles.push(newStyleStr);
                }
			}
			if(addToUndoStack)
			{
                ElementsMediator.set3DProperties(this.application.ninja.selectedElements,
                                                newStyles,
                                                "Change",
                                                "translateTool",
                                                previousStyles
                                              );
                if(this._origin && this._delta)
                {
                    if(this._handleMode !== null)
                    {
                        this._origin[this._handleMode] += this._delta;
                    }
                    else
                    {
                        this._origin[0] += this._delta[0];
                        this._origin[1] += this._delta[1];
                    }
                }
                this._delta = null;
            }
            // Save previous value for undo/redo
            this._undoArray = [];
            for(i = 0, len = this._targets.length; i < len; i++)
            {
                var elt = this._targets[i].elt;
                var _mat = viewUtils.getMatrixFromElement(elt);
                var _dist = viewUtils.getPerspectiveDistFromElement(elt);
                this._undoArray.push({mat:_mat, dist:_dist});
            }

		}
	},

	HandleAltKeyDown: {
		value: function(event) {
			this._inLocalMode = !this._inLocalMode;
			this.DrawHandles();
		}
	},

	HandleAltKeyUp: {
		value: function(event) {
			this._inLocalMode = !this._inLocalMode;
			this.DrawHandles();
		}
	},

	handleScroll: {
		value: function(event) {
			this.captureSelectionDrawn(null);
		}
	},

	_updateHandlesOrigin: {
		value: function () {
			var ctr;

			var len = this.application.ninja.selectedElements.length;
			if(len > 0)
			{
				if(len === 1)
				{
					var item = this._target;
					viewUtils.pushViewportObj( item );
					ctr = viewUtils.getCenterOfProjection();
					viewUtils.popViewportObj();
					ctr[2] = 0;

//					var ctrOffset = item.elementModel.props3D.m_transformCtr;
//					if(ctrOffset)
//					{
//						ctr = vecUtils.vecAdd(3, ctr, ctrOffset);
//					}

					this._origin = viewUtils.localToGlobal(ctr, item);
				}
				else
				{
                    if(this._origin)
                    {
                        if(this._delta)
                        {
                            if(this._handleMode !== null)
                            {
//                                this._origin[this._handleMode] = this._delta;
                            }
                            else
                            {
                                this._origin[0] += this._delta[0];
                                this._origin[1] += this._delta[1];
                            }
                        }
                    }
                    else
                    {
                        this._origin = drawUtils._selectionCtr.slice(0);
                        this._origin[0] += this.application.ninja.stage.userContentLeft;
                        this._origin[1] += this.application.ninja.stage.userContentTop;
                    }
				}
			}
		}
	},

	DrawHandles: {
		value: function (delta) {
			this.application.ninja.stage.clearDrawingCanvas();

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

				// TODO - Using dummy cursors for now

				// translateX
				var rX = toolHandleModule.TranslateHandle.create();
				rX.init("url('images/cursors/Translate_X.png') 0 0, default", 'rgba(255,0,0,1)', "x");
				this._handles.push(rX);

				// translateY
				var rY = toolHandleModule.TranslateHandle.create();
				rY.init("url('images/cursors/Translate_Y.png') 0 0, default", 'rgba(0,255,0,1)', "y");
				this._handles.push(rY);

				// translateZ
				var rZ = toolHandleModule.TranslateHandle.create();
				rZ.init("url('images/cursors/Translate_Z.png') 0 0, default", 'rgba(0,0,255,1)', "z");
				this._handles.push(rZ);
			}

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

			// Draw tool handles

            this._updateHandlesOrigin();
			var base = this._origin.slice(0);

			var len = this.application.ninja.selectedElements.length;
			var lMode = this._inLocalMode;
			if(len === 1)
			{
				viewUtils.pushViewportObj( item );
			}
			else
			{
				lMode = false;
				viewUtils.pushViewportObj( this.application.ninja.currentDocument.documentRoot );
			}

			if(this._handleMode !== null)
			{
				switch(this._handleMode)
				{
					case 0:
						this._handles[1]._strokeStyle = 'rgba(0, 255, 0, 0.2)';
						this._handles[2]._strokeStyle = 'rgba(0, 0, 255, 0.2)';
						break;
					case 1:
						this._handles[0]._strokeStyle = 'rgba(255, 0, 0, 0.2)';
						this._handles[2]._strokeStyle = 'rgba(0, 0, 255, 0.2)';
						break;
					case 2:
						this._handles[0]._strokeStyle = 'rgba(255, 0, 0, 0.2)';
						this._handles[1]._strokeStyle = 'rgba(0, 255, 0, 0.2)';
						break;
				}
                if( delta && (len > 1) )
                {
                    base[this._handleMode] += ~~delta;
                }
			}
			this._handles[0].draw(base, item, lMode);
			this._handles[1].draw(base, item, lMode);
			this._handles[2].draw(base, item, lMode);

			if(delta && (this._handleMode !== null))
			{
				this._handles[this._handleMode].drawDelta(~~delta);
			}

			this._handles[0]._strokeStyle = 'rgba(255, 0, 0, 1)';
			this._handles[1]._strokeStyle = 'rgba(0, 255, 0, 1)';
			this._handles[2]._strokeStyle = 'rgba(0, 0, 255, 1)';

			viewUtils.popViewportObj();
		}
	}
	
});