#include "global.h"
#include "option_menu.h"
#include "main.h"
#include "menu.h"
#include "palette.h"
#include "scanline_effect.h"
#include "sprite.h"
#include "string_util.h"
#include "strings2.h"
#include "task.h"

extern void SetPokemonCryStereo(u32 val);

// Menu items
enum
{
    MENUITEM_TEXTSPEED,
    MENUITEM_BATTLESCENE,
    MENUITEM_BATTLESTYLE,
    MENUITEM_SOUND,
    MENUITEM_BUTTONMODE,
    MENUITEM_FRAMETYPE,
    MENUITEM_CANCEL,
};

// Task data
#define tMenuSelection  data[0]
#define tOptTextSpeed   data[1]
#define tOptBattleScene data[2]
#define tOptBattleStyle data[3]
#define tOptSound       data[4]
#define tOptButtonMode  data[5]
#define tOptFrameType   data[6]

const u16 gUnknown_0839F5FC[] = INCBIN_U16("graphics/misc/option_menu_text.gbapal");
// note: this is only used in the Japanese release
const u8 gUnknown_0839F63C[] = INCBIN_U8("graphics/misc/option_menu_equals_sign.4bpp");

static void Task_OptionMenuFadeIn(u8 taskId);
static void Task_OptionMenuProcessInput(u8 taskId);
static void Task_OptionMenuSave(u8 taskId);
static void Task_OptionMenuFadeOut(u8 taskId);
static void HighlightOptionMenuItem(u8 selection);
static u8   TextSpeed_ProcessInput(u8 selection);
static void TextSpeed_DrawChoices(u8 selection);
static u8   BattleScene_ProcessInput(u8 selection);
static void BattleScene_DrawChoices(u8 selection);
static u8   BattleStyle_ProcessInput(u8 selection);
static void BattleStyle_DrawChoices(u8 selection);
static u8   Sound_ProcessInput(u8 selection);
static void Sound_DrawChoices(u8 selection);
static u8   FrameType_ProcessInput(u8 selection);
static void FrameType_DrawChoices(u8 selection);
static u8   ButtonMode_ProcessInput(u8 selection);
static void ButtonMode_DrawChoices(u8 selection);

static void MainCB(void)
{
    RunTasks();
    AnimateSprites();
    BuildOamBuffer();
    UpdatePaletteFade();
}

static void VBlankCB(void)
{
    LoadOam();
    ProcessSpriteCopyRequests();
    TransferPlttBuffer();
}

