/*********************************************************************

	cococart.c

	CoCo/Dragon cartridge management

*********************************************************************/

#include "cococart.h"
#include "cpuintrf.h"
#include "sndintrf.h"


struct _coco_cartridge
{
	UINT8				(*rh)(coco_cartridge *cartridge, UINT16 addr);
	void				(*wh)(coco_cartridge *cartridge, UINT16 addr, UINT8 data);
	void				(*set_line)(coco_cartridge *cartridge, cococart_line line, cococart_line_value value);
	void				(*map_memory)(coco_cartridge *cartridge, UINT32 offset, UINT32 mask);
	void				*extra_data;
	cococart_line_value	line[3];
	char				dummy[1];
};



static const cococart_getinfo cart_procs[] =
{
	cococart_fdc_coco,
	cococart_fdc_coco3_plus,
	cococart_fdc_dragon,
	cococart_pak,
	cococart_pak_banked16k,
	cococart_orch90
};



/*-------------------------------------------------
    find_cart
-------------------------------------------------*/

static cococart_getinfo find_cart(const char *carttype)
{
	int i;
	for (i = 0; i < ARRAY_LENGTH(cart_procs); i++)
	{
		const char *that_name = cococart_get_info_string(cart_procs[i], COCOCARTINFO_STR_NAME);
		if (!mame_stricmp(carttype, that_name))
			return cart_procs[i];
	}
	return NULL;
}



/*-------------------------------------------------
    cococart_init
-------------------------------------------------*/

coco_cartridge *cococart_init(const char *carttype, const coco_cartridge_config *callbacks)
{
	coco_cartridge *cartridge;
	cococart_getinfo cart_proc;
	size_t extra_data_size;
	void (*init)(coco_cartridge *cartridge);

	/* sanity check */
	assert_always(mame_get_phase(Machine) == MAME_PHASE_INIT, "Can only call cococart_init at init time!");

	/* identify the cartridge type */
	cart_proc = find_cart(carttype);
	assert_always(cart_proc != NULL, "Invalid cartridge hardware type");

	/* allocate the cartridge structure */
	extra_data_size = (size_t) cococart_get_info_int(cart_proc, COCOCARTINFO_INT_DATASIZE);
	cartridge = auto_malloc(sizeof(*cartridge) + extra_data_size - 1);
	memset(cartridge, '\0', sizeof(*cartridge) + extra_data_size - 1);

	/* populate the cartridge structure */
	cartridge->rh			= (UINT8 (*)(coco_cartridge *, UINT16)) cococart_get_info_fct(cart_proc, COCOCARTINFO_PTR_FF40_R);
	cartridge->wh			= (void (*)(coco_cartridge *, UINT16, UINT8)) cococart_get_info_fct(cart_proc, COCOCARTINFO_PTR_FF40_W);
	cartridge->extra_data	= (extra_data_size > 0) ? cartridge->dummy : NULL;

	/* copy callbacks */
	if (callbacks != NULL)
	{
		cartridge->set_line = callbacks->set_line;
		cartridge->map_memory = callbacks->map_memory;
	}

	/* invoke init function */
	init = (void (*)(coco_cartridge *cartridge)) cococart_get_info_fct(cart_proc, COCOCARTINFO_PTR_INIT);
	if (init != NULL)
		init(cartridge);

	/* finish up */
	return cartridge;
}



/*-------------------------------------------------
    cococart_read
-------------------------------------------------*/

UINT8 cococart_read(coco_cartridge *cartridge, UINT16 address)
{
	return cartridge->rh ? cartridge->rh(cartridge, address) : 0xFF;
}



/*-------------------------------------------------
    cococart_write
-------------------------------------------------*/

void cococart_write(coco_cartridge *cartridge, UINT16 address, UINT8 data)
{
	if (cartridge->wh)
		cartridge->wh(cartridge, address, data);
}



/*-------------------------------------------------
    cococart_set_line
-------------------------------------------------*/

void cococart_set_line(coco_cartridge *cartridge, cococart_line line, cococart_line_value value)
{
	assert_always((0 <= line) && (line < ARRAY_LENGTH(cartridge->line)), "Invalid line value");

	if (cartridge->line[line] != value)
	{
		cartridge->line[line] = value;
		if (cartridge->set_line != NULL)
			(*cartridge->set_line)(cartridge, line, value);
	}
}



/*-------------------------------------------------
    cococart_get_line
-------------------------------------------------*/

cococart_line_value cococart_get_line(coco_cartridge *cartridge, cococart_line line)
{
	assert_always((0 <= line) && (line < ARRAY_LENGTH(cartridge->line)), "Invalid line value");
	return cartridge->line[line];
}



/*-------------------------------------------------
    cococart_map_memory
-------------------------------------------------*/

void cococart_map_memory(coco_cartridge *cartridge, UINT32 offset, UINT32 mask)
{
	if (cartridge->map_memory != NULL)
		(*cartridge->map_memory)(cartridge, offset, mask);
}



/*-------------------------------------------------
    cococart_enable_sound
-------------------------------------------------*/

void cococart_enable_sound(coco_cartridge *cartridge, int enable)
{
	/* NYI */
}



/*-------------------------------------------------
    cococart_temp_str
-------------------------------------------------*/

char *cococart_temp_str(void)
{
	static char temp_string_pool[16][256];
	static int temp_string_pool_index;
	char *string = &temp_string_pool[temp_string_pool_index++ % ARRAY_LENGTH(temp_string_pool)][0];
	string[0] = 0;
	return string;
}



/*-------------------------------------------------
    cococart_get_extra_data
-------------------------------------------------*/

void *cococart_get_extra_data(coco_cartridge *cartridge)
{
	return cartridge->extra_data;
}
