"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const SetRules_1 = require("../../protocol/SetRules");
const SteemOperationNumber_1 = require("../../blockchain/SteemOperationNumber");
const Api_1 = require("../Api");
const RulePrototyper_1 = require("../../rules/RulePrototyper");
const ConfirmVote_1 = require("../../protocol/ConfirmVote");
const WiseSQLProtocol_1 = require("./WiseSQLProtocol");
class WiseSQLApi extends Api_1.Api {
    /**
     * You have to specify at least one direct blockchain api.
     */
    constructor(endpointUrl, protocol, directBlockchainApi) {
        super();
        this.directBlockchainApi = undefined;
        this.endpointUrl = endpointUrl;
        this.protocol = protocol;
        if (directBlockchainApi)
            this.directBlockchainApi = directBlockchainApi;
    }
    name() {
        return "WiseSQLApi";
    }
    loadPost(author, permlink) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.directBlockchainApi)
                throw new Error("To use #loadPost method you have to specify a DirectBlockchainApi in constructor");
            return this.directBlockchainApi.loadPost(author, permlink);
        });
    }
    loadRulesets(forWhom, at) {
        return __awaiter(this, void 0, void 0, function* () {
            let ops;
            let path = "";
            let data = {};
            if (forWhom.delegator && forWhom.voter) {
                path = "/rpc/rulesets_by_delegator_for_voter_at_moment";
                data = { delegator: forWhom.delegator, voter: forWhom.voter, moment: this.formatMoment(at) };
            }
            else if (forWhom.delegator && !forWhom.voter) {
                path = "/rpc/rulesets_by_delegator_at_moment";
                data = { delegator: forWhom.delegator, moment: this.formatMoment(at) };
            }
            else if (!forWhom.delegator && forWhom.voter) {
                path = "/rpc/rulesets_by_all_delegators_for_voter_at_moment";
                data = { voter: forWhom.voter, moment: this.formatMoment(at) };
            }
            else
                throw new Error("You have to specify either a voter, a delegator or both of them.");
            ops = yield WiseSQLProtocol_1.WiseSQLProtocol.Handler.query({ endpointUrl: this.endpointUrl, path: path,
                method: "post", limit: 9999, data: data });
            return ops.map((op) => {
                const setRules = op.command;
                if (!SetRules_1.SetRules.isSetRules(setRules))
                    throw new Error("Operation is not an instance of SetRules: " + JSON.stringify(op));
                const prototypedRulesets = setRules.rulesets.map(unprototypedRuleset => RulePrototyper_1.RulePrototyper.prototypeRuleset(unprototypedRuleset));
                const out = {
                    moment: op.moment,
                    voter: op.voter,
                    delegator: op.delegator,
                    rulesets: prototypedRulesets
                };
                return out;
            });
        });
    }
    sendToBlockchain(operations) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.directBlockchainApi)
                throw new Error("To use #sendToBlockchain method you have to specify a DirectBlockchainApi in constructor");
            return this.directBlockchainApi.sendToBlockchain(operations);
        });
    }
    getLastConfirmationMoment(delegator) {
        return __awaiter(this, void 0, void 0, function* () {
            const ops = yield WiseSQLProtocol_1.WiseSQLProtocol.Handler.query({ endpointUrl: this.endpointUrl, path: "/operations", method: "get", limit: 1,
                params: { delegator: "eq." + delegator, operation_type: "eq.confirm_vote", order: "moment.desc" } });
            if (ops.length !== 1)
                throw new Error("Invalid number of rows returned. This query should return a single row.");
            if (!ConfirmVote_1.ConfirmVote.isConfirmVote(ops[0].command))
                throw new Error("Invalid format of response (json_str is not a ConfirmVote operation): "
                    + JSON.stringify(ops[0].command));
            return ops[0].moment;
        });
    }
    getAllWiseOperationsInBlock(blockNum, delegatorFilter) {
        return __awaiter(this, void 0, void 0, function* () {
            const params = { order: "moment.desc", block_num: "eq." + blockNum };
            if (delegatorFilter)
                params.delegator = "eq." + delegatorFilter;
            const ops = yield WiseSQLProtocol_1.WiseSQLProtocol.Handler.query({
                endpointUrl: this.endpointUrl, path: "/operations", method: "get", limit: 9999,
                params: params
            });
            return ops.map((op) => {
                if (SetRules_1.SetRules.isSetRules(op.command)) {
                    op.command.rulesets = op.command.rulesets.map(ruleset => RulePrototyper_1.RulePrototyper.prototypeRuleset(ruleset));
                }
                return op;
            });
        });
    }
    getWiseOperationsRelatedToDelegatorInBlock(delegator, blockNum) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.getAllWiseOperationsInBlock(blockNum, delegator);
        });
    }
    getWiseOperations(username, until) {
        return __awaiter(this, void 0, void 0, function* () {
            const ops = yield WiseSQLProtocol_1.WiseSQLProtocol.Handler.query({ endpointUrl: this.endpointUrl, path: "/operations", method: "get", limit: 9999,
                params: { order: "moment.desc", or: "(voter.eq." + username + ",delegator.eq." + username + ")", timestamp: "gte." + until.toISOString() } });
            return ops.map((op) => {
                if (SetRules_1.SetRules.isSetRules(op.command)) {
                    op.command.rulesets = op.command.rulesets.map(ruleset => RulePrototyper_1.RulePrototyper.prototypeRuleset(ruleset));
                }
                return op;
            });
        });
    }
    getDynamicGlobalProperties() {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.directBlockchainApi)
                throw new Error("To use #getDynamicGlobalProperties method you have to specify a DirectBlockchainApi in constructor");
            return this.directBlockchainApi.getDynamicGlobalProperties();
        });
    }
    getAccountInfo(username) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.directBlockchainApi)
                throw new Error("To use #getAccountInfo method you have to specify a DirectBlockchainApi in constructor");
            return this.directBlockchainApi.getAccountInfo(username);
        });
    }
    getBlogEntries(username, startFrom, limit) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!this.directBlockchainApi)
                throw new Error("To use #getBlogEntries method you have to specify a DirectBlockchainApi in constructor");
            return this.directBlockchainApi.getBlogEntries(username, startFrom, limit);
        });
    }
    formatMoment(moment) {
        if (moment.blockNum === SteemOperationNumber_1.SteemOperationNumber.FUTURE.blockNum) {
            return "99999999999999.0000"; // 14 digits
        }
        return moment.blockNum + "."
            + ("000" + moment.transactionNum).slice(-4);
    }
}
WiseSQLApi.REQUIRED_ENDPOINT_API_VERSION = "1.0";
exports.WiseSQLApi = WiseSQLApi;
//# sourceMappingURL=WiseSQLApi.js.map