#include "paint9.h"
#include "hid.h"
#include "ui.h"


#define PAINT9_BRUSH_SIZE       15  // don't change!
#define PAINT9_N_BRUSHES        6   // don't change!
#define PAINT9_COLSEL_WIDTH     16
#define PAINT9_COLSEL_HEIGHT    220 // don't change!

enum P9BOXES {
    P9BOX_CANVAS = 1,
    P9BOX_PICKER = 2,
    P9BOX_BRUSH_N = 3
};

static const TouchBox paint9_boxes[] = {
    { 30, 0, SCREEN_WIDTH_BOT - (2*30), SCREEN_HEIGHT, P9BOX_CANVAS },
    { SCREEN_WIDTH_BOT - PAINT9_COLSEL_WIDTH - 7, 10, PAINT9_COLSEL_WIDTH, PAINT9_COLSEL_HEIGHT, P9BOX_PICKER },
    { 7, 10 + ((PAINT9_BRUSH_SIZE+3)*0), PAINT9_BRUSH_SIZE, PAINT9_BRUSH_SIZE, P9BOX_BRUSH_N+0 },
    { 7, 10 + ((PAINT9_BRUSH_SIZE+3)*1), PAINT9_BRUSH_SIZE, PAINT9_BRUSH_SIZE, P9BOX_BRUSH_N+1 },
    { 7, 10 + ((PAINT9_BRUSH_SIZE+3)*2), PAINT9_BRUSH_SIZE, PAINT9_BRUSH_SIZE, P9BOX_BRUSH_N+2 },
    { 7, 10 + ((PAINT9_BRUSH_SIZE+3)*3), PAINT9_BRUSH_SIZE, PAINT9_BRUSH_SIZE, P9BOX_BRUSH_N+3 },
    { 7, 10 + ((PAINT9_BRUSH_SIZE+3)*4), PAINT9_BRUSH_SIZE, PAINT9_BRUSH_SIZE, P9BOX_BRUSH_N+4 },
    { 7, 10 + ((PAINT9_BRUSH_SIZE+3)*5), PAINT9_BRUSH_SIZE, PAINT9_BRUSH_SIZE, P9BOX_BRUSH_N+5 }
};

