/******************************************************************************
*
* Copyright (C) 2004-2017  Brian Berlin
* 
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* 
* This program 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 General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>
*
******************************************************************************
*
* FILENAME: kat5200.c
*
* DESCRIPTION:  This contains main and functions for running the system
*
* AUTHORS:  bberlin
*
* CHANGE LOG
*
*  VER     DATE     CHANGED BY   DESCRIPTION OF CHANGE
* ------  --------  ----------   ------------------------------------
* 0.1     07/18/04  bberlin      Creation
* 0.2     03/09/06  bberlin      Updated to use GUI on loading failure
* 0.3.0   04/08/06  bberlin      Added call to 'config_update'
******************************************************************************/
#include <stdio.h>
#include <zlib.h>
#include <string.h>
#ifdef WIN32
#include <windows.h>
#endif
#include "kat5200.h"
#include "core/antic.h"
#include "core/memory.h"
#include "core/debug.h"
#include "core/sio.h"
#include "interface/util.h"
#include "interface/media_if.h"
#include "interface/katconfig.h"
#include "interface/input.h"
#include "gui/gui.h"
#include "gui/guitop.h"
#include "interface/logger.h"
#include "interface/states.h"

/* On Android (and Windows GUI) SDL provides the real entry point and calls
 * SDL_main; including this redefines our main() to SDL_main so the SDLActivity
 * bootstrap in libSDL3.so can launch us.  No-op / harmless elsewhere, but
 * guarded to keep the desktop entry exactly as it was. */
#ifdef __ANDROID__
#include <SDL3/SDL_main.h>
#endif

extern t_antic antic;
extern t_cpu cpu6502;
extern t_debug debug;

double frametime = 1.0;
unsigned int *g_frame;
unsigned int g_kstatus;

int kat5200_debug_exit ( int debug_flag );
int kat5200_show_gui ( int debug_flag );
void kat5200_print_help ( void );

/******************************************************************************
**  Function   :  main
**                                                
**  Objective  :  This is the main used to run kat5200
**                                               
**  Parameters :  NONE                          
**                                             
**  return     :  0 if success                
**                1 if failure               
******************************************************************************/ 
int main ( int argc, char *argv[]  ) {

    t_config *p_config = config_get_global_cfg();
    t_atari *p_console = console_get_ptr();
    int checking_files = 1;
    char version[70];

    g_kstatus = 0;

    /*
     * First check for version or help args and show and exit
     */
    if ( argc > 1 ) {
        if ( strstr(argv[1], "--help") || strstr(argv[1], "-h") ) {
            kat5200_print_help();
            exit(EXIT_SUCCESS);
        }
        else if ( strstr(argv[1], "--version") || strstr(argv[1], "-V") ) {
            printf ( "kat5200 %s\n\n", VERSION );
            printf ( "Zlib version %s\n", ZLIB_VERSION );
            printf ( "%s\n", pc_get_compiled_version(version) );
            printf ( "%s\n", pc_get_linked_version(version) );
            printf ( "%s\n", pc_get_image_compiled_version(version) );
            printf ( "%s\n", pc_get_image_linked_version(version) );
            printf ( "Nuklear version %s\n", gui_get_version() );
            exit(EXIT_SUCCESS);
        }
    }

    /*
     * Detach the inherited console window up front (Windows console-subsystem
     * build) so it is not visible during startup.  pc_init also calls
     * FreeConsole later; this just moves it ahead of the slow path.
     */
#ifdef WIN32
    FreeConsole();
#endif

    /*
     * Initialize our interface
     */
    util_init ( argv[0] );
    logger_init();

    /*
     * Command line factory reset is a self-contained recovery path: restore
     * the default conf + profiles synchronously and exit WITHOUT starting the
     * GUI or any emulation.  It must run before config_init / pc_init and must
     * not depend on them, so a corrupted install that will not boot can still
     * be reset.  util_init (above) has resolved the live data directory it
     * needs; logger_init (above) lets copy failures be logged.
     */
    if ( argc > 1 ) {
        int reset_i;
        for ( reset_i = 1; reset_i < argc; ++reset_i ) {
            if ( strstr(argv[reset_i], "--reset_config") ) {
                int reset_rc = util_factory_reset_cli();
                if ( reset_rc == 0 )
                    printf ( "kat5200: configuration and profiles reset to defaults.\n" );
                else
                    fprintf ( stderr, "kat5200: factory reset failed.\n" );
                exit ( reset_rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE );
            }
        }
    }

    debug_init();
    debug_set_out_function ( kat5200_debug_exit );
    //debug_set_out_function ( kat5200_show_gui );
    console_init();
    mem_init();
    config_init ( argc, argv );
    sio_init();
    pc_init();
    input_init();
    input_set_gui_function ( kat5200_show_gui );

    /*
     * Log Libarary Versions
     */
    sprintf ( version, "Zlib version %s", ZLIB_VERSION );
    logger_log_message ( LOG_INFO, version, "" );
    logger_log_message ( LOG_INFO, pc_get_compiled_version(version), "" );
    logger_log_message ( LOG_INFO, pc_get_linked_version(version), "" );
    logger_log_message ( LOG_INFO, pc_get_image_compiled_version(version), "" );
    logger_log_message ( LOG_INFO, pc_get_image_linked_version(version), "" );
    sprintf ( version, "Nuklear version %s\n", gui_get_version() );
    logger_log_message ( LOG_INFO, version, "" );

     /*
     * GO!
     */
    run_system ( );

    /*
     * Goodbye
     */
    kat5200_exit();

    return 0;

} /* end main */

