/*
 * mdview2.h — общие определения и интерфейс между модулями mdview2.
 *
 * Монолит mdview2.c расщеплён на ядро + модули: index (парсер), md/raw (виды),
 * enc (кодировки), table, help. Здесь — разделяемые константы экрана/атрибутов,
 * словари флагов/стилей, тип cache_rec_t, extern-объявления разделяемого
 * состояния ядра и API каждого модуля (сгруппированы по секциям ниже).
 */
#ifndef MDVIEW2_H
#define MDVIEW2_H

#include <stdint.h>
#include <palette.h>     /* COLOR(), COLOR_* */
#include "mdview2_conf.h" /* WITH_RAW / WITH_HEX — выбор опциональных модулей */

/* ---- Геометрия экрана -------------------------------------------- */
#define SCREEN_W      80
#define SCREEN_H      32
#define VIEW_TOP_ROW   1
#define VIEW_H        30          /* видимая область: строки 1..30 включительно */
#define MENU_ROW      31
#define TAB_STOP       4
#define HPAN_STEP      8u         /* шаг горизонтального сдвига (←/→) */

/* ---- Геометрия статус-бара (строка 0): фиксированные поля и разделители ---- */
#define SPINNER_COL    8          /* слот спиннера загрузки */
#define DIV1_X        45          /* разделитель │ перед числами диапазона строк */
#define DIV2_X        71          /* разделитель │ перед процентом */
/* Числа/метка пишутся с DIVn_X+2; область между разделителями — [DIV1_X+1 .. DIV2_X-1]. */

/* ---- Параметры файла и памяти ------------------------------------ */
#define PAGE_BITS    14u
#define PAGE_SIZE    (1u << PAGE_BITS)        /* размер EMM-страницы: 16 КБ */
#define PAGE_MASK    ((uint16_t)(PAGE_SIZE - 1u))
#define MAX_PAGES    16                       /* 16 страниц × 16 КБ = 256 КБ */
#define MAX_FILE     ((uint32_t)MAX_PAGES * PAGE_SIZE)
#define FILE_BUF     ((char *)0xC000)         /* окно W3, куда мапится текущая EMM-страница */

/* ---- Палитра атрибутов ------------------------------------------- */
#define ATTR_RESET          COLOR(COLOR_LIGHTGRAY,    COLOR_BLACK)
#define ATTR_TEXT           COLOR(COLOR_LIGHTGRAY,    COLOR_BLUE)
#define ATTR_TEXT_TITLE1    COLOR(COLOR_YELLOW,       COLOR_BLUE)
#define ATTR_TEXT_TITLE2    COLOR(COLOR_LIGHTBLUE,    COLOR_BLUE)
#define ATTR_TEXT_TITLE3    COLOR(COLOR_LIGHTGREEN,   COLOR_BLUE)
#define ATTR_TEXT_TITLE4    COLOR(COLOR_LIGHTGREEN,   COLOR_BLUE)
#define ATTR_TEXT_BOLD      COLOR(COLOR_LIGHTRED,     COLOR_BLUE)
#define ATTR_TEXT_ITALIC    COLOR(COLOR_LIGHTGREEN,   COLOR_BLUE)
#define ATTR_TEXT_UNDERSORE COLOR(COLOR_LIGHTMAGENTA, COLOR_BLUE)
#define ATTR_TEXT_CODE      COLOR(COLOR_WHITE,        COLOR_BLUE)
#define ATTR_TEXT_STRIKE    COLOR(COLOR_DARKGRAY,     COLOR_BLUE)
#define ATTR_LIST_MARKER    COLOR(COLOR_LIGHTCYAN,    COLOR_BLUE)
#define ATTR_QUOTE_MARKER   COLOR(COLOR_CYAN,         COLOR_BLUE)
#define ATTR_HR             COLOR(COLOR_CYAN,         COLOR_BLUE)
#define ATTR_BOX            COLOR(COLOR_CYAN,         COLOR_BLUE)
#define ATTR_TRUNC          COLOR(COLOR_YELLOW,       COLOR_BLUE)
#define ATTR_BAR            COLOR(COLOR_BLACK,        COLOR_LIGHTCYAN)
#define ATTR_BAR_SPINNER    COLOR(COLOR_WHITE,        COLOR_LIGHTCYAN)
#define ATTR_MENU_T         COLOR(COLOR_BLACK,        COLOR_LIGHTCYAN)
#define ATTR_MENU_K         COLOR(COLOR_YELLOW,       COLOR_BLACK)
#define ATTR_WARN           COLOR(COLOR_YELLOW,       COLOR_RED)        /* строка-обрыв (исчерпан кэш/лимит) */

