// mktbicon.c -- Generate 16x16 BMP toolbar icons for DVX BASIC IDE
//
// Usage: mktbicon <output.bmp> <type>
// Types: open, save, run, stop, code, design

#include <stdint.h>
#include <stdio.h>
#include <string.h>

#define W 16
#define H 16

static uint8_t pixels[H][W][3]; // BGR

static void clear(uint8_t r, uint8_t g, uint8_t b) {
    for (int y = 0; y < H; y++) {
        for (int x = 0; x < W; x++) {
            pixels[y][x][0] = b;
            pixels[y][x][1] = g;
            pixels[y][x][2] = r;
        }
    }
}

static void px(int x, int y, uint8_t r, uint8_t g, uint8_t b) {
    if (x >= 0 && x < W && y >= 0 && y < H) {
        pixels[y][x][0] = b;
        pixels[y][x][1] = g;
        pixels[y][x][2] = r;
    }
}

static void rect(int x0, int y0, int w, int h, uint8_t r, uint8_t g, uint8_t b) {
    for (int y = y0; y < y0 + h && y < H; y++) {
        for (int x = x0; x < x0 + w && x < W; x++) {
            px(x, y, r, g, b);
        }
    }
}

static void hline(int x0, int y, int w, uint8_t r, uint8_t g, uint8_t b) {
    for (int x = x0; x < x0 + w; x++) {
        px(x, y, r, g, b);
    }
}

static void vline(int x, int y0, int h, uint8_t r, uint8_t g, uint8_t b) {
    for (int y = y0; y < y0 + h; y++) {
        px(x, y, r, g, b);
    }
}

static void outline(int x0, int y0, int w, int h, uint8_t r, uint8_t g, uint8_t b) {
    hline(x0, y0, w, r, g, b);
    hline(x0, y0 + h - 1, w, r, g, b);
    vline(x0, y0, h, r, g, b);
    vline(x0 + w - 1, y0, h, r, g, b);
}


// Open: folder icon (yellow folder with tab)
static void iconOpen(void) {
    clear(192, 192, 192);
    // Folder body
    rect(1, 5, 14, 9, 220, 180, 50);
    outline(1, 5, 14, 9, 160, 120, 20);
    // Folder tab
    rect(2, 3, 5, 3, 220, 180, 50);
    hline(2, 3, 5, 160, 120, 20);
    vline(2, 3, 2, 160, 120, 20);
    vline(6, 3, 2, 160, 120, 20);
    // Front flap (lighter)
    rect(2, 7, 12, 6, 240, 210, 80);
    hline(2, 7, 12, 160, 120, 20);
}


// Save: floppy disk icon (blue disk)
static void iconSave(void) {
    clear(192, 192, 192);
    // Disk body
    rect(2, 1, 12, 14, 60, 60, 160);
    outline(2, 1, 12, 14, 30, 30, 100);
    // Metal slider (silver top)
    rect(5, 1, 6, 5, 200, 200, 200);
    outline(5, 1, 6, 5, 120, 120, 120);
    // Slot in metal
    rect(7, 2, 2, 3, 60, 60, 160);
    // Label (white bottom)
    rect(4, 9, 8, 5, 240, 240, 240);
    outline(4, 9, 8, 5, 120, 120, 120);
    // Lines on label
    hline(5, 11, 6, 160, 160, 160);
    hline(5, 12, 6, 160, 160, 160);
}


// Run: green play triangle
static void iconRun(void) {
    clear(192, 192, 192);
    // Play triangle pointing right
    for (int y = 0; y < 12; y++) {
        int w = (y < 6) ? y + 1 : 12 - y;
        hline(4, 2 + y, w, 0, 160, 0);
    }

    // Darker outline on top and bottom edges
    for (int y = 0; y < 12; y++) {
        int w = (y < 6) ? y + 1 : 12 - y;
        px(4, 2 + y, 0, 100, 0);
        px(4 + w - 1, 2 + y, 0, 100, 0);
    }
}


