"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var response_1 = require("../../../client/impl/response/response");
var request_1 = require("../../../client/impl/request");
var format_helper_1 = require("../../../core/format/format-helper");
var logger_1 = require("../../../logger");
var byte_buffer_1 = require("../../../core/buffer/byte-buffer");
var logger = logger_1.default('MockProtocol');
var EqualRequestFilter = /** @class */ (function () {
    function EqualRequestFilter(command) {
        this.command = command;
    }
    EqualRequestFilter.prototype.test = function (command) {
        if (!command) {
            return true;
        }
        return this.command.toString() === command.toString();
    };
    EqualRequestFilter.prototype.toString = function () {
        return "EqualRequestFilter " + this.command;
    };
    return EqualRequestFilter;
}());
exports.EqualRequestFilter = EqualRequestFilter;
var RegExpFilter = /** @class */ (function () {
    function RegExpFilter(regex) {
        this.regex = regex;
    }
    RegExpFilter.prototype.test = function (input) {
        var cmdString = input.toString();
        return Boolean(cmdString.match(this.regex));
    };
    return RegExpFilter;
}());
exports.RegExpFilter = RegExpFilter;
var Util = /** @class */ (function () {
    function Util() {
    }
    // public static REQUEST_REGEX: RegExp = /^(GET|PUT|POST) ((\/[a-zA-Z0-9])+) (0x([a-zA-Z0-9]+))?$/i;
    Util.parseApiRequestString = function (cmdString) {
        var parts = cmdString.split(' ');
        var methodtype = parts[0].toUpperCase();
        if (['GET', 'PUT', 'POST'].indexOf(methodtype) === -1) {
            throw new Error("Invalid command type: " + methodtype + ". From command: \"" + cmdString + "\"");
        }
        var methodPath = parts[1];
        var payload = undefined;
        if (parts.length >= 3) {
            payload = format_helper_1.FormatHelper.hexStringToBuffer(parts[2]);
        }
        // TODO improve as we can call anyother static function
        // It should be reduce to GET, PUT, POST
        return request_1.ApiRequest[methodtype](methodPath, payload);
    };
    return Util;
}());
exports.Util = Util;
var Router = /** @class */ (function () {
    function Router() {
        this._routes = [];
    }
    Object.defineProperty(Router.prototype, "routes", {
        get: function () {
            return this._routes;
        },
        enumerable: true,
        configurable: true
    });
    Router.prototype.findRoute = function (request) {
        var adapter;
        for (var _i = 0, _a = this._routes; _i < _a.length; _i++) {
            var route = _a[_i];
            // debug("\t- MockProtocol", `Check route: ${route.filter.toString()}`);
            if (route.predicate.test(request)) {
                adapter = route.adapter;
                break;
            }
        }
        var response;
        if (!adapter) {
            return null;
        }
        else {
            response = adapter.adapt(request);
        }
        return response;
    };
    Router.prototype.addRoute = function (left, right) {
        var filter;
        if (typeof left === 'string') {
            left = Util.parseApiRequestString(left);
        }
        if (left instanceof request_1.ApiRequest) {
            filter = new EqualRequestFilter(left);
        }
        else if (left instanceof RegExp) {
            filter = new RegExpFilter(left);
        }
        else if (typeof left === 'function') {
            filter = {
                test: left
            };
        }
        else {
            filter = left;
        }
        var adapter;
        if (right instanceof response_1.Response) {
            adapter = new (/** @class */ (function () {
                function tmp() {
                }
                tmp.prototype.adapt = function (command) {
                    return right;
                };
                return tmp;
            }()));
        }
        else if (right instanceof Uint8Array) {
            adapter = new (/** @class */ (function () {
                function tmp() {
                }
                tmp.prototype.adapt = function (command) {
                    return new response_1.Response(right);
                };
                return tmp;
            }()));
        }
        else if (typeof right === 'function') {
            adapter = {
                adapt: right
            };
        }
        else {
            adapter = right;
        }
        this._routes.push({
            predicate: filter,
            adapter: adapter
        });
        return this;
    };
    /**
     * Mapping a command (represented as a string with format "<request-type> <path> [data]"
     * ie: GET /3//3 0xABCD or POST /1024//0 0xtest
     *
     * Response must either be:
     *  - an hexadecimal data represented as a string (0xABCD)
     *  - An object with a coreRet and a body
     *  - A Uint8Array
     */
    Router.prototype.addRoutes = function (map) {
        for (var pathString in map) {
            var info = map[pathString];
            var command = Util.parseApiRequestString(pathString);
            var response = void 0;
            if (info instanceof Uint8Array) {
                response = new response_1.Response(info);
            }
            else if (info instanceof response_1.Response) {
                response = info;
            }
            else if (typeof info === "number") {
                response = response_1.Response.create(info);
            }
            else if (typeof info === "string") {
                response = new response_1.Response(format_helper_1.FormatHelper.hexStringToBuffer(info));
            }
            else if (typeof info === "object") {
                var codeRet = info.codeRet;
                response = new response_1.Response(byte_buffer_1.ByteBuffer.merge(Uint8Array.from([codeRet]), info.body || new Uint8Array(0)).data);
            }
            else {
                throw new Error("Invalid response type " + typeof info + " with value: " + JSON.stringify(info));
            }
            logger.debug("\t- Add map " + command + " -> " + response);
            this.addRoute(command, response);
        }
        return this;
    };
    Router.prototype.clearRoutes = function () {
        this._routes = [];
        return this;
    };
    return Router;
}());
exports.Router = Router;
