# Source: src/main/js/daemon/model/MoneroOutput.js

    const assert = require("assert");
    const BigInteger = require("../../common/biginteger").BigInteger;
    const GenUtils = require("../../common/GenUtils");
    const MoneroKeyImage = require("./MoneroKeyImage");

    /**
     * Models a Monero transaction output.
     *
     * @class
     */
    class MoneroOutput {

      /**
       * Construct the model.
       *
       * @param {MoneroOutput|object} state is existing state to initialize from (optional)
       */
      constructor(state) {

        // initialize internal state
        if (!state) state = {};
        else if (state instanceof MoneroOutput) state = state.toJson();
        else if (typeof state === "object") state = Object.assign({}, state);
        else throw new MoneroError("state must be a MoneroOutput or JavaScript object");
        this.state = state;

        // deserialize fields if necessary
        if (state.amount !== undefined && !(state.amount instanceof BigInteger)) state.amount = BigInteger.parse(state.amount);
        if (state.keyImage && !(state.keyImage instanceof MoneroKeyImage)) state.keyImage = new MoneroKeyImage(state.keyImage);
      }

      getTx() {
        return this.state.tx;
      }

      setTx(tx) {
        this.state.tx = tx;
        return this;
      }

      getKeyImage() {
        return this.state.keyImage;
      }

      setKeyImage(keyImage) {
        assert(keyImage === undefined || keyImage instanceof MoneroKeyImage);
        this.state.keyImage = keyImage;
        return this;
      }

      getAmount() {
        return this.state.amount;
      }

      setAmount(amount) {
        this.state.amount = amount;
        return this;
      }

      getIndex() {
        return this.state.index;
      }

      setIndex(index) {
        this.state.index = index;
        return this;
      }

      getRingOutputIndices() {
        return this.state.ringOutputIndices;
      }

      setRingOutputIndices(ringOutputIndices) {
        this.state.ringOutputIndices = ringOutputIndices;
        return this;
      }

      getStealthPublicKey() {
        return this.state.stealthPublicKey;
      }

      setStealthPublicKey(stealthPublicKey) {
        this.state.stealthPublicKey = stealthPublicKey;
        return this;
      }

      copy() {
        return new MoneroOutput(this);
      }

      toJson() {
        let json = Object.assign({}, this.state);
        if (this.getAmount()) json.amount = this.getAmount() ? this.getAmount().toString() : undefined;
        if (this.getKeyImage()) json.keyImage = this.getKeyImage() ? this.getKeyImage().toJson() : undefined;
        delete json.tx;
        return json;
      }

      merge(output) {
        assert(output instanceof MoneroOutput);
        if (this === output) return this;

        // merge txs if they're different which comes back to merging outputs
        if (this.getTx() !== output.getTx()) this.getTx().merge(output.getTx());

        // otherwise merge output fields
        else {
          if (this.getKeyImage() === undefined) this.setKeyImage(output.getKeyImage());
          else if (output.getKeyImage() !== undefined) this.getKeyImage().merge(output.getKeyImage());
          this.setAmount(GenUtils.reconcile(this.getAmount(), output.getAmount()));
          this.setIndex(GenUtils.reconcile(this.getIndex(), output.getIndex()));
        }

        return this;
      }

      toString(indent = 0) {
        let str = "";
        if (this.getKeyImage()) {
          str += GenUtils.kvLine("Key image", "", indent);
          str += this.getKeyImage().toString(indent + 1) + "\n";
        }
        str += GenUtils.kvLine("Amount", this.getAmount(), indent);
        str += GenUtils.kvLine("Index", this.getIndex(), indent);
        str += GenUtils.kvLine("Ring output indices", this.getRingOutputIndices(), indent);
        str += GenUtils.kvLine("Stealth public key", this.getStealthPublicKey(), indent);
        return str === "" ? str : str.slice(0, str.length - 1);  // strip last newline
      }
    }

    module.exports = MoneroOutput;