// The MIT License (MIT)
//
// Copyright (C) 2026 Scott Duensing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

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

#include "bmpDraw.h"

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

#define ICON_W 16
#define ICON_H 16

typedef struct {
    const char *name;
    void (*fn)(void);
} IconT;

static BmpCanvasT canvas;

// ============================================================
// Prototypes
// ============================================================

static void iconCode(void);
static void iconDebug(void);
static void iconDesign(void);
static void iconOpen(void);
static void iconRun(void);
static void iconRunToCursor(void);
static void iconSave(void);
static void iconStepInto(void);
static void iconStepOut(void);
static void iconStepOver(void);
static void iconStop(void);


// Single source of truth for type name to draw function mapping.
static const IconT icons[] = {
    {"open",     iconOpen},
    {"save",     iconSave},
    {"run",      iconRun},
    {"stop",     iconStop},
    {"code",     iconCode},
    {"design",   iconDesign},
    {"debug",    iconDebug},
    {"stepinto", iconStepInto},
    {"stepover", iconStepOver},
    {"stepout",  iconStepOut},
    {"runtocur", iconRunToCursor},
    {NULL,       NULL}
};


// Code: text/code icon (page with angle brackets)
static void iconCode(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Page
    bmpFillRect(&canvas, 3, 1, 10, 14, 255, 255, 255);
    bmpRect(&canvas, 3, 1, 10, 14, 80, 80, 80);
    // Dog-ear fold
    bmpFillRect(&canvas, 10, 1, 3, 3, 192, 192, 192);
    bmpHLine(&canvas, 10, 3, 3, 80, 80, 80);
    bmpVLine(&canvas, 10, 1, 3, 80, 80, 80);
    bmpPixel(&canvas, 10, 1, 80, 80, 80);
    bmpPixel(&canvas, 11, 2, 80, 80, 80);
    bmpPixel(&canvas, 12, 3, 80, 80, 80);
    // "<" bracket
    bmpPixel(&canvas, 5, 6, 0, 0, 180);
    bmpPixel(&canvas, 4, 7, 0, 0, 180);
    bmpPixel(&canvas, 5, 8, 0, 0, 180);
    // ">" bracket
    bmpPixel(&canvas, 9, 6, 0, 0, 180);
    bmpPixel(&canvas, 10, 7, 0, 0, 180);
    bmpPixel(&canvas, 9, 8, 0, 0, 180);
    // "/" between
    bmpPixel(&canvas, 8, 5, 0, 0, 180);
    bmpPixel(&canvas, 7, 7, 0, 0, 180);
    bmpPixel(&canvas, 6, 9, 0, 0, 180);
    // Text lines
    bmpHLine(&canvas, 5, 11, 6, 160, 160, 160);
    bmpHLine(&canvas, 5, 13, 4, 160, 160, 160);
}


// Debug: bug icon with magnifying glass
static void iconDebug(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Bug body
    bmpFillRect(&canvas, 5, 4, 6, 8, 60, 160, 60);
    bmpRect(&canvas, 5, 4, 6, 8, 0, 100, 0);
    // Bug head
    bmpFillRect(&canvas, 6, 2, 4, 3, 60, 160, 60);
    bmpRect(&canvas, 6, 2, 4, 3, 0, 100, 0);
    // Antennae
    bmpPixel(&canvas, 6, 1, 0, 100, 0); bmpPixel(&canvas, 5, 0, 0, 100, 0);
    bmpPixel(&canvas, 9, 1, 0, 100, 0); bmpPixel(&canvas, 10, 0, 0, 100, 0);
    // Legs
    bmpPixel(&canvas, 4, 6, 0, 100, 0); bmpPixel(&canvas, 3, 5, 0, 100, 0);
    bmpPixel(&canvas, 4, 8, 0, 100, 0); bmpPixel(&canvas, 3, 8, 0, 100, 0);
    bmpPixel(&canvas, 4, 10, 0, 100, 0); bmpPixel(&canvas, 3, 11, 0, 100, 0);
    bmpPixel(&canvas, 11, 6, 0, 100, 0); bmpPixel(&canvas, 12, 5, 0, 100, 0);
    bmpPixel(&canvas, 11, 8, 0, 100, 0); bmpPixel(&canvas, 12, 8, 0, 100, 0);
    bmpPixel(&canvas, 11, 10, 0, 100, 0); bmpPixel(&canvas, 12, 11, 0, 100, 0);
}


// Design: form/window with grid dots
static void iconDesign(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Window frame
    bmpFillRect(&canvas, 1, 1, 14, 14, 255, 255, 255);
    bmpRect(&canvas, 1, 1, 14, 14, 0, 0, 128);
    // Title bar
    bmpFillRect(&canvas, 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) {
            bmpPixel(&canvas, x, y, 160, 160, 160);
        }
    }

    // Small widget rectangle in the form
    bmpFillRect(&canvas, 4, 8, 6, 3, 192, 192, 192);
    bmpRect(&canvas, 4, 8, 6, 3, 80, 80, 80);
}


