"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var transaction_1 = require("@harmony-js/transaction");
var network_1 = require("@harmony-js/network");
var utils_1 = require("@harmony-js/utils");
var crypto_1 = require("@harmony-js/crypto");
var encoder_1 = require("../utils/encoder");
var status_1 = require("../utils/status");
// todo: have to judge if it is contractConstructor
var ContractMethod = /** @class */ (function () {
    function ContractMethod(methodKey, params, abiItem, contract) {
        this.methodKey = methodKey;
        this.contract = contract;
        this.wallet = contract.wallet;
        this.params = params;
        this.abiItem = abiItem;
        this.transaction = this.createTransaction();
        // this.addEventListeners();
    }
    ContractMethod.prototype.send = function (params) {
        var _this = this;
        try {
            this.transaction = this.transaction.map(function (tx) {
                return tslib_1.__assign({}, tx, params);
            });
            var updateNonce = params.nonce ? false : true;
            this.signTransaction(updateNonce).then(function (signed) {
                _this.sendTransaction(signed).then(function (sent) {
                    var _a = tslib_1.__read(sent, 2), txn = _a[0], id = _a[1];
                    _this.transaction = txn;
                    _this.contract.transaction = _this.transaction;
                    _this.confirm(id).then(function () {
                        _this.transaction.emitter.resolve(_this.contract);
                    });
                });
            });
            return this.transaction.emitter;
        }
        catch (error) {
            throw error;
        }
    };
    ContractMethod.prototype.call = function (options, blockNumber) {
        if (blockNumber === void 0) { blockNumber = 'latest'; }
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var nonce_1, _a, gasLimit_1, _b, from_1, result, error_1;
            return tslib_1.__generator(this, function (_c) {
                switch (_c.label) {
                    case 0:
                        _c.trys.push([0, 6, , 7]);
                        _a = network_1.getResultForData;
                        return [4 /*yield*/, this.wallet.messenger.send("hmy_getTransactionCount" /* GetTransactionCount */, [
                                this.wallet.signer ? this.wallet.signer.address : options.from,
                                blockNumber,
                            ])];
                    case 1:
                        nonce_1 = _a.apply(void 0, [_c.sent()]);
                        if (!options) return [3 /*break*/, 2];
                        gasLimit_1 = options.gas || options.gasLimit;
                        return [3 /*break*/, 4];
                    case 2:
                        _b = utils_1.hexToBN;
                        return [4 /*yield*/, this.estimateGas()];
                    case 3:
                        gasLimit_1 = _b.apply(void 0, [_c.sent()]);
                        _c.label = 4;
                    case 4:
                        if (this.wallet.signer) {
                            from_1 =
                                options && options.from ? options.from : this.wallet.signer.address;
                        }
                        this.transaction = this.transaction.map(function (tx) {
                            return tslib_1.__assign({}, tx, options, { from: from_1 || tx.from, gasPrice: options ? options.gasPrice : tx.gasPrice, gasLimit: gasLimit_1 || tx.gasLimit, nonce: Number.parseInt(utils_1.hexToNumber(nonce_1), 10) });
                        });
                        return [4 /*yield*/, this.wallet.messenger.send("hmy_call" /* Call */, [
                                this.transaction.txPayload,
                                blockNumber,
                            ])];
                    case 5:
                        result = _c.sent();
                        if (result.isError()) {
                            throw result.message;
                        }
                        else if (result.isResult()) {
                            if (result.result === null) {
                                return [2 /*return*/, this.afterCall(undefined)];
                            }
                            else {
                                return [2 /*return*/, this.afterCall(result.result)];
                            }
                        }
                        return [3 /*break*/, 7];
                    case 6:
                        error_1 = _c.sent();
                        throw error_1;
                    case 7: return [2 /*return*/];
                }
            });
        });
    };
    ContractMethod.prototype.estimateGas = function () {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var result, _a, error_2;
            return tslib_1.__generator(this, function (_b) {
                switch (_b.label) {
                    case 0:
                        _b.trys.push([0, 2, , 3]);
                        _a = network_1.getResultForData;
                        return [4 /*yield*/, this.wallet.messenger.send("hmy_estimateGas" /* EstimateGas */, [
                                {
                                    to: this.transaction.txParams.to,
                                    data: this.transaction.txParams.data,
                                },
                            ])];
                    case 1:
                        result = _a.apply(void 0, [_b.sent()]);
                        if (result.responseType === 'error') {
                            throw result.message;
                        }
                        else if (result.responseType === 'raw') {
                            throw new Error('Get estimateGas fail');
                        }
                        else {
                            return [2 /*return*/, result];
                        }
                        return [3 /*break*/, 3];
                    case 2:
                        error_2 = _b.sent();
                        throw error_2;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    ContractMethod.prototype.encodeABI = function () {
        return encoder_1.methodEncoder(this.contract.abiCoder, this.abiItem, this.contract.data);
    };
    ContractMethod.prototype.signTransaction = function (updateNonce) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var signed, error_3;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, this.wallet.signTransaction(this.transaction, this.wallet.signer, undefined, updateNonce, 'rlp', 'pending')];
                    case 1:
                        signed = _a.sent();
                        this.contract.address = transaction_1.TransactionFactory.getContractAddress(signed);
                        this.contract.setStatus(status_1.ContractStatus.SIGNED);
                        return [2 /*return*/, signed];
                    case 2:
                        error_3 = _a.sent();
                        throw error_3;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    ContractMethod.prototype.sendTransaction = function (signed) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var result, error_4;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, signed.sendTransaction()];
                    case 1:
                        result = _a.sent();
                        this.contract.setStatus(status_1.ContractStatus.SENT);
                        return [2 /*return*/, result];
                    case 2:
                        error_4 = _a.sent();
                        throw error_4;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    ContractMethod.prototype.confirm = function (id) {
        return tslib_1.__awaiter(this, void 0, void 0, function () {
            var result, error_5;
            return tslib_1.__generator(this, function (_a) {
                switch (_a.label) {
                    case 0:
                        _a.trys.push([0, 2, , 3]);
                        return [4 /*yield*/, this.transaction.confirm(id)];
                    case 1:
                        result = _a.sent();
                        if (result.receipt && result.receipt.status === '0x1') {
                            if (this.methodKey === 'contractConstructor') {
                                this.contract.setStatus(status_1.ContractStatus.DEPLOYED);
                            }
                            else {
                                this.contract.setStatus(status_1.ContractStatus.CALLED);
                            }
                        }
                        else {
                            this.contract.setStatus(status_1.ContractStatus.REJECTED);
                        }
                        return [3 /*break*/, 3];
                    case 2:
                        error_5 = _a.sent();
                        throw error_5;
                    case 3: return [2 /*return*/];
                }
            });
        });
    };
    ContractMethod.prototype.createTransaction = function () {
        if (this.wallet.messenger) {
            if (this.methodKey === 'contractConstructor') {
                // tslint:disable-next-line: no-string-literal
                this.contract.data = this.params[0]['data'] || '0x';
                this.abiItem.contractMethodParameters =
                    // tslint:disable-next-line: no-string-literal
                    this.params[0]['arguments'] || [];
            }
            else {
                this.abiItem.contractMethodParameters = this.params || [];
            }
            var txObject = tslib_1.__assign({}, this.params[0], { to: this.contract.address === '0x'
                    ? '0x'
                    : crypto_1.getAddress(this.contract.address).checksum, data: this.encodeABI() });
            var result = new transaction_1.TransactionFactory(this.wallet.messenger).newTx(txObject);
            return result;
        }
        else {
            throw new Error('Messenger is not found');
        }
    };
    ContractMethod.prototype.afterCall = function (response) {
        if (!response || response === '0x') {
            return null;
        }
        var outputs = this.abiItem.getOutputs();
        if (outputs.length > 1) {
            return this.contract.abiCoder.decodeParameters(outputs, response);
        }
        return this.contract.abiCoder.decodeParameter(outputs[0], response);
        // return outputs;
    };
    return ContractMethod;
}());
exports.ContractMethod = ContractMethod;
//# sourceMappingURL=method.js.map