#include <stdio.h>
#include <conio.h>
#include <unistd.h>     /* sleep */

/*
 * Exercises every conio function:
 *   clrscr  — clear the screen
 *   gotoxy  — move cursor to (x, y), 0-based
 *   putch   — single character
 *   cputs   — string without auto-newline
 *   kbhit   — non-blocking key probe
 *   getch   — blocking, no echo
 *   getche  — blocking, with echo
 *
 * Sprinter native text mode is 80×32, so we anchor corners at
 * (0,0), (79,0), (0,31), (79,31).
 */

int main(void)
{
    /* 1. clrscr + diagnostic probes + a centered banner.
     *
     * Row-0 probe: figure out why [NW]/[NE] don't paint.
     *   '0','1','2','3' — single putch at row 0, cols 0/5/40/79
     *   "R0"            — cputs at row 0, col 10
     *   'a','b','c','R1'— same pattern on row 1 (control)
     */
    clrscr();

    gotoxy(0, 0);  putch('0');
    gotoxy(5, 0);  putch('1');
    gotoxy(40, 0); putch('2');
    gotoxy(79, 0); putch('3');
    gotoxy(10, 0); cputs("R0");

    gotoxy(0, 1);  putch('a');
    gotoxy(5, 1);  putch('b');
    gotoxy(79, 1); putch('c');
    gotoxy(10, 1); cputs("R1");

    /* Bottom corners moved to row 30 to avoid the auto-wrap-scroll issue —
     * cputs("[SE]") at (76, 31) ends with cursor at col 80 on the last row,
     * which scrolls the screen up by one and eats everything we wrote at
     * row 0.  By staying on row 30, no wraparound is triggered. */
    gotoxy(0, 30);  cputs("[SW]");
    gotoxy(76, 30); cputs("[SE]");

    /* Row 31 single-char probes (col 0 + col 78, no col-80 reach). */
    gotoxy(0, 31);  putch('L');
    gotoxy(78, 31); putch('R');

    gotoxy(30, 4);
    cputs("== conio test ==");

    /* wherex/wherey probe — place cursor at a known spot, read it back. */
    gotoxy(15, 5);
    int cx = wherex();
    int cy = wherey();
    gotoxy(0, 6);
    printf("wherex/wherey after gotoxy(15,5) -> x=%d y=%d", cx, cy);

    /* 2. putch — single chars in a diagonal. */
    for (int i = 0; i < 16; i++) {
        gotoxy(10 + i, 8 + i);
        putch('*');
    }

    /* 3. kbhit polling loop with a spinning indicator. */
    gotoxy(0, 14);
    cputs("kbhit polling - press any key to interrupt");

    static const char spin[] = "|/-\\";
    int frame = 0;
    while (!kbhit()) {
        gotoxy(50, 14);
        putch(spin[frame & 3]);
        frame++;
        /* small delay so the spin is visible (sleep is in 1-sec units;
         * we want ~10 fps — implemented with a busy "halts" later, but
         * here we just rely on kbhit being slow enough to be visible). */
    }
    int probed = kbhit();   /* re-read to clear / display */
    gotoxy(0, 16);
    printf("kbhit captured 0x%02X ('%c')", probed,
           (probed >= 0x20 && probed < 0x7F) ? probed : '?');

    /* 4. getch — drain the key + ask for one with no echo. */
    gotoxy(0, 18);
    cputs("getch (no echo) — press a key: ");
    int k1 = getch();
    gotoxy(0, 19);
    printf("you pressed 0x%02X ('%c')", k1,
           (k1 >= 0x20 && k1 < 0x7F) ? k1 : '?');

    /* 5. getche — same but the keypress should appear on screen. */
    gotoxy(0, 21);
    cputs("getche (with echo) — press a key:   ");
    gotoxy(36, 21);
    int k2 = getche();
    gotoxy(0, 22);
    printf("you pressed 0x%02X (echoed above)", k2);

    /* 6. Finish at the bottom; do NOT scroll. */
    gotoxy(0, 28);
    cputs("All conio functions exercised. Press any key to exit.");
    

    settextmode(TEXT_MODE_40x32);
    
    for (int i = 0; i < 16; i++) {
        wrchar(4 + i * 2, 3, i < 10 ? '0' + i : 'A' - 10 + i, 0x1F);
        wrchar(4 + i * 2 + 1, 3, ' ', 0x1F);
    }
    for (int j = 0; j < 16; j++) {
        wrchar(2, 4 + j, j < 10 ? '0' + j : 'A' - 10 + j, 0x1F);
        wrchar(2 + 1, 4 + j, ' ', 0x1F);
        for (int i = 0; i < 16; i++) {
            wrchar(4 + i * 2, 4 + j, j * 16 + i, 0x2F);
            wrchar(4 + i * 2 + 1, 4 + j, ' ', 0x2F);
        }
    }

    (void)getch();

    settextmode(TEXT_MODE_80x32);

    return 0;
}
