#ifndef lint
static char *RCSid = "$Header: /usr/brule/guest/empire/empire/emprcs/lib/update/distribute.c,v 2.2 1995/10/16 17:58:19 empire Exp $";
#endif

/*
 * distribute.c
 *
 * do distribution sector stuff.  
 *
 * Dave Pare, 1986
 */

#include "misc.h"
#include "var.h"
#include "nat.h"
#include "sect.h"
#include "item.h"
#include "xy.h"
#include "path.h"
#include "file.h"
#include "distribute.h"

int
dodistribute(sp, local, imex, path, dist_i_cost, dist_e_cost)
struct sctstr *sp;
int *local;
int imex; /* import or export? */
s_char	*path;
double	dist_i_cost;
double	dist_e_cost;
{
	struct	sctstr *getdistsp();
	float	distpathcost();
	struct ichrstr *ip;
	struct sctstr *dist;
	int	amt;
	int	thresh;
	int	amt_dist;
	int	amt_sect;
	int	packing;
	float	imcost;
	float	excost;
	int	dist_packing;
	int	diff;
	int	item;
	int	dists[I_MAX+1];
	int	remote[I_MAX+1];
	int	changed;

	if ((sp->sct_dist_x == sp->sct_x) && (sp->sct_dist_y == sp->sct_y))
		return 0;

	if (getvec(VT_DIST, dists, (s_char *)sp, EF_SECTOR) <= 0)
		return 0;

	if (path == (s_char *)0){
		if (sp->sct_own != 0) {
			if (imex == EXPORT) /* only want this once */
			wu(0,sp->sct_own,"No path to dist sector for %s\n",
				ownxy(sp));
		}
		return 0;
	}

	dist = getsectp(sp->sct_dist_x,sp->sct_dist_y);
	if (dist->sct_effic >= 60)
		dist_packing = dchr[dist->sct_type].d_pkg;
	else
		dist_packing = NPKG; /* No packing */
	
	if (sp->sct_effic >= 60)
		packing = dchr[sp->sct_type].d_pkg;
	else
		packing = NPKG; /* No packing */

	if ((dist->sct_effic >= 60) && dchr[dist->sct_type].d_pkg == WPKG)
		packing = dchr[dist->sct_type].d_pkg;

	getvec(VT_ITEM, remote, (s_char *)dist, EF_SECTOR);
	changed = 0;
	for (item = 1; item < I_MAX+1; item++) {
		if (dists[item] == 0)
			continue;
		ip = &ichr[item];
		thresh = dists[item];
		/*
		 * calculate costs for importing and exporting.
		 * the div 4.0 is because delivering straight through
		 * to the dist sect is cheaper than stopping at each
		 * sector along the way (processor-timewise)
		 */
		excost = (dist_e_cost/ip->i_pkg[packing] * ip->i_lbs) / 4.0;
		imcost = (dist_i_cost/ip->i_pkg[dist_packing] * ip->i_lbs)/4.0;
		amt_sect = local[item];
		amt_dist = remote[item];
		diff = amt_sect - thresh;
		if (item == I_CIVIL)
			if (sp->sct_own != sp->sct_oldown)
				continue;
		if (item == I_CIVIL)
			if (dist->sct_own != dist->sct_oldown)
				continue;
		if (diff < 0){
			if (imex != IMPORT)
				continue;

			if (!military_control(dist))
				continue;

			diff = -diff;
			/*
			 * import.
			 * don't import if no mobility.
			 * check to make sure have enough mobility in the
			 * dist sector to import what we need.
			 */
			if (dist->sct_mobil <= 0) {
				/*logerror("  dist mobil < 0");*/
				continue;
			}
			amt = diff;
			if (item == I_CIVIL)
				amt_dist--;	/* Don't send your last civ */

			if (amt_dist < amt) {
				amt = amt_dist;
				if (amt_dist == 0)
					continue;
			}
			if (dist->sct_mobil < imcost * amt)
				amt = dist->sct_mobil / imcost;

			/* XXX replace with vector assign and putvec() */
			remote[item] -= amt;
			changed++;
			dist->sct_mobil -= (int) (imcost * amt);
			local[item] += amt;
		} else {
			if (imex != EXPORT)
				continue;
			if (!military_control(sp))
				continue;
			if ((item == I_CIVIL)&&(sp->sct_work < 100))
				continue;
			if ((item == I_CIVIL)&&(sp->sct_own != sp->sct_oldown))
				continue;
			/*
			 * export.
			 * don't export if no mobility. check to make sure we
			 * have mobility enough to do the right thing.
			 * also make sure that there's enough space in the
			 * target sector to hold the required amt.
			 */
			if (sp->sct_mobil <= 0) {
				/*logerror("  sp mob is zero");*/
				continue;
			}
			amt = diff;
			if (amt > amt_sect)
				amt = amt_sect;
			if (sp->sct_mobil < excost * amt)
				amt = sp->sct_mobil / excost;
			if (amt + amt_dist > 9999)
				amt = 9999 - amt_dist;
			if (amt == 0)
				continue;
			/* XXX replace with vector assign and putvec() */

			local[item] -= amt;
			changed++;
			sp->sct_mobil -= (int) (excost * amt);
			remote[item] += amt;
		}
	}
	putvec(VT_ITEM, remote, (s_char *)dist, EF_SECTOR);
	return changed;
}

