"use strict";
var EXPORTED_SYMBOLS = ["module"];
var module = function (application) {
var log = function (message) {
application.logger.trace("[Windows Juggler] " + message);
}
;
const ACCELERATION = {
FORWARD: 400,
BACKWARD: 500};
const MOVEMENT_TIME_STEP = 30;
function WindowsJuggler() {
this._currentMovementData = {
};
this._movementTimer = null;
this._isBackwardMove = false;
}

WindowsJuggler.prototype = {
constructor: WindowsJuggler,
moveWindows: function WindowsJuggler_moveWindows(params) {
var juggler = this;
var windows = params.windows;
var vector = params.vector;
var acceleration = params.acceleration;
var callback = params.callback;
var checkPosition = params.checkPosition;
var movementData = this._currentMovementData = {
};
movementData.windows = windows;
movementData.callback = callback;
var initialCoordinates = windows.map(function (window) {
return {
x: window.screenX,
y: window.screenY};
}
);
var ySign = Math.abs(vector.y) / vector.y;
var getXCoordinate = function (x) 0;
var getYCoordinate = this.getUniformlyAcceleratedMovementFunction(0,acceleration * ySign);
var stopFlag = false;
log("Start movement " + vector);
var timer = Components.classes["@mozilla.org/timer;1"].createInstance(Components.interfaces.nsITimer);
timer.init({
observe: function () {
var shift = new juggler.Vector(getXCoordinate(0), getYCoordinate(0));
if (Math.abs(shift.x) > Math.abs(vector.x) || Math.abs(shift.y) > Math.abs(vector.y))
{
stopFlag = true;
shift = vector;
}

if ("function" == typeof checkPosition)
{
let check = checkPosition(shift);
if (true === check.stop)
{
stopFlag = true;
shift.x = check.shift.x || vector.x;
shift.y = check.shift.y || vector.y;
}

}

log("Shift is " + shift);
movementData.alreadyMoved = shift;
windows.forEach(function (window, index) {
var initialWindowPosition = initialCoordinates[index];
window.moveTo(initialWindowPosition.x + shift.x,initialWindowPosition.y + shift.y);
}
);
if (stopFlag)
{
juggler.stopMovement();
if ("function" == typeof callback)
{
callback.call(null);
}

}

}
},MOVEMENT_TIME_STEP,timer.TYPE_REPEATING_SLACK);
this._movementTimer = timer;
}
,
moveWindowsInDirection: function WindowsJuggler_moveWindowsInDirection(params) {
this.moveWindows({
windows: params.windows,
vector: this.getVector(params.direction,params.distance),
acceleration: ACCELERATION.FORWARD,
callback: params.callback});
}
,
stopMovement: function WindowsJuggler_stopMovement() {
if (! this.isMoving)
return;
log("Stop movement.");
this._movementTimer.cancel();
this._movementTimer = null;
}
,
cancelWindowsMovement: function WindowsJuggler_cancelMovement() {
if (! this.isMoving)
return;
if (this._isBackwardMove)
return;
this.stopMovement();
var data = this._currentMovementData;
var alreadyMoved = data.alreadyMoved;
this._isBackwardMove = true;
var self = this;
this.moveWindows({
windows: data.windows,
vector: new this.Vector(- alreadyMoved.x, - alreadyMoved.y),
acceleration: ACCELERATION.BACKWARD,
callback: function () {
self._isBackwardMove = false;
}
});
}
,
fallDown: function WindowsJuggler_fallDown(windows, continueFalling, onComplete) {
const BIG_NUMBER = 100000000;
this.moveWindows({
windows: windows,
vector: new this.Vector(0, BIG_NUMBER),
callback: onComplete,
acceleration: ACCELERATION.FORWARD,
checkPosition: continueFalling});
}
,
getVector: function WindowsJuggler_getVector(direction, distance) {
var x = 0, y = 0;
if (this.isVerticalDirection(direction))
{
y = distance;
}
 else
{
x = distance;
}

if (this.isDecreasingDirection(direction))
{
x *= - 1;
y *= - 1;
}

return new this.Vector(x, y);
}
,
get isMoving() {
return null !== this._movementTimer;
}
,
getUniformlyAcceleratedMovementFunction: function WindowsJuggler_getUniformlyAcceleratedMovementFunction(initialSpeed, acceleration) {
var startTime;
var normalizedSpeed = initialSpeed / 1000;
var normalizedAcceleration = acceleration / 1000 / 1000;
return function (startPoint) {
var currentTime = Date.now();
if ("undefined" == typeof startTime)
{
startTime = currentTime;
}

var timeInterval = currentTime - startTime;
return startPoint + normalizedSpeed * timeInterval + normalizedAcceleration * timeInterval * timeInterval / 2;
}
;
}
,
isDecreasingDirection: function WindowsJuggler_isDecreasingDirection(direction) {
return "up" === direction || "left" === direction;
}
,
isVerticalDirection: function WindowsJuggler_isVerticalDirection(direction) {
return "up" === direction || "down" === direction;
}
,
isHorizontalDirection: function WindowsJuggler_isHorizontalDirection(direction) {
return "right" === direction || "left" === direction;
}
,
__mailman: null,
get _mailman() {
return this.__mailman ? this.__mailman : (this.__mailman = application.loadModule("Mailman"));
}
,
_Vector: null,
get Vector() {
return this._Vector ? this._Vector : (this._Vector = application.loadModule("Vector"));
}
};
return new WindowsJuggler();
}
;
