/* 
 * Copyright (C) 2003 Tim Martin
 *
 * 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
 */


#ifndef MAP_H
#define MAP_H

#define NO_OWNER 0

#include "map_item.h"

typedef struct map_s map_t;

typedef struct surrounding_bydir_s {
    mapobj_t above;
    mapobj_t right;
    mapobj_t below;
    mapobj_t left;
} surrounding_bydir_t;

typedef union surrounding_s {
    surrounding_bydir_t dir;
    mapobj_t index[4];
} surrounding_t;

typedef struct mapspot_s
{
    unsigned char mapobj;
    unsigned char height;
    unsigned char owner  : 3;
    unsigned char zoning : 5;
    unsigned char extra;
} mapspot_t;

#define MAPFLAG_SUB 0x08
#define MAPFLAG_NOPOWER 0x10
#define MAPFLAG_NOWATER 0x20

#include "tiles.h"
#include "heightmap.h"
#include "player.h"
#include "mapspot.h"

#define MAPSPECIAL_CURSOR 1
#define MAPSPECIAL_SELECTED 2
#define MAPSPECIAL_HILITE 4
#define MAPSPECIAL_HILITE_INVALID 8
#define MAPSPECIAL_ALREADY_DRAWN 16
#define MAPSPECIAL_SUB 32


int map_init(tiles_t *tiles, int sizex, int sizey, mapobj_t defaultobj, map_t **map);

int map_get_sizex(map_t *map);
int map_get_sizey(map_t *map);

int map_can_place(map_t *map, player_t *player, int x, int y, int dirview, mapobj_t obj, int *cost);

char *map_spot2string(mapspot_t *spot);
int map_string2spot(char *str, mapspot_t *spot);

int map_set_spot(map_t *map, player_t *player, int x, int y, int dirview, int isinit, mapspot_t *spot);
int map_get_spot(map_t *map, int x, int y, mapspot_t *spot);
mapobj_t map_get_info(map_t *map, int x, int y, int dirview, surrounding_t *surrounding, heightsquare_t *heightsquare, int *specials, player_t *me, int *owner);
mapobj_t map_get_type(map_t *map, int x, int y);
int map_set_type(map_t *map, int x, int y, mapobj_t type, int force);
int map_set_owner(map_t *map, int new_owner, player_t *player, int x, int y, int force);
int map_get_owner(map_t *map, int x, int y);

int map_raise_spot(map_t *map, int x, int y);
int map_lower_spot(map_t *map, int x, int y);
int map_islevel(map_t *map, int x, int y);
int map_getsteepness(map_t *map, int x, int y);

int map_set_temporary(map_t *map, player_t *player, int mapx, int mapy,
		      mapobj_t obj, int special_yes, int special_no);
int map_set_temporary_box(map_t *map, player_t *player,
			  int x1, int y1, int x2, int y2, 
			  mapobj_t obj, 
			  int special_yes, int special_no);
int map_set_temporary_line(map_t *map, player_t *player, int x1, int y1, int x2, int y2, 
			   mapobj_t obj, int special_yes, int special_no);
int map_set_temporary_fill(map_t *map, int mapx, int mapy, int special);

typedef int temporary_iterate_callback(map_t *map, int mapx, int mapy, void *rock);

int map_temporary_iterate(map_t *map, int mask, temporary_iterate_callback *callback, void *rcok);

int map_temporary_reset(map_t *map);

int map_randomize(map_t *map);

int map_getowner(map_t *map, int x, int y);

int map_buyland(map_t *map, player_t *player, int x, int y);

int map_isvacant(map_t *map, int x, int y);
typedef int findvacant_func_t(map_t *map, int mapx, int mapy, void *rock);
void map_findvacant(map_t *map, int x, int y, int *resx, int *resy, 
		    findvacant_func_t *func, void *data);
mapspot_list_t *map_find_vacant_list(map_t *map);
mapspot_list_t *map_find_openings_list(map_t *map);
mapspot_list_t *map_find_tile_list(map_t *map, maptype_t mapobj);
mapspot_list_t *map_find_tile_list_obj(map_t *map, mapobj_t obj);
mapspot_list_t *map_find_tile_list_fromlist(map_t *map, 
					    mapobj_t *list);
mapspot_list_t *map_find_tile_list_within(map_t *map, int sx, int sy, 
					  mapobj_t mapobj, int within);

int map_rent(map_t *map, int x, int y, int *owner);
int map_unrent(map_t *map, int x, int y);
void map_live_info(map_t *map, int x, int y, int *live, int *maxlive);

int map_attend_school(map_t *map, int x, int y);
int map_leave_school(map_t *map, int x, int y);
void map_school_info(map_t *map, int x, int y, int *attende, int *maxattend);
int map_is_school_full(map_t *map, int x, int y);