/******************************************************************************
**  Function   :  run_system                
**                                         
**  Objective  :  Run the console system  
**                                       
**  Parameters :  NONE                  
**                                     
**  return     :  0 if success        
**                1 if failure       
******************************************************************************/ 
int run_system (void) {

    double alpha = 0.2;
    double throttle_time = 0;
    double next_frame_time;
    Uint64 getticks,frametimedelta,frametimelast;
    t_atari *p_console = console_get_ptr();
    t_config *p_config = config_get_global_cfg();

    int run = 1;
    int status = 0;
    Uint64 stop;

    char msg[257];

    /*
     * Check for debug
     */
    //if ( p_console->debug_mode )
    //    debug_get_input ();

    //antic.dl_scanline = NTSC_SCAN_LINES;

    /*
    * Initial checks
    */
    if (p_config->general.start_with == START_GUI_ROMS ||
        p_config->general.start_with == START_GUI_BROWSER) {
        /* Start in the GUI on the launcher or file browser instead of
         * auto-launching the last ROM.  Show the GUI first (initializes it),
         * then navigate to the requested screen.  No game is running yet, so
         * "back" must not try to escape to one. */
        g_kstatus |= KSTATUS_GUI;
        g_kstatus &= ~(KSTATUS_RUN);
        gui_show_main(0, 0);
        gui_set_can_go_back(0);
        if (p_config->general.start_with == START_GUI_ROMS)
            guitop_show_launcher();
        else
            guitop_show_rom_browser();
    }
    else {
        g_kstatus |= KSTATUS_LAUNCH;
    }

    /*
     * Calculate throttle_time and start timing
     */
    if ( p_config->general.throttle ) {
        throttle_time = 100000000.0 / p_console->frames_per_sec /
            (double)p_config->general.throttle;
    }
    //printf ("Throttle Time %f\n", throttle_time );
    //throttle_time = ((1.0/p_console->frames_per_sec) * 1000.0) * 
    //                (1/((double)p_config->throttle/100.0));

    next_frame_time = (double)pc_get_ticks_us ();
    frametimelast = pc_get_ticks_us ();
    frametime = 1000000.0 / p_console->frames_per_sec;

    /*
     * Begin the main loop
     */
    while ( run ) {

        /* 
         *Try to launch selected ROM or state in config on request 
         */
        if (g_kstatus & KSTATUS_LAUNCH) {
            status = kat5200_launch(g_kstatus);
            if (status) {
                g_kstatus |= KSTATUS_GUI;
                g_kstatus &= ~(KSTATUS_RUN);
                gui_show_main(status, 0);
            }
            else {
                g_kstatus |= KSTATUS_RUN;
                pc_game_init();
            }

            if ( p_config->general.throttle ) {
                throttle_time = 100000000.0 / p_console->frames_per_sec /
                    (double)p_config->general.throttle;
            }
            else {
                throttle_time = 0;
            }
            next_frame_time = (double)pc_get_ticks_us ();
            frametimelast = (Uint64)next_frame_time;
            frametime = 1000000.0 / p_console->frames_per_sec;

            /* Don't try launch again until requested */
            g_kstatus &= ~(KSTATUS_LAUNCH | KSTATUS_BACK | KSTATUS_LAUNCH_NO_RST);
        }

        /* 
         * Show GUI if that is currently in effect
         *   FIXME: how to handle input if both gui and pc_poll running
         */
        if (g_kstatus & KSTATUS_GUI) {
            g_kstatus = gui_run_frame();
            if (g_kstatus & KSTATUS_EXIT)
                break;
        }

        /* 
         * Run through one frame of console execution 
         */
        if (g_kstatus & KSTATUS_RUN)
            run_frame();

        if (g_kstatus & KSTATUS_RUN) {
            if (!(g_kstatus & KSTATUS_GUI))     /* Normal play: video + sound */
                pc_render_frame_video_sound();
            else {                              /* Debugger run: refresh preview + sound */
                /*
                 * GTIA now renders into an INDEX8 surface, while debugger/video
                 * previews read the converted ARGB output surface.  Keep that
                 * off-screen output current even though the main game window
                 * is not rendered while the GUI is active.
                 */
                pc_refresh_video_output();
                pc_render_frame_sound();
            }
        }

        /* 
         * Now check for PC events (handles both GUI and game) 
         */
        if ( (status = pc_poll_events ()) ) {
            if ( status < 0 )
                break;
            else {
                //throttle_time = ((1.0/p_console->frames_per_sec) * 1000.0) * 
                //                (1.0/((double)p_config->throttle/100.0));
                if ( p_config->general.throttle ) {
                    throttle_time = 100000000.0 / p_console->frames_per_sec /
                        (double)p_config->general.throttle;
                }
                else {
                    throttle_time = 0;
                }

                next_frame_time = (double)pc_get_ticks_us ();
                frametimelast = (Uint64)next_frame_time;
                frametime = 1000000.0 / p_console->frames_per_sec;
            }
        }

        /* Do speed throttling if desired */
        if ( p_config->general.throttle ) {
            throttle_time = 100000000.0 / p_console->frames_per_sec /
                (double)p_config->general.throttle;
            next_frame_time += throttle_time;
            stop = pc_get_ticks_us ();
            if ( (double)stop < next_frame_time )
                pc_delay_precise_ns ( (Uint64)((next_frame_time - (double)stop) * 1000.0) );
            stop = pc_get_ticks_us ();
            if ( ((double)stop - next_frame_time) > throttle_time )
                next_frame_time = (double)stop;
        }

        /*
         * For frame timing calculations
         */
        p_console->frame_number++;
        getticks = pc_get_ticks_us();
        frametimedelta = getticks - frametimelast;
        frametimelast = getticks;
        frametime = alpha * frametimedelta + (1.0 - alpha) * frametime;

    } /* end main loop                                   */

    sprintf ( msg, "Console: frames/sec = %lf", 1000000.0/frametime );
    logger_log_message ( LOG_INFO, msg, "" );

    return 0;
    
} /* end run_system */

