#include <ultra64.h>
#include "core1/core1.h"
#include "functions.h"
#include "variables.h"

#include "bk_time.h"
#include "port/Interpolation/FrameInterpolation.h"

#ifndef ABS
#define	ABS(d)		((d) >= 0) ? (d) : -(d)
#endif

extern u8 D_8037DCC8; //bottles bonus flags???


extern void func_8025AABC(enum comusic_e);
extern f32 controller_clampAndNormaliseJoyAxis(s32, s32, s32);
extern void chBottlesBonus_func_802DEA50(s32);
extern void actor_postdrawMethod(ActorMarker *);
extern void chBottlesBonus_completedPuzzle(void);


typedef struct {
    s32 state; //state
    s32 piece_id; //piece_id
    f32 rotation; //rotation;
    f32 unkC[4];
    f32 unk1C[4];
}Struct_core2_584D0_0;

typedef struct {
    f32 unk0;
    f32 unk4;
}Struct_core2_584D0_1;

void chBottlesBonusCursor_func_802DF99C(void);
void chBottlesBonusCursor_update(Actor *this);

/* .data */
ActorAnimationInfo chBottlesBonusCursorAnimations[] = {
    {0x000, 0.0f},
    {ASSET_2A2_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 1.0f},
    {ASSET_2A5_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 1.0f},
    {ASSET_2A4_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.4f},
    {ASSET_2A3_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.4f},
    {ASSET_2A1_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.3f},
    {ASSET_2A7_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.4f},
    {ASSET_2A1_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 0.3f},
    {ASSET_2A6_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 2.6f},
    {ASSET_2A8_ANIM_BOTTLES_BONUS_CURSOR_UNKNOWN, 2.6f}
};

f32 D_80368400[3] = {570.0f, 328.9f, -186.4f};
f32 D_8036840C[3] = {-11.28f, 3.92f, -52.96f};

ActorInfo chBottlesBonusCursor = {
    MARKER_17A_BOTTLES_BONUS_BANJO_HAND, ACTOR_2B4_BOTTLES_BONUS_BANJO_HAND, ASSET_565_MODEL_BOTTLES_BONUS_BANJO_HAND, 
    0x1, chBottlesBonusCursorAnimations, 
    chBottlesBonusCursor_update, actor_update_func_80326224, func_80325340, 
    0, 0, 0.0f, 0
};

/* .bss */
ActorMarker *chBottlesBonusCursorMarker;
f32 D_8037E068[60][2];
Struct_core2_584D0_0 D_8037E248[20]; //puzzle pieces
s32 D_8037E5B8;

struct {
    s32 unk0;
    u8 pad4[0xC];
    f32 unk10[2];
    f32 unk18[2];
    u16 prev_button; //buttons
    //u8 pad22;
    s32 is_completed;
    f32 unk28;
    f32 unk2C;
} D_8037E5C0;

f32 D_8037E5F0;
f32 D_8037E5F4;
f32 D_8037E5F8[3];

/* .code */
void chBottlesBonusCursor_func_802DF460(s32 indx, ActorMarker *caller, f32 arg2[3]) {
    f32 sp1C[3];

    sp1C[0] = arg2[0] * 100.0f;
    sp1C[1] = arg2[1] * 100.0f;
    sp1C[2] = arg2[2] * 100.0f;
    if (viewport_func_8024E030(sp1C, D_8037E068[indx]) == 0) {
        D_8037E068[indx][0] = D_8037E068[indx][1] = 0.0f;
    }
}

static f32 __XY_dist_square(f32 arg0[2], f32 arg1[2]){
    return (arg0[0] - arg1[0])*(arg0[0] - arg1[0]) + (arg0[1] - arg1[1])*(arg0[1] - arg1[1]);
}

s32 chBottlesBonusCursor_func_802DF50C(void) {
    s32 i;
    f32 min;
    f32 temp_f0;
    s32 min_index;

    min = 1000.0f;
    min_index = -1;
    for(i = 0; i < 60; i++){
        temp_f0 = __XY_dist_square(D_8037E5C0.unk10, D_8037E068[i]);
        if (temp_f0 < ((f32)min + (f32)i)) {
            min_index = i;
            min = temp_f0;
        }
    }

    if(min < 1000.0f)
        return min_index;
    return -1;
}

