static char *rcsid = "$Header: /plaid/homes/zeus/Blind-2.47/report/RCS/Main.c,v 2.47 1998/04/15 21:38:21 zeus Exp zeus $";

/*
 * $Log: Main.c,v $
 * Revision 2.47  1998/04/15 21:38:21  zeus
 * *** empty log message ***
 *
 * Revision 2.46.0.1  1997/05/27 21:08:33  zeus
 * *** empty log message ***
 *
 * Revision 2.46  1997/04/18 12:25:12  zeus
 * *** empty log message ***
 *
 * Revision 2.44  1995/12/31  19:45:18  zeus
 * Revision 2.43  1995/03/20  01:43:09  zeus
 *
 */

#define NOTIMEB
#include "common.h"
#include "prototypes.h"
#include "report-g.h"
#include "report.h"
#include "misc-g.h"
#include "exit.h"
#include "options.h"

void report_main_rcsid (void);

void
report_main_rcsid (void)
{
  printf ("%s\n", rcsid);
}

#ifdef FORECAST
extern int seenlist[];
extern sorted *sorted_planets;

#endif

#ifdef GAMENAME
extern char gamename[MAXTEXT];

#endif

extern char buf[];
extern planet *planets;
extern int turn;
extern player *players;
FILE *pr;
int vieweropts;
char prname[MAXTEXT*2] = "con";

int
player_dead (player * P)
{
  planet *p;

  for (p = planets; p && p->owner != P; p = p->next)
    ;                           /* Does he have Planets ? */

  if (!p && !P->groups)         /* No planets or groups... */
    return (1);
  return (0);
}

int
player_footnote (player * P)
{
  planet *p;
  group *g;

  for (p = planets; p && p->owner != P; p = p->next)
    ;                           /* Does he have Planets ? */

  if (p)
    return (0);                 /* Planets, so still OK */

  for (g = P->groups; g; g = g->next)
  {
    if ((g->type->cargo > 0.0) && (g->loadtype == CG_COL) && (g->load > 0.0))
      return (0);               /* Has a group with COL on board, so OK */
  }
  return (1);                   /* No pop, or COL- You are a goner... */
}

typedef struct strlist_s
{
  struct strlist_s *next;
  char *s[20];
}
strlist;


char *fheading;
strlist *Fdata;
int fcolumns, fcol;
char *ftypes;
int headflag;

void
inputpr (void)
{
AGAIN:
  printf ("Output device? [%s] ", prname);
  getstr ();
  if (buf[0])
    hstrncpy (prname, buf, MAXTEXT);
  pr = stdout;
  if (hstricmp (prname, "con"))
    pr = fopen (prname, "w");
  if (pr == 0)
  {
    printf ("Can't open %s\n", prname);
    goto AGAIN;
  }
}


void
spf (char *s, double x)
{
  int i = 0;

  sprintf (s, "%0.2f", x);
  while (s[i])
    i++;
  while (i && s[i - 1] == '0')
    s[--i] = 0;
  if (i && s[i - 1] == '.')
    s[--i] = 0;
}

void
fpf (FILE * f, double x)
{
  spf (buf, x);
  fprintf (f, buf);
}

void
rpf (double x)
{
  fpf (pr, x);
}


void
ckunderscores (char *s)
{
  if (UNDERSCORES & vieweropts)
    while (*s)
    {
      if (*s == ' ')
        *s = '_';
      s++;
    }
}

void
fbegin (char *heading, char *types)
{
  fheading = strdup (heading);
  fcol = fcolumns = strlen (types);
  ftypes = types;
  Fdata = 0;
}

void
fs (char *s)
{
  strlist *p2;
  static strlist *p;

  if (fcol == fcolumns)
  {
    p2 = alloc (sizeof (strlist) + fcolumns * sizeof (char *));

    addlist (&Fdata, p2);
    p = p2;
    fcol = 0;
  }
  p->s[fcol++] = strdup (s);
  /* ckunderscores (p->s[fcol]); *//* Might work now, took ++ out */
}

