/******************************************************************************
*
* Copyright (C) 2007-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: console.c
*
* DESCRIPTION:  This contains functions for running the system
*
* AUTHORS:  bberlin
*
* CHANGE LOG
*
*  VER     DATE     CHANGED BY   DESCRIPTION OF CHANGE
* ------  --------  ----------   ------------------------------------
* 0.5.0   02/06/07  bberlin      Added call to 'config_update'
******************************************************************************/
#include <stdio.h>
#include "console.h"
#include "memory.h"
#include "sio.h"
#include "debug.h"

/*********************************/
/* Declare the console variable  */
/*********************************/
static t_atari console;
extern t_antic antic;
extern t_gtia gtia;
extern t_pokey pokey;
extern t_pia pia;
extern t_sio_interface sio;
extern t_cpu cpu6502;
extern t_debug debug;
extern t_cart cart;
extern t_cart cart_right;

/******************************************************************************
**  Function   :  console_init                
**                                         
**  Objective  :  Assign chip structs to the console
**                                       
**  Parameters :  NONE                  
**                                     
**  return     :  NONE
**             
******************************************************************************/ 
void console_init (void) {

    console.frame_number = 0;
    console.debug_mode = 0;
    console.throttle = 100;
    console.ram_size = 64;
    console.frames_per_sec = 60;
    console.scanlines = 262;
    console.tv_standard = NTSC;

    console.cpu = &cpu6502;
    console.antic = &antic;
    console.gtia = &gtia;
    console.pokey = &pokey;
    console.pia = &pia;
    console.sio = &sio;
    console.cart = &cart;
    console.cart_right = &cart_right;

    console.cart->loaded = 0;
    console.cart_right->loaded = 0;
    console.basic_enable = 0;
    console.option_key_pressed = 0;
    console.start_key_pressed = 0;

    console.main_media = &cart.media_info;

    sio_init();
    cart_init();

} /* end console_init */

void console_exit (void) {

    memory_exit();
    sio_exit();
    cart_exit();

} /* end console_exit */

/******************************************************************************
**  Function   :  console_reset                
**                                         
**  Objective  :  Reset the system
**                                       
**  Parameters :  type        - machine type 5200, 800, XL/XE
**                system_type - PAL or NTSC
**                ram         - amount of memory to emulate
**                                     
**  return     :  NONE
**
******************************************************************************/ 
void console_reset ( e_machine_type type, int tv_standard, int ram) {

    console.machine_type = type;
    console.tv_standard = tv_standard;
    console.ram_size = ram;
    mem_reset ();
    antic_reset ();
    mem_assign_antic_hyb_ops ();
    gtia_reset ( tv_standard );
    pokey_reset ();
    pia_reset ();
    sio_reset ();
    reset_6502 ();

    if ( tv_standard == PAL ) {
        console.frames_per_sec = 50;
        console.scanlines = 312;
    }
    else {
        console.frames_per_sec = 60;
        console.scanlines = 262;
    }

    console.option_key_pressed = 0;
    console.start_key_pressed = 0;

    if ( !console.basic_enable && (console.machine_type == MACHINE_TYPE_XL) )
        console.option_key_pressed = 1;

    /* FIXME:  do we need a loaded variable here */
    if ( console.main_media->media_type == CART_CASSETTE ) {
        console.start_key_pressed = 2;
    }

} /* end console_reset */

/******************************************************************************
**  Function   :  console_get_ptr
**                                                
**  Objective  :  This grabs the address of the console variable
**                                               
**  Parameters :  NONE                          
**                                             
**  return     :  pointer to atari
**
******************************************************************************/ 
t_atari *console_get_ptr ( void ) {

    return &console;

} /* end console_get_ptr */

/******************************************************************************
**  Function   :  console_open_media
**                                                
**  Objective  :  This opens the input media.  If launch is set, we update
**                main media to the correct cart or sio devices
**                                               
**  Parameters :  p_media   - input media struct with desired media to open.
**                sio_slot  - which disk slot if floppy
**                launch    - if this is the main media, we "launch" it
**                                             
**  return     :  0 on success, otherwise error
**
******************************************************************************/ 
int console_open_media ( t_media *p_media, unsigned char *buffer, int sio_slot, 
        int launch ) {

    if ( p_media->mapping == CART_PC_RIGHT )  {
        media_copy ( p_media, &console.cart_right->media_info );
        if ( launch )
            console.main_media = &console.cart_right->media_info;
        return cart_open ( p_media->file, buffer, p_media->image_size, 
                p_media->crc, p_media->mapping  );
    }
    else if ( p_media->media_type == CART_FLOPPY ) {
        media_copy ( p_media, &console.sio->drives[sio_slot].media_info );
        if ( launch )
            console.main_media = &console.sio->drives[sio_slot].media_info;

        return sio_mount_image ( sio_slot, SIO_TYPE_FLOPPY, p_media->file, 
                p_media->write_protect, buffer, p_media->image_size );
    }
    else if ( p_media->media_type == CART_CASSETTE ) {
        media_copy ( p_media, &console.sio->cassette.media_info );
        if ( launch )
            console.main_media = &console.sio->cassette.media_info;
        return sio_mount_image ( 0, SIO_TYPE_CASSETTE, p_media->file, 1, 
                buffer, p_media->image_size );
    }
    else {
        media_copy ( p_media, &console.cart->media_info );
        if ( launch )
            console.main_media = &console.cart->media_info;
        return cart_open ( p_media->file, buffer, p_media->image_size, 
                p_media->crc, p_media->mapping );
    }

} /* end console_open_media */