bool chBottlesBonusCursor_checkPuzzleCompletion(void) {
    s32 i;

    D_8037E5C0.is_completed = true;
    for(i = 0; i < 20 && D_8037E5C0.is_completed != 0; i++){
        if((D_8037E248[i].state != 3) 
            || (i != D_8037E248[i].piece_id) 
            || !vec4f_isAlmostZero(chBottlesBonus_get_piece_distance_vec4f(i))
        ) {
            D_8037E5C0.is_completed = false;
        }
    }

    if (D_8037E5C0.is_completed) {
        item_set(ITEM_6_HOURGLASS, false);
        timedFunc_set_3(0.25f, (GenFunction_3)comusic_8025AB44, COMUSIC_94_BBONUS, 0, 2000);
        timedFunc_set_2(0.3f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_2D_PUZZLE_SOLVED_FANFARE, 22000);
        timedFunc_set_0(1.5f, (GenFunction_0)chBottlesBonusCursor_func_802DF99C);
        timedFunc_set_0(1.0f, (GenFunction_0)chBottlesBonus_completedPuzzle);
    }
    return D_8037E5C0.is_completed;
}

void chBottlesBonusCursor_draw(Gfx **gfx, Mtx **mtx, Vtx **vtx) {
    f32 rotation[3];
    Actor *this;
    f32 sp3C;

    this = marker_getActorAndRotation(chBottlesBonusCursorMarker, rotation);
    modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)actor_predrawMethod, (void *)this);
    modelRender_setPostDrawCallback((model_render_post_draw_callback_f)actor_postdrawMethod, (void *)chBottlesBonusCursorMarker);
    modelRender_setDepthMode(MODEL_RENDER_DEPTH_NONE);
    actor_setOpacity(this, 0xB9);
    viewport_func_8024E030(this->position, D_8037E5C0.unk18);
    sp3C = (this->scale * 650.0f);
    depthbuffer_clearRegion(gfx, 
        (s32)(D_8037E5C0.unk18[0]  - sp3C/2), (s32)(D_8037E5C0.unk18[1] - sp3C/2),
        (s32)sp3C, (s32)sp3C,
        gFramebuffers[getActiveFramebuffer()]
    );
    FrameInterpolation_RecordOpenChild("bbonus_cursor", 0);
    modelRender_draw(gfx, mtx, this->position, rotation, this->scale, NULL, marker_loadModelBin(chBottlesBonusCursorMarker));
    FrameInterpolation_RecordCloseChild();
    viewport_func_8024E030(this->position, D_8037E5C0.unk10);
    if (this->state == 1) {
        D_8037E5C0.unk10[0] -= 24.0f;
        D_8037E5C0.unk10[1] -= 8.0f;
    } else {
        D_8037E5C0.unk10[0] -= 44.0f;
        D_8037E5C0.unk10[1] -= 8.0f;
    }
}

ActorMarker *chBottlesBonusCursor_spawn(void){
    Actor *this = actor_spawnWithYaw_f32(0x2B4, D_80368400, 0);
    chBottlesBonusCursorMarker = this->marker;
    return chBottlesBonusCursorMarker;
}

void chBottlesBonusCursor_func_802DF928(s32 indx) {
    f32 rotation_3d[3];

    vec4f_clone(D_8037E248[indx].unk1C, D_8037E248[indx].unkC);
    rotation_3d[0] = D_8037E248[indx].rotation;
    rotation_3d[1] = 0.0f; 
    rotation_3d[2] = 0.0f;
    func_80345C78(D_8037E248[indx].unkC, rotation_3d);
}

void chBottlesBonusCursor_func_802DF99C(void){
    musicKeepsPlaying();
    func_8025A55C(-1, 2000, 7);
}

void chBottlesBonusCursor_freeMethod(Actor *this) {
    debugScoreStates();
    clearScoreStates();
    if (func_8034BAFC() != -1) {
        gameSelect_setGameNumber(func_8034BAFC());
        gameFile_load(func_8034BAFC());
        func_80347AA8();
    }
    chBottlesBonusCursorMarker = 0;
}

