#ifndef _CONTENT_H_
#define _CONTENT_H_

#include "common.h"
#include "array.h"

#include <stdint.h>

#define CONTENT_MAX		0x0FFF
#define CONTENT_ARRAY_SIZE	0x1000

/* the top nibble of content_t is a type identifier
 * this allows for 16 possible content types */
#define CONTENT_TYPE_MASK	0xF000
#define CONTENT_TYPE_BLOCK	0x0000
#define CONTENT_TYPE_CLOTHES	0x1000
#define CONTENT_TYPE_MOB	0x2000
#define CONTENT_TYPE_TOOL	0x4000
#define CONTENT_TYPE_CRAFTITEM	0x8000

#define CONTENT_INDEX_BLOCK	0x00
#define CONTENT_INDEX_CLOTHES	0x01
#define CONTENT_INDEX_MOB	0x02
#define CONTENT_INDEX_TOOL	0x04
#define CONTENT_INDEX_CRAFTITEM	0x08

#define CONTENT_TYPE(x) (x&CONTENT_TYPE_MASK)

/* the universal "nothing" value */
#define CONTENT_IGNORE	0x007F

/* Parameter types */
#define CPT_NONE		0x00
#define CPT_LIGHT		0x01
#define CPT_MINERAL		0x02
#define CPT_FACEDIR_SIMPLE	0x03 /* chests and such */
#define CPT_FACEDIR_WALLMOUNT	0x04 /* signs and such */
#define CPT_FACEDIR_MANUAL	0x05 /* planks and such */
#define CPT_LIQUID		0x06
#define CPT_PLANTGROWTH		0x07
#define CPT_ENCHANTMENT		0x08
#define CPT_DROP		0x09
#define CPT_BLOCKDATA		0x0A
#define CPT_SPECIAL		0x0B

/* material type */
#define CMT_AIR			0x00
#define CMT_WOOD		0x01
#define CMT_TREE		0x02
#define CMT_STONE		0x03
#define CMT_LIQUID_SOURCE	0x04
#define CMT_LIQUID		0x05
#define CMT_PLANT		0x06
#define CMT_DIRT		0x07
#define CMT_GLASS		0x08
#define CMT_FLESH		0x09
#define CMT_BONE		0x0A
/* the below are not for blocks */
#define CMT_COTTON		0x0B
#define CMT_CANVAS		0x0C
#define CMT_FUR			0x0D
#define CMT_LEATHER		0x0E
#define CMT_ARMOUR		0x0F

/* clothing types */
#define CCT_NONE		0x00
#define CCT_PANTS		0x01
#define CCT_SHIRT		0x02
#define CCT_HAT			0x03
#define CCT_BOOTS		0x04
#define CCT_JACKET		0x05
#define CCT_BELT		0x06
#define CCT_DECORATIVE		0x07
#define CCT_MEDALLION		0x08

/* tool types */
#define CTT_NONE		0x00
#define CTT_SPECIAL		0x01 /* special tools can't dig */
#define CTT_AXE			0x02
#define CTT_PICK		0x03
#define CTT_SHOVEL		0x04
#define CTT_SHEAR		0x05
#define CTT_BUCKET		0x06
#define CTT_SWORD		0x07
#define CTT_SPEAR		0x08
#define CTT_CLUB		0x09
#define CTT_HAMMER		0x0A
#define CTT_SAW			0x0B

/* flags used for graphics materials */
#define CMF_NONE		0x00
#define CMF_ROTATE		0x01 /* rotate top/bottom with nodebox */
#define CMF_TILED		0X02 /* for plantlike, use bottom/middle/top halves seperately */

/* flags used for collision data */
/* also determines the behaviour when pushed by a piston */
#define CCD_NONE		0x0000
#define CCD_WALKABLE		0x0001 /* can be walked through */
#define CCD_SELECTABLE		0x0002 /* can be pointed at */
#define CCD_TOOL_SELECTABLE	0x0004 /* can be pointed at with a tool, CCD_SELECTABLE applies this */
#define CCD_CLIMBABLE		0x0008 /* think ladders */
#define CCD_REPLACEABLE		0x0010 /* can be replaced by a material placed on/in it (old buildable_to) */
#define CCD_CRUSHABLE		0x0020 /* will be obliterated if pushed against another node */
#define CCD_DROPABLE		0x0040 /* may drop when above an upward-facing piston */
#define CCD_SOLID		0x0080
#define CCD_CRUSHED		0x0100 /* always obliterated when pushed */
#define CCD_MOBSAFE		0x0200 /* destructive_mob_safe */
#define CCD_UNJUMPABLE		0x0400