int map_can_buyland(map_t *map, player_t *player, int x, int y);
int map_can_sellland(map_t *map, player_t *player, int x, int y);

int map_getsalary(map_t *map, int mapx, int mapy, int edlevel);
int map_getrent(map_t *map, int mapx, int mapy);


/*
int map_hasopening(map_t *map, int x, int y);
void map_findjob(map_t *map, int x, int y, int *resx, int *resy, 
		 findvacant_func_t *func, void *data);

int map_takejob(map_t *map, int x, int y, int *owner);
int map_quitjob(map_t *map, int x, int y);
*/

int map_patronize(map_t *map, int x, int y);
int map_clear_patronige(map_t *map);

int map_can_change_height(map_t *map, player_t *player, int x, int y, int change);
int map_can_change_height_quad(map_t *map, player_t *player, int x, int y, int change);

void map_change_height_which(map_t *map, int x, int y, int change, int outx[4], int outy[4]);

typedef void upkeep_iterate_callback(map_t *map, int mapx, int mapy, int owner, int upkeep, void *rock);

void map_upkeep_iterate(map_t *map, upkeep_iterate_callback *callback, void *rock);

typedef void zoning_iterate_callback(map_t *map, int mapx, int mapy, int owner, 
				     mapobj_t obj, void *rock);

void map_zoning_iterate(map_t *map, zoning_iterate_callback *callback, void *rock);

void map_player_quit(map_t *map, player_t *player);

typedef enum iterate_types_e {
    MAP_ITERATE_NORMAL,
    MAP_ITERATE_RANDOM,
    MAP_ITERATE_WITHIN,
    MAP_ITERATE_RADIAL,
} iterate_type;

typedef void map_iterate_callback(map_t *map, int mapx, int mapy, int owner, 
				  mapobj_t obj, void *rock);

typedef int map_iterate_criteria_land(mapobj_t, void *);
typedef int map_iterate_criteria_owner(int, void *);

int map_iterate(map_t *map, iterate_type type, int startx, int starty, 
		int within,
		map_iterate_criteria_land *land_crit, void *land_rock,
		map_iterate_criteria_owner *owner_crit, void *owner_rock,
		map_iterate_callback *cb, void *rock);

int map_vacancies(map_t *map);

int map_positions_avail(map_t *map);

void map_all_iterate(map_t *map, int startx, int starty, 
		     map_iterate_callback *callback, void *rock);

/*
 * is x,y within dist of any tiles of type obj
 */
int map_within(map_t *map, int x, int y, int dist, mapobj_t obj, int owner);
int map_within_type(map_t *map, int x, int y, int dist, maptype_t obj, int owner);

int map_within_count(map_t *map, int x, int y, int dist, mapobj_t obj);
int map_within_count_type(map_t *map, int sx, int sy, int dist, maptype_t type);

extern int map_empty_land(map_t *map, int x, int y);

extern int map_numjobs(map_t *map);

extern float map_density(map_t *map, int x, int y, int radius);

int map_is_connected(map_t *map, int x, int y, int new_owner);

int map_set_spot_cost(map_t *map, int x, int y, mapspot_t *spot);

int map_get_upkeep(map_t *map, int x, int y);
int map_get_revenue(map_t *map, int x, int y);
int map_get_patrons(map_t *map, int x, int y);

extern int map_is_sub(map_t *map, int mapx, int mapy);
extern int map_is_multi(map_t *map, int mapx, int mapy);
extern int map_max_employ(map_t *map, int x, int y);

typedef void map_obj_changed_callback(map_t *map, int x, int y, 
				      mapobj_t old, mapobj_t newobj, 
				      void *rock);

extern void map_set_obj_changed_cb(map_t *map, map_obj_changed_callback *cb, 
				  void *rock);
extern int map_getvariable_cb(char *name, map_t *map, int x, int y);
extern mapobj_t *map_get_houselist(map_t *map);
extern mapobj_t *map_get_typelist(map_t *map, maptype_t type,
				  int (*compar)(const void *, const void *), int *len);

extern int
map_change_height_list(mapspot_list_t **list, map_t *map, player_t *player, int x, int y, int change);
extern int map_get_height(map_t *map, int x, int y);
extern int
map_change_height_square(mapspot_list_t **list, map_t *map, player_t *player, int x, int y, 
			 int change);
int map_occupancy(map_t *map, int x, int y);

extern void
map_setflag(map_t *map, int x, int y, int flag);
extern int
map_isflagset(map_t *map, int x, int y, int flag);
extern void
map_clearflag_wholemap(map_t *map, int flag);
extern maptype_t
map_get_maptype(map_t *map, int x, int y);

extern void map_find_tiletop(map_t *map, int *xp, int *yp);
#endif /* MAP_H */