void
ff (double a)
{
  sprintf (buf, "%0.2f", a);
  fs (buf);
}

void
fi (int n)
{
  sprintf (buf, "%d", n);
  fs (buf);
}

void
fend (void)
{
  int *width;
  int i, l;
  strlist *p;

  if (Fdata && (!headflag || Fdata->next))
  {
    if (*fheading)
      fprintf (pr, "\t\t%s\n\n", fheading);
    for (i = 0; i != fcolumns; i++)
      if (ftypes[i] == 'f')
      {
        int trunc = 1;

        for (p = Fdata->next; p; p = p->next)
          if (p->s[i][0] && p->s[i][strlen (p->s[i]) - 1] != '0')
            trunc = 0;
        if (trunc)
        {
          for (p = Fdata->next; p; p = p->next)
            if (p->s[i][0])
              p->s[i][strlen (p->s[i]) - 1] = 0;
          for (p = Fdata->next; p; p = p->next)
            if (p->s[i][0] && p->s[i][strlen (p->s[i]) - 1] != '0')
              trunc = 0;
          if (trunc)
            for (p = Fdata->next; p; p = p->next)
              if (p->s[i][0] && p->s[i][1])
                p->s[i][strlen (p->s[i]) - 2] = 0;
        }
      }
    width = alloc (fcolumns * sizeof (int));
    memset (width, 0, fcolumns * sizeof (int));

    for (p = Fdata; p; p = p->next)
      for (i = 0; i != fcolumns; i++)
      {
        l = strlen (p->s[i]);
        if (l > width[i])
          width[i] = l;
      }
    for (p = Fdata; p; p = p->next)
    {
      for (i = 0; i != fcolumns; i++)
      {
        l = width[i] - strlen (p->s[i]);
        if (ftypes[i] == 'x')
        {
          fprintf (pr, p->s[i]);
          while (--l >= 0)
            fputc (' ', pr);
        }
        else
        {
          while (--l >= 0)
            fputc (' ', pr);
          fprintf (pr, p->s[i]);
        }
        if (vieweropts & TWOSPACE)
          fprintf (pr, "  ");
        else
          fprintf (pr, " ");
      }
      fputc ('\n', pr);
    }
    fputc ('\n', pr);
    free (width);
  }
  for (p = Fdata; p; p = p->next)
    for (i = 0; i != fcolumns; i++)
      free (p->s[i]);
  freelist (Fdata);
  free (fheading);
  headflag = 0;
}

void
fhead (char *s)
{
  static char lbuf[2];

  if (fcol != strlen (s))
    fprintf (stderr, "Header length mismatch!");
  while (*s)
  {
    lbuf[0] = *s++;
    fs (lbuf);
  }
  headflag = 1;
}

#ifndef EDIT
void
option_on (char *ps, int opt, int popt)
{
  fprintf (pr, ps);
  if (ison (opt, popt))
    fprintf (pr, "on\n");
  else
    fprintf (pr, "off\n");

}

