#include "common.h"

/*  Defines  */

#define IMG_TITLE_W     128
#define IMG_TITLE_H     24
#define IMG_SUBTITLE_W  28
#define IMG_SUBTITLE_H  32
#define IMG_EYE_OFFSET  (WIDTH * 5 + 28)
#define IMG_EYE_W       3

#define EYE_BLINK_TIME  8

enum STATE_T : uint8_t {
    STATE_INIT = 0,
    STATE_TITLE,
    STATE_RECORD,
    STATE_CREDIT,
    STATE_START_GAME,
};

/*  Local Functions  */

static void onStart(void);
static void onRecord(void);
static void onCredit(void);
static void handleAnyButton(void);

static void drawTitleImage(void);
static void drawRecord(void);
static void drawCredit(void);
static void drawText(const char *p, int lines);

/*  Local Variables  */

PROGMEM static const uint8_t imgTitle[384] = { // 128x24
    0xFF, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x1F, 0x08, 0x04, 0x02, 0x01, 0x81, 0x41, 0xA1, 0xD1,
    0x89, 0x05, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x10, 0x28, 0x44, 0x82, 0x44, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x40,
    0x78, 0x08, 0x08, 0x08, 0x78, 0x40, 0xC0, 0x00, 0x00, 0x00, 0xFF, 0x02, 0x04, 0x08, 0x10, 0x20,
    0x50, 0xB8, 0x7C, 0xFE, 0x7C, 0xB8, 0x50, 0x20, 0x10, 0x08, 0x04, 0x02, 0xFF, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x00, 0x02, 0x05, 0x0A, 0x17, 0x2F, 0x5F,
    0x8F, 0x07, 0x02, 0x00, 0x00, 0xFF, 0x01, 0x21, 0x51, 0x89, 0x05, 0x89, 0x52, 0x22, 0x0C, 0xF0,
    0x00, 0xFF, 0x01, 0x01, 0x01, 0xFF, 0x00, 0x70, 0x8C, 0x22, 0x52, 0x89, 0x05, 0x89, 0x52, 0x22,
    0x0C, 0xF0, 0x00, 0xFF, 0x00, 0x20, 0x50, 0x89, 0x05, 0x89, 0x52, 0x22, 0x0C, 0xF0, 0x01, 0x01,
    0xFF, 0x00, 0x00, 0x00, 0xFF, 0x01, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0xF0, 0x20, 0x40,
    0x80, 0x00, 0x01, 0x02, 0x01, 0x00, 0x80, 0x40, 0x20, 0xF0, 0x00, 0x00, 0xFF, 0x00, 0x70, 0x8C,
    0x22, 0x52, 0x89, 0x05, 0x89, 0x52, 0x22, 0x8C, 0x70, 0x07, 0x19, 0xE1, 0x01, 0x07, 0x18, 0x07,
    0x01, 0xE1, 0x19, 0x07, 0x00, 0xFC, 0x02, 0x02, 0x09, 0xD5, 0x63, 0x55, 0x49, 0x42, 0x42, 0x7C,
    0x17, 0x14, 0x14, 0x14, 0x14, 0x14, 0x14, 0x07, 0xE0, 0xD1, 0x92, 0x14, 0x14, 0x14, 0x14, 0x14,
    0x14, 0x15, 0x16, 0x14, 0x10, 0x17, 0x14, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x84, 0xF4, 0x07,
    0x10, 0x17, 0x14, 0x14, 0x14, 0x17, 0x10, 0x00, 0x71, 0x52, 0x52, 0x54, 0x55, 0x5C, 0x40, 0x20,
    0x20, 0x1F, 0x00, 0x17, 0x14, 0x14, 0x14, 0x17, 0x10, 0x17, 0x14, 0x14, 0x14, 0x17, 0x10, 0x10,
    0x11, 0x12, 0x14, 0x14, 0x15, 0x15, 0x17, 0x10, 0x10, 0x10, 0x17, 0x14, 0x14, 0x17, 0x10, 0x10,
    0x10, 0x11, 0x12, 0x14, 0x12, 0x11, 0x10, 0x10, 0x10, 0x17, 0x14, 0x14, 0x17, 0x10, 0x10, 0x11,
    0x12, 0x12, 0x14, 0x15, 0x14, 0x12, 0x12, 0x11, 0x10, 0x10, 0x10, 0x10, 0x13, 0x14, 0x14, 0x14,
    0x13, 0x10, 0x10, 0x10, 0x10, 0x11, 0x12, 0x12, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, 0x15, 0x17
};

PROGMEM static const uint8_t imgSubTitle[112] = { // 28x32
    0x06, 0x2D, 0x5F, 0xFF, 0xFE, 0xFC, 0xFC, 0xF8, 0xF0, 0xB0, 0x60, 0xE0, 0xC0, 0x80, 0x00, 0x40,
    0xA0, 0x50, 0xA0, 0xF4, 0xF6, 0xFB, 0xFD, 0xF3, 0xF8, 0x88, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0A,
    0x15, 0x2F, 0xBF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFC, 0x83, 0x7F, 0xFC, 0x01, 0xAA, 0x55, 0xFE, 0xFF,
    0xBE, 0x3C, 0x7C, 0xFF, 0xFF, 0xFF, 0xBC, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
    0x02, 0x03, 0x07, 0x07, 0x0F, 0x4C, 0xAF, 0x5E, 0xA8, 0xD5, 0xFF, 0xFF, 0xFF, 0xFE, 0xFC, 0x71,
    0x23, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20,
    0x48, 0x54, 0x2A, 0x95, 0xAA, 0xB5, 0xBD, 0xBD, 0xBD, 0xDE, 0x5E, 0x5C, 0x68, 0x20, 0x00, 0x00
};

