import { ReverseChainingContextualSingleSubstitutionTable } from '../tables';
import { LookupTree, LookupTreeEntry } from '../types';

import { listGlyphsByIndex } from './coverage';
import { processLookaheadPosition, processBacktrackPosition, EntryMeta } 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: ReverseChainingContextualSingleSubstitutionTable, tableIndex: number): LookupTree {
    const result: LookupTree = {
        individual: {},
        range: []
    };

    const glyphs = listGlyphsByIndex(table.coverage);

    for (const { glyphId, index } of glyphs) {
        const initialEntry: LookupTreeEntry = {};
        if (Array.isArray(glyphId)) {
            result.range.push({
                entry: initialEntry,
                range: glyphId
            });
        } else {
            result.individual[glyphId] = initialEntry;
        }

        let currentEntries: EntryMeta[] = [{
            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;
}