void
print_options (player * P)
{
  if (P->opts2 & SHOWOPT)
  {
    fprintf (pr, "\t\tOptions:\n");
    fprintf (pr, "Executable version: V%4.2f\n", VER);
    option_on ("Full reports (F) ", FULL, P->opts1);
    option_on ("Forecast         ", FCAST, P->opts2);
    option_on ("Long forecasts   ", LONGFORECAST, P->opts2);
    option_on ("Map printing     ", MAP, P->opts1);
    fprintf (pr, "Size:%6.2f centered X:%6.2f Y:%6.2f\n",
             (double) P->size, (double) P->x, cartesian((double) P->y));
    option_on ("Production       ", PROD, P->opts1);
    option_on ("TechProd         ", TECHPROD, P->opts1);
    option_on ("Smartmap         ", MAPPLUS, P->opts1);
    option_on ("Unknown          ", UNKNOWN, P->opts1);
    if (((P->opts1 & MAP) && !(P->opts1 & UNKNOWN)) ||
        (!(P->opts1 & MAP) && (P->opts1 & UNKNOWN)))
      fprintf (pr, "An unknown planet list will be printed\n");
    else
      fprintf (pr, "An unknown planet list will NOT be printed\n");
    option_on ("Battlesum        ", BATTLESUM, P->opts1);
    option_on ("Longbattle       ", LONGBATTLE, P->opts1);
    if (P->opts1 & LONGBATTLE) 
      fprintf (pr, "A blow-by-blow battle will NOT be printed\n");
    else
      fprintf (pr, "A blow-by-blow battle will be printed\n");
    option_on ("Battlemass       ", BATTLEMASS, P->opts1);
    option_on ("Bombsum          ", BOMBSUM, P->opts1);
    option_on ("Techs            ", TECHS, P->opts2);
    option_on ("Sortgroups       ", SORTGROUPS, P->opts2);
    option_on ("Sortplanets      ", SORTPLANETS, P->opts2);
    option_on ("Techplus         ", TECHPLUS, P->opts2);
    option_on ("Autounload       ", AUTOUNLOAD, P->opts2);
    option_on ("Upgradecost      ", UPCOST, P->opts2);
    option_on ("FullType         ", FULLTYPE, P->opts1);
    option_on ("Shortint         ", SHORTINT, P->opts1);
    option_on ("Showopts         ", SHOWOPT, P->opts2);
    option_on ("Unsafemax        ", UNSAFEMAX, P->opts2);
    fprintf (pr, "MAX will work on the highest group");
    if (P->opts2 & UNSAFEMAX)
      fprintf (pr, " ->NOT<- in hyperspace\n");
    else
      fprintf (pr, "\n");
    option_on ("Unsafebreak      ", UNSAFEBREAK, P->opts1);
    option_on ("Showfrom         ", SHOWFROM, P->opts2);
    option_on ("Sysmass          ", SYSMASS, P->opts2);
    option_on ("Twospace         ", TWOSPACE, P->opts2);
    option_on ("Cartesian        ", CARTESIAN, P->opts2);
    if (P->opts2 & CARTESIAN)
    {
      fprintf (pr, "Maps are using cartesian co-ordinates:\n");
      fprintf (pr, "   +/-  ++\n");
      fprintf (pr, "   -/-  +-\n");
    }
    else
    {
      fprintf (pr, "Maps are using normal galaxy co-ordinates:\n");
      fprintf (pr, "   -/-  +-\n");
      fprintf (pr, "   -/+  ++\n");
    } 
    option_on ("Pedantic         ", PEDANTIC, P->opts2);

    fprintf (pr, "GM controlled options:\n");
#ifdef KCMD
    fprintf (pr, "K Commands are supported\n");
#else
    fprintf (pr, "K Commands are NOT supported\n");
#endif

#ifdef PARTTECH
    fprintf (pr, "Partial Tech support/syntax is enabled\n");
#else
    fprintf (pr, "Partial Tech support/syntax is NOT enabled\n");
#endif

#ifdef PASSWORDS
    fprintf (pr, "Passwords and the Y command are enabled\n");
#else
    fprintf (pr, "Passwords and the Y command are NOT enabled\n");
#endif

#ifdef SMARTC
    fprintf (pr, "Empire name changes should be automatic\n");
#else
    fprintf (pr, "Empire name changes should NOT be automatic\n");
#endif

#ifdef ZCMDOK
    fprintf (pr, "Z commands are supported (sortof)\n");
#else
    fprintf (pr, "Z commands are NOT supported\n");
#endif

    fprintf (pr, "\n");
  }
}

