// ------------------------------------------------------------------
// cwdata.cpp
// ------------------------------------------------------------------
// This is a wrapper over a datafile.
// Basically, it wraps a datafile in resources like bitmaps,
// sound and fonts in a way that can be requested
// and used by the program, just requesting them by name
// ------------------------------------------------------------------
// By Kronoman
// In loving memory of my father
// Copyright (c) 2003-2004, Kronoman
// ------------------------------------------------------------------
// Upgraded in January 2004, based on skin.cpp of my simple GUI manager
// ------------------------------------------------------------------

#include "cwdata.h"
#include "gerror.h" // error manager
#include "filehelp.h" // to find the datafile

bool CWDatafile::die_on_failure = true; // default = die on failure

// ------------------------------------------------------------------
// Constructor
// ------------------------------------------------------------------
CWDatafile::CWDatafile()
{
	datafile = NULL;
	datafile_cache_map.clear();
}

// ------------------------------------------------------------------
// This inits the datafile with a file
// ------------------------------------------------------------------
CWDatafile::CWDatafile(const char *filename)
{
	CWDatafile::CWDatafile();

	this->load_datafile(filename);
}

// ------------------------------------------------------------------
// Destructor, free the datafile RAM...
// ------------------------------------------------------------------
CWDatafile::~CWDatafile()
{
	this->nuke_datafile();
}

// ------------------------------------------------------------------
// Free the memory of the datafile
// ------------------------------------------------------------------
void CWDatafile::nuke_datafile()
{
	if (datafile != NULL)
	{
		unload_datafile(this->datafile);
		datafile = NULL;
	}

	datafile_cache_map.clear();
}

// ------------------------------------------------------------------
// Load a datafile from a disk datafile
// ------------------------------------------------------------------
bool CWDatafile::load_datafile(const char *filename)
{
	char tmp_file_buf[2048];
	this->nuke_datafile(); // old datafile goes to hell

	datafile = ::load_datafile(where_is_the_filename(tmp_file_buf, filename)); // note: the '::' before load_datafile means 'call the Allegro's load_datafile, not this->load_datafile

	if (datafile == NULL)
	{
		if (die_on_failure)
			raise_error("FATAL ERROR\nCWDatafile::load_datafile(\"%s\") failed\nFile not found or can't be loaded", filename);

		return true; // error d00d
	}
	else
	{
		// the data is loaded, cache it!
		this->do_cache();
	}

	return false;
}

// ------------------------------------------------------------------
// This caches the data, is automatically done in data file load
// ------------------------------------------------------------------
void CWDatafile::do_cache()
{

	if (datafile == NULL)
		return ; // no data to cache!

	datafile_cache_map.clear(); // cache start from zero

	// walk the datafile, and cache key->data pairs
	for (int pos = 0; datafile[pos].type != DAT_END; pos++)
	{
		datafile_cache_map[get_datafile_property(datafile + pos, DAT_NAME)] = (DATAFILE *)datafile + pos;
	}

	// cache ready =) God bless STL
}

// ------------------------------------------------------------------
// Overloaded function, just calls void *CWDatafile::get_resource_dat(string resource_name)
// ------------------------------------------------------------------

void *CWDatafile::get_resource_dat(const char *resource_name)
{
	return this->get_resource_dat(string(resource_name));
}

// ------------------------------------------------------------------
// This returns a resource by name, or NULL on error
// Notice, the pointer returned IS THE DATA itself
// So is safe to do things like this:
// 		bmp = (BITMAP *)(this->datafile->get_resource_dat(string("WINDOW_BASE_BMP")));
// 		if (bmp != NULL) blah blah
// ------------------------------------------------------------------
void *CWDatafile::get_resource_dat(const string resource_name)
{
	DATAFILE *p;

	p = this->get_resource(resource_name);

	if (p == NULL)
	{
		if (die_on_failure)
			raise_error("FATAL ERROR!\nCWDatafile::get_resource_dat(\"%s\")\nCan't find resource.", resource_name.c_str());

		return NULL;
	}
	else
	{
		return p->dat;
	}
}

// ------------------------------------------------------------------
// Overloaded, just calls DATAFILE *CWDatafile::get_resource(const string resource_name)
// ------------------------------------------------------------------
DATAFILE *CWDatafile::get_resource(const char *resource_name)
{
	return this->get_resource(string(resource_name));
}

// ------------------------------------------------------------------
// This returns a resource by name, or NULL on error
// Notice,  the pointer returned is a DATAFILE *
// You should add ->dat to get the data itself
// Like this (for example):
// 		bmp = (BITMAP *)((this->datafile->get_resource(string("WINDOW_BASE_BMP"))->dat));
// NOTICE: if you check bmp != NULL like this, you will get a seg fault, because ->dat != NULL
// ------------------------------------------------------------------
DATAFILE *CWDatafile::get_resource(const string resource_name)
{
	DatafileCacheMap::iterator pos;

	pos = datafile_cache_map.find(resource_name);

	if (pos != datafile_cache_map.end() )
	{
		return pos->second; // return the value (a *DATAFILE)
	}
	else
	{
		if (die_on_failure)
			raise_error("FATAL ERROR!\nCWDatafile::get_resource(\"%s\")\nCan't find resource.", resource_name.c_str());

		return NULL; // error
	}

}

// ------------------------------------------------------------------
// This returns a pointer to the whole loaded DATAFILE (in case that you need it for something)
// All coredumps using this are YOUR responsability :P
// ------------------------------------------------------------------

DATAFILE *CWDatafile::get_whole_datafile()
{
	return this->datafile; // all seg faults are YOUR responsability from here, don't screw my nice pointer! =^)
}

// ------------------------------------------------------------------
// This is a debug function, dumps the data loaded on the console
// ------------------------------------------------------------------

void CWDatafile::dump_debug_datafile_data()
{
	DatafileCacheMap::iterator pos;

	cout << "CWDatafile::dump_debug_datafile_data() called " << endl	;

	for (pos = datafile_cache_map.begin(); pos != datafile_cache_map.end(); ++pos)
	{
		cout << "resource name: '" << pos->first << "'\t"
		<< "pointer: " << pos->second << endl;
	}
}
