/**
 * @file data.h
 * @brief The `DATA` item list and the `READ` cursor `RESTORE` resets.
 *
 * The Go reference has neither. Its `READ` does not read: it records the
 * identifiers it wants filled, sets the scope waiting for a `DATA` verb, and
 * lets execution skip forward until one turns up. That has two consequences,
 * both wrong and both fixed here:
 *
 *   - **A `DATA` line before its `READ` is never found.** `10 DATA 1,2` /
 *     `20 READ A#` skipped to the end of the program in silence.
 *   - **There is no cursor**, so `RESTORE` had nothing to reset and could not be
 *     implemented at all.
 *
 * Every `DATA` statement is pre-scanned into one flat list before the program
 * runs, the same way labels are (akbasic_runtime_scan_labels), and `READ` walks
 * a cursor along it. Items are kept as their source text and converted when read,
 * because what a `DATA` item means depends on the variable it is read into --
 * `DATA 5` fills `A#` with an integer and `A$` with "5".
 */

#ifndef _AKBASIC_DATA_H_
#define _AKBASIC_DATA_H_

#include <akerror.h>

#include <akbasic/types.h>

/** @brief How many `DATA` items a program may hold. */
#define AKBASIC_MAX_DATA_ITEMS		512
/** @brief Longest single `DATA` item, terminator included. */
#define AKBASIC_MAX_DATA_ITEM_LENGTH	128

/** @brief One `DATA` item: its text, where it was written, and whether it was quoted. */
typedef struct
{
    char text[AKBASIC_MAX_DATA_ITEM_LENGTH];
    int64_t lineno;			/** so RESTORE (line) can find it	*/
    bool quoted;			/** written with quotes, so it is a string */
} akbasic_DataItem;

/** @brief Every `DATA` item in the program, and how far `READ` has got. */
typedef struct
{
    akbasic_DataItem items[AKBASIC_MAX_DATA_ITEMS];
    int count;
    int cursor;
} akbasic_DataState;

struct akbasic_Runtime;

/**
 * @brief Reset the item list and the cursor.
 * @param obj Object to initialize, inspect, or modify.
 * @return `NULL` on success, otherwise an error context owned by the caller.
 * @throws AKERR_NULLPOINTER When `obj` is NULL.
 */
akerr_ErrorContext AKERR_NOIGNORE *akbasic_data_state_init(akbasic_DataState *obj);

/**
 * @brief Collect every `DATA` item in the stored program, in source order.
 *
 * Called on every entry into AKBASIC_MODE_RUN, beside
 * akbasic_runtime_scan_labels() and for the same reason: it is the one point
 * `RUN`, `CONT`, akbasic_runtime_start() and the end of a RUNSTREAM load all
 * pass through. Re-scanning is what picks up a program edited at the REPL.
 *
 * The scan is textual. `DATA` at the start of a statement, outside a string
 * literal, then comma-separated items up to a `:` or the end of the line -- which
 * is where a Commodore ends a `DATA` statement too.
 *
 * @param obj Object to initialize, inspect, or modify.
 * @return `NULL` on success, otherwise an error context owned by the caller.
 * @throws AKERR_NULLPOINTER When `obj` is NULL.
 * @throws AKBASIC_ERR_BOUNDS When the program holds more than AKBASIC_MAX_DATA_ITEMS items.
 */
akerr_ErrorContext AKERR_NOIGNORE *akbasic_data_scan(struct akbasic_Runtime *obj);

/**
 * @brief Take the next `DATA` item and convert it for a variable of @p type.
 *
 * @param obj Object to initialize, inspect, or modify.
 * @param type The type of the variable being filled.
 * @param dest Output destination populated by the function.
 * @return `NULL` on success, otherwise an error context owned by the caller.
 * @throws AKERR_NULLPOINTER When any argument is NULL.
 * @throws AKBASIC_ERR_STATE When there are no items left -- "OUT OF DATA".
 * @throws AKBASIC_ERR_TYPE When a quoted item is read into a numeric variable.
 */
akerr_ErrorContext AKERR_NOIGNORE *akbasic_data_next(struct akbasic_Runtime *obj, akbasic_Type type, akbasic_Value *dest);

#endif // _AKBASIC_DATA_H_
