/*
 * (C) Copyright Ian D. Romanick 2007
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * on the rights to use, copy, modify, merge, publish, distribute, sub
 * license, and/or sell copies of the Software, and to permit persons to whom
 * the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.  IN NO EVENT SHALL
 * AUTHORS, COPYRIGHT HOLDERS, AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

#include "glsl_glue.h"

#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
#define _CRT_SECURE_NO_DEPRECATE
# include <windows.h>
#else
# include <GL/glx.h>
# include <GL/glxext.h>

# include <sys/types.h>
# include <sys/stat.h>
# include <fcntl.h>
# include <unistd.h>
#endif

#include <stdio.h>

/**
 * Load shader program code from the named source file.
 *
 * \param file_name  Name of the source file to be loaded.
 *
 * \return
 * A pointer to \c NUL terminated program source code on success or \c NULL
 * on failure.
 */
GLcharARB *glsl_load_shader_code(const char *file_name)
{
    GLcharARB *text = NULL;

#if defined(_WIN32)
    FILE *fp = fopen(file_name, "r");

    if (fp == NULL) {
        return NULL;
    }
    
    if (fseek(fp, 0, SEEK_END) == 0) {
        size_t len = ftell(fp);
        rewind(fp);

        text = new(GLcharARB[len + 1]);
        if (text != NULL) {
            size_t total_read = 0;

            do {
                size_t bytes = fread(text + total_read, 1, len - total_read,
                                     fp);

                total_read += bytes;
                if (feof(fp)) {
                    break;
                }

                if (ferror(fp)) {
                    delete text;
                    text = NULL;
                    break;
                }
            } while (total_read < len);

            text[total_read] = '\0';
        }
    }

    fclose(fp);
    return text;
#else
    struct stat st;
    int fd = open(file_name, O_RDONLY);

    if (fd < 0) {
        return NULL;
    }

    if (fstat(fd, & st) == 0) {
        ssize_t total_read = 0;

        text = new(GLcharARB[st.st_size + 1]);
        if (text != NULL) {
            do {
                ssize_t bytes = read(fd, text + total_read, 
                                     st.st_size - total_read);
                if (bytes < 0) {
                    delete text;
                    text = NULL;
                    break;
                }

                if (bytes == 0) {
                    break;
                }

                total_read += bytes;
            } while (total_read < st.st_size);

            text[total_read] = '\0';
        }
    }

    close(fd);

    return text;
#endif
}


void
glsl_print_log(GLhandleARB h)
{
    GLsizei info_size;
    GLcharARB info_log[1024];

    glGetInfoLogARB(h, sizeof(info_log), & info_size, info_log);
    if (info_size) {
	GLcharARB *p = NULL;
	GLsizei p_size;


	if (info_size > (GLsizei)sizeof(info_log)) {
	    p = new char[info_size];
	    p_size = info_size;
	}

	if (p == NULL) {
	    p = info_log;
	    p_size = sizeof(info_log);
	}

	glGetInfoLogARB(h, p_size, & info_size, p);
	printf("Info log:\n%s\n", p);
    }
}