/******************************************************************************
**  Function   :  run_frame                                            
**                                                                    
**  Objective  :  This function executes the emulated console for one frame
**                                                   
**  Parameters :  None
**                 
**  return     :  None
******************************************************************************/ 
void run_frame (void) {

    t_atari* p_console = console_get_ptr();
    int wsync_hold_scanline;

    antic.dl_scanline = 0;
    antic.sl_cycle_count = 0;
    antic.refresh_cycles = 9;

    /*
     * First 8 scanlines no drawing
     */
    while ( antic.dl_scanline < 8 ) {
        antic.vcount = antic.dl_scanline >> 1;
        pokey_init_scanline ();
        wsync_hold_scanline = antic_scanline_wsync_state (0);
        cpu6502.i_cnt += antic_wsync_cycle_adjust();
        //antic.sl_cycle_count = antic.vblank_sl_time;
        //cpu6502.i_cnt += (antic.vblank_sl_time + antic_wsync_cycle_adjust());
        antic.sl_cycle_count = 114;
        //if (!antic.dl_scanline)
            //cpu6502.i_cnt -= 8;

        debug_check_scanline();

        if (!wsync_hold_scanline) {
            //cpu6502.i_cnt += (105 + antic_wsync_cycle_adjust());
            cpu6502.i_cnt += 105;
            run_6502 ();
        }

        antic.dl_scanline++;
    }

    /*
     * Reset cycle map pointers
     */
    antic.dl_byte_number = 0;
    antic.ml_map[0] = antic.dl_map[antic.pl_width][1][0];
    antic.ml_map[1] = 0;

    antic.ml_cycles[0] = antic.dl_cycles[antic.pl_width][1][0];

    antic.refresh_cycles = 0; // handle in maps

    /*
     * Read Display List from ANTIC until JVB
     */
    while ( antic.dl_scanline < NTSC_SCAN_LINES+8 ) {

        /*
         * Do Mode Lines
         */
        antic.mode_line = -1;
        while ( antic.ml_map[++antic.mode_line] ) {
            antic.sl_map = antic.ml_map[antic.mode_line];

            /*
             * Every Scan line do pokey stuff
             */
            pokey_init_scanline ();

            antic_scanline_wsync_state ( 1 );

            if (antic.dl_scanline == 60)
                antic.sl_cycle_count = 0;
            /*
             * Every scanline update counters
             */
            antic.vcount = antic.dl_scanline >> 1;
            antic.sl_cycle_count = 0;
            cpu6502.i_cnt += antic_wsync_cycle_adjust();

            antic.pl_width = antic.next_pl_width;
            antic.normal_pixel_start = antic.pixel_start[antic.pl_width];
            antic.hscroll_pixel_start = antic.pixel_start[antic.pl_width+1] +
                                             antic.hscroll_reg_value;
            if ( antic.mode_line != 0 )
                antic_apply_hscroll ();

            antic.byte_count = -1;
            /* For UP_VID (reflect), font row = physical_row ^ 7.
             * For normal, font row = physical_row (dl_mode_line).
             * 16-line modes use current_ch_base_16_line via dl_mode_line_opp>>1
             * which already counts correctly from lines_for_mode-1. */
            if ( antic.dl_mode_line_ptr == &antic.dl_mode_line_opp )
                antic.current_ch_base = *antic.ch_base_ptr | ((antic.dl_mode_line ^ 7) & 0x7);
            else
                antic.current_ch_base = *antic.ch_base_ptr | (antic.dl_mode_line & 0x7);
            antic.current_ch_base_16_line = *antic.ch_base_ptr | ((*antic.dl_mode_line_ptr>>1) & 0x7);

            debug_check_scanline();

            if (antic.dl_scanline == 41) {
                antic.pl_width = antic.next_pl_width;
            }

            /*
             * Make it so we skip first 7 6502 cycles on line 1
             * FIXME: Then make up 7 at VBLANK - is that right?
             */
            //if ( antic.dl_scanline == 8 )
            //    antic.scan_change = 0;
            //else
                antic.scan_change = -1;

            /*
             * Run through the scanline
             */
            while ( antic.sl_map[++antic.scan_change] ) {

                antic.sl_cycle_count += antic.ml_cycles[antic.mode_line][antic.scan_change];
                antic.sl_map[antic.scan_change][0] ();

            } /* end scan line */

            antic_restore_hscroll ();

            /*
             * Update mode line counters
             */
            antic.dl_scanline++;
            antic.dl_mode_line++;
            antic.dl_mode_line_opp--;

            /*
             * Check for going over scanline limit
             *       Fixes several games (xevious)
             */
            if ( antic.dl_scanline >= NTSC_SCAN_LINES+8 )
                break;

        } /* end mode line */

    } /* end while doing scanlines */
        
    /*
     * Run CPU for VBLANK time - memory refresh if DMA.
     *
     * VBI NMI becomes visible to the CPU at cycle 18 of the first blank
     * scanline. The CPU then takes the edge at the next instruction boundary
     * with a 7-cycle entry cost, or BRK may hijack it if BRK is active.
     */
    antic.sl_cycle_count = 0;
    antic.refresh_cycles = 9;

    //antic.run_6502_ptr = run_6502;
    while ( antic.dl_scanline < p_console->scanlines ) {
        int wsync_adjust = 0;
        //antic.sl_cycle_count = antic.vblank_sl_time;
        //antic.sl_cycle_count = 114;

        antic.vcount = antic.dl_scanline >> 1;
        pokey_init_scanline ();
        wsync_hold_scanline = antic_scanline_wsync_state (0);
        wsync_adjust = antic_wsync_cycle_adjust();

        debug_check_scanline();

        if ( antic.dl_scanline == NTSC_SCAN_LINES + 8 ) {
            /* First blank scanline: run until cycle 19 before asserting VBI */
            if ( !wsync_hold_scanline ) {
                cpu6502.i_cnt = 13 + wsync_adjust;
                antic.sl_cycle_count = 13;
                run_6502 ();
            }

            /* DLI bit is always cleared at VBI time; VBI bit is always set */
            //antic.nmi_status_reg = (antic.nmi_status_reg & ~0x80) | 0x40;
            //antic.nmi_status_reg = (antic.nmi_status_reg | 0x80) & ~0x40;
            //cpu_nmi_edge(antic.dl_scanline, 13, NMI_REQUEST_VBI, (antic.nmi_status_reg & ~0x80) | 0x40, 6);
            if ( antic.nmi_vbi_en )
                antic_set_vbi();
            else
                antic_set_vbi_status();

            if ( !wsync_hold_scanline && (antic.run_6502_ptr != antic_do_nothing)) {
                //cpu6502.i_cnt += antic.vblank_sl_time - (13);
                //antic.sl_cycle_count = cpu6502.i_cnt;
                cpu6502.i_cnt += 105 - (13);
                antic.sl_cycle_count = 114-13;
                run_6502 ();
            }

        } else if ( !wsync_hold_scanline ) {
            //cpu6502.i_cnt = antic.vblank_sl_time + wsync_adjust;
            //antic.sl_cycle_count = antic.vblank_sl_time;
            cpu6502.i_cnt = 105 + wsync_adjust;
            antic.sl_cycle_count = 114;
            run_6502 ();
        }
        antic.dl_scanline++;
    }

} /* end run_frame */

