/* newmenu-custom.m,
 */

#include <allegro.h>
#include <assert.h>
#include <dirent.h>
#include "common.h"
#include "game.h"
#include "input.h"
#include "map-save.h"
#include "newmenu-custom.h"
#include "newmenu-dirty.h"
#include "newmenu-log.h"
#include "newmenu.h"
#include "player.h"
#include "seborrhea/seborrhea-allegro.h"
#include "seborrhea/seborrhea-dirlist.h"
#include "seborrhea/seborrhea-font.h"


static SebFont *menu_font;

/*--------------------------------------------------------------*/
/* Directory listing stuff.					*/
/*--------------------------------------------------------------*/

@interface MapFileSelector: DirectoryList
{
    unsigned int selected_map;
    int offset_y, shown_offset_y;
}
- (BOOL) moveSelection:(int)amount;
- (const char *) selectItem;
- (void) draw:(BITMAP *)dest :(BOOL)map_selection_side :(int)t;
@end

@implementation MapFileSelector
static int map_filter(const FILTER_TYPE *entry)
{
#ifdef __MINGW__
# define ENTRY_NAME		ent->name
    const struct al_ffblk *ent = entry;
#else  /* Linux */
# define ENTRY_NAME		entry->d_name
#endif

    char *ext;
    assert(entry);

    /* Ignore hidden files, but not ../ */
    if (ENTRY_NAME[0] == '.' && not streq(ENTRY_NAME, ".."))
	return 0;

    ext = strrchr(ENTRY_NAME, '.');
    if (ext) {
	ext++;

	if (streq(ext, RAID_MAP_EXTENSION))
	    return 1;
    }

#ifdef __MINGW__
    return 1;
#else  /* Linux */
    /* Keep directories and symlinks. */
    return (entry->d_type == DT_DIR || 
	    entry->d_type == DT_LNK);
#endif

#undef ENTRY_NAME
}

- init
{
    [super init];
    filter = map_filter;
    return self;
}

- (BOOL) moveSelection:(int)amount
{
    unsigned int h = [menu_font textHeight];
    unsigned int old_selected_map = selected_map;

    if (amount < 0 && selected_map < ABS(amount))
	selected_map = 0;
    else {
	selected_map += amount;
	if (selected_map > nentries-1)
	    selected_map = nentries-1;
    }

    if (amount < 0) {
	if ((int)(selected_map*h) + offset_y < 0)
	    offset_y = -selected_map*h;
    }
    else {
	if (selected_map*h + offset_y > 9.5*h)
	    offset_y = 9.5*h - selected_map*h;
    }

    return (selected_map != old_selected_map);
}

- (const char *) selectItem
{
    char selected_path[PATH_MAX];
    BOOL is_directory;
    assert(selected_map < nentries);

    is_directory = [self isDirectory:selected_map];
    strncpy(selected_path, working_directory, sizeof selected_path);

    if (streq(entries[selected_map].d_name, "..")) {
	int l = strlen(selected_path);
	char *delim;

	/* Working_directory contains a / at the end.  Remove it. */
	if (l > 0) {
	    selected_path[l-1] = '\0';
	}

	delim = strrchr(selected_path, '/');
	if (not delim)
	    delim = selected_path;

	*delim = '\0';
    }
    else {
	strncat(selected_path, entries[selected_map].d_name, sizeof selected_path);
    }

    if (is_directory) {
	/* Add a '/'. */
	strncat(selected_path, "/", sizeof selected_path);

	[self freeEntries];
	[self scanDirectory:selected_path];
	selected_map = 0;
	offset_y = shown_offset_y = 0;
	return NULL;
    }
    else
	return strdup(selected_path);
}

