/* GKrellM
|  Copyright (C) 1999-2004 Bill Wilson
|
|  Author:  Bill Wilson    bill@gkrellm.net
|  Latest versions might be found at:  http://gkrellm.net
|
|  This program is free software which I release under the GNU General Public
|  License. You may redistribute and/or modify this program under the terms
|  of that license as published by the Free Software Foundation; either
|  version 2 of the License, or (at your option) any later version.
|
|  This program is distributed in the hope that it will be useful,
|  but WITHOUT ANY WARRANTY; without even the implied warranty of
|  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
|  GNU General Public License for more details.  Version 2 is in the
|  COPYRIGHT file in the top level directory of this distribution.
| 
|  To get a copy of the GNU General Puplic License, write to the Free Software
|  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "gkrellm.h"
#include "gkrellm-private.h"
#include "resource.h"


static gchar ascent_map[26] =
/* a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z */
{  0,1,0,1,0,1,3,1,2,4,1,1,0,0,0,3,3,0,0,1,0,0,0,0,3,0 };

typedef struct
    {
    gint    upper_ascent,    /* All upper case chars should have the same ascent */
            lower_ascent[5],
            digit_ascent,    /* Digit ascent could be different from upper case */
            descent;
    }
    AscentValues;

AscentValues    large_font_ascents,
                normal_font_ascents,
                small_font_ascents;

static int setup_ascents(GdkFont *font, AscentValues *av)
{
    GLYPHMETRICS gm;
    MAT2 mat2;
    HWND wnd;
    HDC hdc;
    DWORD err;

    /* I'm winging this based on an example code fragment I saw on the web */
//    IdentityMat(&mat2); 

    // identity matrix
    mat2.eM11.value = 1;
    mat2.eM11.fract = 0;
    mat2.eM12.value = 0;
    mat2.eM12.fract = 0;
    mat2.eM21.value = 0;
    mat2.eM21.fract = 0;
    mat2.eM22.value = 1;
    mat2.eM22.fract = 0;


    /* somehow SelectObject based on font.  It looks like the gdk code
    does it in _gdk_wchar_text_handle and gdk_text_size_handler in the
    gdkfont-win32.c I sent you.
    */

    wnd = GDK_WINDOW_HWND(gkrellm_get_top_window()->window);
    if (wnd == 0)
        return 1;

    hdc = GetDC(wnd);

    err = GetGlyphOutline(hdc, 'A', GGO_METRICS, &gm, 0, NULL, &mat2);
    if (err == GDI_ERROR) {
        ReleaseDC(wnd, hdc);
        return 1;
    }
    av->upper_ascent = gm.gmBlackBoxY;

    err = GetGlyphOutline(hdc,'8', GGO_METRICS,  &gm, 0, NULL, &mat2);
    if (err == GDI_ERROR) {
        ReleaseDC(wnd, hdc);
        return 1;
    }
    av->digit_ascent = gm.gmBlackBoxY;

    err = GetGlyphOutline(hdc, 'a', GGO_METRICS,  &gm, 0, NULL, &mat2);
    if (err == GDI_ERROR) {
        ReleaseDC(wnd, hdc);
        return 1;
    }
    av->lower_ascent[0] = gm.gmBlackBoxY;
    av->lower_ascent[3] = av->lower_ascent[0];

    err = GetGlyphOutline(hdc, 'f', GGO_METRICS,  &gm, 0, NULL, &mat2);
    if (err == GDI_ERROR) {
        ReleaseDC(wnd, hdc);
        return 1;
    }
    av->lower_ascent[1] = gm.gmBlackBoxY;

    err = GetGlyphOutline(hdc, 'i', GGO_METRICS,  &gm, 0, NULL, &mat2);
    if (err == GDI_ERROR) {
        ReleaseDC(wnd, hdc);
        return 1;
    }
    av->lower_ascent[2] = gm.gmBlackBoxY;
    av->lower_ascent[4] = av->lower_ascent[4];

    err = GetGlyphOutline(hdc, 'y', GGO_METRICS,  &gm, 0, NULL, &mat2);
    if (err == GDI_ERROR) {
        ReleaseDC(wnd, hdc);
        return 1;
    }
    av->descent = gm.gmBlackBoxY - av->lower_ascent[0];

    ReleaseDC(wnd, hdc);
    return 0;
}