/* lighting info */
#define CLM_BLOCKS		0x00
#define CLM_BRIGHT		0x01 /* disable lighting */
#define CLM_CLEAR		0x02 /* sunlight_propogates */
#define CLM_TRANSLUCENT		0x03 /* light_propogates */

/* digging effects */
#define CDE_UNDIGGABLE		0x00
#define CDE_DIGGABLE		0x01
#define CDE_IGNORE_BORDERSTONE	0x08 /* borderstone_diggable */
#define CDE_GIVE_INVENTORY	0x10 /* gives its inventory when dug */
#define CDE_GIVE_INV_AON	0x20 /* all or nothing for inventory */

/* circuits/energy type */
#define CET_NONE		0x00
#define CET_CONDUCTIVE		0x01
#define CET_SOURCE		0x02
#define CET_SWITCH		0x03
#define CET_GATE		0x04
#define CET_SINK		0x05

/* texture types */
#define CT_TOP0			0x00
#define CT_TOP1			0x01
#define CT_TOP2			0x02
#define CT_TOP3			0x03
#define CT_BOTTOM0		0x10
#define CT_BOTTOM1		0x11
#define CT_BOTTOM2		0x12
#define CT_BOTTOM3		0x13
#define CT_RIGHT0		0x20
#define CT_RIGHT1		0x21
#define CT_RIGHT2		0x22
#define CT_RIGHT3		0x23
#define CT_LEFT0		0x30
#define CT_LEFT1		0x31
#define CT_LEFT2		0x32
#define CT_LEFT3		0x33
#define CT_BACK0		0x40
#define CT_BACK1		0x41
#define CT_BACK2		0x42
#define CT_BACK3		0x43
#define CT_FRONT0		0x50
#define CT_FRONT1		0x51
#define CT_FRONT2		0x52
#define CT_FRONT3		0x53
#define CT_BASE0		0x60
#define CT_BASE1		0x61
#define CT_BASE2		0x62
#define CT_BASE3		0x63
#define CT_INVENTORY		0x70
#define CT_META_TOP0		0x80
#define CT_META_TOP1		0x81
#define CT_META_TOP2		0x82
#define CT_META_TOP3		0x83
#define CT_META_BOTTOM0		0x90
#define CT_META_BOTTOM1		0x91
#define CT_META_BOTTOM2		0x92
#define CT_META_BOTTOM3		0x93
#define CT_META_RIGHT0		0xA0
#define CT_META_RIGHT1		0xA1
#define CT_META_RIGHT2		0xA2
#define CT_META_RIGHT3		0xA3
#define CT_META_LEFT0		0xB0
#define CT_META_LEFT1		0xB1
#define CT_META_LEFT2		0xB2
#define CT_META_LEFT3		0xB3
#define CT_META_BACK0		0xC0
#define CT_META_BACK1		0xC1
#define CT_META_BACK2		0xC2
#define CT_META_BACK3		0xC3
#define CT_META_FRONT0		0xD0
#define CT_META_FRONT1		0xD1
#define CT_META_FRONT2		0xD2
#define CT_META_FRONT3		0xD3
#define CT_META_BASE0		0xE0
#define CT_META_BASE1		0xE1
#define CT_META_BASE2		0xE2
#define CT_META_BASE3		0xE3

/* face text types */
#define CFT_NONE		0x00
#define CFT_INFO		0x01
#define CFT_BOOKCONTENT		0x02
#define CFT_OWNER		0x03
#define CFT_INVOWNER		0x04

#ifndef _HAVE_CONTENT_TYPE
#define _HAVE_CONTENT_TYPE
typedef uint16_t content_t;
#endif

#ifndef _HAVE_NODEBOX_TYPE
#define _HAVE_NODEBOX_TYPE
typedef struct nodebox_s {
	aabox_t box;
	v3_t angle;
	v3_t centre;
} nodebox_t;
#endif

#ifndef _HAVE_ITEM_TYPE
#define _HAVE_ITEM_TYPE
typedef struct item_s {
	content_t content;
	uint16_t param1;
	uint16_t param2;
} item_t;
#endif

#ifndef _HAVE_FACETEXT_TYPE
#define _HAVE_FACETEXT_TYPE
typedef struct facetext_s {
	uint16_t type;
	rectf_t pos;
} facetext_t;
#endif

