/* palette-proc.m,
 */

#include <allegro.h>
#include <assert.h>
#include <math.h>
#include "gui/gui-raid.h"
#include "map-editor/palette-proc.h"
#include "map.h"
#include "seborrhea/seborrhea-allegro.h"
#include "seborrhea/seborrhea.h"
#include "tile.h"
#include "unit.h"
#include "units/all-units.h"


#define ITEM_W	(TILE_W+4)
#define ITEM_H	(TILE_H+4)


#define rectfill_wh(b,x,y,w,h,c)	rectfill(b,x,y,x+w-1,y+h-1,c)


@implementation MapPalette
- (int) countItems
{
    if (editing_mode == GROUND_MODE)
	return total_ground_classes;

    if (editing_mode == AIR_MODE)
	return total_air_classes;

    /* Tile/parallax editing modes. */
    return num_tiles();
}

- (int) scrollbarToScrolly:(int)data { return data; }
- (void) scrollyToScrollbar:(int)num { [vscrollbar setHandlePosition:num]; }

- (void) correctScrollbarPrecision
{
    int total_items = [self countItems];
    int total_rows = ceil((double)total_items / items_per_row);
    int rows_per_screen = h / ITEM_H; /* Floored */
    [vscrollbar setSliderPrecision:total_rows - rows_per_screen + 1];
    [self scrollyToScrollbar:scrolly[editing_mode]];
}

- (void) selectLMBItem:(int)n
{
    int old_selected_item = lmb_item[editing_mode];
    int total_items = [self countItems];

    lmb_item[editing_mode] = MID(0, n, total_items-1);

    if (lmb_item[editing_mode] != old_selected_item) {
	[map_proc setSelectedLMBItem:lmb_item[editing_mode]];
	[self setSelectedItemLabel];
	flags |= FLAG_DIRTY;
    }
}

- (void) selectRMBItem:(int)n
{
    int old_selected_item = rmb_item[editing_mode];
    int total_items = [self countItems];

    rmb_item[editing_mode] = MID(0, n, total_items-1);

    if (rmb_item[editing_mode] != old_selected_item) {
	[map_proc setSelectedRMBItem:rmb_item[editing_mode]];
	flags |= FLAG_DIRTY;
    }
}

- (void) setSelectedItemLabel
{
    if (editing_mode == PARALLAX_MODE)
	[label setText:"Parallax Tiles"];
    else if (editing_mode == GROUND_MODE) {
	if (lmb_item[editing_mode] < 0)
	    [self selectLMBItem:0];
	[label setText:[ground_units_table[lmb_item[editing_mode]] name]];
    }
    else if (editing_mode == AIR_MODE) {
	if (lmb_item[editing_mode] < 0)
	    [self selectLMBItem:0];
	[label setText:[air_units_table[lmb_item[editing_mode]] name]];
    }
    else 
	[label setText:"Tiles"];

    [label receiveMessage:MSG_REDRAW];
}

static int class_to_index(Class class)
{
    int end;
    Class *table;

    if (editing_mode == GROUND_MODE) {
	table = ground_units_table;
	end = total_ground_classes;
    }
    else {
	table = air_units_table;
	end = total_air_classes;
    }

    while (--end >= 0) {
	if (class == table[end])
	    return end;
    }

    /* Bad! */
    return 0;
}

/*--------------------------------------------------------------*/

- init
{
    int i;

    [super init];

    for (i = 0; i < NUM_MODES; i++) {
	lmb_item[i] = -1;
	rmb_item[i] = -1;
    }
    w = 1;

    vscrollbar = [[[RaidVScrollbar newWithName:"Palette Scrollbar"]
		      setHPadding:1 VPadding:0]
		     setParentWidget:self];
    [[vscrollbar slider] setHandleH:100];

    min_width = ITEM_W;
    max_width = ITEM_W * 4 + 30;
    h_padding = 1;

    return self;
}

- (id) setX:(int)x_ Y:(int)y_ W:(int)w_ H:(int)h_
{
    int sw;
    [super setX:x_ Y:y_ W:w_ H:h_];

    sw = [vscrollbar maxWidth];
    [vscrollbar setX:x+w-sw Y:y W:sw   H:h];

    items_per_row = (w - [vscrollbar width]) / ITEM_W;
    items_per_col = h / ITEM_H;

    [self correctScrollbarPrecision];

    return self;
}

- free
{
    vscrollbar = [vscrollbar free];
    return [super free];
}

- (Widget *) getWidgetBounding:(int)mx :(int)my
{
    Widget *widget = [vscrollbar getWidgetBounding:mx :my];
    if (widget) return widget;
    return [super getWidgetBounding:mx :my];
}

