
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#include "utils.h"
#include "structs.h"
#include "functions.h"
#include "command.h"
#include "db.h"

/* External variables and globals */
extern struct descriptor_data *desc_list;
extern struct grid_index_element *grid_list;
extern struct zone_data *zone_list;
extern struct room_data *where;

extern char buf[SMALL_BUFSIZE];
extern char buf1[SMALL_BUFSIZE];
extern char buf2[SMALL_BUFSIZE];
extern char buf3[SMALL_BUFSIZE];

extern int top_of_z_table,top_of_rooms;

struct _build_set_ {
	char   name[14];
	void   (*pointer)();
	char   arg1;
	char   arg2;
   char   level;
} build_set[] = {
/******************************************************************/
/* Doing weird shit...   added null first field to sort it out... */
/******************************************************************/
	{"\0",            do_quit,       0,    0,    0},
	{"?",             build_help,    0,    0,    0},
	{"create",        do_create,     0,    0,    0},
	{"delete",        build_delete,  0,    0,    0},
	{"description", 	build_desc,  	0,    0,		0},
	{"exit",          do_exit,       0,    0,    0},
	{"goto",          do_goto,       0,    0,    0},
	{"help",          build_help,    0,    0,    0},
	{"leave",   	 	build_leave,   0,    0,    0},
	{"look",          do_look,       0,    0,    0},
	{"map",     		do_map,        0,    0,    0},
	{"name",          build_name,    0,    0,    0},
	{"quit",    		do_quit,       0,    0,    0},
	{"save",          build_save,    0,    0,    0},
	{"who",           do_who,        0,    0,    0},
};
#define ECTOP ((sizeof(build_set) / sizeof(struct _build_set_)) -1)

/*********************************************************/
/* For help, look at command.c "command_parser" routine. */
/* That is if I was bothered to comment that one...      */
/*********************************************************/
void build_parser(struct char_data *ch, char *arg)
{
	int c, i;

	if(!*arg) {
		ch->desc->prompt=1;
		return;
	}

	for(i=0;i<10;i++) {
		if(!shrt_cmp(arg,exit_list[i].name) || !shrt_cmp(arg,exit_list[i].brief)) {
			do_direction(ch,i);
			return;
		}
	}

	if((i=get_bcommand(arg)) < 0) {
		send_2_output("Not understood...\n\r",ch->desc);
	} else {
		((*build_set[i].pointer)(ch,arg,build_set[i].arg1,build_set[i].arg2));
	}
}

/*******************************************************
	Enter building mode (with its own command parser)
*******************************************************/
void do_build(struct char_data *ch, char *arg)
{
	send_2_room(ch,IGNR_INVIS,"becomes a builder!");
	send_2_output("You become a builder.\n",ch->desc);
	change_status(ch,CON_BUILD);
	return;
}

/*******************************************************
	Leave building mode (with its own command parser)
*******************************************************/
void build_leave(struct char_data *ch, char *arg)
{
	send_2_room(ch,IGNR_INVIS,"stops building...");
	send_2_output("You are no longer a builder.\n",ch->desc);
	change_status(ch,CON_PLYNG);
	return;
}

void build_save(struct char_data *ch, char *arg)
{
}

/*************************************************
	New on 28/12/99.
	About to start exit builder...
*************************************************/
void build_exit(struct char_data *ch, char *arg)
{
	int i;

	/* Get exit name */
	if(!get_arg(buf,arg,1)) {
		send_2_output("You want me to guess where to put the exit?\n\r",ch->desc);
		return;
	}

	/* Search for valid exit */
	for(i=0;i<10;i++)
		if(!str_cmp(buf,exit_list[i].name) || !str_cmp(buf,exit_list[i].brief))
			break;

	/* Did we find a valid exit? */
	if(i==10) {
		send_2_output("Invalid exit direction.\n\r",ch->desc);
		return;
	}

	/* Do we already have an exit in that direction? */
	if(IN_ROOM(ch)->exits[i]) {
		sprintf(buf,"An exit already exists to the %s!\n\r",exit_list[i].name);
		send_2_output(buf,ch->desc);
		return;
	}

	/* Lets create the new exit then... */
	CREATE(IN_ROOM(ch)->exits[i],struct exit_data,1);
	sprintf(buf,"An exit appears to the %s!\n\r",exit_list[i].name);
	send_2_inc(ch,buf);
}

void build_name(struct char_data *ch, char *arg)
{
	if(!get_arg(buf,arg,1)) {
		send_2_output(IN_ROOM(ch)->name,ch->desc);
	} else { 
		free(IN_ROOM(ch)->name);
		get_arg(buf,arg,-1);
		IN_ROOM(ch)->name= (char *)strdup(buf);
		do_look(ch,"+");
	}
	return;
}

void build_desc(struct char_data *ch, char *arg)
{
	if(!get_arg(buf,arg,-1)) {
		send_2_output(IN_ROOM(ch)->description,ch->desc);
		return;
	} else if(!shrt_cmp("+",buf)) {
		get_arg(buf1,arg,-2);
		sprintf(buf,"%s\n\r%s",IN_ROOM(ch)->description,buf1);
	}
	free(IN_ROOM(ch)->description);
	IN_ROOM(ch)->description=(char *)strdup(buf);
	do_look(ch,"+");
	return;
}