// Open: folder icon (yellow folder with tab)
static void iconOpen(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Folder body
    bmpFillRect(&canvas, 1, 5, 14, 9, 220, 180, 50);
    bmpRect(&canvas, 1, 5, 14, 9, 160, 120, 20);
    // Folder tab
    bmpFillRect(&canvas, 2, 3, 5, 3, 220, 180, 50);
    bmpHLine(&canvas, 2, 3, 5, 160, 120, 20);
    bmpVLine(&canvas, 2, 3, 2, 160, 120, 20);
    bmpVLine(&canvas, 6, 3, 2, 160, 120, 20);
    // Front flap (lighter)
    bmpFillRect(&canvas, 2, 7, 12, 6, 240, 210, 80);
    bmpHLine(&canvas, 2, 7, 12, 160, 120, 20);
}


// Run: green play triangle
static void iconRun(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Play triangle pointing right
    for (int y = 0; y < 12; y++) {
        int w = (y < 6) ? y + 1 : 12 - y;
        bmpHLine(&canvas, 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;
        bmpPixel(&canvas, 4, 2 + y, 0, 100, 0);
        bmpPixel(&canvas, 4 + w - 1, 2 + y, 0, 100, 0);
    }
}


// Run to Cursor: arrow pointing right to a cursor line
static void iconRunToCursor(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Horizontal arrow
    bmpHLine(&canvas, 2, 7, 8, 0, 0, 180);
    // Arrow head
    bmpVLine(&canvas, 10, 5, 5, 0, 0, 180);
    bmpVLine(&canvas, 11, 6, 3, 0, 0, 180);
    bmpPixel(&canvas, 12, 7, 0, 0, 180);
    // Cursor (text cursor line)
    bmpVLine(&canvas, 14, 3, 10, 200, 0, 0);
}


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


// Step Into: arrow pointing down into a line
static void iconStepInto(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Vertical arrow shaft
    bmpVLine(&canvas, 8, 2, 8, 0, 0, 180);
    // Arrow head
    bmpHLine(&canvas, 6, 10, 5, 0, 0, 180);
    bmpHLine(&canvas, 7, 11, 3, 0, 0, 180);
    bmpPixel(&canvas, 8, 12, 0, 0, 180);
    // Horizontal line (code line)
    bmpHLine(&canvas, 3, 14, 10, 80, 80, 80);
}


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


// Step Over: arrow curving over a line
static void iconStepOver(void) {
    bmpClear(&canvas, 192, 192, 192);
    // Arc over
    bmpHLine(&canvas, 4, 3, 8, 0, 0, 180);
    bmpVLine(&canvas, 3, 4, 3, 0, 0, 180);
    bmpVLine(&canvas, 12, 4, 5, 0, 0, 180);
    bmpPixel(&canvas, 4, 3, 0, 0, 180);
    bmpPixel(&canvas, 11, 3, 0, 0, 180);
    // Arrow head pointing down
    bmpHLine(&canvas, 10, 9, 5, 0, 0, 180);
    bmpHLine(&canvas, 11, 10, 3, 0, 0, 180);
    bmpPixel(&canvas, 12, 11, 0, 0, 180);
    // Code line
    bmpHLine(&canvas, 3, 14, 10, 80, 80, 80);
}


// Stop: red square
static void iconStop(void) {
    bmpClear(&canvas, 192, 192, 192);
    bmpFillRect(&canvas, 3, 3, 10, 10, 200, 40, 40);
    bmpRect(&canvas, 3, 3, 10, 10, 140, 20, 20);
}


int main(int argc, char **argv) {
    if (argc < 3) {
        fprintf(stderr, "Usage: mktbicon <output.bmp> <type>\n");
        fprintf(stderr, "Types:");

        for (int i = 0; icons[i].name; i++) {
            fprintf(stderr, " %s", icons[i].name);
        }

        fprintf(stderr, "\n");
        return 1;
    }

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

    if (!bmpInit(&canvas, ICON_W, ICON_H)) {
        fprintf(stderr, "Out of memory\n");
        return 1;
    }

    for (int i = 0; icons[i].name; i++) {
        if (strcmp(type, icons[i].name) == 0) {
            icons[i].fn();
            bmpWrite(&canvas, path);
            bmpFree(&canvas);
            printf("Generated %s (%s)\n", path, type);
            return 0;
        }
    }

    fprintf(stderr, "Unknown icon type: %s\n", type);
    bmpFree(&canvas);
    return 1;
}
