// The `GPOS` table contains kerning pairs, among other things.
// https://docs.microsoft.com/en-us/typography/opentype/spec/gpos

import check from '../check';
import { Parser } from '../parse';

const subtableParsers = new Array(10); // subtableParsers[0] is unused

// https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-1-single-adjustment-positioning-subtable
// this = Parser instance
subtableParsers[1] = function parseLookup1() {
    const start = this.offset + this.relativeOffset;
    const posformat = this.parseUShort();
    if (posformat === 1) {
        return {
            posFormat: 1,
            coverage: this.parsePointer(Parser.coverage),
            value: this.parseValueRecord(),
        };
    } else if (posformat === 2) {
        return {
            posFormat: 2,
            coverage: this.parsePointer(Parser.coverage),
            values: this.parseValueRecordList(),
        };
    }
    check.assert(
        false,
        '0x' +
            start.toString(16) +
            ': GPOS lookup type 1 format must be 1 or 2.'
    );
};

// https://docs.microsoft.com/en-us/typography/opentype/spec/gpos#lookup-type-2-pair-adjustment-positioning-subtable
subtableParsers[2] = function parseLookup2() {
    const start = this.offset + this.relativeOffset;
    const posFormat = this.parseUShort();
    check.assert(
        posFormat === 1 || posFormat === 2,
        '0x' +
            start.toString(16) +
            ': GPOS lookup type 2 format must be 1 or 2.'
    );
    const coverage = this.parsePointer(Parser.coverage);
    const valueFormat1 = this.parseUShort();
    const valueFormat2 = this.parseUShort();
    if (posFormat === 1) {
        // Adjustments for Glyph Pairs
        return {
            posFormat: posFormat,
            coverage: coverage,
            valueFormat1: valueFormat1,
            valueFormat2: valueFormat2,
            pairSets: this.parseList(
                Parser.pointer(
                    Parser.list(function () {
                        return {
                            // pairValueRecord
                            secondGlyph: this.parseUShort(),
                            value1: this.parseValueRecord(valueFormat1),
                            value2: this.parseValueRecord(valueFormat2),
                        };
                    })
                )
            ),
        };
    } else if (posFormat === 2) {
        const classDef1 = this.parsePointer(Parser.classDef);
        const classDef2 = this.parsePointer(Parser.classDef);
        const class1Count = this.parseUShort();
        const class2Count = this.parseUShort();
        return {
            // Class Pair Adjustment
            posFormat: posFormat,
            coverage: coverage,
            valueFormat1: valueFormat1,
            valueFormat2: valueFormat2,
            classDef1: classDef1,
            classDef2: classDef2,
            class1Count: class1Count,
            class2Count: class2Count,
            classRecords: this.parseList(
                class1Count,
                Parser.list(class2Count, function () {
                    return {
                        value1: this.parseValueRecord(valueFormat1),
                        value2: this.parseValueRecord(valueFormat2),
                    };
                })
            ),
        };
    }
};

subtableParsers[3] = function parseLookup3() {
    return { error: 'GPOS Lookup 3 not supported' };
};
subtableParsers[4] = function parseLookup4() {
    return { error: 'GPOS Lookup 4 not supported' };
};
subtableParsers[5] = function parseLookup5() {
    return { error: 'GPOS Lookup 5 not supported' };
};
subtableParsers[6] = function parseLookup6() {
    return { error: 'GPOS Lookup 6 not supported' };
};
subtableParsers[7] = function parseLookup7() {
    return { error: 'GPOS Lookup 7 not supported' };
};
subtableParsers[8] = function parseLookup8() {
    return { error: 'GPOS Lookup 8 not supported' };
};
subtableParsers[9] = function parseLookup9() {
    return { error: 'GPOS Lookup 9 not supported' };
};

// https://docs.microsoft.com/en-us/typography/opentype/spec/gpos
function parseGposTable(data, start) {
    start = start || 0;
    const p = new Parser(data, start);
    const tableVersion = p.parseVersion(1);
    check.argument(
        tableVersion === 1 || tableVersion === 1.1,
        'Unsupported GPOS table version ' + tableVersion
    );

    if (tableVersion === 1) {
        return {
            version: tableVersion,
            scripts: p.parseScriptList(),
            features: p.parseFeatureList(),
            lookups: p.parseLookupList(subtableParsers),
        };
    } else {
        return {
            version: tableVersion,
            scripts: p.parseScriptList(),
            features: p.parseFeatureList(),
            lookups: p.parseLookupList(subtableParsers),
            variations: p.parseFeatureVariationsList(),
        };
    }
}

export default { parse: parseGposTable };