static const u8 color_picker_tmp[PAINT9_COLSEL_HEIGHT * BYTES_PER_PIXEL] = {
    0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x01, 0xF8, 0x02, 0xF8, 0x02, 0xF8, 0x03, 0xF8,
    0x04, 0xF8, 0x05, 0xF8, 0x06, 0xF8, 0x07, 0xF8, 0x08, 0xF8, 0x09, 0xF8, 0x0A, 0xF8, 0x0C, 0xF8,
    0x0D, 0xF8, 0x0E, 0xF8, 0x10, 0xF8, 0x11, 0xF8, 0x12, 0xF8, 0x14, 0xF8, 0x16, 0xF8, 0x17, 0xF8,
    0x17, 0xF8, 0x19, 0xF8, 0x1A, 0xF8, 0x1B, 0xF8, 0x1C, 0xF8, 0x1D, 0xF8, 0x1E, 0xF8, 0x1E, 0xF8,
    0x1E, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8, 0x1F, 0xF8,
    0x1F, 0xF8, 0x1F, 0xF0, 0x1F, 0xF0, 0x1F, 0xE8, 0x1F, 0xE0, 0x1F, 0xE0, 0x1F, 0xD8, 0x1F, 0xC8,
    0x1F, 0xC0, 0x1F, 0xB8, 0x1F, 0xB0, 0x1F, 0xA8, 0x1F, 0x98, 0x1F, 0x90, 0x1F, 0x88, 0x1F, 0x78,
    0x1F, 0x70, 0x1F, 0x60, 0x1F, 0x58, 0x1F, 0x48, 0x1F, 0x48, 0x1F, 0x40, 0x1F, 0x30, 0x1F, 0x28,
    0x1F, 0x20, 0x1F, 0x18, 0x1F, 0x10, 0x1F, 0x10, 0x1F, 0x08, 0x1F, 0x08, 0x1F, 0x00, 0x1F, 0x00,
    0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x1F, 0x00, 0x3F, 0x00, 0x5F, 0x00, 0x7F, 0x00, 0x9F, 0x00,
    0xBF, 0x00, 0xFF, 0x00, 0x3F, 0x01, 0x7F, 0x01, 0xBF, 0x01, 0x1F, 0x02, 0x5F, 0x02, 0x9F, 0x02,
    0xFF, 0x02, 0x5F, 0x03, 0x9F, 0x03, 0xFF, 0x03, 0x5F, 0x04, 0xBF, 0x04, 0xFF, 0x04, 0x5F, 0x05,
    0x9F, 0x05, 0xFF, 0x05, 0x3F, 0x06, 0x7F, 0x06, 0xDF, 0x06, 0x1F, 0x07, 0x3F, 0x07, 0x7F, 0x07,
    0x9F, 0x07, 0xBF, 0x07, 0xDF, 0x07, 0xFF, 0x07, 0xFF, 0x07, 0xFF, 0x07, 0xFF, 0x07, 0xFF, 0x07,
    0xFF, 0x07, 0xFF, 0x07, 0xFE, 0x07, 0xFE, 0x07, 0xFE, 0x07, 0xFD, 0x07, 0xFC, 0x07, 0xFA, 0x07,
    0xF9, 0x07, 0xF9, 0x07, 0xF8, 0x07, 0xF6, 0x07, 0xF5, 0x07, 0xF4, 0x07, 0xF2, 0x07, 0xF1, 0x07,
    0xF0, 0x07, 0xEE, 0x07, 0xED, 0x07, 0xEC, 0x07, 0xEA, 0x07, 0xE9, 0x07, 0xE8, 0x07, 0xE7, 0x07,
    0xE5, 0x07, 0xE4, 0x07, 0xE4, 0x07, 0xE3, 0x07, 0xE2, 0x07, 0xE2, 0x07, 0xE1, 0x07, 0xE0, 0x07,
    0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x0F, 0xE0, 0x0F,
    0xE0, 0x17, 0xE0, 0x17, 0xE0, 0x1F, 0xE0, 0x27, 0xE0, 0x37, 0xE0, 0x37, 0xE0, 0x3F, 0xE0, 0x4F,
    0xE0, 0x57, 0xE0, 0x5F, 0xE0, 0x67, 0xE0, 0x77, 0xE0, 0x7F, 0xE0, 0x8F, 0xE0, 0x97, 0xE0, 0xA7,
    0xE0, 0xAF, 0xE0, 0xB7, 0xE0, 0xBF, 0xE0, 0xC7, 0xE0, 0xCF, 0xE0, 0xDF, 0xE0, 0xDF, 0xE0, 0xE7,
    0xE0, 0xF7, 0xE0, 0xF7, 0xE0, 0xF7, 0xE0, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xE0, 0xFF,
    0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0xA0, 0xFF, 0x80, 0xFF, 0x60, 0xFF, 0x40, 0xFF, 0x00, 0xFF,
    0xC0, 0xFE, 0x80, 0xFE, 0x20, 0xFE, 0xE0, 0xFD, 0xA0, 0xFD, 0x40, 0xFD, 0xE0, 0xFC, 0xA0, 0xFC,
    0x40, 0xFC, 0xE0, 0xFB, 0x80, 0xFB, 0x40, 0xFB, 0x00, 0xFB, 0xA0, 0xFA, 0x60, 0xFA, 0x00, 0xFA,
    0xC0, 0xF9, 0x60, 0xF9, 0x20, 0xF9, 0xE0, 0xF8, 0xA0, 0xF8, 0x80, 0xF8, 0x60, 0xF8, 0x40, 0xF8,
    0x20, 0xF8, 0x00, 0xF8, 0x00, 0xF8, 0x00, 0xF8
};