void CB2_InitOptionMenu(void)
{
    switch (gMain.state)
    {
    default:
    case 0:
        SetVBlankCallback(NULL);
        REG_DISPCNT = 0;
        REG_BG2CNT = 0;
        REG_BG1CNT = 0;
        REG_BG0CNT = 0;
        REG_BG2HOFS = 0;
        REG_BG2VOFS = 0;
        REG_BG1HOFS = 0;
        REG_BG1VOFS = 0;
        REG_BG0HOFS = 0;
        REG_BG0VOFS = 0;
        DmaFill16Large(3, 0, (u8 *)VRAM, 0x18000, 0x1000);
        DmaClear32(3, OAM, OAM_SIZE);
        DmaClear16(3, PLTT, PLTT_SIZE);
        gMain.state++;
        break;
    case 1:
        ResetPaletteFade();
        ScanlineEffect_Stop();
        ResetTasks();
        ResetSpriteData();
        gMain.state++;
        break;
    case 2:
        Text_LoadWindowTemplate(&gWindowTemplate_81E71B4);
        gMain.state++;
        break;
    case 3:
        MultistepInitMenuWindowBegin(&gWindowTemplate_81E71B4);
        gMain.state++;
        break;
    case 4:
        if (!MultistepInitMenuWindowContinue())
            return;
        gMain.state++;
        break;
    case 5:
        LoadPalette(gUnknown_0839F5FC, 0x80, 0x40);
        CpuCopy16(gUnknown_0839F63C, (void *)(VRAM + 0xBEE0), 0x40);
        gMain.state++;
        break;
    case 6:
        BeginNormalPaletteFade(0xFFFFFFFF, 0, 16, 0, RGB(0, 0, 0));
        gMain.state++;
        break;
    case 7:
    {
        u16 savedIme;

        REG_WIN0H = 0;
        REG_WIN0V = 0;
        REG_WIN1H = 0;
        REG_WIN1V = 0;
        REG_WININ = 0x1111;
        REG_WINOUT = 0x31;
        REG_BLDCNT = 0xE1;
        REG_BLDALPHA = 0;
        REG_BLDY = 7;
        savedIme = REG_IME;
        REG_IME = 0;
        REG_IE |= INTR_FLAG_VBLANK;
        REG_IME = savedIme;
        REG_DISPSTAT |= DISPSTAT_VBLANK_INTR;
        SetVBlankCallback(VBlankCB);
        REG_DISPCNT = DISPCNT_MODE_0 | DISPCNT_OBJ_1D_MAP | DISPCNT_BG0_ON | DISPCNT_OBJ_ON |
          DISPCNT_WIN0_ON | DISPCNT_WIN1_ON;
        gMain.state++;
        break;
    }
    case 8:
    {
        u8 taskId = CreateTask(Task_OptionMenuFadeIn, 0);

        gTasks[taskId].tMenuSelection = 0;
        gTasks[taskId].tOptTextSpeed   = gSaveBlock2.optionsTextSpeed;
        gTasks[taskId].tOptBattleScene = gSaveBlock2.optionsBattleSceneOff;
        gTasks[taskId].tOptBattleStyle = gSaveBlock2.optionsBattleStyle;
        gTasks[taskId].tOptSound       = gSaveBlock2.optionsSound;
        gTasks[taskId].tOptButtonMode  = gSaveBlock2.optionsButtonMode;
        gTasks[taskId].tOptFrameType   = gSaveBlock2.optionsWindowFrameType;

        Menu_DrawStdWindowFrame(2, 0, 27, 3);   // title box
        Menu_DrawStdWindowFrame(2, 4, 27, 19);  // options list box

        Menu_PrintText(gSystemText_OptionMenu,  4,  1);

        Menu_PrintText(gSystemText_TextSpeed,   4,  5);
        Menu_PrintText(gSystemText_BattleScene, 4,  7);
        Menu_PrintText(gSystemText_BattleStyle, 4,  9);
        Menu_PrintText(gSystemText_Sound,       4, 11);
        Menu_PrintText(gSystemText_ButtonMode,  4, 13);
        Menu_PrintText(gSystemText_Frame,       4, 15);
        Menu_PrintText(gSystemText_Cancel,      4, 17);

        TextSpeed_DrawChoices(gTasks[taskId].tOptTextSpeed);
        BattleScene_DrawChoices(gTasks[taskId].tOptBattleScene);
        BattleStyle_DrawChoices(gTasks[taskId].tOptBattleStyle);
        Sound_DrawChoices(gTasks[taskId].tOptSound);
        ButtonMode_DrawChoices(gTasks[taskId].tOptButtonMode);
        FrameType_DrawChoices(gTasks[taskId].tOptFrameType);

        REG_WIN0H = WIN_RANGE(17, 223);
        REG_WIN0V = WIN_RANGE(1, 31);

        HighlightOptionMenuItem(gTasks[taskId].tMenuSelection);
        gMain.state++;
        break;
    }
    case 9:
        SetMainCallback2(MainCB);
        return;
    }
}

static void Task_OptionMenuFadeIn(u8 taskId)
{
    if (!gPaletteFade.active)
        gTasks[taskId].func = Task_OptionMenuProcessInput;
}

static void Task_OptionMenuProcessInput(u8 taskId)
{
    if (gMain.newKeys & A_BUTTON)
    {
        if (gTasks[taskId].tMenuSelection == MENUITEM_CANCEL)
            gTasks[taskId].func = Task_OptionMenuSave;
    }
    else if (gMain.newKeys & B_BUTTON)
    {
        gTasks[taskId].func = Task_OptionMenuSave;
    }
    else if (gMain.newKeys & DPAD_UP)
    {
        if (gTasks[taskId].tMenuSelection > 0)
            gTasks[taskId].tMenuSelection--;
        else
            gTasks[taskId].tMenuSelection = 6;
        HighlightOptionMenuItem(gTasks[taskId].tMenuSelection);
    }
    else if (gMain.newKeys & DPAD_DOWN)
    {
        if (gTasks[taskId].tMenuSelection < 6)
            gTasks[taskId].tMenuSelection++;
        else
            gTasks[taskId].tMenuSelection = 0;
        HighlightOptionMenuItem(gTasks[taskId].tMenuSelection);
    }
    else
    {
        switch (gTasks[taskId].tMenuSelection)
        {
        case MENUITEM_TEXTSPEED:
            gTasks[taskId].tOptTextSpeed = TextSpeed_ProcessInput(gTasks[taskId].tOptTextSpeed);
            TextSpeed_DrawChoices(gTasks[taskId].tOptTextSpeed);
            break;
        case MENUITEM_BATTLESCENE:
            gTasks[taskId].tOptBattleScene = BattleScene_ProcessInput(gTasks[taskId].tOptBattleScene);
            BattleScene_DrawChoices(gTasks[taskId].tOptBattleScene);
            break;
        case MENUITEM_BATTLESTYLE:
            gTasks[taskId].tOptBattleStyle = BattleStyle_ProcessInput(gTasks[taskId].tOptBattleStyle);
            BattleStyle_DrawChoices(gTasks[taskId].tOptBattleStyle);
            break;
        case MENUITEM_SOUND:
            gTasks[taskId].tOptSound = Sound_ProcessInput(gTasks[taskId].tOptSound);
            Sound_DrawChoices(gTasks[taskId].tOptSound);
            break;
        case MENUITEM_BUTTONMODE:
            gTasks[taskId].tOptButtonMode = ButtonMode_ProcessInput(gTasks[taskId].tOptButtonMode);
            ButtonMode_DrawChoices(gTasks[taskId].tOptButtonMode);
            break;
        case MENUITEM_FRAMETYPE:
            gTasks[taskId].tOptFrameType = FrameType_ProcessInput(gTasks[taskId].tOptFrameType);
            FrameType_DrawChoices(gTasks[taskId].tOptFrameType);
            break;
        }
    }
}

