<commit_before>/**
 * mappings.js
 * @flow
 */

import _ from "lodash";
import Request from "libs/request";
import ErrorHandling from "libs/error_handling";
import type Layer, { DataStoreInfoType } from "oxalis/model/binary/layers/layer";

export type MappingArray = Array<number>;

export type MappingType = {
  parent: ?string;
  name: string;
  classes: ?Array<Array<number>>;
};

class Mappings {

  mappings: {
    [key: string]: MappingType,
  } = {};
  baseUrl: string;
  doWithToken: Function;

  constructor(dataStoreInfo: DataStoreInfoType, datasetName: string, layer: Layer) {
    this.mappings = _.transform(layer.mappings, (result, mappingObject) => {
      result[mappingObject.name] = mappingObject;
    }, {});
    this.baseUrl = `${dataStoreInfo.url}/data/datasets/${datasetName}/layers/${layer.name}/mappings/`;
    this.doWithToken = layer.doWithToken.bind(layer);
  }


  getMappingNames(): Array<string> {
    return _.keys(this.mappings);
  }


  async getMappingArrayAsync(mappingName: string): Promise<MappingArray> {
    await this.fetchMappings(mappingName);
    return this.buildMappingArray(mappingName);
  }


  fetchMappings(mappingName: string): Promise<*> {
    const mappingChain = this.getMappingChain(mappingName);
    return Promise.all(mappingChain.map(curMappingName => this.fetchMapping(curMappingName)));
  }


  fetchMapping(mappingName: string): Promise<?MappingType> {
    const mappingObject = this.mappings[mappingName];
    if (mappingObject != null && mappingObject.classes != null) {
      return Promise.resolve(mappingObject);
    }
    return this.doWithToken((token: string) => Request.receiveJSON(
        `${this.baseUrl + mappingName}?token=${token}`,
      ).then((mapping: MappingType) => {
        this.mappings[mappingName] = mapping;
        console.log("Done downloading:", mappingName);
        return mapping;
      }, error => console.error("Error downloading:", mappingName, error)),
    );
  }


  buildMappingArray(mappingName: string): MappingArray {
    const mappingArray: MappingArray = [];

    for (const currentMappingName of this.getMappingChain(mappingName)) {
      const mappingObject = this.mappings[currentMappingName];
      ErrorHandling.assert(mappingObject.classes,
          "mappingObject must have been fetched at this point");
      if (mappingObject.classes) {
        for (const mappingClass of mappingObject.classes) {
          const minId = _.min(mappingClass);
          const mappedId = mappingArray[minId] || minId;
          for (const id of mappingClass) {
            mappingArray[id] = mappedId;
          }
        }
      }
    }

    return mappingArray;
  }


  getMappingChain(mappingName: string): Array<string> {
    const chain = [mappingName];<commit_msg>adds better assertion message<commit_after>/**
 * mappings.js
 * @flow
 */

import _ from "lodash";
import Request from "libs/request";
import ErrorHandling from "libs/error_handling";
import type Layer, { DataStoreInfoType } from "oxalis/model/binary/layers/layer";

export type MappingArray = Array<number>;

export type MappingType = {
  parent: ?string;
  name: string;
  classes: ?Array<Array<number>>;
};

class Mappings {

  mappings: {
    [key: string]: MappingType,
  } = {};
  baseUrl: string;
  doWithToken: Function;

  constructor(dataStoreInfo: DataStoreInfoType, datasetName: string, layer: Layer) {
    this.mappings = _.transform(layer.mappings, (result, mappingObject) => {
      result[mappingObject.name] = mappingObject;
    }, {});
    this.baseUrl = `${dataStoreInfo.url}/data/datasets/${datasetName}/layers/${layer.name}/mappings/`;
    this.doWithToken = layer.doWithToken.bind(layer);
  }


  getMappingNames(): Array<string> {
    return _.keys(this.mappings);
  }


  async getMappingArrayAsync(mappingName: string): Promise<MappingArray> {
    await this.fetchMappings(mappingName);
    return this.buildMappingArray(mappingName);
  }


  fetchMappings(mappingName: string): Promise<*> {
    const mappingChain = this.getMappingChain(mappingName);
    return Promise.all(mappingChain.map(curMappingName => this.fetchMapping(curMappingName)));
  }


  fetchMapping(mappingName: string): Promise<?MappingType> {
    const mappingObject = this.mappings[mappingName];
    if (mappingObject != null && mappingObject.classes != null) {
      return Promise.resolve(mappingObject);
    }
    return this.doWithToken((token: string) => Request.receiveJSON(
        `${this.baseUrl + mappingName}?token=${token}`,
      ).then((mapping: MappingType) => {
        this.mappings[mappingName] = mapping;
        console.log("Done downloading:", mappingName);
        return mapping;
      }, error => console.error("Error downloading:", mappingName, error)),
    );
  }


  buildMappingArray(mappingName: string): MappingArray {
    const mappingArray: MappingArray = [];

    for (const currentMappingName of this.getMappingChain(mappingName)) {
      const mappingObject = this.mappings[currentMappingName];
      ErrorHandling.assert(mappingObject.classes,
          "mappingObject classes must have been fetched at this point");
      if (mappingObject.classes) {
        for (const mappingClass of mappingObject.classes) {
          const minId = _.min(mappingClass);
          const mappedId = mappingArray[minId] || minId;
          for (const id of mappingClass) {
            mappingArray[id] = mappedId;
          }
        }
      }
    }

    return mappingArray;
  }


  getMappingChain(mappingName: string): Array<string> {
    const chain = [mappingName];
{'fraction_non_alphanumeric': 0.12536023054755044, 'fraction_numerical': 0.0, 'mean_word_length': 3.734015345268542, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5446981', 'n_tokens_mistral': 1623, 'n_tokens_neox': 1577, 'n_words': 333}