#ifndef _HAVE_BLOCKFEATURES_TYPE
#define _HAVE_BLOCKFEATURES_TYPE
typedef struct blockfeatures_s {
	uint8_t vertex_alpha;
	colour_t post_effect_colour;

	/* when dug/punched also affects this */
	pos_t onact_also_affects;
	/* can set the players home */
	uint8_t home;

	facetext_t facetexts[6];
	/* essentially "can mapgen put a tree/plant on this" */
	uint8_t is_ground_content;
	/* 1 - fire can spread to and destroy this
	 * 2 - can be set on fire */
	uint8_t flammable;
	/* basically "can grass grow under this" */
	uint8_t air_equivalent;
	/* what happens if/when dug */
	uint16_t digging_info;

	/* if it has metadata, this is the metadata type */
	content_t metaid;

	struct {
		content_t wallmount; /* when placed on a wall */
		content_t floormount; /* when placed on a floor */
		content_t roofmount; /* when placed on a roof */
		/* special content for things like slabs combining into cubes,
		 * walls connecting to blocks, or seeds growing to plants */
		content_t special;
		/* if locked/unlocked, replace with this */
		content_t lockstate;
		/* if power state changes powered/unpowerd, replace with this */
		content_t powerstate;
	} alternate;

	struct {
		/* liquid, both types of matching liquid */
		content_t source;
		content_t flowing;
		/* a value from 1-7, with 7 being thickest */
		uint8_t viscosity;
	} liquid;

	/* when dropped on dirt, place this instead of inserting in a parcel */
	struct {
		content_t block;
		/* if there's a ^block nearby, place this instead */
		content_t alternate;
	} ondrop;

	/* for circuits, the type of circuit object, and how much energy drops as it pases through */
	struct {
		uint8_t type;
		uint8_t	drop;
	} energy;

	struct {
		content_t replace; /* when dug, this block will replace the dug block */
		content_t replace_requires; /* ^replacement will only occur if this block is nearby (3 node radius) */
		/* if a tool of param2 type is used, give this instead */
		item_t special_drop;
	} ondig;

	struct {
		content_t replace; /* when punched, replace with this block */
		uint8_t borderstone; /* if 0 ignore borderstone protection */
	} onpunch;

	struct {
		uint16_t max_height;
		/* when CPT_PLANTGROWTH < 8 digging gives this */
		content_t small_drop;
		/* when CPT_PLANTGROWTH > 7 digging gives this */
		content_t large_drop;
		/* the maximum number of large items given */
		uint16_t large_count;
		/* whether to also give small when large is given */
		uint8_t large_gives_small;
		/* if this spreads to trellis to continue growing, then this is the on-trellis id */
		content_t trellis_block;
		/* whether punching with fertilizer advances the growth rate */
		uint8_t fertilizer_affects;
	} plant;
} blockfeatures_t;
#endif

#ifndef _HAVE_CLOTHESFEATURES_TYPE
#define _HAVE_CLOTHESFEATURES_TYPE
typedef struct clothesfeatures_s {
	/* the type of this clothing */
	uint8_t type;
	/* the strength as armour */
	float armour;
	/* the effectiveness against the cold zone */
	float warmth;
	/* the effectiveness against vacuum / space */
	float vacuum;
	/* the effectiveness against suffocation */
	float suffocate;
	/* this determines how fast the item wears out from use */
	uint8_t durability;
	/* for medallions, how much the affect durability of other items */
	float effect;
} clothesfeatures_t;
#endif

#ifndef _HAVE_MOBFEATURES_TYPE
#define _HAVE_MOBFEATURES_TYPE
typedef struct mobfeatures_s {
	int stuff; /* TODO: mobfeatures_t */
} mobfeatures_t;
#endif

#ifndef _HAVE_TOOLFEATURES_TYPE
#define _HAVE_TOOLFEATURES_TYPE
typedef struct toolfeatures_s {
	/* the type of this tool */
	uint8_t type;
	/* the number dropped on right click, -1 for all */
	int16_t drop_count;
	/* whether this tool can point at liquid nodes */
	uint8_t liquids_pointable;
	/* whether this tool should die when trying to pick up damaging nodes */
	uint8_t damaging_nodes_diggable;
	/* whether this tool has a punch effect, such as open doors */
	uint8_t has_punch_effect;
	/* whether this tool can lock/unlock nodes (1 for true, 2 for super) */
	uint8_t has_unlock_effect;
	/* whether this tool can rotate nodes */
	uint8_t has_rotate_effect;
	/* whether this tool can start fires */
	uint8_t has_fire_effect;
	/* the dig time of this tool */
	float dig_time;
	/* the level of the tool, this affects the amount of minerals etc */
	uint8_t level;
	/* used for eg. bows throwing an arrow */
	content_t thrown_item;
} toolfeatures_t;
#endif