void chBottlesBonusCursor_update(Actor *this) {
    OSContPad *sp5C;
    f32 sp58;
    f32 sp54;
    f32 sp50;
    Struct_core2_584D0_0 *held_piece;
    s32 i;
    s32 sp44;

    sp5C = joy_getInputsPrimary();
    sp58 = time_func_8033DDB8();
    held_piece = &D_8037E248[D_8037E5C0.unk0];
    if (!this->initialized) {
        this->initialized = true;
        this->scale = 0.18f;
        this->pitch = 59.0f;
        this->roll = 63.0f;
        this->yaw = -6.0f;
        D_8037E5C0.unk28 = D_8037E5C0.unk2C = 1.0f;
        D_8037E5F4 = 0.0f;
        D_8037E5F0 = 0.0f;
        D_8037E5C0.unk0 = -1;
        D_8037E5B8 = -1;
        D_8037E5C0.prev_button = sp5C->button;
        D_8037E5C0.is_completed = 0;
        timedFunc_set_2(3.0f, (GenFunction_2)coMusicPlayer_playMusic, COMUSIC_94_BBONUS, 0x5DC0);
        timedFunc_set_1(3.0f, (GenFunction_1)func_8025AABC, COMUSIC_94_BBONUS);
        for(i = 0; i < 20; i++){
            bzero(&D_8037E248[i], sizeof(Struct_core2_584D0_0));
            D_8037E068[40 + i][0] = D_8037E068[40 + i][1] = 0.0f;
        }
        marker_setFreeMethod(this->marker, chBottlesBonusCursor_freeMethod);
    }

    if (this->state != 8 && this->state != 9 && chBottlesBonus_getState() == 4) {
        if (this->state != 6) {
            sp54 = controller_clampAndNormaliseJoyAxis(sp5C->stick_x, 7, 59);
            sp50 = controller_clampAndNormaliseJoyAxis(sp5C->stick_y, 7, 61);
            if ((sp54 == 0.0f) || (D_8037E5F0 * sp54 < 0.0f)) {
                    D_8037E5C0.unk28 = 1.0f;
            } else {
                D_8037E5C0.unk28 *= 1 + (ABS(sp54 * 0.1));
            }
            if ((sp50 == 0.0f) || (D_8037E5F4 * sp50 < 0.0f)) {
                    D_8037E5C0.unk2C = 1.0f;
            } else {
                D_8037E5C0.unk2C *= 1 + (ABS(sp50 * 0.1));
            }

            D_8037E5F0 = sp54;
            D_8037E5F4 = sp50;

            this->unk1C[1] += (((sp50 * sp58) * 150.0) * D_8037E5C0.unk2C);
            this->unk1C[2] += (((sp54 * sp58) * 150.0) * D_8037E5C0.unk28);

            this->unk1C[1] = MAX(-100.0f, MIN(this->unk1C[1], 110.0f));
            this->unk1C[2] = MAX(-135.0f, MIN(this->unk1C[2], 180.0f));

            this->position[0] = D_80368400[0] + this->unk1C[0];
            this->position[1] = D_80368400[1] + this->unk1C[1];
            this->position[2] = D_80368400[2] + this->unk1C[2];
        }
        
        if ( (sp5C->button & START_BUTTON) && !(D_8037E5C0.prev_button & START_BUTTON) 
            && chBottlesBonus_getState() == 4
        ) {
            chBottlesBonus_lose(&D_8037DCC8, 0xE25);
        }

        if(this->state == 2 || this->state == 3 || this->state == 4){
            if((sp5C->button & L_CBUTTONS) && !(D_8037E5C0.prev_button & L_CBUTTONS)){ 
                held_piece->rotation = mlNormalizeAngle(held_piece->rotation - 90.0);
                chBottlesBonusCursor_func_802DF928(D_8037E5C0.unk0);
                chBottlesBonus_func_802DEA74(D_8037E5C0.unk0);
                func_8030E58C(SFX_12D_CAMERA_ZOOM_CLOSEST, 0.9f);
                subaddie_set_state_with_direction(this, 3, 0.0f, 1);
                actor_playAnimationOnce(this);
            }
            if((sp5C->button & R_CBUTTONS) && !(D_8037E5C0.prev_button & R_CBUTTONS)){ 
                held_piece->rotation = mlNormalizeAngle(held_piece->rotation + 90.0);
                chBottlesBonusCursor_func_802DF928(D_8037E5C0.unk0);
                chBottlesBonus_func_802DEA74(D_8037E5C0.unk0);
                func_8030E58C(SFX_12D_CAMERA_ZOOM_CLOSEST, 1.0f);
                subaddie_set_state_with_direction(this, 4, 0.0f, 1);
                actor_playAnimationOnce(this);
            }
        }

        D_8037E5B8 = chBottlesBonusCursor_func_802DF50C() + 1;
        switch(this->state){
            case 1://L802E00AC //no piece in hand
                if( (D_8037E5B8 > 0) && (D_8037E5B8 < 0x15) 
                     && ((sp5C->button & A_BUTTON) && !(D_8037E5C0.prev_button & A_BUTTON))
                ){
                    if(D_8037E248[D_8037E5B8 - 1].state == 0) {
                        D_8037E5C0.unk0 = D_8037E5B8 - 1;
                        chBottlesBonus_func_802DEA50(D_8037E5C0.unk0);
                        held_piece = &D_8037E248[D_8037E5C0.unk0];
                        held_piece->state = 1;
                        held_piece->rotation = 0.0f; 
                        chBottlesBonusCursor_func_802DF928(D_8037E5C0.unk0);
                        chBottlesBonusCursor_func_802DF928(D_8037E5C0.unk0);
                        coMusicPlayer_playMusic(COMUSIC_96_BBONUS_PICKUP_PIECE, -1);
                        subaddie_set_state_with_direction(this, 2, 0.0f, 1);
                    }
                }

                if( ((D_8037E5B8 >= 0x29) && (D_8037E5B8 < 0x3D))
                    && ((sp5C->button & A_BUTTON) && !(D_8037E5C0.prev_button & A_BUTTON))
                ) {
                    if (D_8037E248[D_8037E5B8 - 41].state == 3) {
                        if( D_8037E5B8 - 41 != D_8037E248[D_8037E5B8 - 41].piece_id
                            || !vec4f_isAlmostZero(chBottlesBonus_get_piece_distance_vec4f(D_8037E5B8 - 41))
                        ) {
                            D_8037E5C0.unk0 = D_8037E5B8 - 41;
                            chBottlesBonus_func_802DEA50(D_8037E5C0.unk0);
                            held_piece = &D_8037E248[D_8037E5C0.unk0];
                            held_piece->state = 2;
                            chBottlesBonusCursor_func_802DF928(D_8037E5C0.unk0);
                            sfxsource_playHighPriority(SFX_112_TINKER_ATTENTION);
                            subaddie_set_state_with_direction(this, 2, 0.0f, 1);
                        }
                    }
                }
                break;

            //holding piece
            case 2://L802E029C 
                if((sp5C->button & B_BUTTON) && !(D_8037E5C0.prev_button & B_BUTTON)){
                    held_piece->state = 0;
                    subaddie_set_state_with_direction(this, 5, 0.0f, 1);
                    coMusicPlayer_playMusic(COMUISC_97_BBONUS_DROP_PIECE, -1);
                    chBottlesBonus_func_802DEA50(D_8037E5C0.unk0);
                    D_8037E5C0.unk0 = -1;
                    break;
                }

                if((sp5C->button & A_BUTTON) && !(D_8037E5C0.prev_button & A_BUTTON)){
                    if ((D_8037E5B8 >= 21) && (D_8037E5B8 < 41)) {
                        held_piece->state = 3;
                        held_piece->piece_id = D_8037E5B8 - 21;
                        if ((D_8037E5C0.unk0 == held_piece->piece_id) && vec4f_isAlmostZero(chBottlesBonus_get_piece_distance_vec4f(D_8037E5C0.unk0))) {
                            //placed correctly
                            sp44 = COMUSIC_2B_DING_B;
                            subaddie_set_state_with_direction(this, 6, 0.0f, 1);
                            actor_playAnimationOnce(this);
                        } else {
                            //placed incorrectly
                            sp44 = COMUSIC_2C_BUZZER;
                            subaddie_set_state_with_direction(this, 1, 0.0f, 1);
                        }

                        if (chBottlesBonusCursor_checkPuzzleCompletion()) {
                            subaddie_set_state_with_direction(this, 8, 0.0f, 1);
                            actor_playAnimationOnce(this);
                        }

                        timedFunc_set_2(0.25f, (GenFunction_2)coMusicPlayer_playMusic, sp44, 26000);
                        chBottlesBonus_func_802DEA50(D_8037E5C0.unk0);
                        D_8037E5C0.unk0 = -1;
                    }
                }
                break;

            //rotate CCW
            case 3://L802E0420
                if (anctrl_isStopped(this->anctrl) ) {
                    subaddie_set_state_with_direction(this, 2, 0.0f, 1);
                    actor_loopAnimation(this);
                }
                break;

            //rotate CW
            case 4://L802E0450
                if (anctrl_isStopped(this->anctrl) ) {
                    subaddie_set_state_with_direction(this, 2, 0.0f, 1);
                    actor_loopAnimation(this);
                }
                break;

            case 7://L802E0480
                if (anctrl_isStopped(this->anctrl) ) {
                    subaddie_set_state_with_direction(this, 2, 0.0f, 1);
                    actor_loopAnimation(this);
                }
                break;

            case 5://L802E04B0
                subaddie_set_state_with_direction(this, 1, 0.0f, 1);
                break;

            //placing correct piece
            case 6://L802E04CC
                if (actor_animationIsAt(this, 0.5f) != 0) {
                    FUNC_8030E624(SFX_6C_LOCKUP_CLOSING, 1.0f, 24000);
                }
                if (anctrl_isStopped(this->anctrl) != 0) {
                    subaddie_set_state_with_direction(this, 1, 0.0f, 1);
                    actor_loopAnimation(this);
                }
                break;

            //puzzle complete
            case 8://L802E0510
                break;

            case 9://L802E0510
                break;
        }
        D_8037E5C0.prev_button = sp5C->button;
    }
}

