import { assert } from "../../assert.js";
import DataType from "./DataType.js";
import { readHexToken } from "./readHexToken.js";
import { readUnsignedIntegerToken } from "./readUnsignedIntegerToken.js";
import { skipWhitespace } from "./skipWhitespace.js";
import Token from "./Token.js";
import TokenType from "./TokenType.js";

/**
 *
 * @param {string} text
 * @param {number} cursor
 * @param {number} length
 * @returns {Token}
 */
export function readNumberToken(text, cursor, length) {
    assert.isString(text, 'text');
    assert.isNonNegativeInteger(cursor, 'cursor');
    assert.isNonNegativeInteger(length, 'length');

    let i = cursor;

    //read optional sign
    function readSign(text) {
        let sign = 1;
        const firstChar = text.charAt(i);
        if (firstChar === '-') {
            sign = -1;
        } else if (firstChar === '+') {
            sign = 1;
        } else {
            return 1;
        }

        i = skipWhitespace(text, i + 1, length);

        return sign;
    }

    const sign = readSign(text);

    let value;

    if (text.charAt(i) === '0' && (text.charAt(i + 1) === 'x' || text.charAt(i + 1) === 'X')) {
        // hex number
        const token = readHexToken(text, i, length);

        i = token.end;

        value = token.value;

    } else {

        const wholePart = readUnsignedIntegerToken(text, i, length);

        i = wholePart.end;

        value = wholePart.value;

        if (i < length) {
            const dot = text.charAt(i);
            if (dot === '.') {
                i++;
                const fraction = readUnsignedIntegerToken(text, i, length);

                const digits = (fraction.end - fraction.start);

                value += fraction.value / Math.pow(10, digits);

                i = fraction.end;
            }
        }
    }

    value *= sign;

    return new Token(value, cursor, i, TokenType.LiteralNumber, DataType.Number);
}