- (BOOL) draw:(BITMAP *)dest :(BOOL)marked_dirty
{
    Class *table = NULL;
    int i, end, x_, y_, x0, y0;
    marked_dirty = [super draw:dest :marked_dirty];

    [vscrollbar draw:dest :marked_dirty];

    if (!marked_dirty)
	return NO;

    if (editing_mode == GROUND_MODE)
	table = ground_units_table;
    else if (editing_mode == AIR_MODE)
	table = air_units_table;

    x0 = x + (w - [vscrollbar width]) % ITEM_W / 2;
    y0 = y + h % ITEM_H / 2;
    i = scrolly[editing_mode] * items_per_row;
    end = MIN(i + items_per_row * items_per_col, [self countItems]);

    for (y_ = y0; (i < end) && (y_ < y+h-ITEM_H); y_ += ITEM_H) {
	for (x_ = x0; (i < end) && (x_ < x+w-[vscrollbar width]-ITEM_W); x_ += ITEM_W) {
	    if (i == lmb_item[editing_mode])
		rectfill_wh(dest, x_-2, y_-2, ITEM_W, ITEM_H, yellow);
	    if (i == rmb_item[editing_mode] && editing_mode == TILE_MODE)
		rectfill_wh(dest, x_-2, y_-2, ITEM_W, ITEM_H, green);

	    if (editing_mode <= TILE_MODE) {
		[get_tile_by_index(i) drawTo:dest X:x_ Y:y_ W:TILE_W H:TILE_H];
		//blit([(SebImageAllegro *)get_tile_by_index(i) bitmap],
		//dest, 0, 0, x_, y_, TILE_W, TILE_H);
	    }
	    else {
		Unit *unit = [table[i] new];
		[unit drawTo:dest at:x_ :y_];
		[unit free];
	    }

	    i++;
	}
    }

    return YES;
}

- (void) receiveMessage:(int)msg :(int)data
{
#define rows_per_screen		items_per_col

    if (items_per_row == 0)
	return;

    //assert(items_per_row != 0);
    int mx = mouse_x, my = mouse_y;
    int total_items = [self countItems];
    int total_rows = (total_items / items_per_row) + 1;
    int old_scrolly = scrolly[editing_mode];

    switch (msg) {
      case MSG_KEY_PRESSED: {
	  if (data == KEY_UP)   scrolly[editing_mode]--;
	  if (data == KEY_DOWN) scrolly[editing_mode]++;
	  break;
      }

      case MSG_MOUSE_HELD: {
	  int x_ = mx - x;
	  int y_ = my - y;
	  int item_n;

	  /* Huh? */
	  x_ = (x_ - (w - [vscrollbar width]) % ITEM_W / 2) / ITEM_W;
	  y_ = (y_ - h % ITEM_H / 2) / ITEM_H;
	  
	  if ((x_ < 0) || (x_ >= items_per_row) ||
	      (y_ < 0) || (y_ >= items_per_col))
	      return;

	  item_n = (scrolly[editing_mode] + y_) * items_per_row + x_;
	  if (data == 1) {
	      /* Only tile mode has rmb_item.  Parallax does NOT. */
	      if (editing_mode == TILE_MODE)
		  [self selectRMBItem:item_n];
	  }
	  else
	      [self selectLMBItem:item_n];
	  break;
      }

      case MSG_MOUSE_WHEEL: {
	  int item_n = lmb_item[editing_mode] + data;
	  [self selectLMBItem:item_n];
	  break;
      }
	  
      case MSG_CHANGED_EDITING_MODE: {
	  [self correctScrollbarPrecision];
	  [self setSelectedItemLabel];
	  flags |= FLAG_DIRTY;
	  return;
      }

      case MSG_RESELECT: {
	  Class new_class = [map_proc getSelectedUnitClass];
	  lmb_item[editing_mode] = class_to_index(new_class);
	  [self setSelectedItemLabel];
	  flags |= FLAG_DIRTY;
	  return;
      }

      default:
	  [super receiveMessage:msg :data];
    }

    scrolly[editing_mode] = MID(0, scrolly[editing_mode], total_rows-rows_per_screen);

    /* If the mouse wheel caused the selected item to go off the
       visible area, make the selected item visible. */
    if (msg == MSG_MOUSE_WHEEL) {
        while (lmb_item[editing_mode] < items_per_row * scrolly[editing_mode])
            scrolly[editing_mode]--;
        while (lmb_item[editing_mode] >= items_per_row*(scrolly[editing_mode]+rows_per_screen))
            scrolly[editing_mode]++;
    }

    if (scrolly[editing_mode] != old_scrolly) {
	[self scrollyToScrollbar:scrolly[editing_mode]];
	flags |= FLAG_DIRTY;
    }

#undef rows_per_screen
}

- (void) receiveMessage:(int)msg :(int)data fromChild:(Widget *)child
{
    (void)child;
    if (msg == MSG_VSLIDER)
	scrolly[editing_mode] = [self scrollbarToScrolly:data];
    flags |= FLAG_DIRTY;
}

- (id) setMapProcWidget:(MapProc *)widget { map_proc = widget; return self; }
- (id) setLabelWidget:(Label *)widget { label = widget; return self; }
@end
