import { assert } from "../../assert.js";
import DataType from "./DataType.js";
import ParserError from "./ParserError.js";
import Token from "./Token.js";

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

    const c0 = text.charAt(cursor);
    const c1 = text.charAt(cursor + 1);

    if (c0 !== '0' || !(c1 === 'x' || c1 === 'X')) {
        throw new ParserError(cursor, 'Expected hex prefix 0x', text);
    }

    let i = cursor + 2;
    let value = 0;

    main_loop: for (; i < length;) {
        const char = text.charAt(i);
        let digit;
        switch (char) {
            case '0':
                digit = 0;
                break;
            case '1':
                digit = 1;
                break;
            case '2':
                digit = 2;
                break;
            case '3':
                digit = 3;
                break;
            case '4':
                digit = 4;
                break;
            case '5':
                digit = 5;
                break;
            case '6':
                digit = 6;
                break;
            case '7':
                digit = 7;
                break;
            case '8':
                digit = 8;
                break;
            case '9':
                digit = 9;
                break;
            case 'a':
            case 'A':
                digit = 10;
                break;
            case 'b':
            case 'B':
                digit = 11;
                break;
            case 'c':
            case 'C':
                digit = 12;
                break;
            case 'd':
            case 'D':
                digit = 13;
                break;
            case 'e':
            case 'E':
                digit = 14;
                break;
            case 'f':
            case 'F':
                digit = 15;
                break;
            default:
                if (i === cursor) {
                    //first character is not a digit
                    throw new ParserError(i, `Expected a digit [0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F] but got '${char}' instead`, text);
                }
                //not a digit
                break main_loop;
        }
        i++;
        value = value * 16 + digit;
    }


    return new Token(value, cursor, i, "uint", DataType.Number);
}
