/*
 * ux_screen.c - Unix interface, screen manipulation
 *
 * This file is part of Frotz.
 *
 * Frotz 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.
 *
 * Frotz 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
 */

#define __UNIX_PORT_FILE

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifdef USE_NCURSES_H
#include <ncurses.h>
#else
#include <curses.h>
#endif

#include "ux_frotz.h"

/*
 * os_erase_area
 *
 * Fill a rectangular area of the screen with the current background
 * colour. Top left coordinates are (1,1). The cursor does not move.
 *
 */

void os_erase_area (int top, int left, int bottom, int right, int win)
{
	int y, x, i, j;

	/* Catch the most common situation and do things the easy way */
	if ((win == -2) || ((top == 1) && (bottom == h_screen_rows) &&
			    (left == 1) && (right == h_screen_cols))) {
#ifdef COLOR_SUPPORT
		/* Only set the curses background when doing an erase, so it won't
		 * interfere with the copying we do in os_scroll_area.
		 */
		bkgdset(u_setup.current_color | ' ');
		erase();
		bkgdset(0);
#else
		erase();
#endif
	} else {
		/* Sigh... */
		int saved_style = u_setup.current_text_style;
		os_set_text_style(u_setup.current_color);
		getyx(stdscr, y, x);
		top--; left--; bottom--; right--;
		for (i = top; i <= bottom; i++) {
			move(i, left);
			for (j = left; j <= right; j++)
				addch(' ');
		}
		move(y, x);
		os_set_text_style(saved_style);
	}
}/* os_erase_area */

/*
 * os_scroll_area
 *
 * Scroll a rectangular area of the screen up (units > 0) or down
 * (units < 0) and fill the empty space with the current background
 * colour. Top left coordinates are (1,1). The cursor stays put.
 *
 */

void os_scroll_area (int top, int left, int bottom, int right, int units)
{
	top--; left--; bottom--; right--;

	if ((left == 0) && (right == h_screen_cols - 1)) {
		static int old_scroll_top = 0;
		static int old_scroll_bottom = 0;

		if (!((old_scroll_top == top) && (old_scroll_bottom == bottom))) {
			old_scroll_top = top; old_scroll_bottom = bottom;
			setscrreg(top, bottom);
		}
		scrollok(stdscr, TRUE);
		scrl(units);
		scrollok(stdscr, FALSE);
	} else {
		int row, col, x, y;
		chtype ch;

		getyx(stdscr, y, x);
		/* Must turn off attributes during copying.  */
		attrset(0);
		if (units > 0) {
			for (row = top; row <= bottom - units; row++)
				for (col = left; col <= right; col++) {
					ch = mvinch(row + units, col);
					mvaddch(row, col, ch);
				}
		} else if (units < 0) {
			for (row = bottom; row >= top - units; row--)
				for (col = left; col <= right; col++) {
					ch = mvinch(row + units, col);
					mvaddch(row, col, ch);
				}
		}
		/* Restore attributes.  */
		os_set_text_style(u_setup.current_text_style);
		move(y, x);
	}
	if (units > 0)
		os_erase_area(bottom - units + 2, left + 1, bottom + 1, right + 1, -1);
	else if (units < 0)
		os_erase_area(top + 1, left + 1, top - units, right + 1, -1);
}/* os_scroll_area */

/*
 * os_window_height
 *
 * Called when the height of a window is changed.
 *
 */
void os_window_height (int x, int y)
{
	/* Do nothing */
}


/*
 * os_wrap_window
 *
 * Return non-zero if the window should have text wrapped.
 *
 */
int os_wrap_window (int x)
{
	return 1;
}

/*
 * os_from_true_cursor
 *
 * Given a true colour, return an appropriate colour index.
 * This is pretty brain-dead, and just makes it 3-bit true-color first.
 *
 */
int os_from_true_colour(zword colour)
{
	if (colour == 0xFFFE)
		return 0;
	else if (colour == 0xFFFF)
		return 1;
	else {
		int r = colour & 0x001F;
		int g = colour & 0x03E0;
		int b = colour & 0x7C00;
		int index = (r ? 4 : 0) | (g ? 2 : 0) | (b ? 1 : 0);

		switch (index) {
		case 0: return 2;
		case 1: return 6;
		case 2: return 4;
		case 3: return 8;
		case 4: return 3;
		case 5: return 7;
		case 6: return 5;
		case 7: return 9;
		default: return 1; /* Can't happen */
		}
	}
}

/*
 * os_to_true_cursor
 *
 * Given a colour index, return the appropriate true colour.
 *
 */
zword os_to_true_colour(int index)
{
	switch (index) {
	case 0: return -2;
	case 1: return -1;
	case 2: return 0x0000;
	case 3: return 0x001D;
	case 4: return 0x0340;
	case 5: return 0x03BD;
	case 6: return 0x59A0;
	case 7: return 0x7C1F;
	case 8: return 0x77A0;
	case 9: return 0x7FFF;
	case 10: return 0x5AD6;
	case 11: return 0x4631;
	case 12: return 0x2D6B;
	default: return 0x0000;
	}
}

