/*
------------------------------------------------------------
   Kobo Deluxe - An enhanced SDL port of XKobo
------------------------------------------------------------
 * Copyright (C) 1995, 1996  Akira Higuchi
 * Copyright (C) 2001-2003, 2005-2007 David Olofson
 * 
 * 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.,
 * 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h>
#include <math.h>

#include "kobo.h"
#include "kobolog.h"
#include "screen.h"
#include "myship.h"
#include "radar.h"
#include "prefs.h"
#include "random.h"

/*---------------------------------------------------------------------
	radar_map_t
---------------------------------------------------------------------*/
radar_map_t::radar_map_t()
{
	w = MAP_SIZEX;
	h = MAP_SIZEY;
	pixel_core = 0;
	pixel_launcher = 0;
	pixel_hard = 0;
	pixel_bg = 0;
}


void radar_map_t::update(int x, int y, int force)
{
	int a = MAP_BITS(screen.get_map(x, y));
	if(IS_SPACE(a))
	{
		if(!force)
			return;
		foreground(pixel_bg);
	}
	else if(a & CORE)
		foreground(pixel_core);
	else if((a == U_MASK) || (a == R_MASK) || (a == D_MASK) || (a == L_MASK))
		foreground(pixel_launcher);
	else if((a & HIT_MASK))
		foreground(pixel_hard);
	point(x, y);
}


void radar_map_t::refresh(SDL_Rect *r)
{
	clear(r);
	SDL_Rect nr;
	if(!r)
	{
		nr.x = 0;
		nr.y = 0;
		nr.w = w;
		nr.h = h;
		r = &nr;
	}
	int i, j;
	for(i = r->x; i < r->w; i++)
		for(j = r->y; j < r->h; j++)
			update(i, j, 0);
}


/*---------------------------------------------------------------------
	radar_window_t
---------------------------------------------------------------------*/
radar_window_t::radar_window_t()
{
	_mode = RM_OFF;
	old_scrollradar = -1;
	xpos = -1;
	ypos = -1;
	xoffs = 0;
	yoffs = 0;
	time = 0;
	refresh_pos = 0;
}


void radar_window_t::update(int mx, int my)
{
	wmap->update(mx, my, 1);
	if(prefs->scrollradar == 1)
		return;	/* No instant updates in sweep mode! */
	SDL_Rect r;
	r.x = (mx - xoffs) & (MAP_SIZEX-1);
	r.y = (my - yoffs) & (MAP_SIZEY-1);
	r.w = r.h = 1;
	invalidate(&r);
}


void radar_window_t::update_player(int px, int py)
{
	SDL_Rect r;
	r.x = (px - pxoffs) & (MAP_SIZEX-1);
	r.y = (py - pyoffs) & (MAP_SIZEY-1);
	r.w = r.h = 1;
	invalidate(&r);
}


void radar_window_t::refresh(SDL_Rect *r)
{
	int t = SDL_GetTicks();
	clear(r);
	switch(_mode)
	{
	  case RM__REINIT:
	  case RM_OFF:
	  case RM_NOISE:
	  case RM_INFO:
		break;
	  case RM_SHOW:
		blit(0, 0, wmap);
		break;
	  case RM_RADAR:
		switch(prefs->scrollradar)
		{
		  case 0:
			blit(0, 0, wmap);
			break;
		  case 1:
			foreground(map_rgb(48, 192, 160));
			fillrect(0, refresh_pos - 1, wmap->w, 1);
			foreground(map_rgb(40, 160, 128));
			fillrect(0, refresh_pos - 2, wmap->w, 1);
			foreground(map_rgb(32, 128, 96));
			fillrect(0, refresh_pos - 3, wmap->w, 1);
			// Fallthrough!
		  case 2:
			blit(-xoffs, MAP_SIZEY - yoffs, wmap);
			blit(-xoffs, -yoffs, wmap);
			blit(MAP_SIZEX - xoffs, MAP_SIZEY - yoffs, wmap);
			blit(MAP_SIZEX - xoffs, -yoffs, wmap);
			break;
		}
		if(_mode != RM_SHOW)
		{
			foreground(map_rgb((t >> 1) & 255,
					120 + ((t >> 2) & 127),
					120 + ((t >> 2) & 127)));
			point((xpos - pxoffs) & (MAP_SIZEX - 1),
					(ypos - pyoffs) & (MAP_SIZEY - 1));
		}
		break;
	}
}