static void fix_ascents(gchar *s, gint len, AscentValues *av, gint *ascent, gint *descent)
{
    gint    i, map, a = 0, a_max = 0, d = 0;
    gchar   c;

    for (i = 0; i < len; ++i)
        {
        c = s[i];
        if (islower(c))
            {
            map = ascent_map[c - 'a'];
            a = av->lower_ascent[map];
            if (map > 2)
                d = av->descent;
            }
        else if (isupper(c))
            a = av->upper_ascent;
        else if (isdigit(c))
            a = av->digit_ascent;
        if (a > a_max)
            a_max = a;
        }
    *ascent = a_max;
    *descent = d;
}

void gkrellm_winop_text_extents(GdkFont *font, gchar *text, gint text_length,
        gint *lbearing, gint *rbearing,
        gint *width, gint *ascent, gint *descent)
{
    static gint font_load_count;
    int done = 1;

    gdk_text_extents(font, text, text_length, lbearing, rbearing,
            width, ascent, descent);
    if (_GK.font_load_count != font_load_count)
    {  /* _GK.font_load_count increments when I load the theme fonts */
        setup_ascents(_GK.large_font, &large_font_ascents);
        setup_ascents(_GK.normal_font, &normal_font_ascents);
        done = setup_ascents(_GK.small_font, &small_font_ascents);
        font_load_count = _GK.font_load_count;
    }
    if (done == 0) 
    {
        // only do this if setup_ascents passed
        if (font == _GK.large_font)
            fix_ascents(text, text_length, &large_font_ascents, ascent, descent);
        else if (font == _GK.normal_font)
            fix_ascents(text, text_length, &normal_font_ascents, ascent, descent);
        else if (font == _GK.small_font)
            fix_ascents(text, text_length, &small_font_ascents, ascent, descent);
    }
    else {
        *ascent -= 3;
        *descent -= 1;
    }
}

void
gkrellm_winop_reset(void)
{
}

//void
//gkrellm_winop_withdraw(void)
//	{
//	}

UINT WM_GKRELLMCALLBACK;
extern void create_config_window(void);
LONG oldval;

LRESULT CALLBACK newWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
    if (Msg == WM_GKRELLMCALLBACK && lParam == WM_LBUTTONUP) {
        SetForegroundWindow(GDK_WINDOW_HWND(gkrellm_get_top_window()->window));
    }
    if (Msg == WM_GKRELLMCALLBACK && lParam == WM_RBUTTONUP) {
        int ret;
        POINT pt;

        HMENU sysMenu = LoadMenu(GetModuleHandle(NULL), MAKEINTRESOURCE(IDR_MENU2));
        HMENU sysMenuPopup = GetSubMenu(sysMenu, 0);
        SetForegroundWindow(GDK_WINDOW_HWND(gkrellm_get_top_window()->window));
        GetCursorPos(&pt);
        ret = TrackPopupMenu(sysMenuPopup, TPM_RETURNCMD | TPM_RIGHTBUTTON, pt.x, pt.y, 0, GDK_WINDOW_HWND(gkrellm_get_top_window()->window), NULL);
        if (ret == ID_FILE_EXIT) {
            gtk_main_quit();
        }
        if (ret == ID_FILE_CONFIG) {
            create_config_window();
        }
        DestroyMenu(sysMenu);
        DestroyMenu(sysMenuPopup);
    }
    if (Msg == WM_SIZE) {
        if (_GK.withdrawn) {
	    	HWND hwnd = FindWindowEx(NULL, NULL, "BControl", "BSlitWindow");
            PostMessage(hwnd, BM_SLITMESSAGE, BSM_UPDATEPOSITIONS, 0);
            InvalidateRgn(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), NULL, FALSE);
        }
    }

    return CallWindowProc((WNDPROC) oldval, hWnd, Msg, wParam, lParam);
}