- (void) draw:(BITMAP *)dest :(BOOL)map_selection_side :(int)t
{
    unsigned int i, r, g, b;
    int y = shown_offset_y;
    int h = [menu_font textHeight];

    shown_offset_y = (shown_offset_y*4 + offset_y) / 5;

    r = 0xff-5*0x08, g = 0xc0-5*0x10, b = 0x60-5*0x10;
    [menu_font putString:working_directory To:dest X:60 Y:60-h Colour:r:g:b
	       Decoration:DECORATION_OUTLINE];
    mark_dirty_rectangle(60, 60-h, dest->w, h);

    mark_dirty_rectangle(70, 65, 320, dest->h-55-65+1);
    set_clip(dest, 70, 65, 70+320, dest->h-55);
    for (i = 0, y += 65; i < nentries; i++, y += h) {
	BOOL is_directory, is_link;

	if (y+h < 65)
	    continue;
	if (y > dest->h-55)
	    break;

	if (i == selected_map)
	    selected_item_colour(&r, &g, &b, t);
	elif (map_selection_side) {
	    int delta = ABS((int)i - (int)selected_map);
	    r = MAX(0xff - delta*0x08, 0);
	    g = MAX(0xc0 - delta*0x10, 0);
	    b = MAX(0x60 - delta*0x10, 0);
	}
	else {
	    r = 0xff-5*0x08;
	    g = 0xc0-5*0x10;
	    b = 0x60-5*0x10;
	}

	is_directory = [self isDirectory:i];
	is_link = [self isLink:i];

	[menu_font putStringTo:dest X:80 Y:y Colour:r:g:b
		   Decoration:DECORATION_OUTLINE
		   :"%s%s", entries[i].d_name, (is_link ? "@" :
						is_directory ? "/" : "")];
    }
    set_clip(dest, 0, 0, dest->w, dest->h);
}
@end

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

static void draw_okay_bit(BITMAP *dest, int selected, BOOL map_selection_side, int t)
{
#define PICK_RGB(n)	if (n == selected) selected_item_colour(&r,&g,&b,t); else r = 0xff-5*0x08, g = 0xc0-5*0x10, b = 0x60-5*0x10

    const char *num_players_text[MAX_PLAYERS] = { "Single Player", "Two Players" };
    int r, g, b;
    int h = [menu_font textHeight];

    if (map_selection_side) {
	r = 0xff-5*0x08, g = 0xc0-5*0x10, b = 0x60-5*0x10;
	[menu_font putString:num_players_text[num_players-1] To:dest X:dest->w-50 Y:dest->h*1/3 Colour:r:g:b Alignment:ALIGN_RIGHT Decoration:DECORATION_OUTLINE];
	[menu_font putString:"Play" To:dest X:dest->w-100 Y:dest->h*2/3   Colour:r:g:b Alignment:ALIGN_RIGHT Decoration:DECORATION_OUTLINE];
	[menu_font putString:"Back" To:dest X:dest->w-100 Y:dest->h*2/3+h Colour:r:g:b Alignment:ALIGN_RIGHT Decoration:DECORATION_OUTLINE];
    }
    else {
	PICK_RGB(0); [menu_font putString:num_players_text[num_players-1] To:dest X:dest->w-50 Y:dest->h*1/3 Colour:r:g:b Alignment:ALIGN_RIGHT Decoration:DECORATION_OUTLINE];
	PICK_RGB(1); [menu_font putString:"Play" To:dest X:dest->w-100 Y:dest->h*2/3   Colour:r:g:b Alignment:ALIGN_RIGHT Decoration:DECORATION_OUTLINE];
	PICK_RGB(2); [menu_font putString:"Back" To:dest X:dest->w-100 Y:dest->h*2/3+h Colour:r:g:b Alignment:ALIGN_RIGHT Decoration:DECORATION_OUTLINE];
    }

    {
	int l = [menu_font textLength:num_players_text[0]];
	mark_dirty_rectangle(dest->w-50-l, dest->h*1/3, l, h);
	l = [menu_font textLength:"Back"];
	mark_dirty_rectangle(dest->w-100-l, dest->h*2/3, l, h*2);
    }

#undef PICK_RGB
}

