import { IReverseChainingContextualSingleSubstitutionTable } from '../tables';
import { ILookupTree, ILookupTreeEntry } from '../types';

import { listGlyphsByIndex } from './coverage';
import { processLookaheadPosition, processBacktrackPosition, IEntryMeta } from './helper';

/**
 * Build lookup tree for GSUB lookup table 8, format 1.
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#81-reverse-chaining-contextual-single-substitution-format-1-coverage-based-glyph-contexts
 *
 * @param table JSON representation of the table
 * @param tableIndex Index of this table in the overall lookup
 */
export default function buildTree(table: IReverseChainingContextualSingleSubstitutionTable, tableIndex: number): ILookupTree {
  const result: ILookupTree = {
    individual: {},
    range: []
  };

  const glyphs = listGlyphsByIndex(table.coverage);

  for (const { glyphId, index } of glyphs) {
    const initialEntry: ILookupTreeEntry = {};
    if (Array.isArray(glyphId)) {
      result.range.push({
        entry: initialEntry,
        range: glyphId
      });
    } else {
      result.individual[glyphId] = initialEntry;
    }

    let currentEntries: IEntryMeta[] = [{
      entry: initialEntry,
      substitutions: [table.substitutes[index]]
    }];

    // We walk forward, then backward
    for (const coverage of table.lookaheadCoverage) {
      currentEntries = processLookaheadPosition(
        listGlyphsByIndex(coverage).map(glyph => glyph.glyphId),
        currentEntries
      );
    }

    for (const coverage of table.backtrackCoverage) {
      currentEntries = processBacktrackPosition(
        listGlyphsByIndex(coverage).map(glyph => glyph.glyphId),
        currentEntries
      );
    }

    // When we get to the end, insert the lookup information
    for (const { entry, substitutions } of currentEntries) {
      entry.lookup = {
        substitutions,
        index: tableIndex,
        subIndex: 0,
        length: 1,
        contextRange: [
          -1 * table.backtrackCoverage.length,
          1 + table.lookaheadCoverage.length
        ]
      };
    }
  }

  return result;
}