// Stop: red square
static void iconStop(void) {
    clear(192, 192, 192);
    rect(3, 3, 10, 10, 200, 40, 40);
    outline(3, 3, 10, 10, 140, 20, 20);
}


// Code: text/code icon (page with angle brackets)
static void iconCode(void) {
    clear(192, 192, 192);
    // Page
    rect(3, 1, 10, 14, 255, 255, 255);
    outline(3, 1, 10, 14, 80, 80, 80);
    // Dog-ear fold
    rect(10, 1, 3, 3, 192, 192, 192);
    hline(10, 3, 3, 80, 80, 80);
    vline(10, 1, 3, 80, 80, 80);
    px(10, 1, 80, 80, 80);
    px(11, 2, 80, 80, 80);
    px(12, 3, 80, 80, 80);
    // "<" bracket
    px(5, 6, 0, 0, 180);
    px(4, 7, 0, 0, 180);
    px(5, 8, 0, 0, 180);
    // ">" bracket
    px(9, 6, 0, 0, 180);
    px(10, 7, 0, 0, 180);
    px(9, 8, 0, 0, 180);
    // "/" between
    px(8, 5, 0, 0, 180);
    px(7, 7, 0, 0, 180);
    px(6, 9, 0, 0, 180);
    // Text lines
    hline(5, 11, 6, 160, 160, 160);
    hline(5, 13, 4, 160, 160, 160);
}


// Design: form/window with grid dots
static void iconDesign(void) {
    clear(192, 192, 192);
    // Window frame
    rect(1, 1, 14, 14, 255, 255, 255);
    outline(1, 1, 14, 14, 0, 0, 128);
    // Title bar
    rect(2, 2, 12, 3, 0, 0, 128);
    // Grid dots
    for (int y = 7; y < 14; y += 2) {
        for (int x = 3; x < 14; x += 2) {
            px(x, y, 160, 160, 160);
        }
    }

    // Small widget rectangle in the form
    rect(4, 8, 6, 3, 192, 192, 192);
    outline(4, 8, 6, 3, 80, 80, 80);
}


// Debug: bug icon with magnifying glass
static void iconDebug(void) {
    clear(192, 192, 192);
    // Bug body
    rect(5, 4, 6, 8, 60, 160, 60);
    outline(5, 4, 6, 8, 0, 100, 0);
    // Bug head
    rect(6, 2, 4, 3, 60, 160, 60);
    outline(6, 2, 4, 3, 0, 100, 0);
    // Antennae
    px(6, 1, 0, 100, 0); px(5, 0, 0, 100, 0);
    px(9, 1, 0, 100, 0); px(10, 0, 0, 100, 0);
    // Legs
    px(4, 6, 0, 100, 0); px(3, 5, 0, 100, 0);
    px(4, 8, 0, 100, 0); px(3, 8, 0, 100, 0);
    px(4, 10, 0, 100, 0); px(3, 11, 0, 100, 0);
    px(11, 6, 0, 100, 0); px(12, 5, 0, 100, 0);
    px(11, 8, 0, 100, 0); px(12, 8, 0, 100, 0);
    px(11, 10, 0, 100, 0); px(12, 11, 0, 100, 0);
}


// Step Into: arrow pointing down into a line
static void iconStepInto(void) {
    clear(192, 192, 192);
    // Vertical arrow shaft
    vline(8, 2, 8, 0, 0, 180);
    // Arrow head
    hline(6, 10, 5, 0, 0, 180);
    hline(7, 11, 3, 0, 0, 180);
    px(8, 12, 0, 0, 180);
    // Horizontal line (code line)
    hline(3, 14, 10, 80, 80, 80);
}


// Step Over: arrow curving over a line
static void iconStepOver(void) {
    clear(192, 192, 192);
    // Arc over
    hline(4, 3, 8, 0, 0, 180);
    vline(3, 4, 3, 0, 0, 180);
    vline(12, 4, 5, 0, 0, 180);
    px(4, 3, 0, 0, 180);
    px(11, 3, 0, 0, 180);
    // Arrow head pointing down
    hline(10, 9, 5, 0, 0, 180);
    hline(11, 10, 3, 0, 0, 180);
    px(12, 11, 0, 0, 180);
    // Code line
    hline(3, 14, 10, 80, 80, 80);
}


