import { SubstitutionTable } from '../tables';

import getCoverageGlyphIndex from './coverage';

/**
 * Get the substitution glyph for the givne glyph, or null if the glyph was not
 * found in the table.
 *
 * @param table JSON representation of the substitution table
 * @param glyphId The index of the glpyh to find substitutions for
 */
export function getRangeSubstitutionGlyphs(table: SubstitutionTable, glyphId: [number, number]): Map<[number, number] | number, number | null> {
  const replacementStart: number = glyphId[0];
  const currentReplacement: number | null = getIndividualSubstitutionGlyph(table, replacementStart);
  let search: number = glyphId[0] + 1;

  const result = new Map<[number, number] | number, number | null>();

  while (search < glyphId[1]) {
    const sub = getIndividualSubstitutionGlyph(table, search);
    if (sub !== currentReplacement) {
      if (search - replacementStart <= 1) {
        result.set(replacementStart, currentReplacement);
      } else {
        result.set([replacementStart, search], currentReplacement);
      }
    }

    search++;
  }

  if (search - replacementStart <= 1) {
    result.set(replacementStart, currentReplacement);
  } else {
    result.set([replacementStart, search], currentReplacement);
  }

  return result;
}

export function getIndividualSubstitutionGlyph(table: SubstitutionTable, glyphId: number): number | null {
  const coverageIndex = getCoverageGlyphIndex(table.coverage, glyphId);

  // istanbul ignore next - invalid font
  if (coverageIndex === null) {
    return null;
  }

  switch (table.substFormat) {
    // https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#11-single-substitution-format-1
    case 1:
      // TODO: determine if there's a rhyme or reason to the 16-bit
      // wraparound and if it can ever be a different number
      return (glyphId + table.deltaGlyphId) % (2 ** 16);
    // https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#12-single-substitution-format-2
    case 2:
      return table.substitute[coverageIndex] ?? null;
  }
}