/* ---- Атрибуты диалога справки ------------------------------------ */
#define ATTR_HELP_BG    COLOR(COLOR_LIGHTGRAY, COLOR_BLACK)
#define ATTR_HELP_BDR   COLOR(COLOR_WHITE,     COLOR_BLACK)
#define ATTR_HELP_TIT   COLOR(COLOR_YELLOW,    COLOR_BLACK)
#define ATTR_HELP_HDR   COLOR(COLOR_WHITE,     COLOR_BLACK)

/* ---- Режимы просмотра -------------------------------------------- */
#define VIEW_MD          0   /* markdown с форматированием (по умолчанию) */
#define VIEW_RAW_WRAP    1   /* RAW: длинные строки переносятся кратно 80 */
#define VIEW_RAW_HSCROLL 2   /* RAW: длинные строки в одну, гориз. скролл */
#define VIEW_HEX         3   /* HEX-дамп оригинального файла */
#define VIEW_IS_RAW(v)   ((v) == VIEW_RAW_WRAP || (v) == VIEW_RAW_HSCROLL)

/* ---- Кодировки --------------------------------------------------- */
/* 8-битные (CP866/CP1251/KOI8R) различаются только ремапом глифов [128-255]
 * на отрисовке; UTF-8 — отдельный декодированный набор. */
#define ENC_CP866       0
#define ENC_CP1251      1
#define ENC_KOI8R       2
#define ENC_UTF8        3
#define ENC_UNSUPPORTED -1   /* UTF16 / UTF32 */
#define CONV_MARGIN  4096u   /* на сколько байт держать UTF-конвертацию впереди индексатора */

/* ---- Флаги сегмента индекса (IF_*) — общие для индексатора/кэша/вью ---- */
#define IF_CONT    0x01u     /* сегмент является продолжением перенесённой строки */
#define IF_NOWRAP  0x02u     /* строка не переносится (кодовый блок / HR / таблица) */
#define IF_BLANK   0x04u     /* визуально пустая строка */
#define IF_CODE    0x08u     /* тело fenced code-блока (verbatim-режим) */
#define IF_HSCROLL 0x10u     /* блок горизонтально скроллируется ЦЕЛИКОМ (код/таблица),
                              * включая строки короче 80 — двигаются как единый блок.
                              * НЕ ставится на HR и границы fence (им нечего прятать). */
#define IF_TRUNC_MSG 0x20u   /* строка-обрыв: рисуется ВЖИВУЮ фикс. текстом (без контент-кэша);
                              * cache_rec.reserved несёт код причины (TRUNC_*). */

/* ---- Причина обрыва индексации (cache_rec.reserved при IF_TRUNC_MSG) ---- */
#define TRUNC_CONTENT  1     /* исчерпан контент-кэш (MAX_CACHE_CONTENT_PAGES) */
#define TRUNC_LINES    2     /* исчерпана ёмкость индекса (max_lines) */
#define TRUNC_FILE     3     /* файл больше MAX_FILE — прочитаны первые 256 КБ */

/* ---- Словарь сегментов/стилей (общий для индексатора и таблиц) ---- */
/* Тип сегмента-продолжения, передаваемый в emit_seg()/inline_scan(). */
#define CK_PLAIN  0
#define CK_QUOTE  1
#define CK_LIST   2
#define CK_OTHER  3

/* Начальный inline-стиль сегмента (INIT_STYLE_*). */
#define INIT_STYLE_PLAIN   0x0
#define INIT_STYLE_BOLD    0x1
#define INIT_STYLE_ITALIC  0x2
#define INIT_STYLE_UNDER   0x3
#define INIT_STYLE_CODE    0x4
#define INIT_STYLE_STRIKE  0x5