void
print_incoming (player * P, planet * p)
{
  player *P2;
  group *g;

  fbegin ("Incoming Groups", "xxxxfff");
  fhead ("ONDNRSM");
  for (P2 = players; P2; P2 = P2->next)
    if (P2 != P)
      for (g = P2->groups; g; g = g->next)
        if (g->dist && g->where->owner == P &&
            (g->ships * shipmass (g)) > 1.0)
          /* Local report and planet, or global */
          if ((g->where == p) || p == NULL)
          {
            if (canseeplanet (P, g->from, 1))
              fs (g->from->name);
            else
              fs ("?");
            fs (g->from->num);
            fs (g->where->name);
            fs (g->where->num);
            ff (g->dist);
            if (g->fleet)
              ff (g->fleet->fleetspeed);
            else
              ff (group_speed (g->tech, g->type, shipmass (g)));
            ff (shipmass (g) * g->ships);
          }
  fend ();
}


void
print_stats (player *P)
{
  double scol, scap, smat, scapacity, ccol, ccap, cmat,hcapacity,dm,wm,sm,cm;
  int nd, nw, ns, nc;
  planet *p;
  group *g;

  scol=scap=smat=scapacity=ccol=ccap=cmat=dm=wm=sm=cm=hcapacity=0.0;
  nd=nw=ns=nc=0;

  
  for (p=planets;p;p=p->next)
  {
    if (p->owner==P)
    {
      scol+=p->col;
      scap+=p->cap;
      smat+=p->mat;
    }
  }
  for (g=P->groups;g;g=g->next)
  {
    if (g->type->cargo>0.0)
    {
       if (g->dist>0.0)
       {
         hcapacity+=g->ships*cargospace(g);
         if (g->load>0.0)
         {
           if (g->loadtype==CG_COL) ccol+=g->load*g->ships;
           if (g->loadtype==CG_CAP) ccap+=g->load*g->ships;
           if (g->loadtype==CG_MAT) cmat+=g->load*g->ships;
         }
       }
       else
       {
         scapacity+=g->ships*cargospace(g);
         if (g->load>0.0)
         {
           if (g->loadtype==CG_COL) scol+=g->load*g->ships;
           if (g->loadtype==CG_CAP) scap+=g->load*g->ships;
           if (g->loadtype==CG_MAT) smat+=g->load*g->ships;
         }
       }
       cm+=g->type->cargo*g->ships;
       nc+=g->ships;
    }
    if (g->type->drive>0.0) {dm+=g->type->drive*g->ships*g->tech.drive;nd+=g->ships;}
    if (g->type->shields>0.0) {sm+=g->type->shields*g->ships*g->tech.shields;ns+=g->ships;}
    if (g->type->guns>0.0) {wm+=weaponmass(g->type)*g->ships*g->tech.guns;nw+=g->ships;}
    
  }

  sprintf (buf, "Cargo Stats for %s\n",P->name);
  fbegin (buf, "xffff");
  fhead (" C$Mc");
  fs("Stockpiled");
  ff(scol);
  ff(scap);
  ff(smat);
  ff(scapacity);
  fs("Hyperspace");
  ff(ccol);
  ff(ccap);
  ff(cmat);
  ff(hcapacity);
  fs("Total");
  ff(ccol+scol);
  ff(ccap+scap);
  ff(cmat+smat);
  ff(hcapacity+scapacity);
  fend();

  sprintf (buf,"Ship Tech Stats for %s\n",P->name);
  fbegin(buf,"ffff");
  fhead("DWSC");
  ff(dm/(double)nd);
  ff(wm/(double)nw);
  ff(sm/(double)ns);
  ff(cm/(double)nc);
  fend();
} 
      

