/* globals angular */
'use strict';


angular.module('EnterpriseDashboardApp.WS', [
		'EnterpriseDashboardApp.Encoder'
	])
	.service('WS', function ProductResource($q, $rootScope, $log, $interval, $location, $window, $timeout, Encoder, HostFactory, Authentication) {

		function WS() {

			this.requestHashToPromise = {};
			this.webSocketUrl = HostFactory.getWebSocketUrl();
			this.open = false;

			this._connect();
		}

		WS.prototype._connect = function() {
			this.ws = new WebSocket(this.webSocketUrl);
			this.ws.onopen = this.getOnOpenHandler();
			this.ws.onclose = this.getOnCloseHandler();
			this.ws.onmessage = this.getOnMessageHandler();
		};

		WS.prototype.isOpen = function() {
			return this.open;
		};

		WS.prototype.getOnCloseHandler = function() {
			var self = this;
			return function() {
				var delay = 2000;

				self.open = false;
				if (!$window.timerID) {
					$window.timerID = $interval(function() {
						$log.info('Websocket disconnected! Trying to reconnect in ' + delay + 'ms');
						self._connect();
					}, delay);
				}

			};
		};

		WS.prototype.getOnMessageHandler = function() {
			var self = this;

			return function(msg) {

				var promiseToRun;

				msg = self.decode(msg);
				promiseToRun = self.requestHashToPromise[msg.hash];

				$log.debug('WS', 'Received message', msg);

				if (msg.response.statusCode === 401) {
					$log.debug('Unauthorized! Going to login...');
					return $location.path('/login');
				}

				if (promiseToRun) {
					if (msg.response.statusCode === 401) {
						return promiseToRun.reject(new Error('Unauthorized!'));
					}
					if (msg.response.statusCode === 500) {
						return promiseToRun.reject(new Error('Server error!'));
					}
					if (msg.response.statusCode === 200) {
						return promiseToRun.resolve(msg.response.body);
					}
					return;
				}

				if (msg.response.statusCode === 200) {
					$rootScope.$emit(Encoder.getEventNameByRequest(msg), msg.response.body);
				}
			};
		};

		WS.prototype.getOnOpenHandler = function() {
			var self = this;
			return function() {
				if ($window.timerID) {
					$interval.cancel($window.timerID);
					$window.timerID = 0;

				}
				self.open = true;
				$log.info('Websocket connected!');
			};
		};

		WS.prototype.stringifyRequest = function(obj) {
			var tmp,
				stringifiedRequest;

			tmp = JSON.parse(JSON.stringify(obj));
			delete tmp.hash;
			stringifiedRequest = JSON.stringify(tmp);

			return stringifiedRequest;
		};

		WS.prototype.decode = function(msg) {
			msg = msg.data || '{}';
			return JSON.parse(msg);
		};

		WS.prototype.send = function(objToSend) {
			var def, self;

			self = this;
			if (this.ws.readyState !== 1) {
				return $timeout(function() {
					return self.send(objToSend);
				}, 500);
			}

			def = $q.defer();
			objToSend.payload.hash = this.stringifyRequest(objToSend);

			this.ws.send(this.encode(objToSend));
			this.setPromiseToRunByHash(objToSend.payload.hash, def);

			return def.promise;
		};

		WS.prototype.encode = function(objToSend) {
			objToSend.payload.headers = {
				'Authorization': 'Bearer ' + Authentication.getAuthenticationToken()
			};
			return JSON.stringify(objToSend);
		};

		WS.prototype.setPromiseToRunByHash = function(hash, promise) {
			this.requestHashToPromise[hash] = promise;
		};

		return new WS();
	});