/* ---- Таблицы: CP866 light box-drawing (общий для индексатора и модуля) ---- */
#define TBL_MAX_COLS  16
#define TBL_ATTR      ATTR_BOX
#define TBL_H   0xC4   /* ─ */
#define TBL_V   0xB3   /* │ */
#define TBL_TL  0xDA   /* ┌ */
#define TBL_TM  0xC2   /* ┬ */
#define TBL_TR  0xBF   /* ┐ */
#define TBL_ML  0xC3   /* ├ */
#define TBL_MM  0xC5   /* ┼ */
#define TBL_MR  0xB4   /* ┤ */
#define TBL_BL  0xC0   /* └ */
#define TBL_BM  0xC1   /* ┴ */
#define TBL_BR  0xD9   /* ┘ */

/* ================================================================== *
 *  Разделяемые символы mdview2.c, используемые модулем RAW.
 * ================================================================== */
extern uint8_t        g_view;          /* активный режим просмотра (VIEW_*) */
extern uint32_t       file_size;       /* размер активного буфера документа */
extern const uint8_t *g_remap;         /* таблица ремапа [128-255] (0 = нет) */
extern uint8_t        g_scratch_phys;  /* scratch EMM-страница для win_rest */

char     fb(uint32_t p);               /* байт активного буфера (W3-маппинг) */
void     win_rest(uint8_t row, uint8_t col, uint8_t h, uint8_t w, uint8_t page, uint16_t off);
void     fill_row(uint8_t y, uint8_t attr);
uint8_t  pct16(uint16_t num, uint16_t den);   /* num*100/den (0..100), 16-бит, без __divulong */
uint32_t seg_off(uint16_t idx);        /* offset исходника для логической строки idx */
uint16_t line_at_off(uint32_t off);    /* обратно: последняя строка с seg_off <= off */

/* ================================================================== *
 *  API модуля RAW (mdview2_raw.c).
 * ================================================================== */
void     raw_seed_from(uint16_t md_top_line);  /* вход в RAW: позиция по top_line */
uint32_t raw_pos(void);                        /* текущий байт-offset верха экрана RAW */
void     raw_reanchor(uint32_t off);           /* поставить RAW на строку с байтом off */
void    raw_draw(void);                        /* перерисовать область документа в RAW */
uint8_t raw_pct(void);                         /* % прокрутки по байтам (для render_raw_status_numbers) */
uint8_t raw_key(uint8_t scan);                 /* навигация RAW; 1 = обработано */
void    raw_screen_init(void);                 /* очистка экрана с нужным аттрибутом */
void    raw_renorm(void);                       /* выровнять позицию при смене под-режима (F3) */

/* ================================================================== *
 *  API модуля HEX (mdview2_hex.c) — дамп ОРИГИНАЛЬНОГО файла (F4).
 *  Позиция hex_pos/hex_reanchor — в байтах ОРИГИНАЛА (orig_file_*);
 *  конвертацию в/из активного буфера делает ядро (map_off).
 * ================================================================== */
uint32_t hex_pos(void);                        /* offset верхнего ряда (кратен 16) */
void     hex_reanchor(uint32_t orig_off);      /* поставить на ряд с байтом orig_off */
void     hex_draw(void);                       /* перерисовать область документа */
uint8_t  hex_key(uint8_t scan);                /* навигация HEX; 1 = обработано */
void     hex_screen_init(void);                /* очистка экрана */

/* ================================================================== *
 *  Запись директории рендер-кэша (одна на видимую строку, РОВНО 8 байт —
 *  cache_dir_get/put адресуют сдвигом idx<<3). Контент — len пар (char,attr).
 * ================================================================== */
typedef struct cache_rec_s {
    uint8_t  page;     /* EMM-страница рендер-кэша (физический номер) */
    uint16_t off;      /* смещение в странице, 0..16383 (байты, не ячейки) */
    uint8_t  len;      /* длина контента в ЯЧЕЙКАХ (char,attr пар), 0..255; 0 = пустая/HR */
    uint8_t  flags;    /* копия IF_NOWRAP/IF_CODE/IF_BLANK на момент рендера */
    uint8_t  reserved; /* не используется */
    uint8_t  pad[2];   /* явный резерв, добивка до 8 байт */
} cache_rec_t;