/******************************************************************************
**  Function   :  console_get_set_functions
**                                                
**  Objective  :  These functions get and set certain parameters
**                                               
**  Parameters :  Varies
**                                             
**  return     :  Varies
**
******************************************************************************/ 
void console_set_machine_type ( e_machine_type type ) {

    console.machine_type = type;

} /* end console_set_machine_type */

e_machine_type console_get_machine_type ( void ) {

    return console.machine_type;

} /* end console_set_machine_type */

e_cart_type console_get_main_media_type ( t_atari *console, int *slot ) {

    int i;

    if ( console->main_media == &console->cart->media_info ) {
        if (slot) *slot = 0;
        return CART_CART;
    }

    if ( console->main_media == &console->cart_right->media_info ) {
        if (slot) *slot = 1;
        return CART_CART;
    }

    if ( console->main_media == &console->sio->cassette.media_info ) {
        if (slot) *slot = 0;
        return CART_CASSETTE;
    }

    for ( i = 0; i < MAX_SIO_DEVICES; ++i ) {
        if ( console->main_media == &console->sio->drives[i].media_info ) {
            if (slot) *slot = i;
            return CART_FLOPPY;
        }
    }

    return CART_MIN;

} /* end console_get_main_media_type */

void console_set_main_media_from_type (t_atari *console, e_cart_type type, int slot ) {

    if ( type == CART_CART ) {
        if ( slot == 0 )
            console->main_media = &console->cart->media_info;
        else
            console->main_media = &console->cart_right->media_info;
    }
    if ( type == CART_CASSETTE ) {
        console->main_media = &console->sio->cassette.media_info;
    }
    if ( type == CART_FLOPPY ) {
        console->main_media = &console->sio->drives[slot].media_info;
    }

} /* end console_set_main_media_from_type */

void console_set_throttle ( int throttle ) {

    console.throttle = throttle;

} /* end console_set_throttle */

void console_set_debug_mode ( int debug_mode ) {

    console.debug_mode = debug_mode;

} /* end console_set_debug_mode */

const char * console_get_machine_string ( e_machine_type type ) {

    switch ( type ) {
        case MACHINE_TYPE_5200: return "Atari 5200"; break;
        case MACHINE_TYPE_800: return "Atari 400/800"; break;
        case MACHINE_TYPE_XL: return "Atari XL/XE"; break;
        default: return "Unknown"; break;
    }

} /* end console_get_machine_string */

const char * console_get_os_string ( e_os_type type ) {

    switch ( type ) {
        case OS_TYPE_5200_4PORT: return "Atari5200 4-port"; break;
        case OS_TYPE_5200_2PORT: return "Atari5200 2-port"; break;
        case OS_TYPE_A: return "OS/A (400/800)"; break;
        case OS_TYPE_B: return "OS/B (400/800)"; break;
        case OS_TYPE_B_NTSC: return "OS/B NTSC (400/800)"; break;
        case OS_TYPE_B_PAL: return "OS/B PAL (400/800)"; break;
        case OS_TYPE_REV_10: return "Rev 10 (1200XL)"; break;
        case OS_TYPE_REV_11: return "Rev 11 (1200XL)"; break;
        case OS_TYPE_REV_1: return "Rev 1 (600XL)"; break;
        case OS_TYPE_REV_2: return "Rev 2 (XL/XE)"; break;
        case OS_TYPE_REV_3: return "Rev 3 (800XE)"; break;
        case OS_TYPE_REV_4: return "Rev 4 (XEGS)"; break;
        default: return "Unknown"; break;
    }

} /* end console_get_os_string */

const char * console_get_tv_string ( int type ) {

    if ( type == PAL )
        return "PAL";
    else
        return "NTSC";

} /* end console_get_tv_string */