/******************************************************************************
**  Function   :  load_os                                            
**                                                                    
**  Objective  :  This function opens the OS file and puts contents in memory
**                                                   
**  Parameters :  filename - file to open
**                type     - machine type used for where to load in memory
**                 
**  return     :  0 if success
**                1 if failure
******************************************************************************/ 
int load_os ( char *filename, e_machine_type type ) {

    int bytes;
    t_config *p_config = config_get_global_cfg();
    char msg[1100];
    char resolved_filename[KAT_PATH_MAX];
    unsigned char *buffer = 0;
    unsigned char sio_patch_bytes[3] = {0xf2,ESC_CODE_SIO,0x60};
    unsigned char disable_chksm_bytes[4] = {0x8e,0xff,0x8e,0xff};
    int patch = 0;

    if ( p_config->general.sio_patch )
        patch |= ESC_CODE_SIO;

    snprintf ( resolved_filename, sizeof(resolved_filename), "%s", filename );
    util_set_file_to_program_dir ( resolved_filename );

    bytes = media_if_open_file ( resolved_filename, &buffer );

    if ( bytes > 0 ) {
        sprintf ( msg, "load_os: Opened BIOS File \"%s\"", resolved_filename );
        logger_log_message ( LOG_INFO, msg, "" );
    }
    else {
        sprintf ( msg, "load_os: Unable to Open BIOS File \"%s\"", resolved_filename );
        logger_log_message ( LOG_ERROR, msg, "" );
        free ( buffer );
        return ERR_BIOS_LOAD; 
    }

    switch ( type ) {
        case MACHINE_TYPE_MIN: 
            memory_write_rom_bytes ( 0xf800, buffer, 0x800 );
            break;
        case MACHINE_TYPE_5200: 
            memory_write_rom_bytes ( 0xf800, buffer, 0x800 );
            break;
        case MACHINE_TYPE_800: 
            memory_write_rom_bytes ( 0xd800, buffer, 0x2800 );
            if ( patch & ESC_CODE_SIO )
                memory_write_rom_bytes ( 0xe459, sio_patch_bytes, 3 );
            //if ( (p_config->general.machine == MACHINE_TYPE_XL) && patch ) {
            //    memory_write_rom_bytes ( 0xc314, disable_chksm_bytes, 2 );
            //    memory_write_rom_bytes ( 0xc319, disable_chksm_bytes+2, 2 );
            //}
            break;
        case MACHINE_TYPE_XL: 
            memory_write_os_bytes ( 0xc000, buffer, 0x4000 );
            if ( patch & ESC_CODE_SIO ) 
                memory_write_os_bytes ( 0xe459, sio_patch_bytes, 3 );
            if ( patch ) {
                memory_write_os_bytes ( 0xc314, disable_chksm_bytes, 2 );
                memory_write_os_bytes ( 0xc319, disable_chksm_bytes+2, 2 );
            }
            break;
    }

    free ( buffer );

    return 0;

} /* end load_os */

