"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = Object.setPrototypeOf ||
        ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
        function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var queue_com_protocol_1 = require("../queue-com-protocol");
var util_1 = require("./util");
var response_encoder_1 = require("../../../client/impl/converter/response-encoder");
var default_command_decoder_1 = require("../../../client/impl/converter/default-command-decoder");
var response_1 = require("../../../client/impl/response/response");
var logger_1 = require("../../../logger");
var rxjs_1 = require("rxjs");
var operators_1 = require("rxjs/operators");
var format_helper_1 = require("../../../core/format/format-helper");
var response_2 = require("../../../client/api/response");
var logger = logger_1.default('MockProtocol');
/**
 *
 * <p>
 * This is a mock com protocol for testing only
 * <p>
 * We can simulate iotize response according to the request message
 */
var MockProtocol = /** @class */ (function (_super) {
    __extends(MockProtocol, _super);
    function MockProtocol() {
        var _this = _super.call(this) || this;
        _this.mockOptions = {
            connect: {
                delay: 100
            },
            disconnect: {
                delay: 100
            },
            write: {
                delay: 1
            },
        };
        _this._router = new util_1.Router();
        // this.connectDelay = 2000;
        // this.disconnectDelay = 2000;
        // this.callback = callback;
        _this.inputData = new Uint8Array(0);
        _this.outputData = new Uint8Array(0);
        _this.commandDecoder = new default_command_decoder_1.DefaultCommandDecoder();
        _this.responseEncoder = new response_encoder_1.DefaultResponseEncoder();
        return _this;
        // this.configuration = new Configuration();
        // this.configuration.connectionTimeoutMillis = 3000;
        // this.configuration.sendTimeoutMillis = 3000;
    }
    MockProtocol.MIRROR = function () {
        var mockProtocol = new MockProtocol();
        mockProtocol.router.addRoute({
            test: function (command) {
                return true;
            },
        }, {
            adapt: function (command) {
                return response_1.Response.SUCCESS(command.getData());
            }
        });
        return mockProtocol;
    };
    Object.defineProperty(MockProtocol.prototype, "router", {
        get: function () {
            return this._router;
        },
        enumerable: true,
        configurable: true
    });
    MockProtocol.prototype.setConnectionState = function (connectionState) {
        logger.debug("setConnectionState: " + connectionState);
        this.connectionState = connectionState;
        return this;
    };
    MockProtocol.prototype.setConnectDelay = function (connectDelay) {
        this.mockOptions.connect.delay = connectDelay;
        return this;
    };
    MockProtocol.prototype.getDisconnectDelay = function () {
        return this.mockOptions.disconnect.delay;
    };
    MockProtocol.prototype.setDisconnectDelay = function (disconnectDelay) {
        this.mockOptions.disconnect.delay = disconnectDelay;
        return this;
    };
    MockProtocol.prototype.hasNewData = function () {
        return this.inputData != null;
    };
    MockProtocol.prototype.setInputData = function (inputData) {
        this.inputData = inputData;
    };
    MockProtocol.prototype.setOutputData = function (outputData) {
        this.outputData = outputData;
    };
    MockProtocol.prototype.setCallback = function (callback) {
        this.callback = callback;
    };
    MockProtocol.prototype._connect = function (options) {
        return rxjs_1.of(null).pipe(operators_1.delay(this.mockOptions.connect.delay));
    };
    MockProtocol.prototype._disconnect = function (options) {
        return rxjs_1.of(null).pipe(operators_1.delay(this.mockOptions.disconnect.delay));
    };
    MockProtocol.prototype.write = function (message) {
        var _this = this;
        try {
            if (this.callback != null) {
                this.callback.beforeWrite(message);
            }
            this.outputData = message;
            // TODO we need to know if it's a command or a response ?
            var request = this.commandDecoder.decode(message);
            logger.debug("MockProtocol decoded input " + format_helper_1.FormatHelper.toHexString(message) + " to " + request);
            var response = this.router.findRoute(request);
            if (!response) {
                response = response_1.Response.ERROR(response_2.ResultCode.IOTIZE_501_NOT_IMPLEMENTED);
            }
            logger.debug("MockProtocol", "Mocking response for " + request + " => " + response);
            var result = this.responseEncoder.encode(response);
            this.inputData = result;
            if (this.callback != null) {
                this.callback.afterWrite(message);
            }
            return new Promise(function (resolve) { return setTimeout(resolve, _this.mockOptions.write.delay); });
        }
        catch (err) {
            return new Promise(function (resolve, reject) { return setTimeout(function () { return reject(err); }, _this.mockOptions.write.delay); });
        }
    };
    MockProtocol.prototype.read = function () {
        try {
            if (this.callback) {
                this.callback.beforeRead();
            }
            while (!this.hasNewData()) {
                // TODO wait ??
            }
            if (this.hasNewData()) {
                var result = rxjs_1.of(this.inputData);
                if (this.callback) {
                    this.callback.afterRead(result);
                }
                return result.toPromise();
            }
            else {
                return Promise.reject(new Error("Read timeout"));
            }
        }
        catch (err) {
            return Promise.reject(err);
        }
    };
    /**
     * @deprecated in favor of {@link #addRoute}
     */
    MockProtocol.prototype.mapResponse = function (left, right) {
        return this.addRoute(left, right);
    };
    MockProtocol.prototype.addRoute = function (left, right) {
        this.router.addRoute(left, right);
        return this;
    };
    //     public Configuration getConfiguration() {
    //     return configuration;
    // }
    /**
     * Create a new instance from roote mapping
     */
    MockProtocol.createFromRoutes = function (map) {
        var mockProtocol = new MockProtocol();
        mockProtocol.router.addRoutes(map);
        return mockProtocol;
    };
    return MockProtocol;
}(queue_com_protocol_1.QueueComProtocol));
exports.MockProtocol = MockProtocol;
//    public addOnRequestListener() {
//        this.mOnRequestListener =
//    }
//    public interface onRequestListener{
//        onRequest(RequestMessage request);
//    }
