var angular = require('angular');
require('../modules');
var emptyFn = function() {};

function initWebSocketState() {
  /* istanbul ignore if: untestable */
  if (typeof WebSocket.OPEN === 'undefined') {
    WebSocket.CONNECTING = 0;
    WebSocket.OPEN = 1;
    WebSocket.CLOSING = 2;
    WebSocket.CLOSED = 3;
  }
}

/**
 * @class ContinuousWebSocket
 *
 * 保持连接的WebScocket封装。
 *
 * @param {String} url       连接的url
 * @param {String} protocols websocket的连接协议
 */
function ContinuousWebSocket(url, protocols) {
  this.url = url;
  this.protocols = protocols;
  this.reallyClosed = false;
  this.prevConnected = false;
  initWebSocketState();
  this.buildWebSocket();
}

ContinuousWebSocket.prototype = {
  /**
   * @private
   * 构建WebSocket连接
   *
   */
  buildWebSocket: function() {
    console.log('请求建立socket链接。');
    /* istanbul ignore else*/
    if (this.reallyClosed) {
      return;
    }
    /* istanbul ignore else*/
    if ([WebSocket.CONNECTING, WebSocket.OPEN].indexOf(this.readyState) === -1) {
      this.prevConnected = false;
      if (this.protocols) {
        this.webSocket = new WebSocket(this.url, this.protocols);
      } else {
        this.webSocket = new WebSocket(this.url);
      }

      this.init();
    }
  },

  /**
   * WebSocket建立连接之后的初始化
   *
   */
  init: function() {
    var self = this;
    this.readyState = this.webSocket.readyState;
    this.bufferedAmount = this.webSocket.bufferedAmount;
    this.extensions = this.webSocket.extensions;
    this.protocol = this.webSocket.protocol;
    this.send = function() {
      if (this.readyState === WebSocket.OPEN) {
        var args = _.toArray(arguments);
        this.webSocket.send.apply(this.webSocket, args);
      }
    };

    function initEvent(eventName) {
      self.webSocket[eventName] = function() {
        self.readyState = self.webSocket.readyState;
        /* istanbul ignore else*/
        if (self.readyState === WebSocket.OPEN) {
          self.prevConnected = true;
        }
        self[eventName].apply(self.webSocket, arguments);
      };
    }
    initEvent('onopen');
    initEvent('onmessage');
    initEvent('onerror');

    this.webSocket.onclose = function() {
      self.readyState = self.webSocket.readyState;
      self.onclose.apply(self, arguments);
      /* istanbul ignore else*/
      if (self.prevConnected) {
        self.buildWebSocket();
      }
    };

    var closeFn = this.webSocket.close,
      ws = this.webSocket;
    ws.close = function() {
      closeFn.apply(ws, arguments);
      self.readyState = ws.readyState;
    };
  },

  onopen: emptyFn,
  onclose: emptyFn,
  onmessage: emptyFn,
  onerror: emptyFn,

  /**
   * 关闭WebSocket连接
   *
   * @param  {String} code   关闭原因代码
   * @param  {String} reason 关闭原因
   */
  close: function(code, reason) {
    this.readyState = WebSocket.CLOSED;
    this.reallyClosed = true;
    if (code) {
      this.webSocket.close(code, reason || '');
    } else {
      this.webSocket.close();
    }
    console.log('socket连接已关闭。');
  },

  /**
   * 打开WebSocket连接
   *
   */
  open: function() {
    this.reallyClosed = false;
    this.buildWebSocket();
  },

  /**
   * 改变WebSocket连接的url
   *
   * @param  {String} url 新的WebSocket URL
   */
  changeUrl: function(url) {
    this.close();
    this.url = url;
    this.open();
  }
};

angular.module('commons.services.common')
  .constant('ContinuousWebSocket', ContinuousWebSocket);

module.exports = ContinuousWebSocket;
