/***************************************************************************
 *            textures.cpp
 *
 *  Thu Dec  1 17:46:50 2005
 *  Copyright  2005  Joe Venzon
 *  joe@venzon.net
 ****************************************************************************/

/*
 *  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 2 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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */
 
#include "textures.h"
#include "globals.h"

//#define DEBUG_TEXTURES

void TEXTURE::Load()
{
	if (file.empty())
		cerr << "ERROR: Tried to load an empty texture" << endl;
	
	if (loaded)
		cerr << "ERROR: Tried to double load texture: " << file << endl;
	
	bool error = false;
	GLuint new_tex_id;

	if (surface)
	{
		new_tex_id = utility.TexLoad( file, surface, GL_RGBA, mipmap, cube, w, h, false, error );
	}
	else
	{
		new_tex_id = utility.TexLoad( file, GL_RGBA, mipmap, cube, w, h, false, error );
	}
	//cout << new_tex_id << endl;

	if( error )
	{
		cerr << "error loading texture file \"" << file << "\"..." << endl;
	}
	else
	{
		loaded = true;
		tex_id = new_tex_id;
	}
}

void TEXTURE::Activate() const
{
	//if (!loaded)
		//cerr << "ERROR:  tried to activate unloaded texture " << file << endl;
	
	if (cube)
	{
		glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, tex_id);
		//cout << "activating cube map: " << file << ", " << tex_id << endl;
	}
	else
		glBindTexture(GL_TEXTURE_2D, tex_id);
}

void TEXTURE::Unload()
{
	if (loaded)
		glDeleteTextures(1,&tex_id);
	loaded = false;
}

void TEXTURE_HANDLE::Activate() const
{
	if (tex != NULL)
	{
		tex->Activate();
	}
	else
	{
		//cerr << "ERROR:  tried to activate NULL texture handle" << endl;
	}
}

bool TEXTURE_HANDLE::Load( string new_tex_file, SDL_Surface* surface, bool mipmap, bool cube, int &w, int &h )
{
	if (tex != NULL)
	{
		if (tex->file == new_tex_file)
		{
			#ifdef DEBUG_TEXTURES
			cout << "TEXTURE_HANDLE::Load(" << new_tex_file << "): already loaded" << endl;
			#endif
			return true;
		}
		else
		{
			#ifdef DEBUG_TEXTURES
			cout << "TEXTURE_HANDLE::Load(" << new_tex_file << "): unloading previous texture" << endl;
			#endif
			Unload();
		}
	}
	else
	{
		#ifdef DEBUG_TEXTURES
		cout << "TEXTURE_HANDLE::Load(" << new_tex_file << "): not yet loaded, calling LoadTexture" << endl;
		#endif
	}
	
	TEXTURE * newtexptr = textures.LoadTexture(new_tex_file, surface, mipmap, cube, w, h);
	
	if (newtexptr != NULL)
	{
		tex = newtexptr;
		tex->references ++;
		#ifdef DEBUG_TEXTURES
		cout << "TEXTURE_HANDLE::Load(" << new_tex_file << "): loaded, references now " << tex->references << endl;
		#endif
	}
	else
	{
		cerr << "ERROR:  LoadTexture returned NULL pointer for " << new_tex_file << endl;
		return false;
	}
	
	return true;
}

void TEXTURE_HANDLE::Unload()
{
	if (tex != NULL)
	{
		tex->references--;
		if (tex->references <= 0)
		{
			#ifdef DEBUG_TEXTURES
			cout << "1TEXTURE_HANDLE::Unload(" << tex->file << "): references <= 0, unloading now" << endl;
			#endif
			
			if (tex->references < 0)
				cerr << "texture " + tex->file + " has < 0 references, now " << tex->references << endl;
			textures.UnloadTexture(tex);
		}
		else
		{
			#ifdef DEBUG_TEXTURES
			cout << "2TEXTURE_HANDLE::Unload(" << tex->file << "): references--, now " << tex->references << endl;
			#endif
		}
	}
	else
	{
		#ifdef DEBUG_TEXTURES
		cout << "3TEXTURE_HANDLE::Unload(): already unloaded, twiddling thumbs" << endl;
		#endif
	}

	tex = NULL;
}

