"use strict";
var inputHandler = function() {
	var startAngle = []; // [alpha, beta, gamma]
	var actualAngle = []; // [alpha, beta, gamma]
	var gammaVec = []; // table of gamma values in interval of beta equal: 90 - off ... 90 + off
	var off = 25; // half of the range where the gyroscope gives uncertain values

	var KEY_CODES = {
		37 : 'left',
		39 : 'right',
		32 : 'fire',
		40 : 'down',
		38 : 'up',
		13 : 'enter'
	};

	/**
	 * Array of key codes for ship's movement
	 */
	var key = [39, 37, 40, 38]; // right, left, down, up

	/**
	 * Sets each direction's value to 1
	 */
	var resetDirection = function() {
		for ( var key in direction) {
			direction[key] = 1;
		}
	};

	/**
	 * direction Object defines possible multiplier for playerShip Vy
	 */
	var direction = {
		left : 1,
		up : 1,
		right : 1,
		down : 1
	};

	/**
	 * Sets the direction and velocity of the playerShip's movement
	 * 
	 * @param delta Number defines difference between initial and actual angles
	 * @param keyOn Number defines code of key which should be set true
	 * @param keyOff Number defines code of key which should be set false
	 */
	var setDirection = function(delta, keyOn, keyOff) {
		if (delta > 90)
			delta = 90; // 90 degrees maximum angle
		if (delta > config.angleOffset) {
			game.keys[KEY_CODES[keyOn]] = true;
			direction[KEY_CODES[keyOn]] = delta / 90;
		} else {
			game.keys[KEY_CODES[keyOn]] = false;
			direction[KEY_CODES[keyOn]] = 0;
		}
		game.keys[KEY_CODES[keyOff]] = false;
		direction[KEY_CODES[keyOff]] = 0;
	};

	/**
	 * Sets proper direction of ship's movement 
	 */
	
	var setUpAndDown = function() {
		var angle0 = startAngle[1]; // initial beta
		var angle1 = actualAngle[1]; // actual beta

		var delta = angle1 - angle0; 
		
		if (Math.abs(delta) < 180){
			if (delta < 0) {
				// down
				setDirection(Math.abs(delta), key[2], key[3]);
			} else {
				// up
				setDirection(Math.abs(delta), key[3], key[2]);
			}
		} else {
			if (angle0 < 0) {
				delta += 360;
				// up
				setDirection(Math.abs(delta), key[3], key[2]);
			} else {
				delta = 360 - delta;
				// down
				setDirection(Math.abs(delta), key[2], key[3]);
			}
		}
	};

	/**
	 * Sets proper direction of ship's movement
	 * 
	 * @param angle {Number} defines angle to count difference between this angle and initial angle
	 */

	var setRightAndLeft = function(angle) {
		var angle0 = startAngle[2];
		var angle1 = angle;
		var delta;

		delta = angle1 - angle0;

		if (delta > 0) {
			// left
			setDirection(Math.abs(delta), key[0], key[1]);
		} else {
			// right
			setDirection(Math.abs(delta), key[1], key[0]);
		}
	}

	/**
	 * Counts deviation, sets movement of ship and clears the array
	 * 
	 * @param trialsNumber {Number} Number of trails to count deviation of ship's initial position
	 */

	var countsForUncertainRange = function(trialsNumber) {
		var i, sr, sum;
		var offset = 20; // tolerable deviation from the average
		var isOut = true;

		while (isOut) {
			// if in previous iteration some element was removed from array clear previous results
			sum = 0;
			sr = 0;
			isOut = false;

			if (gammaVec.length != 0) {
				for (i = 0; i < gammaVec.length; i++)
					sum += gammaVec[i];

				sr = sum / gammaVec.length;

				for (i = 0; i < gammaVec.length; i++) {
					if ((gammaVec[i] > (sr + offset)) || (gammaVec[i] < (sr - offset))) {
						gammaVec.splice(i, 1);
						isOut = true; // means: at least one element was removed in this iteration
					}
				}
			}
		}

		if (sr != 0)
			setRightAndLeft(sr);

		gammaVec = [];
	};

	/**
	 * Sets proper value as parameter of setRightAndLeft() function
	 */
	var setHorizontal = function() {
		if (actualAngle[1] > (90 - off) && actualAngle[1] < (90 + off)) {
			// add actual angle position to gammaVec array
			gammaVec.push(actualAngle[2]);

			// if gammaVec array contains 20 elements -> count ship's movement parameter
			if (gammaVec.length == 20) {
				countsForUncertainRange(20);
			}
		} else {
			// if gammaVec array contains at least 20 elements -> count ship's movement parameter
			if (gammaVec.length >= 6) {
				countsForUncertainRange(gammaVec.length);
			} else {
				// in other case clear array
				gammaVec = [];
				setRightAndLeft(actualAngle[2]);
			}
		}
	};
	
	window.addEventListener('deviceorientation', function(e) {
		actualAngle[0] = e.alpha;
		if (startAngle[0] == undefined)
			startAngle[0] = actualAngle[0];

		var normGamma = e.gamma;
		var normBeta = e.beta;

		// Normalize values of angles
		if (view.isItAndroidWebView()) { // provide for Android
			if (normGamma > 0){ 
				if (normGamma < 90){
					normBeta = -normBeta;
				} else {
					if (normGamma < 180){
						normBeta = -180 + normBeta;
					} else {
						normBeta = 180 + normBeta;
					}
				}				
			} else {
				normBeta = -normBeta;
			}
			
			if (normGamma > 90)
				normGamma -= 180;

		} else { // provide for Tizen

			if (view.isItMobile()) {
				// for device
				if (normGamma >= -90 && normGamma <= 90) {
						normGamma = -normGamma;
				} else {
					if (normGamma >= 90 && normGamma <= 180)
						normGamma = 180 - normGamma;
					else if (normGamma >= -180 && normGamma <= -90)
						normGamma = -180 - normGamma;
				}
			} else {
				// For simulator
				normBeta = -normBeta;
				
				if (normGamma > 90)
					normGamma = -180 + normGamma;
				else if (normGamma < -90)
					normGamma += 180; 
			}
			
		}
		
		// Set normalized values for angles
		actualAngle[1] = normBeta;
		actualAngle[2] = normGamma;

		// if reference position 0,0 is disabled
		if (!config.gyroscopeCalibration) {
			// set initial position
			startAngle[1] = 0;
			startAngle[2] = 0;

		} else { // if should be set reference position for playerShip
			if (startAngle[1] == undefined)
				startAngle[1] = actualAngle[1];

			if (startAngle[2] == undefined)
				startAngle[2] = actualAngle[2];

		}

		setUpAndDown();
		setHorizontal();
	});

	document.getElementById('game').addEventListener('touchstart', function(e) {
		game.keys[KEY_CODES[32]] = true;
		e.preventDefault();
	}, false);

	document.getElementById('game').addEventListener('touchend', function(e) {
		var touchPoints = e.targetTouches.length;
		// if there are no touch points then turn off fire
		if (touchPoints === 0)
			game.keys[KEY_CODES[32]] = false;
		e.preventDefault();
	}, false);

//	 if (config.debug) {
//		 setInterval(function() {
//			 game.log('actual angle: ' + actualAngle[1] + ", start: " + startAngle[1]);
//			 game.log('act delta: ' + delta);
//		 }, 2000);
//	 }

	window.addEventListener('keydown', function(e) {
		resetDirection();
		if (KEY_CODES[e.keyCode]) {
			game.keys[KEY_CODES[e.keyCode]] = true;
			e.preventDefault();
		}
	}, false);

	window.addEventListener('keyup', function(e) {
		resetDirection();
		if (KEY_CODES[e.keyCode]) {
			game.keys[KEY_CODES[e.keyCode]] = false;
			e.preventDefault();
		}
	}, false);

	return {

		getDirection : function() {
			return direction;
		},

		/**
		 * clearStartPosition {Function} Resets set reference point
		 */
		clearStartPosition : function() {
			startAngle[0] = undefined;
			startAngle[1] = undefined;
			startAngle[2] = undefined;
		}
	};

};