#ifdef FORECAST
void
forecast_report (player * P)
{
  planet *p;
  sorted *s;


  vieweropts = P->opts2;

#ifdef FCASTNAMES
  {
    int i;

    i = strlen (P->name);
    while (i && P->name[i - 1] != ' ' && P->name[i - 1] != '\'')
      i--;
    sprintf (buf, "%s.F", P->name + i);
    pr = fopen (buf, "w");
  }

#ifdef VERBOSE
  printf ("Writing forecast file %s\n", buf);
#endif

#else
  pr = fopen ("forecast.F", "w");

#ifdef VERBOSE
  printf ("Writing forecast file forecast.F\n");
#endif

#endif

  if (pr == 0)
  {
    printf ("Can't open %s\n", buf);
    exit (BADREPORT);
  }

  print_options (P);

  strcpy (buf, P->name);
  ckunderscores (buf);

#ifdef GAMENAME
  fprintf (pr, "\t\t%s FORECAST Report for game %s, Turn %d\n\n",
           buf, gamename, turn);
#else
  fprintf (pr, "\t\t%s FORECAST for Galaxy Turn %d\n\n", buf, turn);
#endif

  print_status (P, FORE_STS);
  print_shiptypes (P, 0);
  if (P->opts1 & MAP)
    domap (P);

  fbegin ("Your Systems", "xxffffffxfff");
  fhead ("N#XYSPIRPC$M");
  for (p = planets; p; p = p->next)
    if ((p->owner == P) && seenlist[ptonum (planets, p)])
      printplanet (p, P);
  fend ();

  if (P->opts1 & PROD)
  {

#ifdef PARTTECH
    if (P->opts1 & TECHPROD)
    {
      fbegin ("Ships in Production", "xxffffxffffff");
      fhead ("N#IM$STDWSCCU");
    }
    else
    {
      fbegin ("Ships in Production", "xxffffxff");
      fhead ("N#IM$STCU");
    }
#else
    fbegin ("Ships in Production", "xxffffxff");
    fhead ("N#IM$STCU");
#endif

    for (p = planets; p; p = p->next)
      if ((p->owner == P) && seenlist[ptonum (planets, p)])
        in_production (p, P->opts1 & TECHPROD);
    fend ();
  }

  print_routes (P);

#ifdef KCMD
  print_selective_defenses (P);
#endif

  print_alien_planets (P);
  if (((P->opts1 & MAP) && !(P->opts1 & UNKNOWN)) ||
      (!(P->opts1 & MAP) && (P->opts1 & UNKNOWN)))
  {
    fbegin ("Possible Unknown Systems", "xff");
    fhead ("#XY");
    for (p = planets; p; p = p->next)

      if ((!seenlist[ptonum (planets, p)]) &&
          (fabs (wrap (p->x - P->homex) - P->x) < (double) (P->size / 2)) &&
          (fabs (wrap (p->y - P->homey) - P->y) < (double) (P->size / 2)))
      {
        fs (p->num);
        ff (wrap (p->x - P->homex));    /* GE: relative coordinate fix */
        ff (cartesian(wrap (p->y - P->homey)));
      }
    fend ();
  }

  print_all_your_groups (P);
  print_your_fleets (P);

  if ((P->opts1 & FULL) && (P->opts2 & LONGFORECAST))
  {
    if (P->opts2 & SORTPLANETS)
      for (s = sorted_planets, p = s->p; s; s = s->next)
      {
        p = s->p;
        if ((seenlist[ptonum (planets, p)]) && (p->owner == P))
          print_full_planet (P, p);
      }
    else
      for (p = planets; p; p = p->next)
        if ((seenlist[ptonum (planets, p)]) && (p->owner == P))
          print_full_planet (P, p);
    print_full_alien_planets (P);
    print_unowned_planets (P);
    print_partial_reports (P);
  }

  if (pr && (pr != stdout))
    fclose (pr);
#ifdef VERBOSE
  printf ("Forecast done\n");
#endif
}
#else