void build_help(struct char_data *ch, char *arg)
{
	int i,c;

	send_2_output("A raw list of building commands available to you:\n\r",ch->desc);
	for(i=1,c=0;i<=ECTOP;i++) {
		if(c<4) {
			sprintf(buf,"%14s",build_set[i].name);
			c++;
		} else {
			sprintf(buf,"%14s\n",build_set[i].name);
			c=0;
		}
		send_2_output(buf,ch->desc);
	}
	if(c!=0)
		send_2_output("\n\r",ch->desc);
	return;
}

int get_bcommand(char *arg)
{
	int	top=ECTOP;
	int	mid,found,low=0;

	while(low <= top)
	{
		mid = (low+top)/2;
		if((found = shrt_cmp(arg,build_set[mid].name)) > 0)
			low = mid + 1;
		else if(found < 0)
			top = mid - 1;
		else
			return(mid);
	}
	return(-1);
}

void build_delete(struct char_data *ch, char *arg)
{
}

/****************************************************************
	New on 27/12/99.
	Create parser: 'room' | 'door' | 'object' | 'mob'
****************************************************************/
void do_create(struct char_data *ch, char *arg)
{
	/*======================================
			*********  NOTE  ********** 
			    buf3 is being used!
	======================================*/
	if(!get_arg(buf3,arg,-1)) {
		send_2_output("Create anything in particular, or just havoc?\n\r",ch->desc);
		return;
	} else if(!shrt_cmp("room",buf3)) {
		// Sir requires a room...
		build_room(ch,buf3);
	} else if(!shrt_cmp("exit",buf3)) {
		// Sir requires an exit ...
		build_exit(ch,buf3);
	} else {
		send_2_output("Can't seem to create that...\n\r",ch->desc);
		return;
	}
}

/****************************************************************
	New on 26/12/99.
	Routine to create a room.
****************************************************************/
void build_room(struct char_data *ch, char *arg)
{
	int c,xyz[5];

	/***********************************************/
	/* Find out where we want to create this room. */
	/***********************************************/
	if(!get_arg(buf,arg,1)) {
		xyz[0] = GET_X(ch);
		xyz[1] = GET_Y(ch);
		xyz[2] = GET_Z(ch);
		xyz[3] = ROOM_NUM(ch);
	} else if(!_numeric(&xyz[0],buf)) {
		// Might be a direction from this room.
		for(c=0;c<10;c++) {
			if(!shrt_cmp(buf,exit_list[c].name) || !shrt_cmp(buf,exit_list[c].brief)) {
				get_adjacent_room(&xyz[0],&xyz[1],&xyz[2],&xyz[3],IN_ROOM(ch),c);
				break;
			}
		}
	} else {
		// Maybe co-ordinates to room (more leg-work).
		for(c=1;(c<5) && get_arg(buf,arg,c+1);c++) {
			if(!_numeric(&xyz[c],buf)) {
				send_2_output("The fools I serve...\n\r",ch->desc);
				return;
			}
		}
		// If only one arg then room in current zone.
		switch(c) {
			case 1:
				xyz[3] = xyz[0];
				xyz[0] = GET_X(ch);
				xyz[1] = GET_Y(ch);
				xyz[2] = GET_Z(ch);
				break;
			case 2:
				if(xyz[0] > top_of_z_table || xyz[0] < 0) {
					send_2_output("That zone doesn't exist.\n\r",ch->desc);
					return;
				}
				xyz[3] = xyz[1];
				xyz[2] = ZONE_Z(xyz[0]);
				xyz[1] = ZONE_Y(xyz[0]);
				xyz[0] = ZONE_X(xyz[0]);
				break;
			case 4:
				break;
			default:
				send_2_output("Cannot comply Captain.\n\r",ch->desc);
				return;
		};
	}

	switch(create_room(ch,xyz[0],xyz[1],xyz[2],xyz[3])) {
	case 0:
		send_2_output("New room created.\n\r",ch->desc);
		break;
	case 1:
		send_2_output("Room number is too large!\n\r",ch->desc);
		break;
	case 2:
		send_2_output("This room already exists!\n\r",ch->desc);
		break;
	default:
	}
}

char create_room(struct char_data *ch,int x,int y,int z,int room)
{
	int zone;

	/*******************************************************/
	/* The very difficult task of creating a zone...       */
	/* Just glad this won't be happening every 5 minutes!  */
	/*******************************************************/
	if((zone=get_zone(x,y,z)) < 0) {
		zone=create_zone_entry();
		ZONE_X(zone)=x;
		ZONE_Y(zone)=y;
		ZONE_Z(zone)=z;
		index_zones();

		sprintf(buf,"Created new zone: %d\n\r",zone);
		send_2_output(buf,ch->desc);
	}

	/*******************************************************/
	/* We have found (or created) our zone, so we need to  */
	/* check whether our room is valid or in existance.    */
	/*******************************************************/
	if(room >= ZONE_SIZE) {
		return(1);  // Room number too large!
	} else if(ZONE_ROOM(zone,room)) {
		return(2);	// room already exists 
	}
	
	/*******************************************************/
	/*  We have a zone, so its now safe to create a room.  */
	/*******************************************************/
	CREATE(ZONE_ROOM(zone,room),struct room_data,1);
	ZONE_ROOM(zone,room)->X = x;
	ZONE_ROOM(zone,room)->Y = y;
	ZONE_ROOM(zone,room)->Z = z;
	ZONE_ROOM(zone,room)->ZONE = zone;
	ZONE_ROOM(zone,room)->ROOM = room;
	zone_list[zone].num_rooms++;
	top_of_rooms++;

	return(0);
}

void do_map(struct char_data *ch, char *arg)
{

}

