/*
###
### This file is part of
###
###                        TurboLinux  ZWinPro
###
###                 Copyright (C) 1999-2000 TurboLinux, Inc.
###                        All Rights Reserved
### Distributed under the terms of the GNU General Public License (GPL)
###
###
### Authors:     TurboLinux Chinese Development Team:
###              Justin Yu   <justiny@turbolinux.com.cn>
###              Sean Chen   <seanc@turbolinux.com.cn>
###              Daniel Fang <danf@turbolinux.com.cn>
###
*/

//OffTheSpot implementation
//Tested for rxvt
//OffTheSpot is a bit tricky, by usual, the applications provide
//the status area and preedit area, the IM server will display
//status of current IM and preedit string and candidate list.
//but the application often has problem in drawing into other
//applications' window
//To start rxvt in off-the-spot style, please type in
//        rxvt -fn 8x16 -im Chinput -km gb(big5) -pt OffTheSpot

//Here I use the reparent method to embed the status and preedit
//window into the application. For every IC, if it is the offspot
//input style, these two windows are created.(If use two common windows,
//the windows maybe crashed if the application exit abnormally).

//For qt/kde applications, the specified offthespot areas has problem
//It should be specified by the IM server. To invoke this mode,
//please set the resource file /usr/lib/ZWinPro/Chinput.ad or
//~/.chinput to
//chinput.areamode        =       SERVER
//In such case, Chinput will try to find the top window of the application
//and reparent the preedit and status window to the lower-bottom
//of application's window.
//
//To start qt/kde apps in offthespot style, please add command line
//parameters "-inputstyle offthespot", the default style is overthespot.
//e.g.
//      kedit -inputstyle offthespot
//      ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//FIXME
//For qt-1.44/kde-1.x applications, chinput.areamode should be set to SERVER
//mode. 

#include "all.h"

#define max(a, b) ((a) > (b) ? (a) : (b))
static int preedit_width = 0;

static void chinput_offspot_reparent_windows (IC *ic)
{
	//put the status and preedit window in the
	//client window...
	if (flag_client == HZSERVER_AREAMODE_CLIENT)
	{
		//reparent according to client settings
		if (ic->client_win)
		{
			XReparentWindow(display, ic->status_win, ic->client_win,
					ic->sts_attr.area.x, ic->sts_attr.area.y);
			XReparentWindow(display, ic->preedit_win,ic->client_win,
					ic->pre_attr.area.x, ic->pre_attr.area.y);
		}
	}
	else
	{
		XWindowAttributes xwa;
		Window win;

		win = chinput_util_find_top_win(ic->client_win);
		if (!win)
			return;

		XGetWindowAttributes(display, win, &xwa);

		//reparent in the top window by IM server.
		XReparentWindow(display, ic->status_win, win,
				0, xwa.height - FONT_HEIGHT);
		XReparentWindow(display, ic->preedit_win, win,
				AREA_CHARS * FONT_WIDTH / 2, xwa.height - FONT_HEIGHT);
	}
}

static void chinput_offspot_move_resize_window (IC *ic)
{
	if (flag_client == HZSERVER_AREAMODE_CLIENT)
	{
		XMoveResizeWindow(display, ic->status_win,
				ic->sts_attr.area.x,
				ic->sts_attr.area.y,
				max(ic->sts_attr.area.width, 
				ic->sts_attr.area_needed.width),
				ic->sts_attr.area.height);
		XMoveResizeWindow(display, ic->preedit_win, 
				ic->pre_attr.area.x,
				//ic->sts_attr.area.x + max(ic->sts_attr.area.width,
							//ic->sts_attr.area_needed.width),
				ic->pre_attr.area.y,
				max(ic->pre_attr.area.width, 
				ic->pre_attr.area_needed.width),
				ic->pre_attr.area.height);
	}
	else
	{
		//The server will process the area window position
		//finding the geometry of the top window and reparent
		//the area windows in the lower left corner
		//The area will be 16 pixel in height and fill out
		//the bottom line of the top window.

		//get position in realtime
		XWindowAttributes xwa;
		Window win;

		win = chinput_util_find_top_win(ic->client_win);
		if (!win)
			return;
		XGetWindowAttributes(display, win, &xwa);

		//record
		preedit_width = xwa.width - AREA_CHARS * FONT_WIDTH / 2;

		XMoveResizeWindow(display, ic->status_win, 
				0, xwa.height - FONT_HEIGHT,
				AREA_CHARS * FONT_WIDTH / 2, FONT_HEIGHT);
		XMoveResizeWindow(display, ic->preedit_win, 
				AREA_CHARS * FONT_WIDTH / 2,
				xwa.height - FONT_HEIGHT,
				xwa.width - AREA_CHARS * FONT_WIDTH / 2, FONT_HEIGHT);
	}
}

// Draw small triangle for caret position
static void chinput_offspot_draw_caret (IC *ic, int pos)
{
	//draw the caret
	int caretx = pos  * 8;
	int carety = FONT_ASCENT;
	XPoint point[3];
	point[0].x = caretx + 4;
	point[0].y = carety - 4;
	point[1].x = point[0].x - 4;
	point[1].y = carety + 1;
	point[2].x = point[0].x + 4;
	point[2].y = carety + 1;
	//MyDrawString2(ic->preedit_win,
	//offspot_gc,offspot_gbgc,offspot_big5gc, offspot_big5hkscsgc, 
	//caretx, carety, "|", 1);
	XFillPolygon(display, ic->preedit_win, offspot_gc,
			point, 3, Convex, CoordModeOrigin);
}

