"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.getTypeRegistry = getTypeRegistry;
exports.TypeRegistry = void 0;

var _util = require("@polkadot/util");

var _createClass = require("./createClass");

// Copyright 2017-2019 @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.
class TypeRegistry {
  constructor() {
    this._classes = new Map();
    this._definitions = new Map();
  }

  // eslint-disable-next-line no-dupe-class-members
  register(arg1, arg2) {
    if ((0, _util.isString)(arg1)) {
      const name = arg1;
      const type = arg2;

      this._classes.set(name, type);
    } else if ((0, _util.isFunction)(arg1)) {
      const name = arg1.name;
      const type = arg1;

      this._classes.set(name, type);
    } else {
      this.registerObject(arg1);
    }
  }

  registerObject(obj) {
    Object.entries(obj).forEach((_ref) => {
      let [name, type] = _ref;

      if ((0, _util.isFunction)(type)) {
        // This _looks_ a bit funny, but `typeof Clazz === 'function'
        this._classes.set(name, type);
      } else {
        const def = (0, _util.isString)(type) ? type : JSON.stringify(type); // we already have this type, remove the classes registered for it

        if (this._classes.has(name)) {
          this._classes.delete(name);
        }

        this._definitions.set(name, def);
      }
    });
  }

  get(name) {
    let Type = this._classes.get(name); // we have not already created the type, attempt it


    if (!Type) {
      const definition = this._definitions.get(name); // we have a definition, so create the class now (lazily)


      if (definition) {
        const BaseType = (0, _createClass.createClass)(definition); // NOTE If we didn't extend here, we would have strange artifacts. An example is
        // Balance, with this, new Balance() instanceof u128 is true, but Balance !== u128

        Type = class extends BaseType {};

        this._classes.set(name, Type);
      }
    }

    return Type;
  }

  getDefinition(name) {
    return this._definitions.get(name);
  }

  getOrThrow(name, msg) {
    const type = this.get(name);

    if ((0, _util.isUndefined)(type)) {
      throw new Error(msg || "type ".concat(name, " not found"));
    }

    return type;
  }

  hasClass(name) {
    return this._classes.has(name);
  }

  hasDef(name) {
    return this._definitions.has(name);
  }

  hasType(name) {
    return this.hasClass(name) || this.hasDef(name);
  }

}

exports.TypeRegistry = TypeRegistry;
TypeRegistry.defaultRegistry = new TypeRegistry();

function getTypeRegistry() {
  return TypeRegistry.defaultRegistry;
}