PROGMEM static const uint8_t imgEye[][3] = { // 3x8 x2
    { 0xBD, 0x3D, 0x7D }, { 0xBE, 0x3C, 0x7C }
};

PROGMEM static const char creditText[] = \
        "- " APP_TITLE " -\0\0\0" APP_RELEASED "\0PROGRAMMED BY OBONO\0\0" \
        "THIS PROGRAM IS\0RELEASED UNDER\0THE MIT LICENSE.\0\e";

static STATE_T  state = STATE_INIT;
static uint8_t  eyeCounter;

/*---------------------------------------------------------------------------*/
/*                              Main Functions                               */
/*---------------------------------------------------------------------------*/

void initTitle(void)
{
    if (state == STATE_INIT) {
        readRecord();
        lastScore = 0;
        isBMode = false;
        eyeCounter = FPS * 4;
    }
    clearMenuItems();
    addMenuItem(F("GAME A START"), onStart);
    addMenuItem(F("GAME B START"), onStart);
    addMenuItem(F("RECORD"), onRecord);
    addMenuItem(F("CREDIT"), onCredit);
    setMenuItemPos((isBMode) ? 1 : 0);
    setMenuCoords(44, 40, 82, 24, false, true);
    state = STATE_TITLE;
    isInvalid = true;
}

MODE_T updateTitle(void)
{
    MODE_T ret = MODE_TITLE;
    switch (state) {
    case STATE_TITLE:
        handleMenu();
        if (--eyeCounter == 0) eyeCounter = random(FPS * 2, 256);
        if (state == STATE_START_GAME) ret = MODE_GAME;
        break;
    default:
        handleAnyButton();
        break;
    }
    randomSeed(rand() ^ micros()); // Shuffle random
    return ret;
}

void drawTitle(void)
{
    if (isInvalid) {
        arduboy.clear();
        switch (state) {
        case STATE_TITLE:
            drawTitleImage();
            break;
        case STATE_RECORD:
            drawRecord();
            break;
        case STATE_CREDIT:
            drawCredit();
            break;
        default:
            break;
        }
    }
    if (state == STATE_TITLE) {
        uint8_t idx = (eyeCounter >= EYE_BLINK_TIME);
        memcpy_P(arduboy.getBuffer() + IMG_EYE_OFFSET, imgEye[idx], IMG_EYE_W);
        drawMenuItems(isInvalid);
    }
    isInvalid = false;
}

/*---------------------------------------------------------------------------*/
/*                             Control Functions                             */
/*---------------------------------------------------------------------------*/

static void onStart(void)
{
    isBMode = (getMenuItemPos() == 1);
    state = STATE_START_GAME;
    dprint(F("Game start: mode "));
    dprintln((char)((isBMode) ? 'B' : 'A'));
}

static void onRecord(void)
{
    playSoundClick();
    state = STATE_RECORD;
    isInvalid = true;
    dprintln(F("Show record"));
}


static void onCredit(void)
{
    playSoundClick();
    state = STATE_CREDIT;
    isInvalid = true;
    dprintln(F("Show credit"));
}

static void handleAnyButton(void)
{
    if (arduboy.buttonDown(A_BUTTON | B_BUTTON)) {
        playSoundClick();
        state = STATE_TITLE;
        isInvalid = true;
    }
}

/*---------------------------------------------------------------------------*/
/*                              Draw Functions                               */
/*---------------------------------------------------------------------------*/

static void drawTitleImage(void)
{
    arduboy.drawBitmap(0, 8, imgTitle, IMG_TITLE_W, IMG_TITLE_H, WHITE);
    arduboy.drawBitmap(8, 32, imgSubTitle, IMG_SUBTITLE_W, IMG_SUBTITLE_H, WHITE);
#ifdef DEBUG
    arduboy.printEx(98, 0, F("DEBUG"));
#endif
    if (lastScore > 0) {
        arduboy.printEx(0, 0, (isBMode) ? F("B:") : F("A:"));
        drawNumber(12, 0, lastScore);
    }
}

static void drawRecord(void)
{
    arduboy.printEx(25, 4, F("BEST 3 SCORES"));
    arduboy.drawFastHLine2(0, 12, 128, WHITE);
    for (int i = 0; i < 2; i++) {
        int16_t x = i * 68;
        arduboy.printEx(x + 12, 15, F("MODE "));
        arduboy.print((char)('A' + i));
        for (int j = 0; j < 3; j++) {
            int16_t y = j * 6 + 25;
            arduboy.printEx(x, y, F("[ ]"));
            drawNumber(x + 6, y, j + 1);
            drawNumberR(x + 54, y, getHiscore(j, i));
        }
    }
    arduboy.drawFastHLine2(0, 44, 128, WHITE);
    arduboy.printEx(10, 48, F("PLAY COUNT "));
    arduboy.print(record.playCount);
    arduboy.printEx(10, 54, F("PLAY TIME"));
    drawTime(76, 54, record.playFrames);
}

static void drawCredit(void)
{
    drawText(creditText, 11);
}

static void drawText(const char *p, int16_t y)
{
    while (pgm_read_byte(p) != '\e') {
        uint8_t len = strnlen_P(p, 21);
        arduboy.printEx(64 - len * 3, y, (const __FlashStringHelper *) p);
        p += len + 1;
        y += (len == 0) ? 2 : 6;
    }
}