static void Task_OptionMenuSave(u8 taskId)
{
    gSaveBlock2.optionsTextSpeed       = gTasks[taskId].tOptTextSpeed;
    gSaveBlock2.optionsBattleSceneOff  = gTasks[taskId].tOptBattleScene;
    gSaveBlock2.optionsBattleStyle     = gTasks[taskId].tOptBattleStyle;
    gSaveBlock2.optionsSound           = gTasks[taskId].tOptSound;
    gSaveBlock2.optionsButtonMode      = gTasks[taskId].tOptButtonMode;
    gSaveBlock2.optionsWindowFrameType = gTasks[taskId].tOptFrameType;

    BeginNormalPaletteFade(0xFFFFFFFF, 0, 0, 16, RGB(0, 0, 0));
    gTasks[taskId].func = Task_OptionMenuFadeOut;
}

static void Task_OptionMenuFadeOut(u8 taskId)
{
    if (!gPaletteFade.active)
    {
        DestroyTask(taskId);
        SetMainCallback2(gMain.savedCallback);
    }
}

//This version uses addition '+' instead of OR '|'.
#define WIN_RANGE_(a, b) (((a) << 8) + (b))

static void HighlightOptionMenuItem(u8 index)
{
    REG_WIN1H = WIN_RANGE(24, 215);
    REG_WIN1V = WIN_RANGE_(index * 16 + 40, index * 16 + 56);
}

static void DrawOptionMenuChoice(const u8 *text, u8 x, u8 y, u8 style)
{
    u8 dst[15];
    u16 i;

    for (i = 0; *text != EOS && i < 15; i++)
        dst[i] = *(text++);

    dst[2] = style;
    dst[i] = EOS;
    Menu_PrintTextPixelCoords(dst, x, y, 1);
}

static u8 TextSpeed_ProcessInput(u8 selection)
{
    if (gMain.newKeys & DPAD_RIGHT)
    {
        if (selection < 2)
            selection++;
        else
            selection = 0;
    }
    if (gMain.newKeys & DPAD_LEFT)
    {
        if (selection > 0)
            selection--;
        else
            selection = 2;
    }
    return selection;
}

#if ENGLISH
#define TEXTSPEED_SLOW_LEFT (120)
#define TEXTSPEED_MIX_LEFT (155)
#define TEXTSPEED_FAST_LEFT (184)
#endif
#if GERMAN
#define TEXTSPEED_SLOW_LEFT (120)
#define TEXTSPEED_MIX_LEFT (161)
#define TEXTSPEED_FAST_LEFT (202)
#endif

static void TextSpeed_DrawChoices(u8 selection)
{
    u8 styles[3];

    styles[0] = 0xF;
    styles[1] = 0xF;
    styles[2] = 0xF;
    styles[selection] = 0x8;

    DrawOptionMenuChoice(gSystemText_Slow, TEXTSPEED_SLOW_LEFT, 40, styles[0]);
    DrawOptionMenuChoice(gSystemText_Mid,  TEXTSPEED_MIX_LEFT,  40, styles[1]);
    DrawOptionMenuChoice(gSystemText_Fast, TEXTSPEED_FAST_LEFT, 40, styles[2]);
}

static u8 BattleScene_ProcessInput(u8 selection)
{
    if (gMain.newKeys & (DPAD_LEFT | DPAD_RIGHT))
        selection ^= 1;
    return selection;
}

