#include <com_sun_glass_ui_gtk_GtkWindow.h>
#include <com_sun_glass_events_WindowEvent.h>
#include <com_sun_glass_events_ViewEvent.h>

#include <cstdlib>
#include <cstring>
#include "glass_gtkcompat.h"
#include "glass_general.h"
#include "glass_evloop.h"
#include "glass_window.hpp"

#define JLONG_TO_WINDOW_CTX(ptr) ((WindowContext*)JLONG_TO_PTR(ptr))

static WindowFrameType glass_mask_to_window_frame_type(jint mask) {
    if (mask & com_sun_glass_ui_gtk_GtkWindow_TRANSPARENT) {
        return TRANSPARENT;
    }
    if (mask & com_sun_glass_ui_gtk_GtkWindow_TITLED) {
        return TITLED;
    }
    return UNTITLED;
}

static WindowType glass_mask_to_window_type(jint mask) {
    if (mask & com_sun_glass_ui_gtk_GtkWindow_POPUP) {
        return POPUP;
    }
    if (mask & com_sun_glass_ui_gtk_GtkWindow_UTILITY) {
        return UTILITY;
    }
    return NORMAL;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _createWindow
 * Signature: (JJI)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1createWindow
  (JNIEnv * env, jobject obj, jlong owner, jlong screen, jint mask)
{

    WindowContext* ctx = new WindowContextTop(obj,
            (WindowContext*)JLONG_TO_PTR(owner),
            screen,
            glass_mask_to_window_frame_type(mask),
            glass_mask_to_window_type(mask));

    return PTR_TO_JLONG(ctx);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _createChildWindow
 * Signature: (J)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1createChildWindow
  (JNIEnv * env, jobject obj , jlong owner)
{
    GdkWindow *parent_window = NULL;
    GtkWidget *parent_widget = NULL;
    WindowContext *parent_ctx = NULL;
    WindowContext* ctx = NULL;

    parent_window = GLASS_GDK_WINDOW_LOOKUP_FOR_DISPLAY(
                        gdk_display_get_default(),
                        (GdkNativeWindow)PTR_TO_JLONG(owner));

    if (parent_window != NULL) {
        parent_ctx = (WindowContext*)g_object_get_data(G_OBJECT(parent_window), GDK_WINDOW_DATA_CONTEXT);
        // HACK: do not use get_gtk_window()
        // the method is intended to return GtkWindow that can be used for FileChooser
        // (OK, that's also a hack, but still...)
        parent_widget = GTK_WIDGET(parent_ctx->get_gtk_window());
    }

    if (parent_widget == NULL) {
        ctx = new WindowContextPlug(obj, JLONG_TO_PTR(owner));
    } else {
        ctx = new WindowContextChild(obj, JLONG_TO_PTR(owner), parent_widget, parent_ctx);
    }

    return PTR_TO_JLONG(ctx);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _close
 * Signature: (J)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1close
  (JNIEnv * env, jobject obj, jlong ptr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    delete ctx;
    return JNI_TRUE; // return value not used
}
/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setView
 * Signature: (JLcom/sun/glass/ui/View;)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setView
  (JNIEnv * env, jobject obj, jlong ptr, jobject view)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    try {
        ctx->set_view(view);
    } catch (jni_exception&) {
        return JNI_FALSE;
    }
    return JNI_TRUE;
}
/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _showOrHideChildren
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1showOrHideChildren
  (JNIEnv *env, jobject obj, jlong ptr, jboolean show)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->show_or_hide_children(show);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    minimizeImpl
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow_minimizeImpl
  (JNIEnv * env, jobject obj, jlong ptr, jboolean minimize)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_minimized(minimize);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    maximizeImpl
 * Signature: (JZZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow_maximizeImpl
  (JNIEnv * env, jobject obj, jlong ptr, jboolean maximize, jboolean wasMaximized)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_maximized(maximize);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setBounds
 * Signature: (JIIZZIIII)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow_setBoundsImpl
  (JNIEnv * env, jobject obj, jlong ptr, jint x, jint y, jboolean xSet, jboolean ySet, jint w, jint h, jint cw, jint ch)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_bounds(x, y, xSet, ySet, w, h, cw, ch);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    setVisibleImpl
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow_setVisibleImpl
    (JNIEnv * env, jobject obj, jlong ptr, jboolean visible)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_visible(visible);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setResizable
 * Signature: (JZ)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setResizable
  (JNIEnv * env, jobject obj, jlong ptr, jboolean resizable)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_resizable(resizable);
    return JNI_TRUE;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _requestFocus
 * Signature: (JI)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1requestFocus
  (JNIEnv * env, jobject obj, jlong ptr, jint focus)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->request_focus();
    return JNI_TRUE; //not used
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setFocusable
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setFocusable
  (JNIEnv * env, jobject obj, jlong ptr, jboolean focusable)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_focusable(focusable);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _grabFocus
 * Signature: (J)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1grabFocus
  (JNIEnv * env, jobject obj, jlong ptr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    return ctx->grab_focus();
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _ungrabFocus
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1ungrabFocus
  (JNIEnv * env, jobject obj, jlong ptr)
{

    glass_gdk_mouse_devices_ungrab();
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setTitle
 * Signature: (JLjava/lang/String;)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setTitle
  (JNIEnv * env, jobject obj, jlong ptr, jstring title)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    const char* ctitle = mainEnv->GetStringUTFChars(title, NULL);
    ctx->set_title(ctitle);
    mainEnv->ReleaseStringUTFChars(title, ctitle);

    return JNI_TRUE;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setLevel
 * Signature: (JI)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setLevel
  (JNIEnv * env, jobject obj, jlong ptr, jint level)
{
    //Never called from quantum
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setAlpha
 * Signature: (JF)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setAlpha
  (JNIEnv * env, jobject obj, jlong ptr, jfloat alpha)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_alpha(alpha);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setBackground
 * Signature: (JFFF)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setBackground
  (JNIEnv * env, jobject obj, jlong ptr, jfloat r, jfloat g, jfloat b)
{
    return JNI_TRUE; //Don't know how this should work, it's not used anywhere
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setEnabled
 * Signature: (JZ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setEnabled
  (JNIEnv * env, jobject obj, jlong ptr, jboolean enabled)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_enabled(enabled);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setMinimumSize
 * Signature: (JII)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setMinimumSize
  (JNIEnv * env, jobject obj, jlong ptr, jint w, jint h)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    if (w < 0 || h < 0) return JNI_FALSE;
    ctx->set_minimum_size(w, h);
    return JNI_TRUE;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setMaximumSize
 * Signature: (JII)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setMaximumSize
  (JNIEnv * env, jobject obj, jlong ptr, jint w, jint h)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    if (w == 0 || h == 0) return JNI_FALSE;
    if (w == -1) w = G_MAXSHORT;
    if (h == -1) h = G_MAXSHORT;

    ctx->set_maximum_size(w, h);
    return JNI_TRUE;
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setIcon
 * Signature: (JLcom/sun/glass/ui/Pixels;)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setIcon
  (JNIEnv * env, jobject obj, jlong ptr, jobject pixels)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    GdkPixbuf *pixbuf;
    env->CallVoidMethod(pixels, jPixelsAttachData, PTR_TO_JLONG(&pixbuf));
    CHECK_JNI_EXCEPTION(env)

    ctx->set_icon(pixbuf);
    g_object_unref(pixbuf);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _toFront
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1toFront
  (JNIEnv * env, jobject obj, jlong ptr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->restack(true);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _toBack
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1toBack
  (JNIEnv * env, jobject obj, jlong ptr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->restack(false);

}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _enterModal
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1enterModal
  (JNIEnv * env, jobject obj, jlong ptr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_modal(true);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _enterModalWithWindow
 * Signature: (JJ)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1enterModalWithWindow
  (JNIEnv * env, jobject obj, jlong ptrDialog, jlong ptrWindow)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptrDialog);
    WindowContext* parent_ctx = JLONG_TO_WINDOW_CTX(ptrWindow);
    ctx->set_modal(true, parent_ctx);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _exitModal
 * Signature: (J)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1exitModal
  (JNIEnv * env, jobject obj, jlong ptr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_modal(false);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkCursor
 * Method:    _setCursorType
 * Signature: (JI)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setCursorType
  (JNIEnv * env, jobject obj, jlong ptr, jint type)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    GdkCursor *cursor = get_native_cursor(type);
    ctx->set_cursor(cursor);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkCursor
 * Method:    _setCustomCursor
 * Signature: (JLcom/sun/glass/ui/Cursor;)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setCustomCursor
  (JNIEnv * env, jobject obj, jlong ptr, jobject jCursor)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    GdkCursor *cursor = (GdkCursor*)JLONG_TO_PTR(env->GetLongField(jCursor, jCursorPtr));

    ctx->set_cursor(cursor);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    isVisible
 * Signature: (J)Z
 */
JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkWindow_isVisible
    (JNIEnv * env, jobject obj, jlong ptr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    return ctx->is_visible() ? JNI_TRUE : JNI_FALSE;
}
JNIEXPORT jlong JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1getNativeWindowImpl
    (JNIEnv * env, jobject obj, jlong ptr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    return GDK_WINDOW_XID(ctx->get_gdk_window());
}
/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    getFrameExtents
 * Signature: (J[I)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow_getFrameExtents
    (JNIEnv * env, jobject obj, jlong ptr, jintArray extarr)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    WindowFrameExtents extents = ctx->get_frame_extents();

    env->SetIntArrayRegion(extarr, 0, 1, &extents.left);
    env->SetIntArrayRegion(extarr, 1, 1, &extents.right);
    env->SetIntArrayRegion(extarr, 2, 1, &extents.top);
    env->SetIntArrayRegion(extarr, 3, 1, &extents.bottom);
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _setGravity
 * Signature: (JFF)V
 */
JNIEXPORT void JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1setGravity
    (JNIEnv * env, jobject obj, jlong ptr, jfloat xGravity, jfloat yGravity)
{
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    ctx->set_gravity(xGravity, yGravity);

}


/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _getEmbeddedX
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1getEmbeddedX
  (JNIEnv *env, jobject obj, jlong ptr) {
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    return (jint) ctx->getEmbeddedX();
}

/*
 * Class:     com_sun_glass_ui_gtk_GtkWindow
 * Method:    _getEmbeddedY
 * Signature: (J)I
 */
JNIEXPORT jint JNICALL Java_com_sun_glass_ui_gtk_GtkWindow__1getEmbeddedY
  (JNIEnv *env, jobject obj, jlong ptr) {
    WindowContext* ctx = JLONG_TO_WINDOW_CTX(ptr);
    return (jint) ctx->getEmbeddedY();
}

