#include <stdlib.h>
#include <string.h>
#include <gdk/gdk.h>
#include <cairo.h>
#include <assert.h>
#include <com_sun_glass_ui_gtk_GtkPixels.h>
#include <gdk-pixbuf/gdk-pixbuf-core.h>

#include "glass_general.h"

static void my_free(guchar *pixels, gpointer data) {
    g_free(pixels);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkPixels
 * Method:    _copyPixels
 * Signature: (Ljava/nio/Buffer;Ljava/nio/Buffer;I)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkPixels__1copyPixels
  (JNIEnv *env, jobject obj, jobject jDst, jobject jSrc, jint jSize)
{
    //Taken from MacPixels (and fixed)
    void *src = (*env)->GetDirectBufferAddress(env, jSrc);
    void *dst = (*env)->GetDirectBufferAddress(env, jDst);
    if ((src != NULL) && (dst != NULL) && (jSize > 0))
    {
        memcpy(dst, src, jSize * 4);
    }
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkPixels
 * Method:    _attachInt
 * Signature: (JIILjava/nio/IntBuffer;[II)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkPixels__1attachInt
  (JNIEnv * env, jobject obj, jlong ptr, jint w, jint h, jobject ints, jintArray array, jint offset)
{
    jint *data;
    GdkPixbuf **pixbuf;
    guint8 *dataRGBA;
    
    if (array == NULL) {
        data = (*env)->GetDirectBufferAddress(env, ints);
        assert((w*h*4 + offset * 4) == (*env)->GetDirectBufferCapacity(env, ints));
    } else {
        data = (*env)->GetPrimitiveArrayCritical(env, array, 0);
        assert((w*h + offset) == (*env)->GetArrayLength(env, array));
    }

    pixbuf = (GdkPixbuf**)JLONG_TO_PTR(ptr);
    dataRGBA = convert_BGRA_to_RGBA(data + offset, w*4, h);
    *pixbuf = gdk_pixbuf_new_from_data(dataRGBA, GDK_COLORSPACE_RGB, TRUE, 8,
                  w, h, w * 4, (GdkPixbufDestroyNotify) my_free, NULL);
    if (array != NULL) {
        (*env)->ReleasePrimitiveArrayCritical(env, array, data, 0);
    }
}


/*
 * Class:     com_sun_glass_ui_gtk_GtkPixels
 * Method:    _attachByte
 * Signature: (JIILjava/nio/ByteBuffer;[BI)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkPixels__1attachByte
  (JNIEnv * env, jobject obj, jlong ptr, jint w, jint h, jobject bytes, jbyteArray array, jint offset)
{
    jbyte *data;
    GdkPixbuf **pixbuf;
    guint8 *dataRGBA;
    
    if (array == NULL) {
        data = (*env)->GetDirectBufferAddress(env, bytes);
        assert((w*h*4 + offset) == (*env)->GetDirectBufferCapacity(env, bytes));
    } else {
        data = (*env)->GetPrimitiveArrayCritical(env, array, 0);
        assert((w*h*4 + offset) == (*env)->GetArrayLength(env, array));
    }

    pixbuf = (GdkPixbuf**)JLONG_TO_PTR(ptr);
    dataRGBA = convert_BGRA_to_RGBA((const int*)(data + offset), w*4, h);
    *pixbuf = gdk_pixbuf_new_from_data(dataRGBA, GDK_COLORSPACE_RGB, TRUE, 8,
                  w, h, w * 4, (GdkPixbufDestroyNotify) my_free, NULL);
    if (array != NULL) {
        (*env)->ReleasePrimitiveArrayCritical(env, array, data, 0);
    }
}