void
gkrellm_winop_options(gint argc, gchar **argv)
{
    NOTIFYICONDATA nid;

    // get gtk window procedure and set new one
    oldval = GetWindowLong(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), GWL_WNDPROC);
    SetWindowLong(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), GWL_WNDPROC, (LONG) newWndProc);

    // Get rid of task list icon
    SetWindowLong(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), GWL_EXSTYLE, WS_EX_TOOLWINDOW);

    // Create System Tray Icon
    WM_GKRELLMCALLBACK = RegisterWindowMessage(TEXT("GKrellMCallback"));

    nid.cbSize = sizeof(NOTIFYICONDATA);                
    nid.hWnd = GDK_WINDOW_HWND(gkrellm_get_top_window()->window);
    nid.uID = 1;   
    nid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
    nid.uCallbackMessage = WM_GKRELLMCALLBACK;                                                                               
    strcpy(nid.szTip,"GKrellM for Windows");
    nid.hIcon = LoadIcon(GetModuleHandle(NULL), MAKEINTRESOURCE(IDI_ICON3));
    Shell_NotifyIcon(NIM_ADD, &nid);

    if (_GK.on_top) {
        // set stay on top flag if requested
        SetWindowPos(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
    }
    if (_GK.withdrawn) {
        // put in slit in bluebox
		HWND hwnd = FindWindowEx(NULL, NULL, "BControl", "BSlitWindow");
		SetProp(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), "BSlitControl", (HANDLE)1);
		if (IsWindow(hwnd))
		{
			SendMessage(hwnd, BM_SLITMESSAGE, BSM_ADDWINDOW, (LPARAM) GDK_WINDOW_HWND(gkrellm_get_top_window()->window));
            SetWindowPos(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
            gdk_window_move(gkrellm_get_top_window()->window, 0, 0);
			_GK.x_position = 0;
			_GK.y_position = 0;
			_GK.position_valid = TRUE;
    	    
            SetWindowLong(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), GWL_USERDATA, 0x49474541);
    	    
            PostMessage(hwnd, BM_SLITMESSAGE, BSM_UPDATEPOSITIONS, 0);
            InvalidateRgn(GDK_WINDOW_HWND(gkrellm_get_top_window()->window), NULL, FALSE);
		}
    } 
}

void
gkrellm_winop_withdrawn(void)
    {
	}

void
gkrellm_winop_place_gkrellm(gchar *geom)
    {
		gint newX = _GK.x_position;
		gint newY = _GK.y_position;

		// parse the command line
		// +x+y or -x+y or +x-y or -x-y

		gint startx = -1, starty = -1, endx = -1, endy = -1;
		gint w_gkrell, h_gkrell;
		gint stringSize = strlen(geom);
		gint i;
		gint xsign = 1, ysign = 1;
		gchar* part;

		for (i = 0; i < stringSize; i++) {
			if (geom[i] != '+' && geom[i] != '-') {
				if (startx == -1) {
					startx = i;
				}
				if (starty == -1 && endx != -1) {
					starty = i;
				}
			}
			else {
				if (startx != -1 && endx == -1) {
					endx = i - 1;
					if (geom[i] == '-') {
						xsign = -1;
					}
				}
				if (starty != -1 && endy == -1) {
					endy = i - 1;
					if (geom[i] == '-') {
						ysign = -1;
					}
				}
			}
		}

		if (starty != -1 && endy == -1) {
			endy = stringSize - 1;
		}

		w_gkrell = _GK.chart_width + _GK.frame_left_width + _GK.frame_right_width;
		h_gkrell = _GK.monitor_height + _GK.total_frame_height;

		if (startx >= 0 && startx <= endx && endx >= 0) {
			part = malloc(sizeof(gchar) * (endx - startx + 1 + 1));
			for (i = 0; i < endx - startx + 1; i++) {
				part[i] = geom[i + startx];
			}
			part[i] = '\0';
			newX = atoi(part);
			if (xsign == -1) {
				newX = _GK.w_display - w_gkrell + newX;
			}
			free(part);
		}
		if (starty >= 0 && starty <= endy && endy >= 0) {
			part = malloc(sizeof(gchar) * (endy - starty + 1 + 1));
			for (i = 0; i < endy - starty + 1; i++) {
				part[i] = geom[i + starty];
			}
			part[i] = '\0';
			newY = atoi(part);
			if (ysign == -1) {
				newY = _GK.h_display - h_gkrell + newY;
			}
		}

		if (newX >= 0 && newX < _GK.w_display - 10
			&& newY >= 0 && newY < _GK.h_display - 25) {
			gdk_window_move(gkrellm_get_top_window()->window, newX, newY);
			_GK.y_position = newY;
			_GK.x_position = newX;
		}
	_GK.position_valid = TRUE;
	}

void
gkrellm_winop_flush_motion_events(void)
	{
	}

gboolean
gkrellm_winop_updated_background(void)
	{
	return FALSE;
	}

void  gkrellm_winop_update_struts(void) 
	{
	}

gboolean
gkrellm_winop_draw_rootpixmap_onto_transparent_chart(GkrellmChart *cp)
	{
	return FALSE;
	}

gboolean
gkrellm_winop_draw_rootpixmap_onto_transparent_panel(GkrellmPanel *p)
	{
	return FALSE;
	}

void
gkrellm_winop_apply_rootpixmap_transparency(void)
	{
	}

void
gkrellm_winop_state_skip_taskbar(gboolean state)
	{
	}

void
gkrellm_winop_state_skip_pager(gboolean state)
	{
	}

void
gkrellm_winop_state_above(gboolean state)
	{
	}

void
gkrellm_winop_state_below(gboolean state)
	{
	}
