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

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


extern int terminal_width, terminal_height;

void text_write_area (int, int, int, int);
void cursor_move (int, int);
void cursor_get_position (int*, int*);


int region_top, region_bottom;
#ifdef JUMP_SCROLL
int scroll_delayed = 0;
#endif


#ifndef JUMP_SCROLL
void scroll_up (int count)
{
	debug (DEBUG_FUNCTION, "called with args (count=%d)", count);
	if (region_bottom == terminal_height && region_top == 0) {
		history_scroll_up (count);
		render_scroll_up (count);
	} else {
		history_scroll_up_region (region_top, region_bottom, count);
		render_scroll_up_region (region_top, region_bottom, count);
	}
	text_write_area (0, region_bottom-count, terminal_width, count);
	debug (DEBUG_FUNCTION, "Leaving");
}

#else
/* This function must be called before the number of differed scrollups has reached
   the number of lines in the scrolling region. This way every line can be seen
   by the user. It must of course be called before changing the scrolling region.
   And whenever an escape sequence causes the area above the current cursor
   position to be modified...
   If we someday do  not call render_scroll_up_region() anymore, and redraw
   everything instead, this last condition will be gone
*/
void scroll_up_resync()
{
	int tmp;

	debug (DEBUG_FUNCTION, "called with no args");
	if (scroll_delayed) {
		render_scroll_up_region(region_top, region_bottom, scroll_delayed);
		/* text_write_area() writes nothing if scroll_delayed != 0 */
		tmp = scroll_delayed;
		scroll_delayed = 0;
		text_write_area(0, region_bottom - tmp - 1,
		                terminal_width, tmp + 1);
		render_flush_area(0, region_bottom - tmp - 1,
		                  terminal_width, tmp + 1);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}

void scroll_up(int count)
{
	debug (DEBUG_FUNCTION, "called with args (count=%d)", count);
	while (count--) {
		if (region_bottom == terminal_height && region_top == 0) {
			history_scroll_up(1);
		} else {
			history_scroll_up_region (region_top, region_bottom, 1);
		}
		scroll_delayed++;
		if (scroll_delayed >= region_bottom - region_top) {
			scroll_up_resync();
		}
	}
	debug (DEBUG_FUNCTION, "Leaving");
}
#endif

void scroll_down (int count)
{
	debug (DEBUG_FUNCTION, "called with args (count=%d)", count);
#ifdef JUMP_SCROLL
	scroll_up_resync();
#endif
	history_scroll_down_region (region_top, region_bottom, count);
	render_scroll_down_region (region_top, region_bottom, count);
	text_write_area (0, region_top, terminal_width, count);
	debug (DEBUG_FUNCTION, "Leaving");
}

void scroll_change_region (int top, int bottom)
{
	int x, y;

	debug (DEBUG_FUNCTION, "called with args (top=%d, bottom=%d)", top, bottom);
#ifdef JUMP_SCROLL
	scroll_up_resync();
#endif
	region_top = top < 0 ? 0 : top;
	region_top = top > terminal_height ? terminal_height : top;
	region_bottom = bottom < region_top ? region_top : bottom;
	region_bottom = bottom > terminal_height ? terminal_height : bottom;
	cursor_get_position(&x, &y);
	if (y < region_top) {
		cursor_move(x, region_top);
	}
	if (y > region_bottom) {
		cursor_move(x, region_bottom);
	}
	debug (DEBUG_FUNCTION, "Leaving");
}
