import { ChainingContextualSubstitutionTable, Lookup } from '../tables';
import { ILookupTree } from '../types';

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

/**
 * Build lookup tree for GSUB lookup table 6, format 1.
 * https://docs.microsoft.com/en-us/typography/opentype/spec/gsub#61-chaining-context-substitution-format-1-simple-glyph-contexts
 *
 * @param table JSON representation of the table
 * @param lookups List of lookup tables
 * @param tableIndex Index of this table in the overall lookup
 */
export default function buildTree(table: ChainingContextualSubstitutionTable.IFormat1, lookups: Lookup[], tableIndex: number): ILookupTree {
  const result: ILookupTree = {
    individual: {},
    range: []
  };

  const firstGlyphs = listGlyphsByIndex(table.coverage);

  for (const { glyphId, index } of firstGlyphs) {
    const chainRuleSet = table.chainRuleSets[index];

    // If the chain rule set is null there's nothing to do with this table.
    if (!chainRuleSet) {
      continue;
    }

    for (const [subIndex, subTable] of chainRuleSet.entries()) {
      let currentEntries: IEntryMeta[] = getInputTree(
        result,
        subTable.lookupRecords,
        lookups,
        0,
        glyphId
      ).map(({ entry, substitution }) => ({ entry, substitutions: [substitution] }));

      // We walk forward, then backward
      for (const [index, glyph] of subTable.input.entries()) {
        currentEntries = processInputPosition(
          [glyph],
          index + 1,
          currentEntries,
          subTable.lookupRecords,
          lookups
        );
      }

      for (const glyph of subTable.lookahead) {
        currentEntries = processLookaheadPosition(
          [glyph],
          currentEntries
        );
      }

      for (const glyph of subTable.backtrack) {
        currentEntries = processBacktrackPosition(
          [glyph],
          currentEntries
        );
      }

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

  return result;
}
