#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/commands/sync.c,v 2.8 1995/10/11 02:49:09 empire Exp $";
#endif /* not lint */

/*
 * sync.c
 *
 * Synchronize the client database with the server database
 *
 * Ken Stevens, 1995
 */

#include <stdio.h>
#include <time.h>
#include "gamesdef.h"
#include "misc.h"
#include "player.h"
#include "edb.h"
#include "xy.h"
#include "nsc.h"
#include "version.h"
#include "file.h"
#include "sect.h"
#include "ship.h"
#include "plane.h"
#include "land.h"
#include "nuke.h"
#include "nat.h"
#include "map.h"

int
sync()
{
	if (!player->argp[1])
		return RET_SYN;
	
	switch (*player->argp[1]) {
	case 'o':
		return sync_object();
	case 'c':
		return sync_class();
	case 'r':
		return sync_catchup();
	case 'v':
		return sync_version();
	case 's':
		return sync_checksum();
	case 'd':
		return sync_define();
	default:
		return RET_SYN;
	}

	return RET_OK;
}

int
sync_version()
{
	pr_sync("%d %d.%d.%d %d.%d.%d %s %s %d\n",
		EDB_VERSION,
		EMP_VERS_MAJOR,
		EMP_VERS_MINOR,
		EMP_VERS_PATCH,
		EDB_VERS_MAJOR,
		EDB_VERS_MINOR,
		EDB_VERS_PATCH,
		EMP_HOST,
		EMP_PORT,
		player->cnum);
	
	return RET_OK;
}

int
sync_checksum()
{
	return RET_OK;
}

int
sync_define()
{
	struct	edbstr	*ed;
	struct	castr	*ca;

	for (ed = edbchr; ed->edb_class != EDB_BAD; ++ed) {
		if (ca = ed->edb_cf) {
			pr_sync("%d %d %d ",
				EDB_TYPE_DEF,
				EDB_CLASS,
				ed->edb_class);
			pr_field_defs(ca, 0L);
			if (ed->edb_last_com)
				pr_field_defs(var_ca, ed->edb_last_com);
			pr_sync("\n");
		} else if (ed->edb_class == VER_CLASS)
			pr_ver_defs();

		if (ca = ed->edb_of) {
			pr_sync("%d %d %d ",
				EDB_TYPE_DEF,
				ed->edb_parent,
				ed->edb_object);
			pr_field_defs(ca, 0L);
			if (ed->edb_last_var)
				pr_field_defs(var_ca, ed->edb_last_var);
			pr_sync("\n");
		}
	}

	return RET_OK;
}

int
sync_object()
{
	int	type;
	struct	nstr_sect nstr;
	struct	nstr_item ni;
	struct	sctstr sect;
	struct	shpstr ship;
	struct	plnstr plane;
	struct	lndstr land;
	struct	nukstr nuke;
	struct	natstr *natp;
	struct	nstr_sect ns;
	struct	bmpstr bmp;
	s_char	c;
	struct	range range;
	int	i;
	s_char	*usage = "Usage: sync object <sector|ship|land|plane|nuke|nation|bmap|all>\n";
	
	if (!player->argp[2]) {
		pr(usage); return RET_OK;
	}
	if (*player->argp[2] == 'a')
		type = EF_BAD;
	else if ((type = ef_byname(player->argp[2])) < 0) {
		pr(usage); return RET_OK;
	}
	
	if (type == EF_BAD) {
		for (type = EF_SECTOR; type < EF_MAX; ++type) {
			if (!edbchr[type].edb_of)
				continue;
			player->argp[2] = empfile[type].name;
			player->argp[3] = "*";
			sync_object();
		}
		return RET_OK;
	}
	
	switch (type) {
	case EF_SECTOR:
		if (!snxtsct(&nstr, player->argp[3])) {
			pr(usage); return RET_OK;
		}
		while (nxtsct(&nstr, &sect)) {
			if (!player->owner)
				continue;
			prsync(player->cnum, &sect, EDV_ALL);
		}
		break;
	case EF_SHIP:
	case EF_LAND:
	case EF_PLANE:
		if (!snxtitem(&ni, type, player->argp[3])) {
			pr(usage); return RET_OK;
		}
		switch (type) {
		case EF_SHIP:
			while(nxtitem(&ni, &ship)) {
				if (!player->owner)
					continue;
				prsync(player->cnum, &ship, EDV_ALL);
			}
			break;
		case EF_LAND:
			while(nxtitem(&ni, &land)) {
				if (!player->owner)
					continue;
				prsync(player->cnum, &land, EDV_ALL);
			}
			break;
		case EF_PLANE:
			while(nxtitem(&ni, &plane)) {
				if (!player->owner)
					continue;
				prsync(player->cnum, &plane, EDV_ALL);
			}
			break;
		case EF_NUKE:
			while(nxtitem(&ni, &nuke)) {
				if (!player->owner)
					continue;
				prsync(player->cnum, &nuke, EDV_ALL);
			}
			break;
		}
		break;
	case EF_NATION:
		prsync(player->cnum, getnatp(player->cnum), EDV_ALL);
		break;
	case EF_BMAP:
		snxtsct_all(&ns);
		natp = getnatp(player->cnum);
		xyrelrange(natp, &ns.range, &range);
		bmp.ef_type = EF_BMAP;
		bmp.bmp_own = player->cnum;
		bmp.bmp_leftx = ns.x;
		bmp.bmp_y = ns.y;
		i = 0;
		while (bmnxtsct(&ns) && !player->aborted) {
			if (ns.y != bmp.bmp_y) {
				bmp.bmp_rightx = ns.x;
				bmp.bmp_row[i] = '\0';
				if (!blankrow(bmp.bmp_row)) {
					squeeze_bmap(&bmp);
					prsync(player->cnum, &bmp, EDV_ALL);
				}
				bmp.bmp_leftx = ns.x;
				bmp.bmp_y = ns.y;
				i = 0;
			}
			if (c = player->bmap[sctoff(ns.x, ns.y)])
				bmp.bmp_row[i++] = c;
			else
				bmp.bmp_row[i++] = ' ';
		}
			       
		break;
	}
	
	return RET_OK;
}

