/****************************************************************************
 * Copyright (C) 2015-2016 by the SotS Team                                 *
 *                                                                          *
 * This file is part of Sovereign of the Skies.                             *
 *                                                                          *
 *   Sovereign of the Skies is free software: you can redistribute it       *
 *   and/or modify it                                                       *
 *   under the terms of the GNU Lesser General Public License as published  *
 *   by the Free Software Foundation, either version 3 of the License, or   *
 *   (at your option) any later version provided you include a copy of the  *
 *   licence and this header.                                               *
 *                                                                          *
 *   Sovereign of the Skies is distributed in the hope that it will be      *
 *   useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the          *
 *   GNU Lesser General Public License for more details.                    *
 *                                                                          *
 *   You should have received a copy of the GNU Lesser General Public       *
 *   License along with Sovereign of the Skies.                             *
 *   If not, see <http://www.gnu.org/licenses/>.                            *
 ****************************************************************************/

/**
 * @file trainer_battle.c
 * @author Sturmvogel
 * @date 04 Jan 2014
 * @brief trainerbattle script command overhaul
 * 
 */

/* === INCLUDE === */

#include <types.h>
#include <game_engine.h>
#include <debug.h>
#include <config.h>
#include <callback.h>

/* === ENGINE EXTERNS === */
extern void battle_init();
extern void battle_80801F0_something();

extern volatile u8 trainerbattle_battle_type;
extern volatile u16 trainerbattle_flag_id;
extern volatile u16 trainerbattle_arg2;
extern volatile char* trainerbattle_message_intro;
extern volatile char* trainerbattle_message_defeat;
extern volatile char* trainerbattle_message_2;
extern volatile char* trainerbattle_message_need_2_poke;
extern volatile char* trainerbattle_message_4;
extern volatile void* trainerbattle_next_scr_cmd;
extern volatile u16 trainerbattle_unknown;

char*** trainer_text_array;
char* str_invalid_text_ref;

/* === PROTOTYPES === */

/* === IMPLEMENTATIONS === */

/**
 * @brief loads a byte
 * @param ptr pointer to load byte from
 * @return byte loaded
 */
u8 load_byte(void* ptr)
{
    u8* to_load = (u8*)ptr;
    return (u8)(*to_load);
}

/**
 * @brief loads an unaligned hword
 * @param ptr pointer to load from
 * @return half word at pointer
 */
u16 load_hword(void* ptr)
{
    u8* to_load = (u8*)ptr;
    u16 result = *to_load;
    u16 result2 = *(to_load+1) << 8;
    return result | result2;
}

/**
 * @brief loads an unaligned word
 * @param ptr pointer to load from
 * @return word read at pointer
 */
u32 load_word(void* ptr)
{
    u8* to_load = (u8*)ptr;
    u32 result = *to_load;
    u32 result2 = *(to_load+1);
    u32 result3 = *(to_load+2);
    u32 result4 = *(to_load+3);
    return (result) | (result2 << 8) | (result3 << 16) | (result4 << 24);
}

/**
 * @brief modifies the given flag by game difficulty
 * @param flag flag to modify
 * @return flag +1 for medium, flag +2 for hard
 */
u16 tb_modify_flag_id(u16 flag)
{
    u16 difficulty = var_get(0x5052);
    switch(difficulty)
    {
        case 0:
            return flag;
        case 1:
            return flag + 1;
        case 2:
            return flag + 2;
    }
    return 0;
}

/**
 * @brief modifies null text pointers according to the trainer text table
 * @param original original pointer, will be modified only if equal to NULL
 * @param index index of the requested text in the trainer table
 * @return 
 */
char* tb_modify_text(char* original, u8 index)
{
    if(original != NULL)
        return original;
    u8 flag_index = trainerbattle_flag_id;   /* NOTE: divide by 3 eventually */
    for(int i = 0; i <= flag_index; ++i)
    {
        if(trainer_text_array[i] == (char**)0xDEADBEEF)
        {
            return str_invalid_text_ref;
        }
    }
    for(int i = 0; i <= index; ++i)
    {
        if(trainer_text_array[flag_index][i] == (char*)0xDEADBEEF)
        {
            return str_invalid_text_ref;
        }
    }
    return trainer_text_array[flag_index][index];
}

/**
 * @brief read parameters and initialize a trainerbattle instance
 * @param ptr_script pointer to current executed script
 * @return new script pointer
 */
