// This file written completely by Tim Johnson (Tim@TimMUD)

static void close_callback(int fd){
	string mudname;
	debug("close_callback: fd="+fd+"\n");
	foreach(mudname in keys(muds_on_this_fd(fd))){
		debug("Removing mud from connected_muds list: "+mudname);
		mudinfo[mudname]["disconnect_time"] = time();
		map_delete(connected_muds, mudname);
		broadcast_mudlist(mudname);
	}
	close_connection(fd);
}

static void listen_callback(int fd){
	int nfd;
	debug("listen_callback: fd="+fd+"\n");
	if ((nfd = socket_accept(fd, "read_callback", "write_callback")) < 0) {
		log_file("server", "listen_callback: socket_accept failed.\n");
		return;
	}
}

void write_callback(int fd)
{
	if (sockets[fd]["write_status"] == EEALREADY) {
		write_data(fd, sockets[fd]["pending"]);
		map_delete(sockets[fd], "pending");
	} else {
		sockets[fd]["write_status"] = EESUCCESS;
#if 0
		close_connection(fd);
#endif
	}
}

static void write_data_retry(int fd, mixed data, int counter){
	int rc;
	if (counter == MAXIMUM_RETRIES) {
		close_connection(fd);
		return;
	}
	rc = socket_write(fd, data);
	if(!sockets[fd]) sockets[fd]=([]); // Tim
	sockets[fd]["write_status"] = rc;
	switch (rc) {
		case EESUCCESS:
			// we're finished with this fd.
			// Oops, Leto :) close_connection(fd);
			//close_connection(fd);
			break;
		case EEALREADY:
			// driver must have set the socket marked as BLOCKED when
			// it was created by socket_accept().  Just wait for
			// write_callback to be called so that we can write out the
			// pending data.
			sockets[fd]["pending"] = data;
			break;
		case EECALLBACK:
			// wait for write_callback before accessing socket fd again.
			break;
		case EEWOULDBLOCK:
		case EESEND:
			// try again in two seconds
			if (counter < MAXIMUM_RETRIES) {
				call_out("retry_write", 2, ({fd, data, counter + 1}));
				return;
			}
			// fall through to the default case and write an error.
		default:
			log_file("server", "write_data_retry: " + socket_error(rc) + "\n");
			close_connection(fd);
			break;
	}
}

static void close_connection(int fd){
	int errcode;
	debug("Attempting to close socket\n");
// The code below caused sockets to linger after a "quit" command. -- Leto
#if 0
	if (sockets[fd]["write_status"] == EECALLBACK) {
		// write_callback() will call close_connection() when socket fd
		// is drained.
	debug("write_callback() will call close_connection() when socket fd"+
		"is drained.\n");
		return;
	}
#endif
	map_delete(sockets, fd);
	errcode = socket_close(fd);
	debug("Socket closed with code:"+errcode+".\n");
}

static void write_data(int fd, mixed data){
	debug("Sending to fd="+fd+":\n"+dump_variable(data),DEB_OUT);
	write_data_retry(fd, data, 0);
}
static void broadcast_data(mapping targets, mixed data){
	int fd;
	int *arr;
	// Unique_array was way too complicated to figure out.
	// What this does is take the values for all the connected_muds,
	// get rid of duplicates (so that if 2 muds are on the same fd
	// then it doesn't re-send messages to the fd)
	foreach(arr in unique_array(values(targets), (: $1 :))){
		write_data(arr[0], data);
	}
}