int
sync_class()
{
	int	type;
	int	class;
	struct	edbstr	*ed;
	s_char	*usage = "Usage: sync class <sector|ship|land|plane|nuke|item|product|version|all>\n";
	
	if (!player->argp[2]) {
		pr(usage); return RET_OK;
	}
	if (*player->argp[2] == 'a')
		class = 0;
	else if (*player->argp[2] == 'i')
		class = ITM_CLASS;
	else if (*player->argp[2] == 'p' &&
		 player->argp[2][1] == 'r')
		class = PRD_CLASS;
	else if (*player->argp[2] == 'v')
		class = VER_CLASS;
	else if ((type = ef_byname(player->argp[2])) >= 0) {
		class = type | EDB_CLASS;
	} else {
		pr(usage); return RET_OK;
	}
	
	if (class) {
		ed = &edbchr[class & ~EDB_CLASS];
		if (class == VER_CLASS)
			pr_ver();
		else if (ed->edb_chr)
			pr_chr(ed);
		else {
			pr(usage);
			return RET_OK;
		}
	} else {
		for (ed = edbchr; ed->edb_class != EDB_BAD; ++ed) {
			if (!ed->edb_chr)
				continue;
			pr_chr(ed);
		}
	}
	
	return RET_OK;
}

static
squeeze_bmap(mp)
	struct	bmpstr	*mp;
{
	s_char	row[WORLD_X/2 + 1];
	s_char	*rp = row;
	s_char	*sp;

	mp->bmp_y += 1;
	if (mp->bmp_y < -WORLD_Y/2)
		mp->bmp_y += WORLD_Y;
	strcpy(row, mp->bmp_row);
	while (*rp && *rp == ' ')
		++rp;
	if (*rp) {
		strcpy(mp->bmp_row, rp);
		mp->bmp_leftx += 2 * (rp - row) + 1;
		if (mp->bmp_leftx >= WORLD_X/2)
			mp->bmp_leftx -= WORLD_X;
	}
	if (strlen(mp->bmp_row)) {
		sp = rp = &mp->bmp_row[strlen(mp->bmp_row) - 1];
		while (rp != &mp->bmp_row[0] && *rp == ' ')
			--rp;
		mp->bmp_rightx += 2 * (rp - sp - (mp->bmp_y)%2);
		if (mp->bmp_rightx < -WORLD_X/2)
			mp->bmp_rightx += WORLD_X;
		*(++rp) = '\0';
	}
}

sync_catchup()
{
	struct	natstr	*natp = getnatp(player->cnum);
	s_char	buf[4096];
	FILE	*fp;
	s_char	*p = "Can I throw this information away now? ";
	s_char	filename[512];

	if (!natp->nat_synctim)
		return;

	syncbox(filename, player->cnum);
	if (!(fp = fopen(filename, "r"))) {
		logerror("Read failed: %s", filename);
		return;
	}
	while (fgets(buf, 4096, fp))
		pr_sync(buf);

	p = getstarg(player->argp[2], p, buf);
	if (p && *p == 'y') {
		natp->nat_synctim = 0;
		putnat(natp);
#ifdef sys5
		/* I don't have ftruncate, so here's my stand in */
		FILE *holdf;
		holdf = fopen(filename, "w+"); /* I hope this kills */
		rewind(fp);
		fclose(holdf);
	}
#else
		ftruncate(fileno(fp), 0);
	}
#endif /* sys5 */

	fclose(fp);

}
