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

  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"
#include "lowlevel.h"


/* We redefine ggiCopyBox() so that it always flushes the concerned region
   beforehand. This is because GGI does not garantee the serialization, and we
   need to be sure that the box we copy contains what was drawn into it */
#define ggiCopyBox(vis, x, y, w, h, nx, ny) {			\
	ggiFlushRegion ((vis), (x), (y), (w), (h));		\
	ggiCopyBox ((vis), (x), (y), (w), (h), (nx), (ny));	\
	}

/* External variables */
extern ggi_visual_t vis;
extern int cell_w, cell_h;
extern int visible_w, visible_h;
extern ggi_pixel color[];
extern int current_origin;

/* Global variables */
int setorigin_offset;
	
/* External functions */
int backend_write_char (int, int, wchar_t, int, int, int);


void setorigin_flash ()
{
	debug (DEBUG_FUNCTION, "called with no args");
	ggiSetGCForeground (vis, color[default_fgcolor]);
	ggiFillscreen (vis);
	ggiFlush (vis);
	ggiSetGCForeground (vis, color[default_bgcolor]);
	ggiFillscreen (vis);
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_write_char (int cursor_x, int cursor_y, wchar_t glyph, int fgcolor, int bgcolor, int underline)
{
	int x, y;
	
	debug (DEBUG_FUNCTION,
	       "called with args (cursor_x=%d, cursor_y=%d, glyph=0x%X, fgcolor=%d, bgcolor=%d, underline=%d",
	       cursor_x, cursor_y, (int)glyph, fgcolor, bgcolor, underline);
	x = cursor_x * cell_w;
	y = cursor_y * cell_h + current_origin;
	backend_write_char (x, y, glyph, fgcolor, bgcolor, underline);
	if (y > visible_h) {
		backend_write_char (x, y- setorigin_offset, glyph, fgcolor, bgcolor, underline);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_delete_chars (int cursor_x, int cursor_y, unsigned int nb_chars)
{
	int x, y;
	
	debug (DEBUG_FUNCTION,
	       "called with args (cursor_x=%d, cursor_y=%d, nb_chars=%d",
	       cursor_x, cursor_y, nb_chars);
	x = cursor_x * cell_w;
	y = cursor_y * cell_h + current_origin;
	ggiSetGCForeground (vis, color[default_bgcolor]);
	/* Copy area between current+nb_chars and EOL to current position */
	ggiCopyBox (vis,
			x+(nb_chars*cell_w), y,
			visible_w-x-(nb_chars*cell_w), cell_h,
			x, y);
	/* Then blank the nb_chars last cells */
	ggiDrawBox (vis,
	                visible_w-(nb_chars*cell_w), y,
	                nb_chars*cell_w, cell_h);
	/* Do the same offscreen */
	if (y > visible_h) {
		ggiCopyBox (vis,
				x+(nb_chars*cell_w), y - setorigin_offset,
				visible_w-x-(nb_chars*cell_w), cell_h,
				x, y - setorigin_offset);
		ggiDrawBox (vis,
		                visible_w-(nb_chars*cell_w), y - setorigin_offset,
		                nb_chars*cell_w, cell_h);
		}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_insert_chars (int cursor_x, int cursor_y, unsigned int nb_chars)
{
	int x, y;

	debug (DEBUG_FUNCTION,
	       "called with args (cursor_x=%d, cursor_y=%d, nb_chars=%d",
	       cursor_x, cursor_y, nb_chars);
	x = cursor_x * cell_w;
	y = cursor_y * cell_h + current_origin;
	ggiSetGCForeground (vis, color[default_bgcolor]);
	/* First, copy the rest of the line nb_chars to the right */
	ggiCopyBox (vis,
			x, y,
			visible_w-x, cell_h,
			x+(nb_chars*cell_w), y);
	/* Then blank the newly created char cells */
	ggiDrawBox (vis, x, y, nb_chars*cell_w, cell_h);
	if (y > visible_h) {
		ggiCopyBox (vis,
				x, y - setorigin_offset,
				visible_w-x, cell_h,
				x+(nb_chars*cell_w), y - setorigin_offset);
		ggiDrawBox (vis, x, y - setorigin_offset, nb_chars*cell_w, cell_h);
		}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_erase_chars (int cursor_x, int cursor_y, unsigned int nb_chars)
{
	int x, y;

	debug (DEBUG_FUNCTION,
	       "called with args (cursor_x=%d, cursor_y=%d, nb_chars=%d",
	       cursor_x, cursor_y, nb_chars);
	x = cursor_x * cell_w;
	y = cursor_y * cell_h + current_origin;
	ggiSetGCForeground (vis, color[default_bgcolor]);
	ggiDrawBox (vis, x, y, nb_chars*cell_w, cell_h);
	if (y > visible_h) {
		ggiDrawBox (vis, x, y - setorigin_offset, nb_chars*cell_w, cell_h);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_erase_line_from (int cursor_x, int cursor_y)
{
	int x, y;
	
	debug (DEBUG_FUNCTION,
	       "called with args (cursor_x=%d, cursor_y=%d",
	       cursor_x, cursor_y);
	x = cursor_x * cell_w;
	y = cursor_y * cell_h + current_origin;
	ggiSetGCForeground (vis, color[default_bgcolor]);
	ggiDrawBox (vis, x, y, visible_w-x, cell_h);
	if (y > visible_h) {
		ggiDrawBox (vis, x, y - setorigin_offset, visible_w-x, cell_h);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_erase_line_to (int cursor_x, int cursor_y)
{
	int w, y;

	debug (DEBUG_FUNCTION,
	       "called with args (cursor_x=%d, cursor_y=%d",
	       cursor_x, cursor_y);

	w = (cursor_x + 1) * cell_w;
	y = cursor_y * cell_h + current_origin;
	ggiSetGCForeground (vis, color[default_bgcolor]);
	ggiDrawBox (vis, 0, y, w, cell_h);
	if (y > visible_h) {
		ggiDrawBox (vis, 0, y - setorigin_offset, w, cell_h);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_erase_line (int cursor_y)
{
	int y;
	
	debug (DEBUG_FUNCTION, "called with args (cursor_y=%d", cursor_y);
	y = cursor_y * cell_h + current_origin;
	ggiSetGCForeground (vis, color[default_bgcolor]);
	ggiDrawBox (vis, 0, y, visible_w, cell_h);
	if (y > visible_h) {
		ggiDrawBox (vis, 0, y - setorigin_offset, visible_w, cell_h);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_erase_screen_from (int cursor_x, int cursor_y)
{
	int y;

	debug (DEBUG_FUNCTION,
	       "called with args (cursor_x=%d, cursor_y=%d",
	       cursor_x, cursor_y);
	setorigin_erase_line_from (cursor_x, cursor_y);
	/*y = cell_h * cursor_y + current_origin;*/
	y = cursor_y * cell_h + current_origin + cell_h;
	ggiSetGCForeground (vis, color[default_bgcolor]);
	/*ggiDrawBox (vis, 0, y+cell_h, visible_w, visible_h - y + current_origin - cell_h);*/
	ggiDrawBox (vis, 0, y, visible_w, visible_h - y + current_origin);
	while (y <= visible_h) y += cell_h;
	/*if (y > visible_h) {*/
	if (y >= (visible_h - visible_h%cell_h) - cell_h) {
		/*ggiDrawBox (vis, 0, y - (visible_h - visible_h%cell_h), visible_w, visible_h - y + current_origin - cell_h);*/
		ggiDrawBox (vis, 0, y - setorigin_offset, visible_w, current_origin - (y - setorigin_offset));
	}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_erase_screen_to (int cursor_x, int cursor_y)
{
	int y;
	
	debug (DEBUG_FUNCTION,
	       "called with args (cursor_x=%d, cursor_y=%d",
	       cursor_x, cursor_y);
	setorigin_erase_line_to (cursor_x, cursor_y);
	y = cursor_y * cell_h + current_origin;
	ggiSetGCForeground (vis, color[default_bgcolor]);
	ggiDrawBox (vis, 0, current_origin+0, visible_w, y - current_origin);
	if (y > setorigin_offset) {
		ggiDrawBox (vis, 0, 0, visible_w, y - setorigin_offset);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_erase_screen ()
{
	debug (DEBUG_FUNCTION, "called with no args");
	ggiSetGCForeground (vis, color[default_bgcolor]);
	ggiFillscreen (vis);
	debug (DEBUG_FUNCTION, "Leaving");
}

#ifndef JUMP_SCROLL
void setorigin_scroll_up (int count)
{
	debug (DEBUG_FUNCTION, "called with args (count=%d)", count);
	ggiSetGCForeground (vis, color[default_bgcolor]);
	while (count) {
		count--;
		if (current_origin + cell_h <= visible_h) {
			ggiDrawBox (vis,
			            0, current_origin+visible_h,
			            visible_w, cell_h*2);
			current_origin += cell_h;
			ggiSetOrigin (vis, 0, current_origin);
			ggiDrawBox (vis,
			            0, current_origin-cell_h,
			            visible_w, cell_h);
		} else {
			ggiDrawBox (vis,
			            0, current_origin,
			            visible_w, cell_h);
			current_origin = 0;
			ggiSetOrigin (vis, 0, current_origin);
		}
	}
	debug (DEBUG_FUNCTION, "Leaving");
}
#endif

void setorigin_scroll_up_region (int reg_top, int reg_bottom, int count)
{
	debug (DEBUG_FUNCTION,
	       "called with args (reg_top=%d, reg_bottom=%d, count=%d)",
	       reg_top, reg_bottom, count);
	ggiCopyBox (vis,
	            0, current_origin+(reg_top+count)*cell_h,
	            visible_w, (reg_bottom-reg_top-count)*cell_h,
	            0, current_origin+reg_top*cell_h);
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_scroll_down_region (int reg_top, int reg_bottom, int count)
{
	debug (DEBUG_FUNCTION,
	       "called with args (reg_top=%d, reg_bottom=%d, count=%d)",
	       reg_top, reg_bottom, count);
	ggiCopyBox (vis,
	            0, current_origin+reg_top*cell_h,
	            visible_w, (reg_bottom-reg_top-count)*cell_h,
	            0, current_origin+(reg_top+count)*cell_h);
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_flush ()
{
	debug (DEBUG_FUNCTION, "called with no args");
	ggiFlush (vis);
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_flush_area (int x, int y, int w, int h)
{
	debug (DEBUG_FUNCTION,
	       "called with args (x=%d, y=%d, w=%d, h=%d)", x, y, w, h);
	ggiFlushRegion (vis, x * cell_w, y * cell_h + current_origin, w * cell_w, h * cell_h);
	debug (DEBUG_FUNCTION, "Leaving");
}

void setorigin_prepare ()
{
	debug (DEBUG_FUNCTION, "called with no args");

	ggiSetOrigin (vis, 0, current_origin);
	setorigin_offset = visible_h - visible_h%cell_h + cell_h;
	
	debug (DEBUG_FUNCTION, "Leaving");
}
