"use strict";
// Copyright 2017-2020 @polkadot/types authors & contributors
// This software may be modified and distributed under the terms
// of the Apache-2.0 license. See the LICENSE file for details.
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const util_1 = require("@polkadot/util");
const util_crypto_1 = require("@polkadot/util-crypto");
const create_1 = require("../../codec/create");
const Base_1 = __importDefault(require("../../codec/Base"));
const AccountId_1 = __importDefault(require("./AccountId"));
const AccountIndex_1 = __importDefault(require("./AccountIndex"));
exports.ACCOUNT_ID_PREFIX = new Uint8Array([0xff]);
/**
 * @name Address
 * @description
 * A wrapper around an AccountId and/or AccountIndex that is encoded with a prefix.
 * Since we are dealing with underlying publicKeys (or shorter encoded addresses),
 * we extend from Base with an AccountId/AccountIndex wrapper. Basically the Address
 * is encoded as `[ <prefix-byte>, ...publicKey/...bytes ]` as per spec
 */
class Address extends Base_1.default {
    constructor(registry, value = new Uint8Array()) {
        super(registry, Address.decodeAddress(registry, value));
    }
    /** @internal */
    static decodeAddress(registry, value) {
        if (value instanceof AccountId_1.default || value instanceof AccountIndex_1.default) {
            return value;
        }
        else if (value instanceof Address) {
            return value.raw;
        }
        else if (util_1.isBn(value) || util_1.isNumber(value)) {
            return create_1.createType(registry, 'AccountIndex', value);
        }
        else if (Array.isArray(value) || util_1.isHex(value) || util_1.isU8a(value)) {
            return Address.decodeU8a(registry, util_1.u8aToU8a(value));
        }
        return Address.decodeString(registry, value);
    }
    /** @internal */
    static decodeString(registry, value) {
        const decoded = util_crypto_1.decodeAddress(value);
        return decoded.length === 32
            ? create_1.createType(registry, 'AccountId', decoded)
            : create_1.createType(registry, 'AccountIndex', util_1.u8aToBn(decoded, true));
    }
    /** @internal */
    static decodeU8a(registry, value) {
        // This allows us to instantiate an address with a raw publicKey. Do this first before
        // we checking the first byte, otherwise we may split an already-existent valid address
        if (value.length === 32) {
            return create_1.createType(registry, 'AccountId', value);
        }
        else if (value[0] === 0xff) {
            return create_1.createType(registry, 'AccountId', value.subarray(1));
        }
        const [offset, length] = AccountIndex_1.default.readLength(value);
        return create_1.createType(registry, 'AccountIndex', util_1.u8aToBn(value.subarray(offset, offset + length), true));
    }
    /**
     * @description The length of the value when encoded as a Uint8Array
     */
    get encodedLength() {
        const rawLength = this.rawLength;
        return rawLength + (
        // for 1 byte AccountIndexes, we are not adding a specific prefix
        rawLength > 1
            ? 1
            : 0);
    }
    /**
     * @description The length of the raw value, either AccountIndex or AccountId
     */
    get rawLength() {
        return this.raw instanceof AccountIndex_1.default
            ? AccountIndex_1.default.calcLength(this.raw)
            : this.raw.encodedLength;
    }
    /**
     * @description Returns a hex string representation of the value
     */
    toHex() {
        return util_1.u8aToHex(this.toU8a());
    }
    /**
     * @description Returns the base runtime type name for this instance
     */
    toRawType() {
        return 'Address';
    }
    /**
     * @description Encodes the value as a Uint8Array as per the SCALE specifications
     * @param isBare true when the value has none of the type-specific prefixes (internal)
     */
    toU8a(isBare) {
        const encoded = this.raw.toU8a().subarray(0, this.rawLength);
        return isBare
            ? encoded
            : util_1.u8aConcat(this.raw instanceof AccountIndex_1.default
                ? AccountIndex_1.default.writeLength(encoded)
                : exports.ACCOUNT_ID_PREFIX, encoded);
    }
}
exports.default = Address;
