// ---------------------------------------------------------------------------
// 
//   Lily Engine alpha
// 
//   Copyright (c) 2010 Clifford Jolly
//     http://cliffjolly.com
//     cliff@cliffjolly.com
// 
// ---------------------------------------------------------------------------
// 
//   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
// -------------------------- END HEADER -------------------------------------

#pragma once

#include <string>

#ifdef WIN32
#include <SDL.h>
#else
#include <SDL/SDL.h>
#endif

class Image;
class TextureManager;

/** @brief OpenGL texture resource. Handles background (threaded)
 * loading and uses SDL and SDL_image to load images. */
class Texture {

    public:

        /// Constructor.
        Texture(void);
        virtual ~Texture(void);
		
        /// Set up the texture for loading. (Set filename, etc.)
        virtual void startLoad(const std::string &fileName);
    
		/// If an image is needed RIGHT NOW then this blocks until the
		/// file finishes loading. Note that this will cause a warning
		/// to appear every time it actually ends up blocking. Try to
		/// avoid using this.
		virtual void waitForLoad(void);
		
		/// Checks to see if the background load is complete.
		virtual bool isLoaded(void);
		
		/// Returns true if the background load AND conversion to a GL
		/// texture are done.
		bool hasGLTexture(void);
		
		/** @brief Get the file name of the texture.
		 * @return The file name.
		 * */
		std::string getName(void);
		
		/** @brief Get the number of frames since the last access of
		 * this texture. Old textures will be purged by the texture
		 * manager.
		 * @return The number of frames since last used. */
		unsigned int getTimeSinceAccess(void);
		
		/** @brief Increment the age of the texture by one frame. (Call
		 * this every frame.) */
		void incrementAge(void);
		
		/** @brief Bind the OpenGL texture. Checks to see if it's bound
		 * already first. (FIXME: Is that even needed?)
		 * */
		virtual void bindTexture(void);
		
		/** @brief Get the original Image that's sitting around
		 * in system memory.
		 * @return The Image.
		 * */
		virtual Image *getOriginalImage(void);
		
		/// Reload from the raw image data. Use this if it's changed
		/// and you want to update the texture.
		void reloadFromImage(void);
		
		inline float getTexSpaceForX(float x) {
			return x / pow2Width;
		}
		
		inline float getTexSpaceForY(float y) {
			return y / pow2Height;
		}
		
		inline int getOrigWidth(void) {
			return origWidth;
		}
		
		inline int getOrigHeight(void) {
			return origHeight;
		}
		
		inline int getAdjustedWidth(void) {
			return pow2Width;
		}
		
		inline int getAdjustedHeight(void) {
			return pow2Height;
		}

		/// Set exclusion to pruning rule. Use this for textures that
		/// can't be reloaded automatically in a nice way like
		/// generated textures or textures that were modified since
		/// they were loaded.
		void setDontPrune(bool dontPrune);
		
		/// Get the pruning exclusion value.
		bool getDontPrune(void);
	
		/// Set linear filtering on or off.
		/// NOTE: Set this on the TextureManager if you want it to stay
		///   after the texture is pruned and reloaded!
		void setFilter(bool filter);
		
		/// Get linear filtering.
		bool getFilter(void);
	
         /// Get the OpenGL texture number.
		int getGLTextureNumber(void);

	protected:
	
		/// My filename.
		std::string name;
		
		// Sizes of the original image. Original, and after being
		// resized to fit the power of two requirement.
		int origWidth;
		int origHeight;
		int pow2Width;
		int pow2Height;

		/// This does the actual work of loading the image off the
		/// disk. Called from texture loader thread.
		virtual void backgroundLoad(void);

		/// Original image. In theory, we can actually get rid of this
		/// but things like the fonts like to mess around with them.
		/// Make it explicit?
		Image *image;

		/// Time since last access. Used for pruning. Just a count of
		/// the number of calls to TextureManager::cleanOldTextures().
		unsigned int timeSinceAccess;
		
		/// True if the loader thread is done pulling the data off the
		/// disk. Does not mean it's in a GL texture yet!
		bool loaded;
		
        // This is true if the backgroundLoad() function has been called
        // and completed, regardless of success or failure.
        bool backgroundLoadFinished;

    private:
		
		void makeGLTexture(void);
		
		/// True if we've converted to a GL texture.
		bool glTexDone;
		
		/// OpenGL texture number.
		unsigned int texNum;
		
		bool dontPrune;
		
		bool linearFilter;

        // Texture manager's loader thread is a friend so it can
        // access backgroundLoad(). Nothing else should call that.
        friend int textureLoadWorkerFunc(TextureManager *manager);

};