static void BattleScene_DrawChoices(u8 selection)
{
    u8 styles[2];

    styles[0] = 0xF;
    styles[1] = 0xF;
    styles[selection] = 0x8;

    DrawOptionMenuChoice(gSystemText_On,  120, 56, styles[0]);
    DrawOptionMenuChoice(gSystemText_Off, 190, 56, styles[1]);
}

static u8 BattleStyle_ProcessInput(u8 selection)
{
    if (gMain.newKeys & (DPAD_LEFT | DPAD_RIGHT))
        selection ^= 1;
    return selection;
}

#if ENGLISH
#define BATTLESTYLE_SHIFT (120)
#define BATTLESTYLE_SET (190)
#elif GERMAN
#define BATTLESTYLE_SHIFT (120)
#define BATTLESTYLE_SET (178)
#endif

static void BattleStyle_DrawChoices(u8 selection)
{
    u8 styles[2];

    styles[0] = 0xF;
    styles[1] = 0xF;
    styles[selection] = 0x8;

    DrawOptionMenuChoice(gSystemText_Shift, BATTLESTYLE_SHIFT, 72, styles[0]);
    DrawOptionMenuChoice(gSystemText_Set,   BATTLESTYLE_SET,   72, styles[1]);
}

static u8 Sound_ProcessInput(u8 selection)
{
    if (gMain.newKeys & (DPAD_LEFT | DPAD_RIGHT))
    {
        selection ^= 1;
        SetPokemonCryStereo(selection);
    }
    return selection;
}

static void Sound_DrawChoices(u8 selection)
{
    u8 styles[3];

    styles[0] = 0xF;
    styles[1] = 0xF;
    styles[selection] = 0x8;

    DrawOptionMenuChoice(gSystemText_Mono,   120, 88, styles[0]);
    DrawOptionMenuChoice(gSystemText_Stereo, 172, 88, styles[1]);
}

static u8 FrameType_ProcessInput(u8 selection)
{
    if (gMain.newKeys & DPAD_RIGHT)
    {
        if (selection < 19)
            selection++;
        else
            selection = 0;
        Menu_LoadStdFrameGraphicsOverrideStyle(selection);
    }
    if (gMain.newKeys & DPAD_LEFT)
    {
        if (selection > 0)
            selection--;
        else
            selection = 19;
        Menu_LoadStdFrameGraphicsOverrideStyle(selection);
    }
    return selection;
}

static void FrameType_DrawChoices(u8 selection)
{
#if ENGLISH
    u8 text[6];
    u8 n = selection + 1;
    u16 i;

    for (i = 0; gSystemText_Terminator[i] != EOS && i < 6; i++)
        text[i] = gSystemText_Terminator[i];

    //Convert number to decimal string
    if (n / 10 != 0)
    {
        text[i] = n / 10 + CHAR_0;
        i++;
        text[i] = n % 10 + CHAR_0;
        i++;
    }
    else
    {
        text[i] = n % 10 + CHAR_0;
        i++;
        text[i] = CHAR_SPACE;
        i++;
    }

    text[i] = EOS;
    Menu_PrintText(gSystemText_Type, 15, 15);
    Menu_PrintText(text, 18, 15);
#elif GERMAN
    u8 text[16];
    u8 n = selection + 1;
    u8 *str;

    StringCopy(text, gSystemText_Type);
    str = StringAppend(text, gSystemText_Terminator);

    if (n / 10 != 0)
    {
        *str++ = n / 10 + CHAR_0;
        *str++ = n % 10 + CHAR_0;
    }
    else
    {
        *str++ = n % 10 + CHAR_0;
        *str++ = CHAR_SPACE;
    }
    *str = EOS;
    Menu_PrintText(text, 15, 15);
#endif
}

static u8 ButtonMode_ProcessInput(u8 selection)
{
    if (gMain.newKeys & DPAD_RIGHT)
    {
        if (selection < 2)
            selection++;
        else
            selection = 0;
    }
    if (gMain.newKeys & DPAD_LEFT)
    {
        if (selection > 0)
            selection--;
        else
            selection = 2;
    }
    return selection;
}

static void ButtonMode_DrawChoices(u8 selection)
{
    u8 styles[3];

    styles[0] = 0xF;
    styles[1] = 0xF;
    styles[2] = 0xF;
    styles[selection] = 0x8;

    DrawOptionMenuChoice(gSystemText_Normal, 120, 104, styles[0]);
    DrawOptionMenuChoice(gSystemText_LR,     166, 104, styles[1]);
    DrawOptionMenuChoice(gSystemText_LA,     188, 104, styles[2]);
}