#ifndef NEWGAME
void
report (player * P)
{
  planet *p;

  vieweropts = P->opts2;

  if (abs (P->lastorders) < turn)
  {
    fprintf (pr, "\t\tWarning!!!\nOrders were last received for turn %d\n\n\n",
             abs (P->lastorders));
  }


  if (player_dead (P))
  {
    fprintf (pr, "\tWe regret to inform you, but all your forces have been destroyed.\n");
    fprintf (pr, "This will be the last turn report for %s.\n\n\n", P->name);
  }
  else if (player_footnote (P) && (P->lastorders > 0))
  {

#ifdef GAMENAME
    fprintf (pr, "\tCongratulations %s, you are now an historic ", P->name);
    fprintf (pr, "footnote in %s\nWith no colonists or population, ", gamename);
    fprintf (pr, "you have no way to build new ships. ");
#else
    fprintf (pr, "\tCongratulations %s, you are now an historic footnote in the\n", P->name);
    fprintf (pr, "galaxy. With no colonists or population, you have no way to build new ships.\n");
#endif

    fprintf (pr, "Your only\nchances of winning are to arrange the ");
    fprintf (pr, "depopulation of everyone else's systems,\nand then the");
    fprintf (pr, "destruction (or scrapping) of their remaining ships. ");
    fprintf (pr, "Should you\nmanage this from the early part of the");
    fprintf (pr, "game (or actually, any part but the last\nfew turns), you ");
    fprintf (pr, "will go down in history as the best galaxy player ever!\n\n");

    P->lastorders = -P->lastorders;     /* Do not repeat message */
  }
  else if ((turn < 5) && (!P->groups) && (turn !=0))
  {
    fprintf (pr, "WARNING: You have not produced any ships!\nYour species is in danger of becoming reproductively challenged!!\n\n");
  }

  print_options (P);

#ifdef GAMENAME
  strcpy (buf, P->name);
  ckunderscores (buf);
  fprintf (pr, "\tBlind Galaxy game %s Report for %s, Turn %d\n\n", gamename, buf, turn);
#else
  strcpy (buf, P->name);
  ckunderscores (buf);
  fprintf (pr, "\t\t%s Report for Galaxy Turn %d\n\n", buf, turn);
#endif

  print_status (P, NORM_STS);   /* Do the Status section */
  if (P->opts1 & STATS)
    print_stats (P);
  print_shiptypes (P, 1);       /* Print out visible ship types */
  print_battles (P);
  if (P->opts1 & BATTLEMASS)
    print_battle_sum (P);
  print_bombings (P);
  if (P->opts1 & BOMBSUM)
    print_bombing_summary (P);

  if (P->opts1 & MAP)
    domap (P);

  print_incoming (P, NULL);     /* Incoming report section */

  fbegin ("Your Systems", "xxffffffxfff");
  fhead ("N#XYSPIRPC$M");
  for (p = planets; p; p = p->next)
    if (p->owner == P)
      printplanet (p, P);
  fend ();

  if (P->opts1 & PROD)
  {

#ifdef PARTTECH
    if (P->opts1 & TECHPROD)
    {
      fbegin ("Ship in production", "xxffffxffffff");
      fhead ("N#IM$STDWSCCU");
    }
    else
    {
      fbegin ("Ships in Production", "xxffffxff");
      fhead ("N#IM$STCU");
    }
#else
    fbegin ("Ships in Production", "xxffffxff");
    fhead ("N#IM$STCU");
#endif

    for (p = planets; p; p = p->next)
      if (p->owner == P)
        in_production (p, P->opts1 & TECHPROD);
    fend ();
  }
  print_routes (P);

#ifdef KCMD
  print_selective_defenses (P);
#endif

  print_alien_planets (P);
  print_uninhabited_planets (P);
  if (((P->opts1 & MAP) && !(P->opts1 & UNKNOWN)) ||
      (!(P->opts1 & MAP) && (P->opts1 & UNKNOWN)))
    print_unknown_planets (P);

  print_all_your_groups (P);
  print_your_fleets (P);
  print_alien_groups (P);

  /* GE: planet-group matrix */

  /* your planets */
  if (P->opts1 & FULL)
  {
    print_full_your_planets (P);
    print_full_alien_planets (P);
    print_unowned_planets (P);
    print_partial_reports (P);
  }
}
#endif

#endif

#endif
