/*
 *                      S C A N V E R S I O N . C
 *
 *  Many paramters of empire can only be determined at run time.  This
 *  is done at startup when also the possible options a scanned.  These
 *  may trigger actions in more specific parts of the code.
 *
 *  Version      : $Revision: 1.3 $
 *
 *  Created      : Wed May 25 23:58:24 1994
 *  Author       : Ulrich Drepper <drepper@mydec>
 *
 *  Last modified: Fri Jul  8 23:59:24 1994
 *  Author       : Ulrich Drepper <drepper@mydec>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 1, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */
#if !defined(lint)
static const char *vcid = "$Id: scanversion.c,v 1.3 1994/07/09 00:18:50 drepper Exp $";
#endif /* lint */

#include <stdio.h>
#include <string.h>

#include "empire.h"
#include "proto.h"

/*
 * localtype defintions
 */

/* entry for an integer version info */
typedef struct {
    int   flag;             /* is info found */
    char *fmt;              /* scanf format string */
    int   count;            /* number values */
    int  *p1;               /* pointers to int variables */
    int  *p2;
    int  *p3;
    int  *p4;
} VersionIntInfo;

/* entry for an float/double version info */
typedef struct {
    int     flag;           /* is info found */
    char   *fmt;            /* scanf format string */
    int     count;          /* number values */
    double *p1;             /* pointers to double vars */
    double  f1;             /* included factors */
    double *p2;
    double  f2;
    double *p3;
    double  f3;
} VersionFloatInfo;

/*
 * exported functions 
 */
