text: 'use strict';
  
  const EventEmitter = require('events');
  const Errors = require('../misc/errors');
  const ServerStatus = require('../const/server-status');
  const StateChange = require('../const/state-change');
  const Collations = require('../const/collations');
  const OkPacket = require('./class/ok-packet');
  
  /**
   * Default command interface.
   */
  class Command extends EventEmitter {
    constructor(resolve, reject) {
      super();
      this.sequenceNo = -1;
      this.compressSequenceNo = -1;
      this.resolve = resolve;
      this.reject = reject;
      this.sending = false;
    }
  
    displaySql() {}
  
    /**
     * Throw an an unexpected error.
     * server exchange will still be read to keep connection in a good state, but promise will be rejected.
     *
     * @param msg message
     * @param fatal is error fatal for connection
     * @param info current server state information
     * @param sqlState error sqlState
     * @param errno error number
     */
    throwUnexpectedError(msg, fatal, info, sqlState, errno) {
      if (this.reject) {
        process.nextTick(
          this.reject,
          Errors.createError(msg, fatal, info, sqlState, errno, this.stack, false)
        );
        this.resolve = null;
        this.reject = null;
      }
    }
  
    /**
     * Create and throw new Error from error information
     * only first called throwing an error or successfully end will be executed.
     *
     * @param msg message
     * @param fatal is error fatal for connection
     * @param info current server state information
     * @param sqlState error sqlState
     * @param errno error number
     */
    throwNewError(msg, fatal, info, sqlState, errno) {
      this.onPacketReceive = null;
      if (this.reject) {
        process.nextTick(
          this.reject,
          Errors.createError(msg, fatal, info, sqlState, errno, this.stack, false)
        );
        this.resolve = null;
        this.reject = null;
      }
      this.emit('end');
    }
  
    /**
     * Throw Error
     *  only first called throwing an error or successfully end will be executed.
     *
     * @param err error to be thrown
     * @param info current server state information
     */
    throwError(err, info) {
      this.onPacketReceive = null;
      if (this.reject) {
        if (this.stack) {
          err = Errors.createError(
            err.message,
            err.fatal,
            info,
            err.sqlState,
            err.errno,
            this.stack,
            false
          );
        }
        this.resolve = null;
        process.nextTick(this.reject, err);
        this.reject = null;
      }
      this.emit('end', err);
    }
  
    /**
     * Successfully end command.
     * only first called throwing an error or successfully end will be executed.
     *
     * @param val return value.
     */
    successEnd(val) {
      this.onPacketReceive = null;
      if (this.resolve) {
        this.reject = null;
        process.nextTick(this.resolve, val);
        this.resolve = null;
      }
      this.emit('end');
    }
  
    static parseOkPacket(packet, out, opts, info) {
      packet.skip(1); //skip header
  
      const affectedRows = packet.readUnsignedLength();
      const insertId = packet.readSignedLength();
  
      info.status = packet.readUInt16();
  
      const okPacket = new OkPacket(affectedRows, insertId, packet.readUInt16());
  
      if (info.status & ServerStatus.SESSION_STATE_CHANGED) {
        packet.skipLengthCodedNumber();
        while (packet.remaining()) {
          const subPacket = packet.subPacketLengthEncoded();
          while (subPacket.remaining()) {
            const type = subPacket.readUInt8();
            switch (type) {
              case StateChange.SESSION_TRACK_SYSTEM_VARIABLES:
                const subSubPacket = subPacket.subPacketLengthEncoded();
                const variable = subSubPacket.readStringLength();
                const value = subSubPacket.readStringLength();
  
                switch (variable) {
                  case 'character_set_client':
                    opts.collation = Collations.fromCharset(value);
                    if (opts.collation === undefined) {
                      this.throwError(new Error("unknown charset : '" + value + "'"), info);
                      return;
                    }
                    opts.emit('collation', opts.collation);
                    break;
  
                  default:
                  //variable not used by driver
                }
                break;
  
              case StateChange.SESSION_TRACK_SCHEMA:
                const subSubPacket2 = subPacket.subPacketLengthEncoded();
                info.database = subSubPacket2.readStringLength();
                break;
            }
          }
        }
      }
  
      return okPacket;
    }
  }
  
  module.exports = Command;
  