void* tb_configure_by_script(void* ptr_script)
{
    battle_init();
    trainerbattle_battle_type = load_byte(ptr_script);
    switch(trainerbattle_battle_type)
    {
        case 1:
        case 2:
            trainerbattle_battle_type = load_byte(ptr_script);
            ptr_script++;
            
            trainerbattle_flag_id = tb_modify_flag_id(load_hword(ptr_script));
            ptr_script+=2;
            
            trainerbattle_arg2 = load_hword(ptr_script);
            ptr_script+=2;
            
            trainerbattle_message_intro = tb_modify_text((char*)load_word(ptr_script), 0);
            ptr_script+=4;
            
            trainerbattle_message_defeat = tb_modify_text((char*)load_word(ptr_script), 1);
            ptr_script+=4;
            
            trainerbattle_message_2 = NULL;
            trainerbattle_message_need_2_poke = NULL;
            
            trainerbattle_message_4 = tb_modify_text((char*)load_word(ptr_script), 2);
            ptr_script+=4;
            trainerbattle_next_scr_cmd = ptr_script;
            battle_80801F0_something();
            return (void*) (0x081A4EC1) /* some script to execute */;
        case 3:
            trainerbattle_battle_type = load_byte(ptr_script);
            
            trainerbattle_flag_id = tb_modify_flag_id(load_hword(ptr_script));
            ptr_script+=2;
            
            trainerbattle_arg2 = load_hword(ptr_script);
            ptr_script+=2;
            
            trainerbattle_message_intro = NULL;
            
            trainerbattle_message_defeat = tb_modify_text((char*)load_word(ptr_script), 0);
            ptr_script++;
            
            trainerbattle_message_2 = NULL;
            trainerbattle_message_need_2_poke = NULL;
            
            trainerbattle_message_4 = NULL;
            
            trainerbattle_next_scr_cmd = ptr_script;
            return (void*) (0x081A4F21); /* some script to execute*/
        case 4:
            trainerbattle_battle_type = load_byte(ptr_script);
            ptr_script++;
            
            trainerbattle_flag_id = tb_modify_flag_id(load_hword(ptr_script));
            ptr_script+=2;
            
            trainerbattle_arg2 = load_hword(ptr_script);
            ptr_script+=2;
            
            trainerbattle_message_intro = tb_modify_text((char*)load_word(ptr_script), 0);
            ptr_script+=4;
            
            trainerbattle_message_defeat = tb_modify_text((char*)load_word(ptr_script), 1);
            ptr_script+=4;
            
            trainerbattle_message_2 = NULL;
            
            trainerbattle_message_need_2_poke = tb_modify_text((char*)load_word(ptr_script), 2);
            ptr_script+= 4;
            
            trainerbattle_message_4 = NULL;
            ptr_script+= 4;
            trainerbattle_next_scr_cmd = ptr_script;
            battle_80801F0_something();
            return (void*) (0x081A4EE9); /* some script to execute */
            
            //this will merge case 5 with default which might not be as intended
        case 6:
        case 8:
            trainerbattle_battle_type = load_byte(ptr_script);
            ptr_script++;
            
            trainerbattle_flag_id = tb_modify_flag_id(load_hword(ptr_script));
            ptr_script+=2;
            
            trainerbattle_arg2 = load_hword(ptr_script);
            ptr_script+=2;
            
            trainerbattle_message_intro = tb_modify_text((char*)load_word(ptr_script), 0);
            ptr_script+=4;
            
            trainerbattle_message_defeat = tb_modify_text((char*)load_word(ptr_script), 1);
            ptr_script+=4;
            
            trainerbattle_message_2 = NULL;
            
            trainerbattle_message_need_2_poke = tb_modify_text((char*)load_word(ptr_script), 2);
            ptr_script += 4;
            trainerbattle_message_4 = tb_modify_text((char*)load_word(ptr_script), 3);
            ptr_script += 4;
            trainerbattle_next_scr_cmd = ptr_script;
            battle_80801F0_something();
            return (void*) (0x081A4EE9); /* some script to execute */
            
            //this will merge case 7 with default
        case 9:
            /* WIN / LOSE resume script */
            
            trainerbattle_battle_type = load_byte(ptr_script);
            ptr_script++;
            
            trainerbattle_flag_id = tb_modify_flag_id(load_hword(ptr_script));
            ptr_script += 2;
            
            trainerbattle_unknown = load_hword(ptr_script);
            ptr_script += 2;
            
            trainerbattle_message_intro = NULL;
            
            trainerbattle_message_defeat = tb_modify_text((char*)load_word(ptr_script), 0);
            ptr_script += 4;
            
            trainerbattle_message_2 = tb_modify_text((char*)load_word(ptr_script), 1);
            ptr_script += 4;
            
            trainerbattle_message_need_2_poke = NULL;
            
            trainerbattle_message_4 = NULL;
            
            trainerbattle_next_scr_cmd = ptr_script;
            
            battle_80801F0_something();
            
            return (void*) (0x081A4EC1); /* some script to execute */
        default:
            trainerbattle_battle_type = load_byte(ptr_script);
            ptr_script++;
            
            trainerbattle_flag_id = tb_modify_flag_id(load_hword(ptr_script));
            ptr_script+=2;
            
            trainerbattle_arg2 = load_hword(ptr_script);
            ptr_script+=2;
            
            trainerbattle_message_intro = tb_modify_text((char*)load_word(ptr_script), 0);
            ptr_script+=4;
            
            trainerbattle_message_defeat = tb_modify_text((char*)load_word(ptr_script), 1);
            ptr_script+=4;
            
            trainerbattle_message_2 = NULL;
            trainerbattle_message_need_2_poke = NULL;
            trainerbattle_message_4 = NULL;
            trainerbattle_next_scr_cmd = ptr_script;
            battle_80801F0_something();
            return (void*) (0x081A4EC1); /* some script to execute */
    }
    /* should never be reached */
    //assert(0);
   // return NULL;
}