import Resource from './resource';
export default class ResourceManager {
  constructor(props) {
    var _props$device;

    this.protocol = void 0;
    this._context = void 0;
    this._resources = void 0;
    this._consumers = void 0;
    this._pruneRequest = void 0;
    this.protocol = props.protocol || 'resource://';
    this._context = {
      device: props.device,
      gl: (_props$device = props.device) === null || _props$device === void 0 ? void 0 : _props$device.gl,
      resourceManager: this
    };
    this._resources = {};
    this._consumers = {};
    this._pruneRequest = null;
  }

  contains(resourceId) {
    if (resourceId.startsWith(this.protocol)) {
      return true;
    }

    return resourceId in this._resources;
  }

  add({
    resourceId,
    data,
    forceUpdate = false,
    persistent = true
  }) {
    let res = this._resources[resourceId];

    if (res) {
      res.setData(data, forceUpdate);
    } else {
      res = new Resource(resourceId, data, this._context);
      this._resources[resourceId] = res;
    }

    res.persistent = persistent;
  }

  remove(resourceId) {
    const res = this._resources[resourceId];

    if (res) {
      res.delete();
      delete this._resources[resourceId];
    }
  }

  unsubscribe({
    consumerId
  }) {
    const consumer = this._consumers[consumerId];

    if (consumer) {
      for (const requestId in consumer) {
        const request = consumer[requestId];
        const resource = this._resources[request.resourceId];

        if (resource) {
          resource.unsubscribe(request);
        }
      }

      delete this._consumers[consumerId];
      this.prune();
    }
  }

  subscribe({
    resourceId,
    onChange,
    consumerId,
    requestId = 'default'
  }) {
    const {
      _resources: resources,
      protocol
    } = this;

    if (resourceId.startsWith(protocol)) {
      resourceId = resourceId.replace(protocol, '');

      if (!resources[resourceId]) {
        this.add({
          resourceId,
          data: null,
          persistent: false
        });
      }
    }

    const res = resources[resourceId];

    this._track(consumerId, requestId, res, onChange);

    if (res) {
      return res.getData();
    }

    return undefined;
  }

  prune() {
    if (!this._pruneRequest) {
      this._pruneRequest = setTimeout(() => this._prune(), 0);
    }
  }

  finalize() {
    for (const key in this._resources) {
      this._resources[key].delete();
    }
  }

  _track(consumerId, requestId, resource, onChange) {
    const consumers = this._consumers;
    const consumer = consumers[consumerId] = consumers[consumerId] || {};
    let request = consumer[requestId];
    const oldResource = request && request.resourceId && this._resources[request.resourceId];

    if (oldResource) {
      oldResource.unsubscribe(request);
      this.prune();
    }

    if (resource) {
      if (request) {
        request.onChange = onChange;
        request.resourceId = resource.id;
      } else {
        request = {
          onChange,
          resourceId: resource.id
        };
      }

      consumer[requestId] = request;
      resource.subscribe(request);
    }
  }

  _prune() {
    this._pruneRequest = null;

    for (const key of Object.keys(this._resources)) {
      const res = this._resources[key];

      if (!res.persistent && !res.inUse()) {
        res.delete();
        delete this._resources[key];
      }
    }
  }

}
//# sourceMappingURL=resource-manager.js.map