char *select_custom_level(BITMAP *dbuf)
{
    MapFileSelector *map_list;
    const char *level_filename = NULL;
    BOOL exit = NO, redraw = YES, map_selection_side = YES;
    int h, selected_item, t;
    BITMAP *bg;

    /* Scan all of the seborrhea root directories. */
    map_list = [MapFileSelector new];
    for (t = 0; seborrhea_data_root_directories[t]; t++) {
	char dirname[PATH_MAX], canonical_name[PATH_MAX];

	snprintf(dirname, sizeof dirname, "%s/maps/",
		 seborrhea_data_root_directories[t]);

	/* Use the old name for compatability with Allegro 4.0.x */
	fix_filename_path(canonical_name, dirname, sizeof canonical_name);

	if ([map_list scanDirectory:canonical_name])
	    break;

	/* This is the last directory to try.  Not maps directory
	   found, so just go to the raid binary directory. */
	if (not seborrhea_data_root_directories[t+1])
	    [map_list scanDirectory:raid_binary_directory];
    }

    menu_font = (SebFont *)[base_sebum getSebumByName:MENU_FONT_NAME];
    h = [menu_font textHeight];
    mark_entire_screen_dirty();

    /* Scan the map directory. */
    bg = [(SebImageAllegro *)[menu_sebum getSebumByName:"backdrop"] bitmap];
    selected_item = 0;

    while (not (exit || emergency_exit)) {
	while (counter) {
	    counter--;
	    redraw = YES;

	    t += 12;
	    if (t >= 360)
		t = 0;

	    menu_common_update();

	    if (menu_released()) {
		if (not map_selection_side && selected_item == 2) { /* Back. */
		    exit = YES;
		    goto dont_play;
		}
		else {
		    map_selection_side = NO;
		    selected_item = 2;
		}
	    }

	    if (okay_released()) {
		if (not map_selection_side && selected_item == 0) { /* Num players. */
		    if (num_players == 1)
			num_players = 2;
		    else
			num_players = 1;
		}
		elif (not map_selection_side && selected_item == 2) { /* Back. */
		    goto dont_play;
		}
		else {			/* Play. */
		    level_filename = [map_list selectItem];

		    if (level_filename) /* File. */
			exit = YES;
		}
	    }

	    if (map_selection_side) {
		BOOL moved = NO;

		if (menu_select_previous() && [map_list moveSelection:-1])
		    moved = YES;
		if (menu_select_next() && [map_list moveSelection:+1])
		    moved = YES;
		if (key[KEY_PGUP] && [map_list moveSelection:-3])
		    moved = YES;
		if (key[KEY_PGDN] && [map_list moveSelection:+3])
		    moved = YES;

		if (moved)
		    play_bing_sound();
	    }
	    else {
		if (menu_select_previous() && selected_item > 0) {
		    selected_item--;
		    play_bing_sound();
		}
		if (menu_select_next() && selected_item < 2) {
		    selected_item++;
		    play_bing_sound();
		}
	    }

	    if (menu_select_left() && not map_selection_side) {
		map_selection_side = YES;
		play_bing_sound();
	    }
	    if (menu_select_right() && map_selection_side) {
		map_selection_side = NO;
		play_bing_sound();
	    }

	    rest(0);
	}

	if (redraw) {
	    redraw = NO;

	    blit(bg, dbuf, 0, 0, 0, 0, dbuf->w, dbuf->h);

	    [map_list draw:dbuf :map_selection_side :t];
	    draw_okay_bit(dbuf, selected_item, map_selection_side, t);
	    draw_log(dbuf);

	    blit_dirty_rectangles(dbuf, screen);
	}
    }

    [map_list free];
    return strdup(level_filename);

 dont_play:
    [map_list free];
    return NULL;
}
