/*
 * Copyright (c) 2004 Nokia. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the
 * distribution.
 *
 * Neither the name of Nokia nor the names of its contributors may be
 * used to endorse or promote products derived from this software
 * without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include <assert.h>
#include <gdk/gdk.h>
#if 0
#include <gdk/gdkx.h>
#endif
#include <gtk/gtk.h> //pango stuff
#include <pango/pango.h>
#include <pango/pangofc-fontmap.h>
#include <pango/pangowin32.h>

#if defined(__WIN32__)
#define UNICODE
#include <windows.h>
#include <GdiPlus.h>
#include <fontconfig/fontconfig.h>
#endif 

#include "Win32TextRendererFactory.h"

void Win32TextRendererFactory::useAsSharedFactory()
{
    static Win32TextRendererFactory singleton;
    m_sharedFactory = &singleton;
}

Win32NSFont::Win32NSFont(Win32TextRendererFactory* acreator, Gdiplus::Font* afont, gpointer ahash)
    :win32Font(afont)
     ,hash(ahash)
     ,creator(acreator)
{
    assert(win32Font);
    HDC dc = GetDC(0L);
    Gdiplus::Graphics graphics(dc);
    Gdiplus::SizeF size;

    ascent = 0;
    descent = 0;
    lineSpacing = (int) win32Font->GetHeight(&graphics);

    // measure x height
    // Set up the string.
    WCHAR string[] = L"x\0";
    // should matter while it is big enough to fit single 'x'
    Gdiplus::RectF layoutRect(0, 0, 100, 50);
    Gdiplus::RectF boundRect;
    // Measure the string.
    graphics.MeasureString(string, 1, win32Font, layoutRect, &boundRect);
    boundRect.GetSize(&size);
    xHeight = (int) size.Height;

    // measure space width. Needed because we don't draw '\n' -chars, just skip them
    WCHAR string2[] = L" \0";
    // should matter while it is big enough to fit single 'x'
    // Measure the string.
    graphics.MeasureString(string2, 1, win32Font, layoutRect, &boundRect);    
    boundRect.GetSize(&size);
    spaceWidth = (int) size.Width;

    // FIXME: fixedPitch from font families --psalmi
//     int spacing = 0;
//     if (FcPatternGetInteger(xftFont->pattern, FC_SPACING, 0, &spacing) == FcResultMatch) {
// 	fixedPitch = (spacing == FC_MONO);
//     } else {
	fixedPitch = false;
//     }

    ReleaseDC(0L, dc);
}

Win32NSFont::~Win32NSFont()
{
    if (creator) creator->fontDeleted(this);
}

gpointer Win32NSFont::createHash(const gchar * const * families, NSFontTraitMask traits, float size)
{
    int hash = 0;

    for (int i = 0;families[i]; i++)
	hash ^=  g_direct_hash(families[i]);	

    hash ^= (((int)traits) << 16);
    hash ^= ((int)size*100);
    return (gpointer) hash;
}

/**
 * Loads Win32 font
 * from fontconfig(3)
 * Fontconfig  performs matching by measuring the distance from a provided
 * pattern to all of the available  fonts  in  the  system.   The  closest
 * matching  font  is  selected.   This ensures that a font will always be
 * returned, but doesn't ensure that it is  anything  like  the  requested
 * pattern.
 *
 * cannot fail (sure..)
 * @return font (must be freed)
 */

static 
Gdiplus::Font* try_load_font(const char* const * family, double size, int weight, int slant)
{
    assert(family);

#if 0
    FcPattern *pattern,*matched;
    FcResult result;

    pattern = FcPatternBuild(0,
			     FC_WEIGHT, FcTypeInteger, weight,
			     FC_SLANT,  FcTypeInteger, slant,
			     FC_PIXEL_SIZE, FcTypeDouble, size,
			     FC_DPI, FcTypeDouble, 96.0,
			     FC_SCALE, FcTypeDouble, 1.0,
			     NULL);
    while (*family) {      
	FcPatternAddString(pattern, FC_FAMILY, reinterpret_cast<const FcChar8*>(*family));
	family++;
    }

    PangoFontDescription * pd = pango_fc_font_description_from_pattern(pattern, true);   

    if (!pd) {
        FcPatternDestroy(pattern);
        //g_warning("%s Font Matching Failed.", __PRETTY_FUNCTION__);
	return 0;
    }
#endif
    
    Gdiplus::Font * f = new Gdiplus::Font(reinterpret_cast<const WCHAR*>(*family), size, 
                                          Gdiplus::FontStyleRegular, Gdiplus::UnitPoint, 0L);

    // FontConfig should destroy the pattern
    return f;
}

extern "C" {
static

void nsfonts_key_destroy(gpointer data)
{

}

void nsfonts_value_destroy(gpointer data)
{
}

void nsfonts_value_detach(gpointer key, gpointer value, gpointer user_data)
{

    Win32NSFont *f = static_cast<Win32NSFont*>(value);
    assert(f);
    f->detach();
}
}

Win32TextRendererFactory::Win32TextRendererFactory()
{
    nsfonts = g_hash_table_new_full(g_direct_hash, 
				    g_direct_equal, 
				    nsfonts_key_destroy, 
				    nsfonts_value_destroy);

}

Win32TextRendererFactory::~Win32TextRendererFactory()
{
    g_hash_table_foreach(nsfonts, nsfonts_value_detach, this);
    g_hash_table_destroy(nsfonts);
}

// Assume families[0..] are atomic string ptrs
// assumes hashing is perfect and no clashes occur. FIXME!!!!

NSFont* Win32TextRendererFactory::fontWithFamilies(const gchar * const * families, NSFontTraitMask traits, float size)
{
    assert(families);

    gpointer hash = Win32NSFont::createHash(families, traits, size);
    Win32NSFont* font = static_cast<Win32NSFont*>(g_hash_table_lookup(nsfonts, hash));

    if (!font) {
	// font cache miss
	int w,s;        
	w = FC_WEIGHT_MEDIUM;
	s = FC_SLANT_ROMAN;
	
	if (traits & NSBoldFontMask)
	    w = FC_WEIGHT_BOLD;
	
	if (traits & NSItalicFontMask) 
	    s = FC_SLANT_ITALIC;
	

	Gdiplus::Font* win32font = try_load_font(families, size, w, s);
	assert(win32font);
	font = new Win32NSFont(this, win32font, hash);

        //FIXME: store families too, in case of hashing clashes
	g_hash_table_insert(nsfonts, hash, font);
    }

    return font;
}

Win32TextRenderer* Win32TextRendererFactory::rendererWithFont(NSFont *nsfont, bool isPrinterFont)
{
    assert(nsfont);

    Win32NSFont* font = static_cast<Win32NSFont*>(nsfont); 

    return new Win32TextRenderer(this, font);
}

void Win32TextRendererFactory::rendererDeleted(Win32TextRenderer* renderer)
{

}

void Win32TextRendererFactory::fontDeleted(Win32NSFont* font)
{
    bool ret =  g_hash_table_remove(nsfonts, font->hash);
    assert(ret);
}

bool Win32TextRendererFactory::isFontFixedPitch(NSFont* nsfont)
{
    Win32NSFont* font = static_cast<Win32NSFont*>(nsfont);     
    return font->fixedPitch;
}