void TEXTURES::ReloadAll()
{
	//list <TEXTURE>::iterator tex;
	/*GLuint tex_id;
	string file;
	int w, h;
	bool mipmap;
	bool error;*/

	for (list <TEXTURE>::iterator tex = textures.begin(); tex != textures.end(); tex++)
	{
		tex->Unload();
		/*file = tex->GetFile();
		mipmap = tex->GetMipmap();
		tex_id = utility.TexLoad( file, GL_RGBA, mipmap, w, h, false, error);
		if( error ) cout << "error encountered while reloading texture \"" << file << "\"..." << endl;

		tex->Set(file, tex_id, mipmap);*/
		tex->Load();
	}
}

TEXTURE * TEXTURES::LoadTexture( string new_tex_file, SDL_Surface* surface, bool mipmap, bool cube, int &w, int &h )
{
	TEXTURE * texptr = FindTexture(new_tex_file);

	if (texptr == NULL)
	{
		#ifdef DEBUG_TEXTURES
		cout << "TEXTURES::LoadTexture(" << new_tex_file << "): not yet loaded, loading now" << endl;
		#endif
		
		//texptr = textures.DB_Add();
		TEXTURE newtex;
		textures.push_back(newtex);
		texptr = &(textures.back());
		
		//actually load the texture
		texptr->file = new_tex_file;
		texptr->mipmap = mipmap;
		texptr->cube = cube;
		texptr->surface = surface;
		texptr->Load(); //this will populate the tex_id and set loaded
		w = texptr->w;
		h = texptr->h;
	}
	else
	{
		#ifdef DEBUG_TEXTURES
		cout << "TEXTURES::LoadTexture(" << new_tex_file << "): already loaded" << endl;
		#endif
	}
	
	return texptr;
}

void TEXTURES::UnloadTexture(TEXTURE * textodel)
{
	for (list <TEXTURE>::iterator i = textures.begin(); i != textures.end(); i++)
	{
		if (&(*i) == textodel)
		{
			list <TEXTURE>::iterator tempit = i;
			tempit++;
			textures.erase(i);
			i = tempit;
		}
	}
}

TEXTURE * TEXTURES::FindTexture(string searchname)
{
	TEXTURE * tptr = NULL;
	
	for (list <TEXTURE>::iterator i = textures.begin(); i != textures.end(); i++)
	{
		if (i->file == searchname)
			tptr = &(*i);
	}

	return tptr;
}

TEXTURE_HANDLE & TEXTURE_HANDLE::CopyFrom(const TEXTURE_HANDLE & other)
{
	//Unload();
	
	//tex = other.tex;
	//tex->references++;
	
	if (other.tex == NULL)
	{
		#ifdef DEBUG_TEXTURES
		cout << "TEXTURE_HANDLE::CopyFrom(): other texture handle is NULL" << endl;
		#endif
		Unload();
		return *this;
	}
	else
	{
		#ifdef DEBUG_TEXTURES
		cout << "TEXTURE_HANDLE::CopyFrom() called" << endl;
		cout << "TEXTURE_HANDLE::CopyFrom(" + other.tex->file + "): calling Load(" << other.tex->file << ")" << endl;
		#endif
		Load(other.tex->file, other.tex->surface, other.tex->mipmap);
		#ifdef DEBUG_TEXTURES
		cout << "TEXTURE_HANDLE::CopyFrom(" + tex->file + "): loaded, references now " << tex->references << endl;
		#endif
	}
	
	return *this;
}

TEXTURE_HANDLE::TEXTURE_HANDLE(const TEXTURE_HANDLE & other)
{
	tex = NULL;
	#ifdef DEBUG_TEXTURES
	cout << "TEXTURE_HANDLE Copy constructor called" << endl;
	#endif
	CopyFrom(other);
}

TEXTURE_HANDLE::~TEXTURE_HANDLE()
{
	Unload();
}
