#include "../simtypes.h"
#ifndef IMGLOADER_H
#define IMGLOADER_H

/**
 * \enum ImgResult
 * ImgResult is for storing return values from the various functions in the img_loader class
 */
enum ImgResult {
    IMGR_OK,                    /// Image Successfully Loaded
    IMGR_NULL,                  /// NULL value passed
    IMGR_FILE_DOES_NOT_EXIST,   /// File refered to does not exist
    IMGR_UNABLE_TO_OPEN,        /// File refered to exists but is not able to be opened
    IMGR_UNSUPPORTED_FORMAT,    /// File refered to exists but is in an unsupported format
    IMGR_INVALID_FORMAT,        /// File refered to exists and indicates it is a supported format, but is not
    IMGR_UNKNOWN_ERROR          /// An unknown error occured...
};

#ifndef __LITTLE_ENDIAN__
	#ifndef __BIG_ENDIAN__
		#define __LITTLE_ENDIAN__
	#endif
#endif

#ifdef __LITTLE_ENDIAN__
	#define BITMAP_SIGNATURE 0x4d42
#else
	#define BITMAP_SIGNATURE 0x424d
#endif

#pragma pack(push, 1)
typedef struct _BITMAP_FILEHEADER {
    uint16 Signature;
    uint32 Size;
    uint32 Reserved;
    uint32 BitsOffset;
} BITMAP_FILEHEADER;

const int BITMAP_FILEHEADER_SIZE=14;

typedef struct _BITMAP_HEADER {
    uint32 HeaderSize;
	sint32 Width;
	sint32 Height;
	uint16 Planes;
	uint16 BitCount;
	uint32 Compression;
	uint32 SizeImage;
	sint32 PelsPerMeterX;
	sint32 PelsPerMeterY;
	uint32 ClrUsed;
	uint32 ClrImportant;
	uint32 RedMask;
	uint32 GreenMask;
	uint32 BlueMask;
	uint32 AlphaMask;
	uint32 CsType;
	uint32 Endpoints[9]; // see http://msdn2.microsoft.com/en-us/library/ms536569.aspx
	uint32 GammaRed;
	uint32 GammaGreen;
	uint32 GammaBlue;
} BITMAP_HEADER;

typedef struct _RGBA {
	uint8 Red;
	uint8 Green;
	uint8 Blue;
	uint8 Alpha;
} RGBA;

typedef struct _BGRA {
	uint8 Blue;
	uint8 Green;
	uint8 Red;
	uint8 Alpha;
} BGRA;

#pragma pack(pop)

/**
 * \class img_loader
 * The img_loader class is for the loading of images. It currently supports most BMP & PBM formats, and all PNG formats.
 */
class img_loader {
    public:
        /**
         * img_loader constructor
         * @param filename is an optional filename parameter to load an image.
         */
        img_loader(const char *filename=NULL);
        ~img_loader();
        /**
         * load_image
         * @param filename is the name/path to the file to load.
         * @return Returns an ImgResult enum indicating the result of the attempt to load the file.
         */
        ImgResult load_image(const char *filename);
        /**
         * get_bits
         * @return returns a void * array pointing to the ARGB buffer of this image.
         */
        void * get_bits();
        /**
         * get_bits
         * @param buffer is a buffer for the image to be loaded into.
         * @param buffer_size is the size of the buffer passed in
         * @param red_mask is the mask that should be used for the red bits
         * @param green_mask is the mask that should be used for the green bits
         * @param blue_mask is the mask that should be used for the blue bits
         * @param alpha_mask is an option mask that should be used for the alpha bits (defaults to 0)
         * @param include_padding is an option to include padding on the image (defaults to false)
         * @return Returns an ImgResult enum indicating the result of the attempt to load the file.
         * Get Bits returns the image data in the format requested
         */
        ImgResult get_bits(void *buffer, uint32 &buffer_size, uint32 red_mask, uint32 green_mask,uint32 blue_mask,uint32 alpha_mask=0,bool include_padding=false);

        /**
         * set_bits
         * @param buffer is a buffer to load the bits from
         * @param width is the width of the image
         * @param height is the height of the image
         * @param red_mask is the mask that should be used for the red bits
         * @param green_mask is the mask that should be used for the green bits
         * @param blue_mask is the mask that should be used for the blue bits
         * @param alpha_mask is an option mask that should be used for the alpha bits (defaults to 0)
         * @return returns true on success, false of failure
         * Set Bits sets the data from the format specified
         */
        bool set_bits(void *buffer, uint32 width, uint32 height, uint32 red_mask, uint32 green_mask, uint32 blue_mask,uint32 alpha_mask=0);

        /**
         * dispose
         * Disposes of current Bitmap Data
         */
        void dispose(void);

        /**
         * save_BMP
         * @param filename is the name to save the file as
         * @param BitCount to save as, defaults to 32
         * @return true on success, false on failure
         * Saves the image as a BMP file
         */
        bool save_BMP(char * filename, uint32 BitCount=32);

        /**
         * save_PNG
         * @param filename is the name to save the file as
		 * @return true on success, false on failure
         * Saves the image as a PNG file
         */
        bool save_PNG(char * filename);

        /**
         * save_PBM
         * @param filename is the name to save the file as
         * @param level is the type of PBM to save as (defaults to P6)
		 * @return true on success, false on failure
         * Saves the image as a PBM file
         */
        bool save_PXM(char * filename,int level=6);

        /**
         * is_greyscale
         * @return Returns true if the image is Greyscale, false otherwise
         * Returns true if the image is greyscale
         */
        bool is_greyscale(void);

        /**
         * get_width
         * @return returns the width of the image
         * Returns the width of the image - where no image is loaded, it will return 0
         */
        uint32 get_width(void);

        /**
         * get_height
         * @return returns the height of the image
         * Returns the height of the image - where no image is loaded, it will return 0
         */
        uint32 get_height(void);

        /**
         * get_bit_count
         * @return returns the bit_count of the image
         * Returns the bit_count of the image - where no image is loaded, it will return 0
         */
        uint32 get_bit_count(void);

        class color {
        public:
            static uint32 bit_count_by_mask(uint32 mask);
            static uint32 bit_position_by_mask(uint32 mask);
            static uint32 component_by_mask(uint32 color, uint32 mask);
            static uint32 bit_count_to_mask(uint32 bit_count);
            static uint32 convert(uint32 color, uint32 from_bit_count, uint32 to_bit_count);
        };
	private:
        ImgResult load_bmp(const char *filename);
        ImgResult load_png(const char *filename);
        ImgResult load_pxm(const char *filename);
        uint32 read_next_number_pxm(std::ifstream& file);
        sint32 standardize_number_pxm(sint32 val, sint32 maxval);
        bool get_bits_with_palette(void* Buffer, uint32 &Size, uint32 BitCount, BGRA* &Palette, uint32 &PaletteSize, bool OptimalPalette=false, bool IncludePadding=true);
        BITMAP_FILEHEADER m_bitmap_file_header;
        BITMAP_HEADER m_bitmap_header;
        RGBA *m_bitmap_data;
        sint32 m_bitmap_size;
        sint8 m_greyscale;

};
#endif