static void chinput_offspot_preedit_draw (char *s, int len, int pos)
{
	IC *ic = (IC *)chinput_find_ic (last_icid);

	if (!ic)
		return;

	//clear the preedit area
	if (flag_client == HZSERVER_AREAMODE_CLIENT)
		XFillRectangle (display, ic->preedit_win, offspot_bggc, 0, 0,
				max(ic->pre_attr.area.width, ic->pre_attr.area_needed.width),
				ic->pre_attr.area.height);
	else if (flag_client == HZSERVER_AREAMODE_SERVER)
		XFillRectangle(display, ic->preedit_win, offspot_bggc, 0, 0,
				preedit_width, FONT_HEIGHT);

	//draw the string in the preedit area
	//chinput_util_draw_str(ic->preedit_win, HZServer.lightGC, 0, FONT_ASCENT, s, len);
//	MyDrawString2 (ic->preedit_win, offspot_gc,
//			offspot_gbgc, offspot_big5gc, offspot_big5hkscsgc, 
//			0, FONT_ASCENT, s, len);
	chinput_util_draw_str(ic->preedit_win, offspot_gc, 0, FONT_ASCENT, s, len);

	chinput_offspot_draw_caret (ic, pos);
}

void chinput_offspot_status_draw (void)
{
	char buf[128];
	IC *ic = (IC *)chinput_find_ic (last_icid);

	if (!ic)
		return;

	//only status area style supported
	if (!(ic->input_style & XIMStatusArea))
		return;

	chinput_offspot_move_resize_window (ic);
	if (ic->reparented)
	{
		chinput_offspot_map_windows ();
	}
	else
	{
		//if not reparented, init all first
		chinput_offspot_reparent_windows (ic);
		chinput_offspot_map_windows ();
		ic->reparented = 1;
	}

	//clear status area
	if (flag_client == HZSERVER_AREAMODE_CLIENT)
		XFillRectangle(display, ic->status_win, offspot_bggc, 0, 0,
				max(ic->sts_attr.area.width, ic->sts_attr.area_needed.width),
				ic->sts_attr.area.height);
	else if(flag_client == HZSERVER_AREAMODE_SERVER)
		XFillRectangle(display, ic->status_win, offspot_bggc, 0, 0,
				AREA_CHARS * FONT_WIDTH / 2, FONT_HEIGHT);
#ifdef IMLIB
	Imlib_paste_image(icon_id, im_chinput, ic->status_win, 0, 0, 16, 16);
#endif

	//draw preedit string and candidate string
	//in preedit window
	chinput_util_print_dbg_msg ("printing status for offspot\n");
	if(HZServer.encoding == HZSERVER_ENCODING_GB2312){
		strcpy(buf, "");
		if (flag_corner)
			strcat(buf, "¡¾È«");
		else
			strcat(buf, "¡¾°ë");
		if (flag_punct)
			strcat(buf, "£ï¡¿");
		else
			strcat(buf, " .¡¿");
		strcat(buf, chinputime[cur_inputmethod].namegb);
		strcat(buf, ": ");
	}
	if(HZServer.encoding == HZSERVER_ENCODING_GB18030){
		strcpy(buf, "");
		if (flag_corner)
			strcat(buf, "¡¾È«");
		else
			strcat(buf, "¡¾°ë");
		if (flag_punct)
			strcat(buf, "£ï¡¿");
		else
			strcat(buf, " .¡¿");
		strcat(buf, chinputime[cur_inputmethod].namegb);
		strcat(buf, ": ");
	}
	// Again, for big5 and big5hkscs
	else
	{
		strcpy (buf, "");
		if (flag_corner)
			strcat(buf, "¡i¥þ");
		else
			strcat(buf, "¡i¥b");
		if (flag_punct)
			strcat(buf, "¡³¡j");
		else
			strcat(buf, "¡E¡j");
		strcat(buf, chinputime[cur_inputmethod].namebig5);
		strcat(buf, ": ");
	}
	chinput_util_print_dbg_msg ("pirnt candidate for offspot\n");
	chinput_util_draw_str(ic->status_win, offspot_gc, 16, FONT_ASCENT, buf, strlen(buf));
//	MyDrawString2(ic->status_win, offspot_gc,
//			offspot_gbgc, offspot_big5gc, offspot_big5hkscsgc, 
//			16, FONT_ASCENT, buf, strlen(buf));
}

void chinput_offspot_map_windows (void)
{
	IC *ic = (IC *)chinput_find_ic (last_icid);

	if(!ic)
		return;

	XMapRaised (display, ic->status_win);
	XMapRaised (display, ic->preedit_win);
}

void chinput_offspot_hide_windows (void)
{
	IC *ic = (IC *)chinput_find_ic (last_icid);

	if (!ic)
		return;

	XUnmapWindow(display, ic->status_win);
	XUnmapWindow(display, ic->preedit_win);
}

void chinput_offspot_hide_status_window (IC *ic)
{
	if (!ic)
		return;
	XUnmapWindow(display, ic->status_win);
}

void chinput_offspot_flush (void)
{
	char mbuf1[256], mbuf2[256], mbuf[256];
	//if(flag_refresh)return;
	bzero(mbuf1, 256);
	bzero(mbuf2, 256);

	//draw status area
	//The contents of status area contains
	//	1. corner mode
	//	2. punctuation mode
	//	3. input method
	chinput_offspot_status_draw ();

	if (flag_english)
		strcpy(mbuf1, input_buf);
	else
		IMM_GetInputDisplay (chinput_imm, mbuf1, sizeof (mbuf1));
       	IMM_GetSelectDisplay (chinput_imm, mbuf2, sizeof (mbuf2));
	if (strlen(mbuf2) == 0)
		flag_found = 0;
	else
		flag_found = 1;
	sprintf (mbuf, "%s  %s", mbuf1, mbuf2);
	chinput_offspot_preedit_draw  (mbuf, strlen(mbuf), strlen(mbuf1));
}
