"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.getTypeClass = getTypeClass;

var _types = require("./types");

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

var _BTreeMap = _interopRequireDefault(require("../BTreeMap"));

var _Compact = _interopRequireDefault(require("../Compact"));

var _Enum = _interopRequireDefault(require("../Enum"));

var _Linkage = _interopRequireDefault(require("../Linkage"));

var _Option = _interopRequireDefault(require("../Option"));

var _Result = _interopRequireDefault(require("../Result"));

var _Set = _interopRequireDefault(require("../Set"));

var _Struct = _interopRequireDefault(require("../Struct"));

var _Tuple = _interopRequireDefault(require("../Tuple"));

var _U8aFixed = _interopRequireDefault(require("../U8aFixed"));

var _Vec = _interopRequireDefault(require("../Vec"));

var _VecFixed = _interopRequireDefault(require("../VecFixed"));

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

var _registry = require("./registry");

// 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.
function getSubDefArray(value) {
  (0, _util.assert)(value.sub && Array.isArray(value.sub), "Expected subtype as TypeDef[] in ".concat(JSON.stringify(value)));
  return value.sub;
}

function getSubDef(value) {
  (0, _util.assert)(value.sub && !Array.isArray(value.sub), "Expected subtype as TypeDef in ".concat(JSON.stringify(value)));
  return value.sub;
}

function getSubType(value) {
  return getSubDef(value).type;
} // create a maps of type string constructors from the input


function getTypeClassMap(value) {
  const result = {};
  return getSubDefArray(value).reduce((result, sub) => {
    result[sub.name] = sub.type;
    return result;
  }, result);
} // create an array of type string constructors from the input


function getTypeClassArray(value) {
  return getSubDefArray(value).map((_ref) => {
    let {
      type
    } = _ref;
    return type;
  });
}

const infoMapping = {
  [_types.TypeDefInfo.BTreeMap]: value => {
    const [keyType, valueType] = getTypeClassArray(value); // eslint-disable-next-line @typescript-eslint/no-use-before-define

    return _BTreeMap.default.with(keyType, valueType);
  },
  [_types.TypeDefInfo.Compact]: value => _Compact.default.with(getSubType(value)),
  // eslint-disable-next-line @typescript-eslint/no-use-before-define
  [_types.TypeDefInfo.DoubleMap]: value => getTypeClass(getSubDef(value)),
  [_types.TypeDefInfo.Enum]: value => _Enum.default.with(getTypeClassMap(value)),
  [_types.TypeDefInfo.Linkage]: value => _Linkage.default.withKey(getSubType(value)),
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  [_types.TypeDefInfo.Null]: _ => (0, _createClass.ClassOf)('Null'),
  [_types.TypeDefInfo.Option]: value => _Option.default.with(getSubType(value)),
  [_types.TypeDefInfo.Plain]: value => (0, _registry.getTypeRegistry)().getOrThrow(value.type, "Unable to find plain type for ".concat(JSON.stringify(value))),
  [_types.TypeDefInfo.Result]: value => {
    const [Ok, Error] = getTypeClassArray(value); // eslint-disable-next-line @typescript-eslint/no-use-before-define

    return _Result.default.with({
      Ok,
      Error
    });
  },
  [_types.TypeDefInfo.Set]: value => {
    const result = {};
    return _Set.default.with(getSubDefArray(value).reduce((result, _ref2) => {
      let {
        name,
        index
      } = _ref2;
      result[name] = index;
      return result;
    }, result));
  },
  [_types.TypeDefInfo.Struct]: value => _Struct.default.with(getTypeClassMap(value)),
  [_types.TypeDefInfo.Tuple]: value => _Tuple.default.with(getTypeClassArray(value)),
  [_types.TypeDefInfo.Vec]: value => {
    const subType = getSubType(value);
    return subType === 'u8' ? (0, _createClass.ClassOf)('Bytes') : _Vec.default.with(subType);
  },
  [_types.TypeDefInfo.VecFixed]: value => {
    (0, _util.assert)(value.ext, 'Expected length & type information for fixed vector');
    const ext = value.ext;
    return ext.type === 'u8' ? _U8aFixed.default.with(ext.length * 8) : _VecFixed.default.with(ext.type, ext.length);
  }
}; // Returns the type Class for construction

function getTypeClass(value) {
  const Type = (0, _registry.getTypeRegistry)().get(value.type);

  if (Type) {
    return Type;
  }

  const getFn = infoMapping[value.info];

  if (!getFn) {
    throw new Error("Unable to determine type from ".concat(JSON.stringify(value)));
  }

  return getFn(value);
}