#include <cstdio>
#include <cassert>
#include <cstring>

#ifndef NULL
#define NULL 0
#endif

#include "pic.h"
#include "loadfile.h"
#include "loadjpeg.h"
#include "loadtga.h"
#include "loadpng.h"

namespace ogl2d
{

namespace image
{

typedef struct FileTypeName
{
    char* name;
    Ogl2dPicType type;
}FileTypeName;

FileTypeName s_filetypenames[] = 
{
    "tga", OGL2D_PIC_TGA,
    "jpg", OGL2D_PIC_JPEG,
    "jpeg", OGL2D_PIC_JPEG,
    "bmp", OGL2D_PIC_BMP,
    "gif", OGL2D_PIC_GIF,
    "png", OGL2D_PIC_PNG,
    NULL, OGL2D_PIC_UNKNOWN,
};

Pic::Pic():width(0), height(0), nchannels(0), buf(NULL), type(OGL2D_PIC_UNKNOWN)
{
    
}

Pic::~Pic()
{
    Release();
}

Ogl2dPicType Pic::PictureType(const char* filename)
{
    assert(filename);
    int i;
    // check extend name for default type.
    const char* extname = filename + strlen(filename);
    while (extname > filename && *extname != '.')
        extname--;
    if (*extname != '.')
        return OGL2D_PIC_UNKNOWN;

    extname++;
    for (i=0; s_filetypenames[i].name; i++)
    {
        if (!strcmp(s_filetypenames[i].name, extname))
            return s_filetypenames[i].type;
    }
    
    return OGL2D_PIC_UNKNOWN;
}

void Pic::Load(const char* filename, Ogl2dPicType _type)
{
    Release();
    type = _type;
    switch(type)
    {
    case OGL2D_PIC_JPEG:
        ::ogl2d::Utilities::DecodeJPGFileToGeneralBuffer(filename, &width, &height, &nchannels, &buf);
        break;
    case OGL2D_PIC_BMP:
        assert(0 && "BMP not surport now");
        break;
    case OGL2D_PIC_TGA:
        unsigned char* filebuf;
        unsigned long size;
        
        if (!::ogl2d::Utilities::LoadGeneralBinaryFile(filename, &filebuf, &size))
            return;
        assert(filebuf);
        if (!::ogl2d::Utilities::DecodeTgaBufferToGeneralBuffer(filebuf, size, &width, &height, &nchannels, &buf))
        {
            ::ogl2d::Utilities::CleanupGeneralBuffer(&filebuf);
            return;
        }
        ::ogl2d::Utilities::CleanupGeneralBuffer(&filebuf);        
        break;
    case OGL2D_PIC_PNG:
        {
            FILE *fp = fopen(filename, "rb");
            fseek(fp, 0, SEEK_END);
            int len = ftell(fp);
            if (len == 0)
            {
                fclose(fp);
                break;
            }
            unsigned char* ptr = new unsigned char[len];
            if (ptr == NULL)
            {
                fclose(fp);
                break;
            }
            fseek(fp, 0, SEEK_SET);
            size_t s = fread(ptr, 1, len, fp);
            fclose(fp);
            ::ogl2d::Utilities::DecodePngBufferToGeneralBuffer(ptr, len, &width, &height, &nchannels, &buf);
            delete [] ptr;
            //::ogl2d::Utilities::DecodePngFileToGeneralBuffer(filename, &width, &height, &nchannels, &buf);
        }
        break;
    default:
        assert(0 && "unknown format");
        break;
    }
}

void Pic::Release()
{
    width = 0;
    height = 0;
    nchannels = 0;
    switch(type)
    {
    case OGL2D_PIC_JPEG:
        ::ogl2d::Utilities::CleanupJPGGeneralBuffer(&buf);
        break;
    case OGL2D_PIC_BMP:
        assert(0 && "BMP not surport now");
        break;
    case OGL2D_PIC_TGA:
        ::ogl2d::Utilities::CleanupTgaGeneralBuffer(&buf);
        break;
    case OGL2D_PIC_PNG:
        ::ogl2d::Utilities::CleanupPngGeneralBuffer();
        break;
    case OGL2D_PIC_UNKNOWN:
        break;
    default:
        assert(0 && "unknown format");
        break;
    }
}
        
};
};