"use strict";
// Copyright 2023 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
    var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
    if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
    else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
    return c > 3 && r && Object.defineProperty(target, key, r), r;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.DelegationOutput = exports.NftOutput = exports.FoundryOutput = exports.AnchorOutput = exports.AccountOutput = exports.BasicOutput = exports.CommonOutput = exports.OutputType = exports.Output = exports.OutputDiscriminator = void 0;
const unlock_condition_1 = require("./unlock-condition");
const feature_1 = require("./feature");
// Temp solution for not double parsing JSON
const class_transformer_1 = require("class-transformer");
const token_scheme_1 = require("./token-scheme");
const address_1 = require("../address");
/**
 * All of the output types.
 */
var OutputType;
(function (OutputType) {
    /** A Basic output. */
    OutputType[OutputType["Basic"] = 0] = "Basic";
    /** An Account output. */
    OutputType[OutputType["Account"] = 1] = "Account";
    /** An Anchor output. */
    OutputType[OutputType["Anchor"] = 2] = "Anchor";
    /** A Foundry output. */
    OutputType[OutputType["Foundry"] = 3] = "Foundry";
    /** An NFT output. */
    OutputType[OutputType["Nft"] = 4] = "Nft";
    /** A Delegation output. */
    OutputType[OutputType["Delegation"] = 5] = "Delegation";
})(OutputType || (OutputType = {}));
exports.OutputType = OutputType;
/**
 * The base class for outputs.
 */
class Output {
    /**
     * @param type The type of output.
     * @param amount The amount of the output as big-integer or string.
     */
    constructor(type, amount) {
        this.type = type;
        if (typeof amount == 'bigint') {
            this.amount = amount.toString(10);
        }
        else {
            this.amount = amount;
        }
    }
    /**
     * Get the amount of the output.
     */
    getAmount() {
        return BigInt(this.amount);
    }
    /**
     * Parse an output from a plain JS JSON object.
     */
    static parse(data) {
        if (data.type == OutputType.Basic) {
            return (0, class_transformer_1.plainToInstance)(BasicOutput, data);
        }
        else if (data.type == OutputType.Account) {
            return (0, class_transformer_1.plainToInstance)(AccountOutput, data);
        }
        else if (data.type == OutputType.Anchor) {
            return (0, class_transformer_1.plainToInstance)(AnchorOutput, data);
        }
        else if (data.type == OutputType.Foundry) {
            return (0, class_transformer_1.plainToInstance)(FoundryOutput, data);
        }
        else if (data.type == OutputType.Nft) {
            return (0, class_transformer_1.plainToInstance)(NftOutput, data);
        }
        else if (data.type == OutputType.Delegation) {
            return (0, class_transformer_1.plainToInstance)(DelegationOutput, data);
        }
        throw new Error('Invalid JSON');
    }
}
exports.Output = Output;
/**
 * The base class for common outputs.
 */
class CommonOutput extends Output {
    /**
     * @param type The type of output.
     * @param amount The amount of the output.
     * @param unlockConditions Conditions to unlock the output.
     */
    constructor(type, amount, unlockConditions) {
        super(type, amount);
        this.unlockConditions = unlockConditions;
    }
    /**
     * The native token held by the output.
     */
    getNativeToken() {
        if (!this.features) {
            return undefined;
        }
        for (const feature of this.features) {
            if (feature instanceof feature_1.NativeTokenFeature) {
                return feature.asNativeToken();
            }
        }
        return undefined;
    }
}
__decorate([
    (0, class_transformer_1.Type)(() => unlock_condition_1.UnlockCondition, {
        discriminator: unlock_condition_1.UnlockConditionDiscriminator,
    })
], CommonOutput.prototype, "unlockConditions", void 0);
__decorate([
    (0, class_transformer_1.Type)(() => feature_1.Feature, {
        discriminator: feature_1.FeatureDiscriminator,
    })
], CommonOutput.prototype, "features", void 0);
exports.CommonOutput = CommonOutput;
/**
 * A Basic output.
 */
class BasicOutput extends CommonOutput {
    /**
     * @param amount The amount of the output.
     * @param mana The mana of the output.
     * @param unlockConditions The unlock conditions for the output.
     */
    constructor(amount, mana, unlockConditions) {
        super(OutputType.Basic, amount, unlockConditions);
        this.mana = mana;
    }
}
exports.BasicOutput = BasicOutput;
/**
 * Base class for immutable feature outputs.
 */
class ImmutableFeaturesOutput extends CommonOutput {
    /**
     * @param type The type of output.
     * @param amount The amount of the output.
     * @param unlockConditions The unlock conditions for the output.
     */
    constructor(type, amount, unlockConditions) {
        super(type, amount, unlockConditions);
    }
}
__decorate([
    (0, class_transformer_1.Type)(() => feature_1.Feature, {
        discriminator: feature_1.FeatureDiscriminator,
    })
], ImmutableFeaturesOutput.prototype, "immutableFeatures", void 0);
/**
 * An Account output.
 */