/******************************************************************************
**  Function   :  kat5200_launch                                            
**                                                                    
**  Objective  :  This function checks for a new rom or state file to launch
**                                                   
**  Parameters :  reload - load the file and reset and console
**                 
**  return     :  0 for success, else return failure code
******************************************************************************/ 
int kat5200_launch ( unsigned int kstatus ) {

    int status = 0;
    int reset = 0;
    t_config *p_config = config_get_global_cfg();
    t_atari *p_console = console_get_ptr();

    /*
     * Check for state to load — highest priority, always resets
     */
    if ( (p_config->general.state && strlen(p_config->general.state)) ||
            p_config->general.quick_state ) {
        t_media *main_media;

        if ( p_config->general.quick_state )
            status = states_recall_quick_state ( p_config->general.quick_state, p_console );
        else
            status = states_recall ( p_config->general.state, p_console );

        /* Reset state variables */
        p_config->general.quick_state = 0;
        util_alloc_string ( &p_config->general.state, "" );

        if ( status )
            return status;

        mem_assign_ops ( p_console->cpu );

        main_media = p_console->main_media;
        media_copy ( main_media, media_if_get_ptr() );
        util_alloc_string ( &p_config->general.rom,
                ( main_media && main_media->file ) ? main_media->file : "" );
    }

    /*
     * Else load the OS and image if not just returning to a running game
     */
    else if ( !(kstatus & KSTATUS_BACK) ) {
        int rom_mapping = p_config->general.rom_mapping;
        p_config->general.rom_mapping = CART_MIN;
        status=media_if_open_rom (p_config->general.rom, rom_mapping, 0, 1 );
        if ( status )
            return status;

        config_refresh_machine_settings();

        status=load_os ( p_config->machine.bios, p_config->general.machine);
        if ( status )
            return status;

        /* Reset unless caller asked for no-reset */
        if ( !(kstatus & KSTATUS_LAUNCH_NO_RST) )
            reset = 1;
    }
    else {
        /* Returning to running game — restore normal memory dispatch */
        mem_assign_ops ( p_console->cpu );
    }

    config_load_for_media ( console_get_ptr()->main_media->crc );
    config_check_arguments ( );

    if ( reset )
        console_reset ( p_config->general.machine, p_config->machine.tv_standard,
                p_config->machine.ram );

    return status;

} /* kat5200_launch */