s32 chBottlesBonusCursor_func_802E0538(s32 indx){
    return D_8037E248[indx].state;
}

s32 chBottlesBonusCursor_getState(void){
    Actor *this;

    this = marker_getActor(chBottlesBonusCursorMarker);
    return this->state;
}

s32 chBottlesBonusCursor_func_802E0588(s32 indx){
    return D_8037E248[indx].piece_id;
}

f32 *chBottlesBonusCursor_func_802E05AC(s32 indx) {
    if (indx == D_8037E5C0.unk0) {
        D_8037E5F8[0] = D_8036840C[0] + marker_getActor(chBottlesBonusCursorMarker)->position[0];
        D_8037E5F8[1] = D_8036840C[1] + marker_getActor(chBottlesBonusCursorMarker)->position[1];
        D_8037E5F8[2] = D_8036840C[2] + marker_getActor(chBottlesBonusCursorMarker)->position[2];
    } else {
        ml_vec3f_assign(D_8037E5F8, 0, 0, 0);
    }
    return D_8037E5F8;
}

f32 *chBottlesBonusCursor_func_802E0664(s32 indx){
    return D_8037E248[indx].unkC;
}

f32 *chBottlesBonusCursor_func_802E068C(s32 indx){
    return D_8037E248[indx].unk1C;
}

s32 chBottlesBonusCursor_func_802E06B4(void){
    return D_8037E5B8;
}

bool chBottlesBonusCursor_isPuzzleCompleted(void){
    return D_8037E5C0.is_completed;
}

void chBottlesBonusCursor_lose(void){
    Actor *this;

    this = marker_getActor(chBottlesBonusCursorMarker);
    subaddie_set_state_with_direction(this, 9, 0.0f, 1);
    actor_playAnimationOnce(this);
}