void cache_dir_get(uint16_t idx, cache_rec_t *r);   /* читатель директории кэша (ядро) */
void put_str_attr(uint8_t x, uint8_t y, const char *s, uint8_t attr); /* печать строки с атрибутом */

/* ================================================================== *
 *  Состояние навигации/представления (определено в mdview2.c).
 * ================================================================== */
extern uint16_t n_lines;                /* всего строк в индексе текущего набора */
extern uint16_t top_line;               /* верхняя видимая строка */
extern uint8_t  viewport_x;             /* горизонтальный сдвиг (nowrap-строки) */
extern char     filename[];             /* имя файла для статус-бара */
extern uint8_t  g_loading;              /* 1 во время index_lines() */
extern uint8_t  g_ready;                /* 1 когда первичный документ построен (F2 RAW) */
extern uint8_t  g_f8_enabled;           /* можно ли сейчас переключать кодировку */

/* ================================================================== *
 *  Статус-бар (строка 0), меню (строка 31), спиннер — mdview2_status.c.
 *  Атомарные части: prerender (фикс. хром, один раз) / encoding (поле кодировки)
 *  / numbers (диапазон строк + %) / menu / spinner — обновляются по отдельности.
 * ================================================================== */
void     prerender_status(void);                /* фикс. часть: фон, разделители, MDVIEW, имя файла (1 раз) */
void     status_encoding(void);                 /* только поле кодировки (col 37) */
void     render_md_status_numbers(void);        /* числа MD: диапазон строк + % */
void     render_raw_status(void);               /* RAW mode: метка режима */
void     render_hex_status(void);               /* HEX mode: метка режима */
void     render_full_status(void);              /* encoding + numbers (MD) */
void     render_menu(void);                     /* строка меню (по смене режима/готовности) */
uint16_t drawable_lines(void);                  /* число строк, готовых к показу */
void     spinner_tick(void);                    /* кадр спиннера загрузки */
void     spinner_show(uint8_t on);              /* вкл/выкл спиннер */
void     render_percent_progress(uint8_t pct);  /* показать процентный прогресс просмотра */

/* ================================================================== *
 *  Отрисовка области MD-документа и прокрутка (mdview2_md.c).
 * ================================================================== */
void     draw_viewport_from_cache(void);    /* перерисовать область документа из кэша */
void     clamp_top(void);                   /* привести top_line к диапазону */
void     md_scroll_up(uint16_t n);
void     md_scroll_down(uint16_t n);
void     md_scroll_horizon(int8_t delta);            /* горизонтальный сдвиг nowrap-блоков */
uint8_t  md_key(uint8_t scan);              /* навигация MD (после загрузки); 1 = обработано */

/* ================================================================== *
 *  API модуля справки (mdview2_help.c).
 * ================================================================== */
void show_help(void);                   /* модальный диалог F1 */

/* ================================================================== *
 *  Парсер/индексатор (mdview2_index.c) и разделяемое с ним состояние.
 *  Хранилище индекса (index_blk/pages/phys, n_lines/max_lines) — в ядре
 *  (аллокация/doc-slot), индексатор пишет в него; cache_*-писатели и
 *  progress_tick ядро экспортирует индексатору (spinner_tick — из status).
 * ================================================================== */
#define INDEX_RECS_PER_PAGE  2048u      /* 16384 / 8; запись всегда в одной странице */
#define MAX_CACHE_LINE_LEN   255u       /* кап длины контента строки в ячейках (буфер g_cells) */

extern uint16_t max_lines;              /* ёмкость индекса: index_pages * 2048 */
extern uint8_t  index_blk, index_pages; /* дескриптор EMM-блока индекса */
extern uint8_t  index_phys[];           /* физ. страницы индекса */
extern uint8_t  index_truncated;        /* индекс упёрся в ёмкость */
extern uint8_t  g_abort;                /* F10/Esc во время загрузки → прервать индексацию */
extern uint8_t  g_file_clamped;         /* файл был обрезан до MAX_FILE при загрузке (>256 КБ) */