Bool
scanVersion(void)
{
    static int   chainsaw = 0;
    ServerAnswer answer;           /* status when reading line */
    char        *buf;
    /* things for version information in int form */
    enum { CHAINSAW, MAPSIZE, SECPERETU, ETUPERUPDATE, 
	   NOFOODNEEDED, MOBMAX, MOBGAIN };
    static VersionIntInfo verIntInfo[] = {
	[CHAINSAW]     ILSEP { 0, "Chainsaw version 3.", 0,
			       &chainsaw, NULL, },
	[MAPSIZE]      ILSEP { 0, "World size is %d by %d", 2,
			       &empire.xMapSize, &empire.yMapSize, NULL, },
	[SECPERETU]    ILSEP { 0, "An Empire time unit is %d", 1,
			       &empire.secPerEtu, NULL, },
	[ETUPERUPDATE] ILSEP { 0, "An update consists of %d", 1,
			       &empire.etuPerUpdate, NULL, },
	[NOFOODNEEDED] ILSEP { 0, "No food is needed!!", 0, 
			       &empire.noFoodNeeded, NULL, },
	[MOBMAX]       ILSEP { 0, "Maximum mobility %d %d %d %d", 4,
			       &empire.sectMobMax, &empire.shipMobMax,
			       &empire.planeMobMax, &empire.landMobMax },
	[MOBGAIN]      ILSEP { 0, "Max mob gain per update %d %d %d %d", 4,
			       &empire.sectMobGain, &empire.shipMobGain,
			       &empire.planeMobGain, &empire.landMobGain },
    };
    int lastVerInt  = sizeof(verIntInfo)/sizeof(VersionIntInfo);
    int firstVerInt = 0;
    /* things for version information in float form */
    enum { BANKPAY, MONEYCIV, MONEYMIL, NAGGIGROW, CIVHARVEST, 
	   CIVBIRTH, UWBIRTH, EATRATE, BABYRATE, EFFGAIN };
    static VersionFloatInfo verFloatInfo[] = {
	[BANKPAY]    ILSEP { 0, "Banks pay $%lf", 1,
			     &empire.bankPay, 1000.0, NULL, 0, NULL, },
	[MONEYCIV]   ILSEP { 0, "1000 civilians generate $%lf, "
			        "uncompensated workers $%lf", 2,
			     &empire.moneyCiv, 1000.0,
			     &empire.moneyUw, 1000.0, NULL, },
	[MONEYMIL]   ILSEP { 0, "1000 active military cost $%lf, "
                                "reserves cost $%lf", 2,
			     &empire.moneyMil, 1000.0,
			     &empire.moneyRes, 1000.0, NULL, },
	[NAGGIGROW]  ILSEP { 0, "A non-aggi, 100 fertility sector"
			        " can grow %lf", 1,
			     &empire.nAggiGrow, 100.0, NULL, },
	[CIVHARVEST] ILSEP { 0, "1000 civilians will harvest %lf", 1,
			     &empire.civHarvest, 1000.0, NULL, },
	[CIVBIRTH]   ILSEP { 0, "1000 civilians will give birth to %lf", 1,
			     &empire.civBirth, 1000.0, NULL, },
	[UWBIRTH]    ILSEP { 0, "1000 uncompensated workers will give "
			        "birth to %lf", 1,
			     &empire.uwBirth, 1000.0, NULL, },
	[EATRATE]    ILSEP { 0, "In one time unit, 1000 people eat %lf", 1,
			     &empire.eatRate, 1000.0, NULL, },
	[BABYRATE]   ILSEP { 0, "1000 babies eat %lf", 1,
			     &empire.babyRate, 1000.0, NULL, },
	[EFFGAIN]    ILSEP { 0, "Max eff gain per update %*s %lf %lf %lf", 3,
			     &empire.shipEffGain, 1.0,
			     &empire.planeEffGain, 1.0,
			     &empire.landEffGain, 1.0 },
    };
    int lastVerFloat  = sizeof(verFloatInfo)/sizeof(VersionFloatInfo);
    int firstVerFloat = 0;

    /* initiate version information retrieval */
    sendCmd(empSocket, VERS, NULL);
    
#define IFLAG(idx) verIntInfo[idx].flag
#define FFLAG(idx) verFloatInfo[idx].flag

    do {
	int          found = 0;
	int          i;

	if (!getEmpLineD(empSocket, &answer, &buf)) {
	    message(ERROR, "cannot read version information");
	}

	for (i = firstVerInt; i < lastVerInt; i++) {
	    if (!IFLAG(i)) {
		if (verIntInfo[i].count == 0) {
		    if (strstr(buf, verIntInfo[i].fmt) != NULL) {
			*verIntInfo[i].p1 = 1;
			IFLAG(i) = 1;
			if (i == firstVerInt) {
			    while (firstVerInt < lastVerInt &&
				   IFLAG(firstVerInt))
				firstVerInt++;
			}
			found = 1;
			break;
		    }
		} else {
		    if (sscanf(buf, verIntInfo[i].fmt,
			       verIntInfo[i].p1, verIntInfo[i].p2,
			       verIntInfo[i].p3, verIntInfo[i].p4) == 
			verIntInfo[i].count) {
			IFLAG(i) = 1;
			if (i == firstVerInt) {
			    while (firstVerInt < lastVerInt &&
				   IFLAG(firstVerInt))
				firstVerInt++;
			}
			found = 1;
			break;
		    }
		}
	    }
	}

	/* if no integer flag is found search for float flag */
	if (!found) {
	    for (i = firstVerFloat; i < lastVerFloat; i++) {
		if (!FFLAG(i)) {
		    if (sscanf(buf, verFloatInfo[i].fmt,
			       verFloatInfo[i].p1, verFloatInfo[i].p2,
			       verFloatInfo[i].p3) ==
			verFloatInfo[i].count) {
			FFLAG(i) = 1;
			*verFloatInfo[i].p1 /= verFloatInfo[i].f1;
			if (verFloatInfo[i].count > 1) {
			    *verFloatInfo[i].p2 /= verFloatInfo[i].f2;
			    if (verFloatInfo[i].count > 2) {
				*verFloatInfo[i].p3 /= verFloatInfo[i].f3;
			    }
			}
			if (i == firstVerFloat) {
			    while (firstVerFloat < lastVerFloat &&
				   FFLAG(firstVerFloat))
				firstVerFloat++;
			}
		    }
		}
	    }
	}
    } while (answer != C_PROMPT);

    /*
     * assure all important values are set
     */
    if (!IFLAG(CHAINSAW) || !IFLAG(MAPSIZE) || !IFLAG(SECPERETU) ||
        !IFLAG(ETUPERUPDATE) || !(IFLAG(NOFOODNEEDED) || FFLAG(EATRATE)) ||
        !IFLAG(MOBMAX) || !IFLAG(MOBGAIN) || !FFLAG(BANKPAY) ||
        !FFLAG(MONEYCIV) || !FFLAG(MONEYMIL) || !FFLAG(NAGGIGROW) ||
        !FFLAG(CIVHARVEST) || !FFLAG(CIVBIRTH) || !FFLAG(UWBIRTH) ||
        !FFLAG(BABYRATE) || !FFLAG(EFFGAIN)) {
        /*
         * well, I developed with another server.
         * send me the necessary changes and I will incorporate them.
         */
        message(ERRORREP, "The client is not appropriate for this server");
	return False;
    }

#undef IFLAG
#undef FFLAG

    /* here a scan for the options of this version is be made */
    /* NOT YET */

    /* yet no other command is sent so we can/have to wait for a prompt */
    while (answer != C_PROMPT) {
    	getEmpLineD(empSocket, &answer, &buf);
    }

    return True;
}

/*
 * Local Variables:
 *  mode:c
 *  c-indent-level:4
 *  c-continued-statement-offset:4
 *  c-continued-brace-offset:0
 *  c-brace-offset:0
 *  c-imaginary-offset:0
 *  c-argdecl-indent:4
 *  c-label-offset:-2
 * End:
 */
