"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handshake = void 0;
const binary_1 = __importDefault(require("binary"));
const buffer_1 = require("buffer");
const constants_1 = require("./constants");
/**
 * +----+----------+----------+
 * |VER | NMETHODS | METHODS  |
 * +----+----------+----------+
 * | 1  |    1     | 1 to 255 |
 * +----+----------+----------+
 *
 * @param {Socket} socket - a socket
 * @param {Buffer} buffer - a buffer
 * @param {any} options
 * @param {Function} connet
 * @param {Function} authenticate
 * @param {Function} end
 * @param {Function} onHandshakeCompleted
 *
 * @returns {undefined}
 **/
function handshake({ socket, buffer, options, connect, authenticate, end, onHandshakeCompleted, }) {
    const clientHandshakeBuffer = buffer;
    binary_1.default
        .stream(buffer)
        .word8('version')
        .word8('nmethods')
        .buffer('methods', 'nmethods')
        .tap((args) => {
        // verify version is appropriate
        if (args.version !== constants_1.RFC_1928_VERSION) {
            return end(constants_1.RFC_1928_REPLIES.GENERAL_FAILURE, args);
        }
        // convert methods buffer to an array
        const acceptedMethods = [].slice
            .call(args.methods)
            .reduce((methods, method) => {
            methods[method] = true;
            return methods;
        }, {});
        const basicAuth = typeof options.authenticate === 'function';
        const noAuth = !basicAuth && typeof acceptedMethods[0] !== 'undefined' && acceptedMethods[0];
        const responseBuffer = buffer_1.Buffer.allocUnsafe(2);
        // form response Buffer
        responseBuffer[0] = constants_1.RFC_1928_VERSION;
        responseBuffer[1] = constants_1.RFC_1928_METHODS.NO_AUTHENTICATION_REQUIRED;
        let next = connect;
        // check for basic auth configuration
        if (basicAuth) {
            responseBuffer[1] = constants_1.RFC_1928_METHODS.BASIC_AUTHENTICATION;
            next = authenticate;
            // if NO AUTHENTICATION REQUIRED and
        }
        else if (!basicAuth && noAuth) {
            responseBuffer[1] = constants_1.RFC_1928_METHODS.NO_AUTHENTICATION_REQUIRED;
            next = connect;
            // basic auth callback not provided and no auth is not supported
        }
        else {
            return end(constants_1.RFC_1928_METHODS.NO_ACCEPTABLE_METHODS, args);
        }
        // respond then listen for cmd and dst info
        socket.write(responseBuffer, () => {
            // emit handshake event
            socket.once('data', next);
            onHandshakeCompleted && onHandshakeCompleted({ clientHandshakeBuffer, responseBuffer });
            // now listen for more details
        });
    });
}
exports.handshake = handshake;
//# sourceMappingURL=handshake.js.map