void radar_window_t::mode(radar_modes_t newmode)
{
	if(newmode == RM__REINIT)
		newmode = _mode;
	wmap->offscreen();
	wmap->pixel_core = wmap->map_rgb(255, 255, 128);
	wmap->pixel_hard = wmap->map_rgb(64, 128, 128);
	wmap->pixel_launcher = wmap->map_rgb(64, 200, 240);
	wmap->pixel_bg = wmap->map_rgb(32, 48, 64);
	wmap->background(wmap->pixel_bg);
	wmap->colorkey(wmap->pixel_bg);
	_mode = newmode;
	refresh_pos = 0;
	time = SDL_GetTicks();
	wmap->invalidate();
	invalidate();
}


void radar_window_t::set_scroll(int xs, int ys)
{
	xoffs = (xs + MAP_SIZEX / 2) & (MAP_SIZEX - 1);
	yoffs = (ys + MAP_SIZEY / 2) & (MAP_SIZEY - 1);
}


void radar_window_t::sweep(void)
{
	int start_y = refresh_pos;
	int ct = SDL_GetTicks();
	int t = ct - time;
	int end_y = t / 8;
	if((t < 0) || (end_y >= wmap->h))
	{
		end_y = wmap->h;
		time = ct;
		refresh_pos = 0;
		set_scroll(xpos, ypos);
		platched = 0;
	}
	else
		refresh_pos = end_y;
	if(!platched)
		if(refresh_pos > ((ypos - pyoffs) & (MAP_SIZEY - 1)))
		{
			pxoffs = xoffs;
			pyoffs = yoffs;
			platched = 1;
		}
	SDL_Rect r;
	r.x = 0;
	r.y = start_y >= 3 ? start_y - 3 : 0;
	r.w = wmap->w;
	r.h = end_y - start_y + 1;
	invalidate(&r);
}


void radar_window_t::radar()
{
	int xpos_new = (myship.get_x() & (WORLD_SIZEX - 1)) >> 4;
	int ypos_new = (myship.get_y() & (WORLD_SIZEY - 1)) >> 4;
	switch(prefs->scrollradar)
	{
	  case 0:	/* No scrolling */
		// Note this first one just invalidates the *area*
		// that the player is in! That is, if the player
		// has moved, the player will be somewhere else
		// when the rendering is performed, and no player
		// cursor is rendered.
		update_player(xpos, ypos);
		if((xpos_new == xpos) && (ypos_new == ypos))
			break;
		xpos = xpos_new;
	 	ypos = ypos_new;
		pxoffs = pyoffs = xoffs = yoffs = 0;
		update_player(xpos, ypos);
		break;
	  case 1:	/* Radar screen sweep */
		update_player(xpos, ypos);
		xpos = xpos_new;
	 	ypos = ypos_new;
		sweep();
		update_player(xpos, ypos);
		break;
	  case 2:	/* Plain scrolling */
		if((xpos_new == xpos) && (ypos_new == ypos))
			break;
		xpos = xpos_new;
	 	ypos = ypos_new;
		set_scroll(xpos, ypos);
		pxoffs = xoffs;
		pyoffs = yoffs;
		invalidate();
		break;
	}
}


void radar_window_t::frame()
{
	if(prefs->scrollradar != old_scrollradar)
	{
		old_scrollradar = prefs->scrollradar;
		refresh_pos = 0;
		time = SDL_GetTicks();
		pxoffs = pyoffs = xoffs = yoffs = 0;
		invalidate();
	}
	switch(_mode)
	{
	  case RM__REINIT:
	  case RM_OFF:
		break;
	  case RM_RADAR:
		radar();
		break;
	  case RM_SHOW:
		break;
	  case RM_NOISE:
	  case RM_INFO:
		invalidate();
		break;
	}
}
