function Connection(endpoint, protocolVersion, options) {
  events.EventEmitter.call(this);
  this.setMaxListeners(0);

  if (!options) {
    throw new Error('options is not defined');
  }

  /**
   * Gets the ip and port of the server endpoint.
   * @type {String}
   */
  this.endpoint = endpoint;

  /**
   * Gets the friendly name of the host, used to identify the connection in log messages.
   * With direct connect, this is the address and port.
   * @type {String}
   */
  this.endpointFriendlyName = endpoint;

  if (!this.endpoint || this.endpoint.indexOf(':') < 0) {
    throw new Error('EndPoint must contain the ip address and port separated by : symbol');
  }

  const portSeparatorIndex = this.endpoint.lastIndexOf(':');
  this.address = this.endpoint.substr(0, portSeparatorIndex);
  this.port = this.endpoint.substr(portSeparatorIndex + 1);

  Object.defineProperty(this, "options", { value: options, enumerable: false, writable: false});

  if (protocolVersion === null) {
    // Set initial protocol version
    protocolVersion = types.protocolVersion.maxSupported;
    if (options.protocolOptions.maxVersion) {
      // User provided the protocol version
      protocolVersion = options.protocolOptions.maxVersion;
    }
    // Allow to check version using this connection instance
    this._checkingVersion = true;
  }

  this.protocolVersion = protocolVersion;
  /** @type {Object.<String, OperationState>} */
  this._operations = {};
  this._pendingWrites = [];
  this._preparing = {};

  /**
   * The timeout state for the idle request (heartbeat)
   */
  this._idleTimeout = null;
  this.timedOutOperations = 0;
  this._streamIds = new StreamIdStack(this.protocolVersion);
  this._metrics = options.metrics;

  this.encoder = new Encoder(protocolVersion, options);
  this.keyspace = null;
  this.emitDrain = false;
  /**
   * Determines if the socket is open and startup succeeded, whether the connection can be used to send requests / 
   * receive events
   */
  this.connected = false;
  /**
   * Determines if the socket can be considered as open
   */
  this.isSocketOpen = false;
}