/*******************************************************************************

  Copyright(c) 2003-2004 Aurelien Reynaud.

  This program is free software; you can redistribute it and/or modify it
  under the terms of the GNU General Public 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.

  You should have received a copy of the GNU General Public License along with
  this program; if not, write to the Free Software Foundation, Inc., 59
  Temple Place - Suite 330, Boston, MA  02111-1307, USA.

  The full GNU General Public License is included in this distribution in the
  file called COPYING.

*******************************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "ggiterm.h"
#include "debug.h"


/* GGI */
#include <ggi/ggi.h>
#ifdef HAVE_LIBGGIWMH
# include <ggi/wmh.h>
#endif

/* Global variables */
ggi_visual_t vis;
int visible_w, visible_h;
int current_origin;
ggi_pixel color[16];
ggi_color palette[16] = {
	{ 0x0000, 0x0000, 0x0000, 0xFFFF },
	{ 0xB000, 0x0000, 0x0000, 0xFFFF },
	{ 0x0000, 0xB000, 0x0000, 0xFFFF },
	{ 0xB000, 0xB000, 0x0000, 0xFFFF },
	{ 0x0000, 0x0000, 0xB000, 0xFFFF },
	{ 0xB000, 0x0000, 0xB000, 0xFFFF },
	{ 0x0000, 0xB000, 0xB000, 0xFFFF },
	{ 0xB000, 0xB000, 0xB000, 0xFFFF },
	
	{ 0x1000, 0x1000, 0x1000, 0xFFFF },
	{ 0xFFFF, 0x0000, 0x0000, 0xFFFF },
	{ 0x0000, 0xFFFF, 0x0000, 0xFFFF },
	{ 0xFFFF, 0xFFFF, 0x0000, 0xFFFF },
	{ 0x0000, 0x0000, 0xFFFF, 0xFFFF },
	{ 0xFFFF, 0x0000, 0xFFFF, 0xFFFF },
	{ 0x0000, 0xFFFF, 0xFFFF, 0xFFFF },
	{ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF }
	};