static const u16 brushes_tmp[PAINT9_N_BRUSHES][PAINT9_BRUSH_SIZE] = {
    { 0x0FE0, 0x1FF0, 0x3FF8, 0x7FFC, 0xFFFE, 0xFFFE, 0xFFFE,0xFFFE,
        0xFFFE, 0xFFFE, 0xFFFE, 0x7FFC, 0x3FF8, 0x1FF0, 0x0FE0 },
    { 0x0000, 0x0000, 0x07C0, 0x0FE0, 0x1FF0, 0x3FF8, 0x3FF8, 0x3FF8,
        0x3FF8, 0x3FF8, 0x1FF0, 0x0FE0, 0x07C0, 0x0000, 0x0000 },
    { 0x0000, 0x0000, 0x0000, 0x0000, 0x0380, 0x07C0, 0x0FE0, 0x0FE0,
        0x0FE0, 0x07C0, 0x0380, 0x0000, 0x0000, 0x0000, 0x0000 },
    { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0380, 0x07C0, 0x07C0,
        0x07C0, 0x0380, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
    { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100, 0x0380,
        0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 },
    { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0100,
        0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }
};


void Paint9_DrawBrush(u16 px, u16 py, u32 color_fg, u32 color_bg, u32 id) {
    const u16* brush = brushes_tmp[id];

    // fix px / py
    s16 pxf = px - (PAINT9_BRUSH_SIZE/2);
    s16 pyf = py - (PAINT9_BRUSH_SIZE/2);

    // draw brush, pixel by pixel
    for (s16 y = 0; y < PAINT9_BRUSH_SIZE; y++) {
        s16 pyc = pyf + y;
        if ((pyc < 0) || (pyc >= SCREEN_HEIGHT)) continue;

        for (s16 x = 0; x < PAINT9_BRUSH_SIZE; x++) {
            s16 pxc = pxf + x;
            if ((pxc < 0) || (pxc >= SCREEN_WIDTH_BOT)) continue;

            if ((brush[y]>>(PAINT9_BRUSH_SIZE-x))&0x1) {
                DrawPixel(BOT_SCREEN, pxc, pyc, color_fg);
            } else if (color_bg != COLOR_TRANSPARENT) {
                DrawPixel(BOT_SCREEN, pxc, pyc, color_bg);
            }
        }
    }
}

u32 Paint9(void) {
    static u32 brush_bg = RGB(0x20, 0x20, 0x20);
    static u32 outline_bg = RGB(0x18, 0x18, 0x18);
    u16 x_cb = paint9_boxes[2].x + (PAINT9_BRUSH_SIZE/2) + 1;
    u16 y_cb = SCREEN_HEIGHT - 10 - (PAINT9_BRUSH_SIZE/2) - 1;

    u32 color = COLOR_RED;
    u32 brush_id = 0;

    // clear screens, draw title
    ClearScreenF(true, true, COLOR_STD_BG);
    DrawStringCenter(TOP_SCREEN, COLOR_STD_FONT, COLOR_TRANSPARENT,
        "Paint9\n \nYou may save your creation at\nany time via the screenshot\nfunction (L+R).\n \nHave fun!");

    // outline canvas
    DrawRectangle(BOT_SCREEN, 0, 0, 30, SCREEN_HEIGHT, outline_bg);
    DrawRectangle(BOT_SCREEN, SCREEN_WIDTH_BOT - 30, 0, 30, SCREEN_HEIGHT, outline_bg);

    // draw color picker
    u32 pick_x = paint9_boxes[1].x;
    u32 pick_y = paint9_boxes[1].y;
    for (u32 y = 0; y < PAINT9_COLSEL_HEIGHT; y++) {
        const u16* color = (u16*)(void*) (color_picker_tmp + (y * BYTES_PER_PIXEL));
        for (u32 x = 0; x < PAINT9_COLSEL_WIDTH; x++)
            DrawPixel(BOT_SCREEN, pick_x + x, pick_y + y, *color);
    }

    // draw brushes
    for (u32 i = 0; i < PAINT9_N_BRUSHES; i++) {
        u32 color_fg = COLOR_STD_FONT;
        u16 x = paint9_boxes[2+i].x + (PAINT9_BRUSH_SIZE/2) + 1;
        u16 y = paint9_boxes[2+i].y + (PAINT9_BRUSH_SIZE/2) + 1;
        Paint9_DrawBrush(x, y, color_fg, brush_bg, i);
    }

    // Paint9 main loop
    while (1) {
        DrawStringF(TOP_SCREEN, 16, 16, COLOR_STD_FONT, COLOR_STD_BG,
            "Touchscreen coordinates (0/0)    ");
        Paint9_DrawBrush(x_cb, y_cb, color, brush_bg, brush_id);
        if (InputWait(0) & BUTTON_B) break;

        u16 tx, ty;
        u32 tb_id;
        while (HID_ReadTouchState(&tx, &ty)) {
            DrawStringF(TOP_SCREEN, 16, 16, COLOR_STD_FONT, COLOR_STD_BG,
                "Touchscreen coordinates (%d/%d)    ", tx, ty);
            TouchBoxGet(&tb_id, tx, ty, paint9_boxes, 8);
            if (tb_id == P9BOX_CANVAS) {
                Paint9_DrawBrush(tx, ty, color, COLOR_TRANSPARENT, brush_id);
                continue;
            } else if (tb_id == P9BOX_PICKER) {
                color = GetColor(BOT_SCREEN, tx, ty);
            } else if (tb_id >= P9BOX_BRUSH_N) {
                brush_id = tb_id - P9BOX_BRUSH_N;
            } else {
                continue;
            }
            Paint9_DrawBrush(x_cb, y_cb, color, brush_bg, brush_id);
        }
    }

    ClearScreenF(true, true, COLOR_STD_BG);
    return 0;
}