class AccountOutput extends ImmutableFeaturesOutput {
    /**
     * @param amount The amount of the output.
     * @param mana The amount of stored mana.
     * @param accountId The account ID as hex-encoded string.
     * @param foundryCounter A counter that denotes the number of foundries created by this account output.
     * @param unlockConditions The unlock conditions of the output.
     */
    constructor(amount, mana, accountId, foundryCounter, unlockConditions) {
        super(OutputType.Account, amount, unlockConditions);
        this.accountId = accountId;
        this.foundryCounter = foundryCounter;
        this.mana = mana;
    }
}
exports.AccountOutput = AccountOutput;
/**
 * An Anchor output.
 */
class AnchorOutput extends ImmutableFeaturesOutput {
    /**
     * @param amount The amount of the output.
     * @param mana The amount of stored mana.
     * @param anchorId The anchor ID as hex-encoded string.
     * @param stateIndex A counter that must increase by 1 every time the anchor output is state transitioned.
     * @param unlockConditions The unlock conditions of the output.
     */
    constructor(amount, mana, anchorId, stateIndex, unlockConditions) {
        super(OutputType.Account, amount, unlockConditions);
        this.anchorId = anchorId;
        this.stateIndex = stateIndex;
        this.mana = mana;
    }
}
exports.AnchorOutput = AnchorOutput;
/**
 * A Foundry output.
 */
class FoundryOutput extends ImmutableFeaturesOutput {
    /**
     * @param amount The amount of the output.
     * @param serialNumber The serial number of the Foundry with respect to the controlling account.
     * @param unlockConditions The unlock conditions of the output.
     * @param tokenScheme The token scheme for the Foundry.
     */
    constructor(amount, serialNumber, unlockConditions, tokenScheme) {
        super(OutputType.Foundry, amount, unlockConditions);
        this.serialNumber = serialNumber;
        this.tokenScheme = tokenScheme;
    }
}
__decorate([
    (0, class_transformer_1.Type)(() => token_scheme_1.TokenScheme, {
        discriminator: token_scheme_1.TokenSchemeDiscriminator,
    })
], FoundryOutput.prototype, "tokenScheme", void 0);
exports.FoundryOutput = FoundryOutput;
/**
 * An NFT output.
 */
class NftOutput extends ImmutableFeaturesOutput {
    /**
     * @param amount The amount of the output.
     * @param mana The amount of stored mana.
     * @param nftId The NFT ID as hex-encoded string.
     * @param unlockConditions The unlock conditions of the output.
     */
    constructor(amount, mana, nftId, unlockConditions) {
        super(OutputType.Nft, amount, unlockConditions);
        this.nftId = nftId;
        this.mana = mana;
    }
}
exports.NftOutput = NftOutput;
/**
 * A Delegation output.
 */
class DelegationOutput extends Output {
    /**
     * @param amount The amount of the output.
     * @param delegatedAmount The amount of delegated coins.
     * @param delegationId Unique identifier of the Delegation Output, which is the BLAKE2b-256 hash of the Output ID that created it.
     * @param validatorAddress The Account address of the validator to which this output is delegating.
     * @param startEpoch The index of the first epoch for which this output delegates.
     * @param endEpoch The index of the last epoch for which this output delegates.
     * @param unlockConditions The unlock conditions of the output.
     */
    constructor(amount, delegatedAmount, delegationId, validatorAddress, startEpoch, endEpoch, unlockConditions) {
        super(OutputType.Delegation, amount);
        this.delegatedAmount = delegatedAmount;
        this.delegationId = delegationId;
        this.validatorAddress = validatorAddress;
        this.startEpoch = startEpoch;
        this.endEpoch = endEpoch;
        this.unlockConditions = unlockConditions;
    }
}
__decorate([
    (0, class_transformer_1.Type)(() => address_1.Address, {
        discriminator: address_1.AddressDiscriminator,
    })
], DelegationOutput.prototype, "validatorAddress", void 0);
__decorate([
    (0, class_transformer_1.Type)(() => unlock_condition_1.UnlockCondition, {
        discriminator: unlock_condition_1.UnlockConditionDiscriminator,
    })
], DelegationOutput.prototype, "unlockConditions", void 0);
exports.DelegationOutput = DelegationOutput;
const OutputDiscriminator = {
    property: 'type',
    subTypes: [
        { value: BasicOutput, name: OutputType.Basic },
        { value: AccountOutput, name: OutputType.Account },
        { value: AnchorOutput, name: OutputType.Anchor },
        { value: FoundryOutput, name: OutputType.Foundry },
        { value: NftOutput, name: OutputType.Nft },
        { value: DelegationOutput, name: OutputType.Delegation },
    ],
};
exports.OutputDiscriminator = OutputDiscriminator;
//# sourceMappingURL=output.js.map