
// textures.cpp - arc length texture patterns

#include <stdio.h>
#include <assert.h>
#include <GL/glew.h>
#ifdef __APPLE__
# include <GLUT/glut.h>
#else
# include <GL/glut.h>
# ifdef _WIN32
#  include <windows.h>  // for wglGetProcAddress
# else
#  include <GL/glx.h>  // for glXGetProcAddress
# endif
#endif

#include <vector>
#include <string>
#include <boost/shared_ptr.hpp>

using std::vector;
using std::string;
using boost::shared_ptr;

#include "textures.hpp"

#include "gl_texture.hpp"
#include "sRGB_math.h"
#include "countof.h"
#include "glcolor.hpp"
#include "hairline.hpp"

#ifdef _WIN32
#include "common/win32_dirent.h"  // dirent API for Microsoft Visual Studio
#else
#include <dirent.h>
#endif

typedef shared_ptr<GLTexture2D> GLTexture2DPtr;

struct TextureInfo {
    string filename;
    GLTexture2DPtr texture;
    float scale;
public:
    void load() {
        texture = GLTexture2DPtr(new GLTexture2D());
        if (texture) {
            bool success = texture->loadImageFromFile(filename.c_str(), true);
            if (success) {
                texture->setParameter(GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
                texture->setParameter(GL_TEXTURE_MAX_ANISOTROPY, 16);
                texture->configureMipmaps();
                scale = float(texture->Height()) / texture->Width();
            } else {
                texture = GLTexture2DPtr();
                scale = 0;
            }
        }
    }

    TextureInfo(const char* name)
        : filename(name)
        , scale(0)
    {}
    TextureInfo(const TextureInfo& ti)
        : filename(ti.filename)
        , texture(ti.texture)
        , scale(ti.scale)
    {}
    TextureInfo& operator = (const TextureInfo& rhs) {
        filename = rhs.filename;
        texture = rhs.texture;
        scale = rhs.scale;
        return *this;
    }
};

typedef shared_ptr<TextureInfo> TextureInfoPtr;

vector<TextureInfo> texture_info;
static string initial_texture_filename;

size_t current_texture = 0;

static void textureMenu(int item)
{
    assert(size_t(item) < texture_info.size());
    if (texture_info[item].texture) {
        current_texture = item;
        postMainWindowRedisplay();
    } else {
        printf("could not access %s\n", texture_info[item].filename.c_str());
    }
}

int createTextureMenu()
{
    int menu = glutCreateMenu(textureMenu);
    for (size_t i=0; i<texture_info.size(); i++) {
        glutAddMenuEntry(texture_info[i].filename.c_str(), int(i));
    }
    return menu;
}

void bindCurrentTexture()
{
    if (texture_info[current_texture].texture) {
        texture_info[current_texture].texture->bind(0);
    } else {
        printf("texture %s not available\n", texture_info[current_texture].filename.c_str());
    }
}

void bindCurrentTexture(size_t ndx)
{
    if (texture_info[ndx].texture) {
        texture_info[ndx].texture->bind(0);
    } else {
        printf("texture %s not available\n", texture_info[ndx].filename.c_str());
    }
}

float getCurrentTextureScale()
{
    float s = texture_info[current_texture].scale;
    assert(s > 0);
    return s;
}

void advanceTexture()
{
    unsigned int new_texture = (current_texture + 1) % static_cast<unsigned int>(texture_info.size());
    if (texture_info[new_texture].texture) {
        current_texture = new_texture;
        printf("texture = %s\n", texture_info[current_texture].filename.c_str());
    } else {
        printf("texture %s not available\n", texture_info[current_texture].filename.c_str());
    }
}

#ifdef _WIN32
#define snprintf _snprintf
#endif

void loadTextures(const char* dir_name)
{
    DIR *dir = opendir(dir_name);
    if (!dir) {
        return;
    }

    while (struct dirent *cur_skp_file = readdir(dir)) {
        const char* name = cur_skp_file->d_name;
        if (cur_skp_file->d_type == DT_DIR) {
            if (!strcmp(name, ".") || !strcmp(name, "..")) {
                continue;
            }
        } else {
            const size_t len = strlen(name);
            const char suffix[] = ".png";
            const size_t suffix_len = sizeof(suffix);  // == 5 with nul terminal
            if (len >= suffix_len
                && name[0] != '.'
                && !strcmp(name + len - suffix_len + 1, suffix)) {
                char buffer[1024];
                snprintf(buffer, sizeof(buffer), "%s/%s", dir_name, name);
                if (initial_texture_filename == buffer) {
                    printf("matched requested texture %s\n", buffer);
                    current_texture = texture_info.size();
                }
                texture_info.push_back(buffer);
            }
        }
    }

    closedir(dir);

    for (size_t i = 0; i<texture_info.size(); i++) {
        texture_info[i].load();
    }
}

void setInitialTexture(const char* filename)
{
    initial_texture_filename = filename;
}