/******************************************************************************
**  Function   :  kat5200_exit                                            
**                                                                    
**  Objective  :  This function call the necessary functions to cleanup and get
**                out of here
**                                                   
**  Parameters :  NONE
**                 
**  return     :  NONE
******************************************************************************/ 
void kat5200_exit ( void ) {

    t_config *p_config = config_get_global_cfg();

    gui_exit();
    sio_exit();
    p_config->general.exit_status = 0;
    config_save_general ( config_get_global_table(), KCFG_GENERAL_EXIT );
    pc_exit ();
    input_exit ();
    logger_exit();
    config_exit();
    console_exit();

    exit ( EXIT_SUCCESS );

} /* kat5200_exit */

/******************************************************************************
**  Function   :  kat5200_debug_exit                                            
**                                                                    
**  Objective  :  This function tests for exiting the debugger.  It is assigned
**                to a function pointer in the debug module
**                                                   
**  Parameters :  debug_flag - off to enter debug mode
**                 
**  return     :  gui status
******************************************************************************/ 
int kat5200_debug_exit ( int debug_flag ) {

    int i;

    g_kstatus |= KSTATUS_GUI;
    g_kstatus &= ~(KSTATUS_RUN);
    i = gui_show_main (ERR_CPU_CRASH,debug_flag);
    if ( i == -1 ) {
        kat5200_exit ();
    }
    /*
    pc_game_init();
    return i;
    */
    return 1;

} /* kat5200_debug_exit */

/******************************************************************************
**  Function   :  kat5200_show_gui
**                                                                    
**  Objective  :  This function shows the gui and waits for exit to continue
**                Check for debug desired
**                                                   
**  Parameters :  debug_flag - off to enter debug mode
**                 
**  return     :  gui status
******************************************************************************/ 
int kat5200_show_gui ( int debug_flag ) {

    int i;

    /* Clear any stuck combo modifier state — button-up events are missed when GUI opens */
    input_combo_disengage_all();

    g_kstatus |= KSTATUS_GUI;
    g_kstatus &= ~(KSTATUS_RUN);
    gui_show_main(0, debug_flag);

    return 1;

} /* kat5200_show_gui */


void kat5200_print_help ( void ) {
    char text[] = {
    #include "../doc/help.txt"
    };

    printf ( "%s", text );
}

void kat5200_set_status ( unsigned int status ) {
    g_kstatus = status;
}

unsigned int kat5200_get_status ( void ) {
    return g_kstatus;
}