void
assemble_dist_paths(paths, imcost, excost)
s_char	*paths[WORLD_X][WORLD_Y];
double	imcost[WORLD_X][WORLD_Y];
double	excost[WORLD_X][WORLD_Y];
{
	s_char	*BestDistPath(), *path, *malloc(), *p, *ReversePath();
	double	pathcost(), d;
	struct	sctstr *sp, *dist;
	int	n;
	s_char	buf[512];

	bzero(paths,sizeof(paths));

	for (n=0; sp = getsectid(n); n++) {
		if ((sp->sct_dist_x == sp->sct_x) && (sp->sct_dist_y == sp->sct_y))
			continue;

		dist = getsectp(sp->sct_dist_x,sp->sct_dist_y);
		if (dist == (struct sctstr *)0){
			logerror("Bad dist sect %d,%d for %d,%d !\n",sp->sct_dist_x,
				sp->sct_dist_y,sp->sct_x,sp->sct_y);
			continue;
		}
		
		path = BestDistPath(buf, sp,dist,&d);
		if (path != (s_char *)0){
			paths[sp->sct_x][sp->sct_y] = malloc(strlen(path));
			if (paths[sp->sct_x][sp->sct_y] == (s_char *)0){
				logerror("malloc failed in assemble_dist_path!\n");
				return;
			}
			bcopy(path,paths[sp->sct_x][sp->sct_y],strlen(path));
			excost[sp->sct_x][sp->sct_y] = d;
			p = ReversePath(path);
			imcost[sp->sct_x][sp->sct_y] = pathcost(dist,p);
		}
	}
}

free_dist_paths(paths)
s_char	*paths[WORLD_X][WORLD_Y];
{
	int	x,y;

	for(x=0;x<WORLD_X;x++)
		for(y=0;y<WORLD_Y;y++)
			if (paths[x][y] != (s_char *)0)
				free(paths[x][y]);
}

s_char *ReversePath (path)
s_char *path;
{
	static s_char new_path[512];
	int ind, x=0;

	if (path == (s_char *)0)
		return (s_char *)0;

	bzero(new_path,512);
	ind = strlen (path);

	if (ind == 0)
		return (s_char *)0;

	if (*(path+ind-1) == 'h')
		*(path+(ind--)-1) = '\0';

	new_path [ind --] = '\0';

	while (* (path+x) != '\0'){
		switch (* (path+(x++))){

		case 'g':
			new_path [ind --] = 'j';
			break;

		case 'y':
			new_path [ind --] = 'n';
			break;

		case 'u':
			new_path [ind --] = 'b';
			break;

		case 'j':
			new_path [ind --] = 'g';
			break;

		case 'n':
			new_path [ind --] = 'y';
			break;

		case 'b':
			new_path [ind --] = 'u';
			break;
		}
	}

	return new_path;
}
