#include <com_sun_glass_ui_gtk_GtkView.h>
#include <com_sun_glass_events_ViewEvent.h>

#include <cstdlib>
#include <cstring>
#include <cassert>

#include "glass_general.h"
#include "glass_view.hpp"
#include "glass_window.hpp"
#include "glass_gtkcompat.h"

#define JLONG_TO_GLASSVIEW(value) ((GlassView *) JLONG_TO_PTR(value))

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _enableInputMethodEvents
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkView_enableInputMethodEventsImpl
  (JNIEnv * env, jobject obj, jlong ptr, jboolean enable)
{
    if (enable) {
        JLONG_TO_GLASSVIEW(ptr)->current_window->enableOrResetIME();
    } else {
        JLONG_TO_GLASSVIEW(ptr)->current_window->disableIME();
    }
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _create
 * Signature: (Ljava/util/Map;)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_glass_ui_gtk_GtkView__1create
  (JNIEnv * env, jobject obj, jobject caps)
{
    GlassView *view = new GlassView();
    return PTR_TO_JLONG(view);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _getNativeView
 * Signature: (J)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_glass_ui_gtk_GtkView__1getNativeView
  (JNIEnv * env, jobject obj, jlong ptr)
{
    return 0;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _getX
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkView__1getX
  (JNIEnv * env, jobject obj, jlong ptr)
{
    GlassView* view = JLONG_TO_GLASSVIEW(ptr);
    if (view && view->current_window) {
        return view->current_window->get_frame_extents().left;
    }
    return 0;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _getY
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkView__1getY
  (JNIEnv * env, jobject obj, jlong ptr)
{
    GlassView* view = JLONG_TO_GLASSVIEW(ptr);
    if (view && view->current_window) {
        return view->current_window->get_frame_extents().top;
    }
    return 0;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _setParent
 * Signature: (JJ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkView__1setParent
  (JNIEnv * env, jobject obj, jlong ptr, jlong parent)
{
    GlassView* view = JLONG_TO_GLASSVIEW(ptr);
    if (view->current_window && !parent) {
        env->CallVoidMethod(obj, jViewHandleViewEvent, com_sun_glass_events_ViewEvent_REMOVE);
    } else {
        env->CallVoidMethod(obj, jViewHandleViewEvent, com_sun_glass_events_ViewEvent_ADD);
    }
    CHECK_JNI_EXCEPTION(env);
    view->current_window = (WindowContext*)JLONG_TO_PTR(parent);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _close
 * Signature: (J)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkView__1close
  (JNIEnv * env, jobject obj, jlong ptr)
{
    delete JLONG_TO_GLASSVIEW(ptr);
    return JNI_TRUE;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _repaint
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkView__1repaint
  (JNIEnv * env, jobject obj, jlong ptr)
{
    // Seems to be unused
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _begin
 * Signature: (JZ)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkView__1begin
  (JNIEnv * env, jobject obj, jlong ptr, jboolean valid)
{
    return JNI_TRUE; // No need to lock, done automatically by GDK
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _end
 * Signature: (JZZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkView__1end
  (JNIEnv * env, jobject obj, jlong ptr, jboolean valid, jboolean flush)
{
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _uploadPixelsDirect
 * Signature: (JLjava/nio/Buffer;II)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkView__1uploadPixelsDirect
(JNIEnv *env, jobject jView, jlong ptr, jobject buffer, jint width, jint height)
{
    void *data = env->GetDirectBufferAddress(buffer);

    (JLONG_TO_GLASSVIEW(ptr))->current_window->paint(data, width, height);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _uploadPixelsIntArray
 * Signature:  (J[IIII)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkView__1uploadPixelsIntArray
  (JNIEnv * env, jobject obj, jlong ptr, jintArray array, jint offset, jint width, jint height)
{
    int *data = NULL;
    data = (int*)env->GetPrimitiveArrayCritical(array, 0);
    assert((width*height + offset) == env->GetArrayLength(array));

    (JLONG_TO_GLASSVIEW(ptr))->current_window->paint(data + offset, width, height);

    env->ReleasePrimitiveArrayCritical(array, data, JNI_ABORT);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _uploadPixelsByteArray
 * Signature:  (J[BIII)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkView__1uploadPixelsByteArray
  (JNIEnv * env, jobject obj, jlong ptr, jbyteArray array, jint offset, jint width, jint height)
{
    unsigned char *data = NULL;

    data = (unsigned char*)env->GetPrimitiveArrayCritical(array, 0);
    assert((4*width*height + offset) == env->GetArrayLength(array));

    (JLONG_TO_GLASSVIEW(ptr))->current_window->paint(data + offset, width, height);

    env->ReleasePrimitiveArrayCritical(array, data, JNI_ABORT);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _enterFullscreen
 * Signature: (JZZZ)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkView__1enterFullscreen
  (JNIEnv * env, jobject obj, jlong ptr, jboolean animate, jboolean keepRation, jboolean hideCursor)
{
    GlassView* view = JLONG_TO_GLASSVIEW(ptr);
    if (view->current_window)
        view->current_window->enter_fullscreen();
    return JNI_TRUE;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkView
 * Method:    _exitFullscreen
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkView__1exitFullscreen
  (JNIEnv * env, jobject obj, jlong ptr, jboolean animate)
{
    GlassView* view = JLONG_TO_GLASSVIEW(ptr);
    if (view->current_window)
        view->current_window->exit_fullscreen();

}
