var EventEmitter = require('events').EventEmitter;
var util = require('util');
var WSProcessor = require('./wsprocessor');
var TCPProcessor = require('./tcpprocessor');
var logger = require('pomelo-logger').getLogger('pomelo', __filename);

var HTTP_METHODS = [
  'GET', 'POST', 'DELETE', 'PUT', 'HEAD'
];

var ST_STARTED = 1;
var ST_CLOSED = 2;

var DEFAULT_TIMEOUT = 90;

/**
 * Switcher for tcp and websocket protocol
 *
 * @param {Object} server tcp server instance from node.js net module
 */
var Switcher = function(server, opts) {
  EventEmitter.call(this);
  this.server = server;
  this.wsprocessor = new WSProcessor();
  this.tcpprocessor = new TCPProcessor(opts.closeMethod);
  this.id = 1;
  this.timers = {};
  this.timeout = opts.timeout || DEFAULT_TIMEOUT;
  this.setNoDelay = opts.setNoDelay;

  if (!opts.ssl) {
    this.server.on('connection', this.newSocket.bind(this));
  } else {
    this.server.on('secureConnection', this.newSocket.bind(this));
    this.server.on('clientError', function(e) {
      logger.warn('an ssl error occured before handshake established: ', e);
    });
  }

  this.wsprocessor.on('connection', this.emit.bind(this, 'connection'));
  this.tcpprocessor.on('connection', this.emit.bind(this, 'connection'));

  this.state = ST_STARTED;
};
util.inherits(Switcher, EventEmitter);

module.exports = Switcher;

Switcher.prototype.newSocket = function(socket) {
  if(this.state !== ST_STARTED) {
    return;
  }
  // if set connection timeout
  if(!!this.timeout) {
    var timer = setTimeout(function() {
      logger.warn('connection is timeout without communication, the remote ip is %s && port is %s', socket.remoteAddress, socket.remotePort);
      socket.destroy();
    }, this.timeout * 1000);

    this.timers[this.id] = timer;
    socket.id = this.id++;
  }

  var self = this;
  socket.once('close', function() {
    if (!!socket.id) {
      clearTimeout(self.timers[socket.id]);
      delete self.timers[socket.id];
    }
  });

  socket.once('data', function(data) {
    if(!!socket.id) {
      clearTimeout(self.timers[socket.id]);
      delete self.timers[socket.id];
    }
    // FIXME: handle incomplete HTTP method
    if(isHttp(data)) {
      processHttp(self, self.wsprocessor, socket, data);
    } else {
      if(!!self.setNoDelay) {
        socket.setNoDelay(true);
      }
      processTcp(self, self.tcpprocessor, socket, data);
    }
  });
};

Switcher.prototype.close = function() {
  if(this.state !== ST_STARTED) {
    return;
  }

  this.state = ST_CLOSED;
  this.wsprocessor.close();
  this.tcpprocessor.close();
};

var isHttp = function(data) {
  var head = data.toString('utf8', 0, 4);

  for(var i=0, l=HTTP_METHODS.length; i<l; i++) {
    if(head.indexOf(HTTP_METHODS[i]) === 0) {
      return true;
    }
  }

  return false;
};

var processHttp = function(switcher, processor, socket, data) {
  processor.add(socket, data);
};

var processTcp = function(switcher, processor, socket, data) {
  processor.add(socket, data);
};

@@ -699,28 +699,8 @@
  1;%0A
-  this.timers = %7B%7D;%0A
   th
@@ -712,21 +712,17 @@
 meout = 
-opts.
+(
 timeout 
@@ -739,16 +739,24 @@
 _TIMEOUT
+) * 1000
 ;%0A  this
@@ -1466,45 +1466,15 @@
 t%0A  
-if(!!this.timeout) %7B%0A    var timer = 
+socket.
 setT
@@ -1489,25 +1489,24 @@
 unction() %7B%0A
- 
      logger.
@@ -1635,25 +1635,24 @@
 Port);%0A     
- 
 socket.destr
@@ -1657,18 +1657,16 @@
 troy();%0A
-  
   %7D, thi
@@ -1678,404 +1678,69 @@
 eout
- * 1000);%0A%0A    this.timers%5Bthis.id%5D = timer;%0A    socket.id = this.id++;%0A  %7D%0A%0A  var self = this;%0A  socket.once('close', function() %7B%0A    if (!!socket.id) %7B%0A      clearTimeout(self.timers%5Bsocket.id%5D);%0A      delete self.timers%5Bsocket.id%5D;%0A    %7D%0A  %7D);%0A%0A  socket.once('data', function(data) %7B%0A    if(!!socket.id) %7B%0A      clearTimeout(self.timers%5Bsocket.id%5D);%0A      delete self.timers%5Bsocket.id%5D;%0A    %7D
+)%0A%0A  var self = this;%0A%0A  socket.once('data', function(data) %7B
 %0A   

fix incorrect merge for pull request #444