uint8_t cache_reserve(uint16_t nbytes, uint8_t *out_page, uint16_t *out_off);
void    cache_commit(uint8_t page, uint16_t off, const void *buf, uint16_t len);
void    cache_dir_put(uint16_t idx, const cache_rec_t *r);
void    progress_tick(void);            /* кооперативный шаг loading-loop (рисует/листает) */

/* Резюмируемая индексация (для фоновой сборки второго набора): begin сбрасывает
 * проход, step выполняет до budget итераций (блоков исходника) и возвращает 1,
 * когда индекс финализирован. Межшаговое состояние — статики модуля index;
 * оно не входит в docset_t (см. bg_step ядра). */
void    index_begin(void);
uint8_t index_step(uint8_t budget);
extern uint8_t g_bg_building;           /* 1 = фоновый шаг индексации: не трогать экран (спиннер) */

/* ================================================================== *
 *  Буфер ячеек рендера (mdview2.c) — общий с модулем таблиц.
 *  Таблицы эмитят свои строки теми же примитивами, что и индексатор.
 * ================================================================== */
extern uint8_t g_ncells;                            /* ячеек в текущем сегменте */
void    gc_put(char ch, uint8_t attr);              /* добавить ячейку в g_cells */
void    gc_fill(char ch, uint8_t attr, uint8_t n);  /* n одинаковых ячеек */
uint8_t inline_scan(uint32_t q, uint32_t q_end, uint8_t col,
                    uint8_t ckind, uint8_t line_style, uint8_t base_attr,
                    uint8_t nowrap);

/* ================================================================== *
 *  API модуля таблиц (mdview2_table.c) — вызывается из index_lines().
 * ================================================================== */
uint32_t row_end(uint32_t p);                    /* offset завершающего '\n' (или file_size) */
uint32_t table_first_cell(uint32_t row_start);   /* контент первой ячейки строки */
uint8_t  table_next_cell(uint32_t *pp, uint32_t lineend, uint32_t *cs, uint32_t *ce);
uint8_t  table_is_sep_row(uint32_t row_start, uint32_t lineend);
void     table_border(const uint8_t *widths, uint8_t ncols, char left, char mid, char right);
void     table_data_row(uint32_t row_start, uint32_t lineend, const uint8_t *widths, uint8_t ncols);

/* ================================================================== *
 *  Кодировки и UTF-8 конвертация (mdview2_enc.c).
 *  Состояние кодека владеется модулем; build_doc()/index_lines() ядра
 *  оркестрируют его (привязка UTF-буфера к живому file_*, сборка наборов).
 * ================================================================== */
extern uint8_t  g_encoding;             /* активная кодировка (ENC_*) */
extern uint8_t  g_utf_building;         /* 1 пока UTF-конвертация не дошла до конца исходника */
extern uint8_t  utf_avail;              /* 1 = страницы UTF-8 выделены */
extern uint8_t  utf_blk, utf_pages;     /* дескриптор EMM-буфера UTF-набора */
extern uint8_t  utf_phys[];             /* физ. страницы UTF-буфера */
extern uint32_t utf_size;               /* размер сконвертированного UTF-потока */

/* Ядро-owned состояние, читаемое кодеком (определено в mdview2.c). */
extern uint8_t  cur_page;               /* текущая страница файла в W3 (инвалидация маппинга) */
extern uint8_t  orig_file_phys[];       /* физ. страницы снимка исходного файла */
extern uint8_t  orig_file_pages;
extern uint32_t orig_file_size;

void        set_encoding(uint8_t enc);          /* активная кодировка + таблица ремапа */
const char *enc_name(uint8_t enc);              /* короткое имя для статус-бара */
uint8_t     detect_encoding(void);              /* автоопределение по сэмплу байт */
void        win_rest_remap(uint8_t row, uint8_t w, uint8_t page, uint16_t off); /* вывод среза с ремапом */
void        utf_convert_more(uint32_t target);  /* инкрементальная конвертация до target байт */
uint8_t     utf_alloc(void);                    /* выделить EMM-страницы под UTF-набор; 0 = нет EMM */
uint8_t     utf_cp_glyph(uint32_t cp);          /* кодпойнт → один CP866-глиф ('?' без аналога) */

#endif /* MDVIEW2_H */
