/*
 * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
 */
#include <windows.h>

#include "common.h"

#include "com_sun_rain_graphics_Font.h"

static jclass jFontClass = NULL;
static jclass jFontMetricsClass = NULL;
static jclass jRectangleClass = NULL;

extern "C" {

/*
 * Class:     com_sun_rain_graphics_Font
 * Method:    _initIDs
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_sun_rain_graphics_Font__1initIDs
    (JNIEnv *env, jclass jFontClass)
{
    jFontClass = (jclass)env->NewGlobalRef(env->FindClass("com/sun/rain/graphics/Font"));
    jFontMetricsClass = (jclass)env->NewGlobalRef(env->FindClass("com/sun/rain/graphics/Font$Metrics"));
    jRectangleClass = (jclass)env->NewGlobalRef(env->FindClass("com/sun/rain/shapes/Rectangle"));
}

/*
 * Class:     com_sun_rain_graphics_Font
 * Method:    _createFont
 * Signature: (Ljava/lang/String;IFLcom/sun/rain/graphics/Font/Metrics;)J
 */
JNIEXPORT jlong JNICALL Java_com_sun_rain_graphics_Font__1createFont
    (JNIEnv *env, jobject jfont, jstring name, jint type, jfloat size, jobject jmetrics)
{

    LOGFONT logFont;

    logFont.lfWidth = 0;
    logFont.lfEscapement = 0;
    logFont.lfOrientation = 0;
    logFont.lfUnderline = FALSE;
    logFont.lfStrikeOut = FALSE;
    logFont.lfCharSet = ANSI_CHARSET;
    logFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
    logFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    logFont.lfQuality = DEFAULT_QUALITY;
    logFont.lfPitchAndFamily = DEFAULT_PITCH;

    // Set style
    logFont.lfWeight = FW_NORMAL;
    logFont.lfItalic = FALSE;
    logFont.lfUnderline = 0;

    // Get point size
    logFont.lfHeight = -(int)size;

    // Set font name
    int length = env->GetStringLength(name);
    WCHAR* buffer = new WCHAR[length + 1];
    env->GetStringRegion(name, 0, length, reinterpret_cast<jchar*>(buffer));
    buffer[length] = L'\0';
#pragma warning(disable: 4996)
    // The safe wcsncpy_s is unavailable on VS2003,
    // thus disable the warning for newer compilers
    wcsncpy(&(logFont.lfFaceName[0]), buffer, LF_FACESIZE);
#pragma warning(default: 4996)
    delete[] buffer;

    HFONT hFont = ::CreateFontIndirect(&logFont);

    if (!hFont) {
        fprintf(stderr, "createFont: unable to create font\n");
        return 0L;
    }

    TEXTMETRIC tm;
    HDC hdc = ::CreateCompatibleDC(NULL);
    HFONT oldFont = (HFONT)::SelectObject(hdc, hFont);

    if (::GetTextMetrics(hdc, &tm)) {
        env->SetFloatField(jmetrics, env->GetFieldID(jFontMetricsClass, "ascent", "F"), (jfloat)tm.tmAscent);
        env->SetFloatField(jmetrics, env->GetFieldID(jFontMetricsClass, "descent", "F"), (jfloat)tm.tmDescent);
        env->SetFloatField(jmetrics, env->GetFieldID(jFontMetricsClass, "leading", "F"), (jfloat)tm.tmInternalLeading);

        // The x, y, width, and height arn't set. This is some CTFontGetBoundingBox() on Mac
        // for which I can't find a equivalent on Windows. Anyway, they are unused.
    }

    ::SelectObject(hdc, oldFont);
    ::DeleteDC(hdc);

    //TODO: why not set the ptr directly from here? Why do we return the handle?
    return ptr_to_jlong(hFont);
}

/*
 * Class:     com_sun_rain_graphics_Font
 * Method:    _getBoundingBox
 * Signature: (Ljava/lang/String;Lcom/sun/rain/shapes/Rectangle;)Lcom/sun/rain/shapes/Rectangle;
 */
JNIEXPORT jobject JNICALL Java_com_sun_rain_graphics_Font__1getBoundingBox
  (JNIEnv *env, jobject jfont, jstring string, jobject jbbox)
{
    HFONT hFont = (HFONT)jlong_to_ptr(env->GetLongField(jfont, env->GetFieldID(jFontClass, "ptr", "J")));
    if (!hFont) {
        fprintf(stderr, "getBoundingBox(): NULL font\n");
        return jbbox;
    }

    int length = env->GetStringLength(string);
    WCHAR* chars = new WCHAR[length + 1];
    env->GetStringRegion(string, 0, length, reinterpret_cast<jchar*>(chars));
    chars[length] = L'\0';

    HDC hdc = ::CreateCompatibleDC(NULL);
    HFONT oldFont = (HFONT)::SelectObject(hdc, hFont);
    
    SIZE size;

    //XXX: not sure if GetStringUTFChars() better than GetStringChars here.
    //Also, the length might be just -1 if the string is null-termianted, I think.
    ::GetTextExtentPoint32(hdc, chars, env->GetStringLength(string), &size);
    
    ::SelectObject(hdc, oldFont);
    ::DeleteDC(hdc);
    delete[] chars;
    
    env->SetFloatField(jbbox, env->GetFieldID(jRectangleClass, "x", "F"), 0);
    env->SetFloatField(jbbox, env->GetFieldID(jRectangleClass, "y", "F"), 0);
    env->SetFloatField(jbbox, env->GetFieldID(jRectangleClass, "width", "F"), (jfloat)size.cx);
    env->SetFloatField(jbbox, env->GetFieldID(jRectangleClass, "height", "F"), (jfloat)size.cy);
    
    return jbbox;
}



} // extern "C"