// Step Out: arrow pointing up out of a bracket
static void iconStepOut(void) {
    clear(192, 192, 192);
    // Vertical arrow shaft going up
    vline(8, 2, 8, 0, 0, 180);
    // Arrow head pointing up
    hline(6, 4, 5, 0, 0, 180);
    hline(7, 3, 3, 0, 0, 180);
    px(8, 2, 0, 0, 180);
    // Bracket (representing the function)
    vline(4, 10, 4, 80, 80, 80);
    hline(4, 10, 3, 80, 80, 80);
    hline(4, 13, 3, 80, 80, 80);
    vline(11, 10, 4, 80, 80, 80);
    hline(9, 10, 3, 80, 80, 80);
    hline(9, 13, 3, 80, 80, 80);
}


// Run to Cursor: arrow pointing right to a cursor line
static void iconRunToCursor(void) {
    clear(192, 192, 192);
    // Horizontal arrow
    hline(2, 7, 8, 0, 0, 180);
    // Arrow head
    vline(10, 5, 5, 0, 0, 180);
    vline(11, 6, 3, 0, 0, 180);
    px(12, 7, 0, 0, 180);
    // Cursor (text cursor line)
    vline(14, 3, 10, 200, 0, 0);
}


static void writeBmp(const char *path) {
    int32_t rowPad  = (4 - (W * 3) % 4) % 4;
    int32_t rowSize = W * 3 + rowPad;
    int32_t dataSize = rowSize * H;
    int32_t fileSize = 54 + dataSize;

    uint8_t header[54];
    memset(header, 0, sizeof(header));

    header[0]  = 'B';
    header[1]  = 'M';
    *(int32_t *)&header[2]  = fileSize;
    *(int32_t *)&header[10] = 54;
    *(int32_t *)&header[14] = 40;
    *(int32_t *)&header[18] = W;
    *(int32_t *)&header[22] = H;
    *(int16_t *)&header[26] = 1;
    *(int16_t *)&header[28] = 24;
    *(int32_t *)&header[34] = dataSize;

    FILE *f = fopen(path, "wb");

    if (!f) {
        fprintf(stderr, "Cannot write: %s\n", path);
        return;
    }

    fwrite(header, 1, 54, f);

    uint8_t pad[3] = {0};

    for (int y = H - 1; y >= 0; y--) {
        fwrite(pixels[y], 1, W * 3, f);

        if (rowPad > 0) {
            fwrite(pad, 1, rowPad, f);
        }
    }

    fclose(f);
}


int main(int argc, char **argv) {
    if (argc < 3) {
        fprintf(stderr, "Usage: mktbicon <output.bmp> <type>\n");
        fprintf(stderr, "Types: open, save, run, stop, code, design\n");
        return 1;
    }

    const char *path = argv[1];
    const char *type = argv[2];

    if (strcmp(type, "open") == 0)        { iconOpen(); }
    else if (strcmp(type, "save") == 0)   { iconSave(); }
    else if (strcmp(type, "run") == 0)    { iconRun(); }
    else if (strcmp(type, "stop") == 0)   { iconStop(); }
    else if (strcmp(type, "code") == 0)   { iconCode(); }
    else if (strcmp(type, "design") == 0)  { iconDesign(); }
    else if (strcmp(type, "debug") == 0)   { iconDebug(); }
    else if (strcmp(type, "stepinto") == 0) { iconStepInto(); }
    else if (strcmp(type, "stepover") == 0) { iconStepOver(); }
    else if (strcmp(type, "stepout") == 0)  { iconStepOut(); }
    else if (strcmp(type, "runtocur") == 0) { iconRunToCursor(); }
    else {
        fprintf(stderr, "Unknown icon type: %s\n", type);
        return 1;
    }

    writeBmp(path);
    printf("Generated %s (%s)\n", path, type);
    return 0;
}