#ifndef _HAVE_CRAFTITEMFEATURES_TYPE
#define _HAVE_CRAFTITEMFEATURES_TYPE
typedef struct craftitemfeatures_s {
	/* whether the item can be stacked in inventory */
	uint8_t stackable;
	/* whether the item can be eaten/drank, must be non-zero for *_effect to work */
	uint8_t consumable;
		/* if an item has both hunger and health effects, it will
		 * not affect health unless hunger is full
		 * number of hunger points this will refill */
		int16_t hunger_effect;
		/* number of health points this will refill */
		int16_t health_effect;
		/* number of seconds will protect player against cold damage */
		int16_t cold_effect;
		/* will refill energy at double full speed for this many seconds */
		int16_t energy_effect;
	/* the number dropped on right click, -1 for all */
	int16_t drop_count;
	/* if this teleports the player home, -2 = no, -1 = default home
	 * 0-7 for specific flag colours */
	int8_t teleports;
	/* used by mobs that are picked up */
	content_t drop_item;
	/* used by snowballs and such... things that are thrown */
	content_t thrown_item;
	/* used by arrows and such... things that are shot by a tool */
	content_t shot_item;
} craftitemfeatures_t;
#endif

#ifndef _HAVE_CONTENTFEATURES_TYPE
#define _HAVE_CONTENTFEATURES_TYPE
typedef struct contentfeatures_s {
	content_t content;

	uint8_t param1_type;
	uint8_t param2_type;

	/* determines digging properties */
	uint8_t material_type;
	float hardness;

	char* description;

	/* graphics stuff */
	array_t materials;
	uint16_t materials_info;
	char* overlay;

	/* collision info, for players, mobs, piston pushes, digging, placing etc */
	array_t collision_boxes;
	uint16_t collision_info;

	/* if an item has a nodebox style wield, use this */
	array_t wield_boxes;

	/* same info about how light reacts on this */
	uint8_t light_data;
	uint8_t light_source;

	/* what is returned when this is dug, a primary item, and a secondary item
	 * plus randomness for the extra item, and tool levels to obtain it */
	item_t dug_item;
	item_t extra_dug_item;
	int extra_dug_item_rarity;
	uint8_t extra_dug_item_min_level;
	uint8_t extra_dug_item_max_level;

	item_t cook_result;
	float fuel_time;

	/* wield it and use it, replaced with this */
	item_t onuse_replace;
	/* if it can be enchanted, it gives this */
	content_t enchanted_item;

	/* sound effects for the content */
	struct {
		char* access; /* formspec accessed */
		char* step; /* stepped on/in */
		char* dig; /* when dug or killed */
		char* place; /* when placed or spawned */
		char* punch; /* when punched */
		char* ambient; /* constant sound effect */
		char* use; /* when weilded and used */
	} sound;

	/* damage effects per second to players/mobs */
	struct {
		uint8_t hard; /* hard damage cannot be protected against */
		uint8_t suffocation;
		uint8_t temperature; /* hot/cold */
		uint8_t pressure; /* vacuum */
	} damage;

	/* the features for individual types */
	union {
		blockfeatures_t block;
		clothesfeatures_t clothes;
		mobfeatures_t mob;
		toolfeatures_t tool;
		craftitemfeatures_t craftitem;
	} data;
} contentfeatures_t;
#endif

#ifdef _CONTENT_LOCAL
/* defined in content.c */
extern contentfeatures_t *contentfeatures[16];
void content_defaults(contentfeatures_t *f);
#endif

/* defined in content.c */
contentfeatures_t *content_features(content_t id);
item_t *content_item(item_t *i, content_t content, uint8_t param1, uint8_t param2);
aabox_t *content_box(aabox_t *b, float min_x, float min_y, float min_z, float max_x, float max_y, float max_z);
facetext_t *content_facetext(facetext_t *f, uint16_t type, float x, float y, float w, float h);
int content_init(void);
void content_exit(void);

/* defined in content_block.c */
int content_block_init(void);

/* defined in content_clothes.c */
int content_clothes_init(void);

/* defined in content_craftitem.c */
int content_craftitem_init(void);

/* defined in content_mob.c */
int content_mob_init(void);

/* defined in content_tool.c */
int content_tool_init(void);

#endif

