'use strict';

var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');

var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);

var _createClass2 = require('babel-runtime/helpers/createClass');

var _createClass3 = _interopRequireDefault(_createClass2);

var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');

var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);

var _inherits2 = require('babel-runtime/helpers/inherits');

var _inherits3 = _interopRequireDefault(_inherits2);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

var TYPE_PREFIX = '$CHANNEL_TYPE_';
var _uuid = 0;
var Emitter = require('events').EventEmitter;

var Channel = function (_Emitter) {
    (0, _inherits3.default)(Channel, _Emitter);

    function Channel() {
        (0, _classCallCheck3.default)(this, Channel);

        var _this = (0, _possibleConstructorReturn3.default)(this, Object.getPrototypeOf(Channel).call(this));

        _this.sockets = {};
        _this.indexMap = [];
        return _this;
    }

    (0, _createClass3.default)(Channel, [{
        key: 'has',
        value: function has(socket) {
            return !!(this.sockets[this.indexMap[0]] && this.sockets[this.indexMap[0]].socket === socket || this.sockets[this.indexMap[1]] && this.sockets[this.indexMap[1]].socket === socket);
        }

        //实现的效果就是一个channel里只能有两个socket
        //如果手动指定socket 的type 则是可以支持替换的，如果不手动指定type而是自动分配的话，那加满就不能再加入了

    }, {
        key: 'join',
        value: function join(socket, type) {
            if (!this.has(socket)) {
                var index = type !== undefined ? type : TYPE_PREFIX + _uuid++;
                var existed = this.sockets[index];
                if (existed) {
                    this.sockets[index] = { socket: socket, cache: [] };
                    this.emit('socket replaced', existed, socket);
                } else {
                    if (this.indexMap.length < 2) {

                        this.sockets[index] = { socket: socket, cache: [] };
                        this.indexMap.push(index);
                        this.emit('socket joined', socket);
                        this._flushCache();
                    } else {
                        console.warn('[Channel] Join Failed:channel is full.');
                    }
                }
            } else {
                console.warn('[Channel] Join Ignored:Try to join a existed socket');
            }
        }
    }, {
        key: 'clear',
        value: function clear() {
            this.sockets = [];
            this.indexMap = [];
        }
    }, {
        key: '_findIndex',
        value: function _findIndex(socket) {
            if (this.sockets[this.indexMap[0]] && this.sockets[this.indexMap[0]].socket === socket) {
                return 0;
            } else if (this.sockets[this.indexMap[1]] && this.sockets[this.indexMap[1]].socket === socket) {
                return 1;
            } else {
                return -1;
            }
        }
    }, {
        key: 'send',
        value: function send(socket, msg, disableCache) {
            var index = this._findIndex(socket);
            if (index != -1) {
                return this._send(index, msg, disableCache);
            } else {
                console.warn('[Channel] Send Failed:unknown socket');
                return 0;
            }
        }
    }, {
        key: 'sendByType',
        value: function sendByType(type, msg, disableCache) {
            return this.send(this.sockets[type].socket, msg, disableCache);
        }
    }, {
        key: '_send',
        value: function _send(index, msg, disableCache) {
            var theOther = this.sockets[this.indexMap[(index + 1) % 2]];
            if (theOther) {
                theOther.socket.send(msg);
                return 1;
            } else if (!disableCache) {
                this.sockets[this.indexMap[index]].cache.push(msg);
                return -1;
            }
        }
    }, {
        key: 'clearCache',
        value: function clearCache(socket) {
            if (socket) {
                var index = this._findIndex(socket);
                this.sockets[this.indexMap[index]].cache = [];
            } else {
                for (var k in this.sockets) {
                    if (this.sockets.hasOwnProperty(k)) {
                        this.sockets[k].cache = [];
                    }
                }
            }
        }
    }, {
        key: '_flushCache',
        value: function _flushCache() {
            if (this.indexMap.length == 2) {
                for (var i = 0; i < 2; i++) {
                    if (this.sockets[this.indexMap[i]] && this.sockets[this.indexMap[i]].cache.length > 0) {
                        var cache = this.sockets[this.indexMap[i]].cache;
                        this.sockets[this.indexMap[i]].cache = [];
                        for (var j = 0; j < cache.length; j++) {
                            this._send(i, cache[j]);
                        }
                    }
                }
            }
        }
    }, {
        key: 'leave',
        value: function leave(socket) {
            var index = this._findIndex(socket);
            if (index >= 0) {
                delete this.sockets[this.indexMap[index]];
                this.indexMap = [this.indexMap[(index + 1) % 2]];
            } else {
                console.warn('[Channel] Remove Ignored: this socket not found in the chanel');
            }
        }
    }]);
    return Channel;
}(Emitter);

Channel.MASTER = 0;
Channel.SLAVER = 1;
module.exports = Channel;