"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 dopts = require("default-options");
const commonTypes_1 = require("../commonTypes");
const configService_1 = require("../configService");
const contractWrapperBase_1 = require("../contractWrapperBase");
const contractWrapperFactory_1 = require("../contractWrapperFactory");
const utils_1 = require("../utils");
class VestingSchemeWrapper extends contractWrapperBase_1.ContractWrapperBase {
    constructor() {
        super(...arguments);
        this.name = "VestingScheme";
        this.frendlyName = "Vesting Scheme";
        this.factory = exports.VestingSchemeFactory;
        /**
         * Events
         */
        /* tslint:disable:max-line-length */
        this.ProposalExecuted = this.createEventFetcherFactory("ProposalExecuted");
        this.AgreementProposal = this.createEventFetcherFactory("AgreementProposal");
        this.NewVestedAgreement = this.createEventFetcherFactory("NewVestedAgreement");
        this.SignToCancelAgreement = this.createEventFetcherFactory("SignToCancelAgreement");
        this.RevokeSignToCancelAgreement = this.createEventFetcherFactory("RevokeSignToCancelAgreement");
        this.AgreementCancel = this.createEventFetcherFactory("AgreementCancel");
        this.Collect = this.createEventFetcherFactory("Collect");
        /* tslint:enable:max-line-length */
        /**
         * see CreateVestingAgreementConfig
         */
        this.defaultCreateOptions = {
            amountPerPeriod: undefined,
            beneficiaryAddress: undefined,
            cliffInPeriods: undefined,
            numOfAgreedPeriods: undefined,
            periodLength: undefined,
            returnOnCancelAddress: undefined,
            signaturesReqToCancel: undefined,
            signers: undefined,
            startingBlock: null,
        };
    }
    /**
     * Propose a new vesting agreement
     * @param {ProposeVestingAgreementConfig} opts
     */
    propose(opts = {}) {
        return __awaiter(this, void 0, void 0, function* () {
            /**
             * see ProposeVestingAgreementConfig
             */
            const options = dopts(opts, Object.assign({ avatar: undefined }, this.defaultCreateOptions), { allowUnknown: true });
            if (!options.avatar) {
                throw new Error("avatar is not defined");
            }
            yield this.validateCreateParams(options);
            const tx = yield this.contract.proposeVestingAgreement(options.beneficiaryAddress, options.returnOnCancelAddress, options.startingBlock, utils_1.Utils.getWeb3().toBigNumber(options.amountPerPeriod), options.periodLength, options.numOfAgreedPeriods, options.cliffInPeriods, options.signaturesReqToCancel, options.signers, options.avatar);
            return new contractWrapperBase_1.ArcTransactionProposalResult(tx);
        });
    }
    /**
     * Create a new vesting agreement
     * @param {CreateVestingAgreementConfig} opts
     */
    create(opts = {}) {
        return __awaiter(this, void 0, void 0, function* () {
            /**
             * See these properties in CreateVestingAgreementConfig
             */
            const options = dopts(opts, this.defaultCreateOptions, { allowUnknown: true });
            yield this.validateCreateParams(options);
            if (!options.token) {
                throw new Error("token is not defined");
            }
            const amountPerPeriod = utils_1.Utils.getWeb3().toBigNumber(options.amountPerPeriod);
            /**
             * approve immediate transfer of the given tokens from currentAccount to the VestingScheme
             */
            if (configService_1.ConfigService.get("autoApproveTokenTransfers")) {
                const token = yield (yield utils_1.Utils.requireContract("StandardToken")).at(options.token);
                yield token.approve(this.address, amountPerPeriod.mul(options.numOfAgreedPeriods));
            }
            const tx = yield this.contract.createVestedAgreement(options.token, options.beneficiaryAddress, options.returnOnCancelAddress, options.startingBlock, amountPerPeriod, options.periodLength, options.numOfAgreedPeriods, options.cliffInPeriods, options.signaturesReqToCancel, options.signers);
            return new ArcTransactionAgreementResult(tx);
        });
    }
    /**
     * Sign to cancel a vesting agreement
     * @param {SignToCancelVestingAgreementConfig} opts
     */
    signToCancel(opts = {}) {
        return __awaiter(this, void 0, void 0, function* () {
            /**
             * See these properties in SignToCancelVestingAgreementConfig
             */
            const defaults = {
                agreementId: undefined,
            };
            const options = dopts(opts, defaults, { allowUnknown: true });
            if (options.agreementId === null) {
                throw new Error("agreementId is not defined");
            }
            const tx = yield this.contract.signToCancelAgreement(options.agreementId);
            return new contractWrapperBase_1.ArcTransactionResult(tx);
        });
    }
    /**
     * Revoke vote for cancelling a vesting agreement
     * @param {RevokeSignToCancelVestingAgreementConfig} opts
     */
    revokeSignToCancel(opts = {}) {
        return __awaiter(this, void 0, void 0, function* () {
            /**
             * See these properties in RevokeSignToCancelVestingAgreementConfig
             */
            const defaults = {
                agreementId: undefined,
            };
            const options = dopts(opts, defaults, { allowUnknown: true });
            if (options.agreementId === null) {
                throw new Error("agreementId is not defined");
            }
            const tx = yield this.contract.revokeSignToCancelAgreement(options.agreementId);
            return new contractWrapperBase_1.ArcTransactionResult(tx);
        });
    }
    /**
     * Collects for a beneficiary, according to the agreement
     * @param {CollectVestingAgreementConfig} opts
     */
    collect(opts = {}) {
        return __awaiter(this, void 0, void 0, function* () {
            /**
             * See these properties in CollectVestingAgreementConfig
             */
            const defaults = {
                agreementId: undefined,
            };
            const options = dopts(opts, defaults, { allowUnknown: true });
            if (options.agreementId === null) {
                throw new Error("agreementId is not defined");
            }
            const tx = yield this.contract.collect(options.agreementId);
            return new contractWrapperBase_1.ArcTransactionResult(tx);
        });
    }
    /**
     * Return all agreements ever created by this scheme
     * Filter by the optional agreementId.
     */
    getAgreements(opts = {}) {
        return __awaiter(this, void 0, void 0, function* () {
            const defaults = {
                agreementId: null,
                avatar: undefined,
            };
            const options = dopts(opts, defaults, { allowUnknown: true });
            if (!options.avatar) {
                throw new Error("avatar address is not defined");
            }
            const agreements = new Array();
            if (options.agreementId) {
                const agreement = this.schemeAgreementToAgreement(yield this.contract.agreements(options.agreementId), options.agreementId);
                agreements.push(agreement);
            }
            else {
                const eventFetcher = this.NewVestedAgreement({}, { fromBlock: 0 });
                yield new Promise((resolve) => {
                    eventFetcher.get((err, log) => __awaiter(this, void 0, void 0, function* () {
                        for (const event of log) {
                            const agreementId = event.args._agreementId.toNumber();
                            const agreement = this.schemeAgreementToAgreement(yield this.contract.agreements(agreementId), agreementId);
                            agreements.push(agreement);
                        }
                        resolve();
                    }));
                });
            }
            return agreements;
        });
    }
    setParameters(params) {
        const _super = name => super[name];
        return __awaiter(this, void 0, void 0, function* () {
            this.validateStandardSchemeParams(params);
            return _super("setParameters").call(this, params.voteParametersHash, params.votingMachineAddress);
        });
    }
    getDefaultPermissions(overrideValue) {
        // return overrideValue || Utils.numberToPermissionsString(DefaultSchemePermissions.VestingScheme);
        return (overrideValue || commonTypes_1.DefaultSchemePermissions.VestingScheme);
    }
    getSchemePermissions(avatarAddress) {
        return __awaiter(this, void 0, void 0, function* () {
            return this._getSchemePermissions(avatarAddress);
        });
    }
    getSchemeParameters(avatarAddress) {
        return __awaiter(this, void 0, void 0, function* () {
            return this._getSchemeParameters(avatarAddress);
        });
    }
    getParameters(paramsHash) {
        return __awaiter(this, void 0, void 0, function* () {
            const params = yield this.getParametersArray(paramsHash);
            return {
                voteParametersHash: params[0],
                votingMachineAddress: params[1],
            };
        });
    }
    validateCreateParams(options) {
        return __awaiter(this, void 0, void 0, function* () {
            if (!Number.isInteger(options.periodLength) || (options.periodLength <= 0)) {
                throw new Error("periodLength must be greater than zero");
            }
            if (utils_1.Utils.getWeb3().toBigNumber(options.amountPerPeriod) <= 0) {
                throw new Error("amountPerPeriod must be greater than zero");
            }
            if (!Number.isInteger(options.numOfAgreedPeriods) || (options.numOfAgreedPeriods <= 0)) {
                throw new Error("numOfAgreedPeriods must be greater than zero");
            }
            if (!Number.isInteger(options.cliffInPeriods) || (options.cliffInPeriods < 0)) {
                throw new Error("cliffInPeriods must be greater than or equal to zero");
            }
            const web3 = utils_1.Utils.getWeb3();
            if ((typeof options.startingBlock === "undefined") || (options.startingBlock === null)) {
                options.startingBlock = yield web3.eth.blockNumber;
            }
            if (!Number.isInteger(options.startingBlock) || (options.startingBlock < 0)) {
                throw new Error("startingBlock must be greater than or equal to zero");
            }
        });
    }
    schemeAgreementToAgreement(schemeAgreement, agreementId) {
        return {
            agreementId,
            amountPerPeriod: schemeAgreement[4],
            beneficiaryAddress: schemeAgreement[1],
            cliffInPeriods: schemeAgreement[7],
            collectedPeriods: schemeAgreement[9],
            numOfAgreedPeriods: schemeAgreement[6],
            periodLength: schemeAgreement[5],
            returnOnCancelAddress: schemeAgreement[2],
            signaturesReqToCancel: schemeAgreement[8],
            startingBlock: schemeAgreement[3],
            tokenAddress: schemeAgreement[0],
        };
    }
}
exports.VestingSchemeWrapper = VestingSchemeWrapper;
class ArcTransactionAgreementResult extends contractWrapperBase_1.ArcTransactionResult {
    constructor(tx) {
        super(tx);
        this.agreementId = this.getValueFromTx("_agreementId").toNumber();
    }
}
exports.ArcTransactionAgreementResult = ArcTransactionAgreementResult;
exports.VestingSchemeFactory = new contractWrapperFactory_1.default("VestingScheme", VestingSchemeWrapper);
//# sourceMappingURL=vestingscheme.js.map