#ifdef DEBUG
void render_grid (int step_x, int step_y)
{
	int x, y;
	
	debug (DEBUG_FUNCTION, "called with no args");
	
	ggiSetGCForeground (vis, color[2]);
	for (x = 0; x < visible_w; x += step_x) {
		ggiDrawVLine (vis, x, 0, visible_h);
	}
	for (y = 0; y < visible_h; y += step_y) {
		ggiDrawHLine (vis, 0, y, visible_w);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}
#endif /* DEBUG */


void render_map_colors ()
{
	int i;
	
	debug (DEBUG_FUNCTION, "called with no args");
	for (i=0; i<16; i++) color[i] = ggiMapColor (vis, palette+i);
	debug (DEBUG_FUNCTION, "Leaving");
}


int render_init (char *mode, char *title, int *width_px, int *height_px)
{
	int err, render_method = RENDER_COPYBOX;
	ggi_mode sug_mode, final_mode;
	ggi_flags flags;
	/*const ggi_pixelformat *mypixelformat;*/
	char dummy[64];

	debug (DEBUG_FUNCTION, "called with no args");

	if (ggiInit () < 0) {
		error ("Cannot initalize LibGGI!");
		debug (DEBUG_FUNCTION, "Leaving");
		return RENDER_ERROR;
	}
	debug (DEBUG_INIT, "LibGGI initialization successful");

	vis = ggiOpen (NULL);
	if (vis == NULL) {
		error ("Couldn't open default visual!");
		ggiExit ();
		debug (DEBUG_FUNCTION, "Leaving");
		return RENDER_ERROR;
	}
	debug (DEBUG_INIT, "Default visual opened");
	
	ggiSetFlags (vis, GGIFLAG_ASYNC);
	flags = ggiGetFlags (vis);
	if (flags & GGIFLAG_ASYNC) {
		debug (DEBUG_INIT, "Asynchronous mode: ON");
	} else {
		debug (DEBUG_INIT, "Asynchronous mode: OFF");
	}
	
	/* Get the default mode */
	err = ggiParseMode(mode, &sug_mode);
	if (err) {
		error ("Unable to parse mode");
		ggiExit ();
		debug (DEBUG_FUNCTION, "Leaving");
		return RENDER_ERROR;
	}
	if (GT_SCHEME(sug_mode.graphtype) == GT_TEXT) {
		error ("A graphics mode is mandatory");
		ggiExit ();
		debug (DEBUG_FUNCTION, "Leaving");
		return RENDER_ERROR;
	}
	err = ggiCheckMode (vis, &sug_mode);
	/*err = ggiCheckGraphMode (vis, GGI_AUTO, GGI_AUTO, GGI_AUTO, GGI_AUTO,
				 GT_AUTO, &sug_mode);*/
	if (err) {
		error ("Mode not available!");
		ggiExit ();
		debug (DEBUG_FUNCTION, "Leaving");
		return RENDER_ERROR;
	}
	debug (DEBUG_INIT, "Mode check succeeded");
	ggiSPrintMode (dummy, &sug_mode);
	debug (DEBUG_INIT, "Suggested mode is: %s", dummy);
	debug (DEBUG_INIT,
	       "Physical resolution: %dx%d mm",
	       sug_mode.size.x, sug_mode.size.y);
	visible_w = sug_mode.visible.x;
	visible_h = sug_mode.visible.y;
	/*virtual_w = sug_mode.virt.x;
	virtual_h = sug_mode.virt.y;*/

	final_mode = sug_mode;
	
#ifdef FORCE_RENDER_COPYBOX
	debug (DEBUG_INIT, "CopyBox rendering forced at compile time");
#else
	/* Try virtual height = visible_height*2 to enable fast scrolling */
	debug (DEBUG_INIT, "Negociating mode suitable for SetOrigin rendering");
	err = ggiCheckGraphMode (vis, visible_w, visible_h, visible_w, visible_h*2,
				 GT_AUTO, &final_mode);
	if (!err) {
		debug (DEBUG_INIT, "Success: SetOrigin rendering possible");
		/*virtual_h = final_mode.virt.y;*/
		render_method = RENDER_SETORIGIN;
	} else {
		debug (DEBUG_INIT, "Failed: Back to CopyBox rendering mode");
		final_mode = sug_mode;
	}
	ggiSPrintMode (dummy, &final_mode);
	debug (DEBUG_INIT, "Negociated mode is: %s", dummy);
#endif

#ifdef HAVE_LIBGGIWMH
	err = ggiWmhInit ();
	if (!err) {
		debug (DEBUG_INIT, "Libggiwmh initialized");
		err = ggiWmhAttach (vis);
		if (!err) {
			debug (DEBUG_INIT, "Attached WMH extension");
		} else {
			debug (DEBUG_INIT, "Couldn't attach WMH extension");
		}
	} else {
		debug (DEBUG_INIT, "Couldn't initialize libggiwmh");
	}
#else
	debug (DEBUG_INIT, "Libggiwmh support not compiled in");
#endif
	
	debug (DEBUG_INIT, "Setting graphics mode");
	err = ggiSetMode (vis, &final_mode);
	if (err) {
		error ("Set mode failed although check was OK!");
		ggiExit ();
		debug (DEBUG_FUNCTION, "Leaving");
		return RENDER_ERROR;
	}
	
	/*mypixelformat = ggiGetPixelFormat (vis);
	debug (DEBUG_INIT, "Pixel depth = %d",
	                   mypixelformat->depth);
	debug (DEBUG_INIT, "Pixel size = %d",
	                   mypixelformat->size);
	debug (DEBUG_INIT, "Pixel red shift = %d",
	                   mypixelformat->red_shift);
	debug (DEBUG_INIT, "Pixel red mask = 0x%08lX",
	                   (unsigned long)mypixelformat->red_mask);
	debug (DEBUG_INIT, "Pixel green shift = %d",
	                   mypixelformat->green_shift);
	debug (DEBUG_INIT, "Pixel green mask = 0x%08lX",
	                   (unsigned long)mypixelformat->green_mask);
	debug (DEBUG_INIT, "Pixel blue shift = %d",
	                   mypixelformat->blue_shift);
	debug (DEBUG_INIT, "Pixel blue mask = 0x%08lX",
	                   (unsigned long)mypixelformat->blue_mask);
	debug (DEBUG_INIT, "Pixel alpha shift = %d",
	                   mypixelformat->alpha_shift);
	debug (DEBUG_INIT, "Pixel alpha mask = 0x%08lX",
	                   (unsigned long)mypixelformat->alpha_mask);
	debug (DEBUG_INIT, "Pixel clut shift = %d",
	                   mypixelformat->clut_shift);
	debug (DEBUG_INIT, "Pixel clut mask = 0x%08lX",
	                   (unsigned long)mypixelformat->clut_mask);
	debug (DEBUG_INIT, "Pixel fg shift = %d",
	                   mypixelformat->fg_shift);
	debug (DEBUG_INIT, "Pixel fg mask = 0x%08lX",
	                   (unsigned long)mypixelformat->fg_mask);
	debug (DEBUG_INIT, "Pixel bg shift = %d",
	                   mypixelformat->bg_shift);
	debug (DEBUG_INIT, "Pixel bg mask = 0x%08lX",
	                   (unsigned long)mypixelformat->bg_mask);
	debug (DEBUG_INIT, "Pixel texture shift = %d",
	                   mypixelformat->texture_shift);
	debug (DEBUG_INIT, "Pixel texture mask = 0x%08lX",
	                   (unsigned long)mypixelformat->texture_mask);*/

	debug (DEBUG_INIT, "Setting color palette");
	render_map_colors ();
	
	ggiSetGCForeground (vis, color[0]);
	ggiFillscreen (vis);

	*width_px  = visible_w;
	*height_px = visible_h;
	
#ifdef HAVE_LIBGGIWMH
	ggiWmhSetTitle (vis, title);
	ggiWmhSetIconTitle (vis, title);
	/*err = ggiWmhGetRootSize (vis, &rootw, &rooth, GGIWMH_ROOTWIN_DEFAULT);
	debug (DEBUG_INIT, "Root window size is %dx%d", rootw, rooth);
	err = ggiWmhAllowResize (vis, cell_w, cell_h, rootw, rooth, cell_w, cell_h);
	if (!err) {
		debug (DEBUG_INIT, "Resize feature: AVAILABLE");
	} else {
		debug (DEBUG_INIT, "Resize feature: NOT AVAILABLE");
	}*/
#endif

	current_origin = 0;

	debug (DEBUG_FUNCTION, "Leaving");
	return render_method;
}

void render_exit (void)
{
	debug (DEBUG_FUNCTION, "called with no args");
#ifdef HAVE_LIBGGIWMH
	ggiWmhDetach (vis);
	ggiWmhExit ();
#endif
	ggiClose (vis);
	ggiExit ();
	debug (DEBUG_FUNCTION, "Leaving");
}
