/*
** Astrolog (Version 3.05) File: options.c
**
** IMPORTANT: The planetary calculation routines used in this program
** have been Copyrighted and the core of this program is basically a
** conversion to C of the routines created by James Neely as listed in
** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
** available from Matrix Software. The copyright gives us permission to
** use the routines for our own purposes but not to sell them or profit
** from them in any way.
**
** IN ADDITION: the graphics database and chart display routines used in
** this program are Copyright (C) 1991-1993 by Walter D. Pullen. Permission
** is granted to freely use and distribute these routines provided one
** doesn't sell, restrict, or profit from them in any way. Modification
** is allowed provided these notices remain with any altered or edited
** versions of the program.
*/

#include "astrolog.h"


/*
*******************************************************************************
** Display subroutines
*******************************************************************************
*/

/* This is a subprocedure of CreateGrid() and CreateGridRelation(). Given */
/* two planets, determine what aspect, if any, is present between them,   */
/* and save the aspect name and orb in the specified grid cell.           */

void GetAspect(planet1, planet2, i, j)
real *planet1, *planet2;
int i, j;
{
  int k;
  real l, m;

  grid->n[i][j] = grid->v[i][j] = 0;
  l = MinDistance(planet2[i], planet1[j]);
  for (k = aspects; k >= 1; k--) {
    m = l-aspectangle[k];
    if (dabs(m) < Orb(i, j, k)) {
      grid->n[i][j] = k;

      /* If -ga switch in effect, then change the sign of the orb to    */
      /* correspond to whether the aspect is applying or separating.    */
      /* To do this, we check the velocity vectors to see if the        */
      /* planets are moving toward, away, or are overtaking each other. */

      if (exdisplay & DASHga)
        m = (ret[j]-ret[i] < 0 ? -1 : 1)*Sgn(planet1[j]-planet2[i])*
          (dabs(planet1[j]-planet2[i])>180.0 ? -1.0 : 1.0)*Sgn(m)*dabs(m);
          grid->v[i][j] = (int) (m*60.0);
    }
  }
}


/* Set up the aspect/midpoint grid. Allocate memory for this array, if not */
/* already done. Allocation is only done once, first time this is called.  */

void EnsureGrid()
{
  if (grid != NULL)
    return;
  Allocate(grid, sizeof(gridstruct), gridstruct PTR);
  if (grid == NULL
#ifndef NOPC
    /* For PC's the grid better not cross a segment boundary. */
    || HIWORD(LOWORD(grid) + sizeof(gridstruct)) > 0
#endif
    ) {
    fprintf(stderr, "%s: Out of memory for grid.\n", appname);
    Terminate(1);
  }
}


/* Fill in the aspect grid based on the aspects taking place among the */
/* planets in the present chart. Also fill in the midpoint grid.       */

void CreateGrid(acc)
int acc;
{
  int i, j, k;
  real l;

  EnsureGrid();
  for (j = 1; j <= total; j++) if (!ignore[j])
    for (i = 1; i <= total; i++) if (!ignore[i])

      /* The parameter 'acc' determine what half of the grid is filled in */
      /* with the aspects and what half is filled in with the midpoints.  */

      if (acc ? i > j : i < j)
        GetAspect(planet, planet, i, j);
      else if (acc ? i < j : i > j) {
        l = Mod(Midpoint(planet[i], planet[j])); k = (int)l;    /* Calculate */
        grid->n[i][j] = k/30+1;                                 /* midpoint. */
        grid->v[i][j] = (int)((l-(real)(k/30)*30.0)*60.0);
      } else {
        grid->n[i][j] = (int)planet[j]/30+1;
        grid->v[i][j] = (int)(planet[j]-(real)(grid->n[i][j]-1)*30.0);
      }
}


/* This is similar to the previous function; however, this time fill in the */
/* grid based on the aspects (or midpoints if 'acc' set) taking place among */
/* the planets in two different charts, as in the -g -r0 combination.       */

void CreateGridRelation(acc)
int acc;
{
  int i, j, k;
  real l;

  EnsureGrid();
  for (j = 1; j <= total; j++) if (!ignore[j])
    for (i = 1; i <= total; i++) if (!ignore[i])
      if (!acc)
        GetAspect(planet1, planet2, i, j);
      else {
        l = Mod(Midpoint(planet2[i], planet1[j])); k = (int)l;  /* Calculate */
        grid->n[i][j] = k/30+1;                                 /* midpoint. */
        grid->v[i][j] = (int)((l-(real)(k/30)*30.0)*60.0);
      }
}


/* Print an interpretation for a particular aspect in effect in a comparison */
/* relationship chart. This is called from the InterpretGridRelation and     */
/* the DisplayAspectRelation routines.                                       */

void InterpretAspectRelation(x, y)
{
  int n;

  n = grid->n[y][x];
  if (n > 0 && n <= ASPECTI && x <= OBJECTS && y <= OBJECTS) {
    AnsiColor(aspectansi[n]);
    sprintf(string, "%s %s %s: Person1's", objectname[x],
      aspectname[n], objectname[y]);
    FieldWord(string); FieldWord(mindpart[x]);
    sprintf(string, interact[n],
      modifier[MIN(abs(grid->v[y][x])/150, 2)][n-1]);
    FieldWord(string);
    sprintf(string, "Person2's %s.", mindpart[y]); FieldWord(string);
    if (therefore[n][0]) {
      if (n != 1) {
        sprintf(string, "%s.", therefore[n]); FieldWord(string);
      } else
        FieldWord("These parts affect each other prominently.");
    }
    FieldWord("");
  }
}


/* Print the interpretation of each aspect in the relationship aspect grid, */
/* as specified with the -r0 -g -I switch combination.                      */

void InterpretGridRelation()
{
  int i, j;

  for (i = 1; i <= OBJECTS; i++) if (!ignore[i])
    for (j = 1; j <= OBJECTS; j++) if (!ignore[j])
      InterpretAspectRelation(i, j);
}


/* Print out an aspect (or midpoint if -g0 switch in effect) grid of a      */
/* relationship chart. This is similar to the ChartGrid() routine; however, */
/* here we have both axes labeled with the planets for the two charts in    */
/* question, instead of just a diagonal down the center for only one chart. */

void DisplayGridRelation()
{
  int i, j, k, tot = total, temp;

  if (interpret && !(exdisplay & DASHg0)) {
    InterpretGridRelation();
    return;
  }
  printf(" 2>");
  for (temp = 0, i = 1; i <= total; i++) if (!ignore[i]) {
    putchar(BOXV);
    AnsiColor(objectansi[i]);
    printf("%c%c%c", OBJNAM(i));
    AnsiColor(-1);
    temp++;
    if (column80 && temp >= 19) {
      tot = i;
      i = total;
    }
  }
  printf("\n1  ");
  for (i = 1; i <= tot; i++) if (!ignore[i]) {
    putchar(BOXV);
    AnsiColor(elemansi[(int)(planet2[i]/30.0) & 3]);
    printf("%2d%c", (int)planet2[i] % 30, DEGR2);
    AnsiColor(-1);
  }
  printf("\nV  ");
  for (i = 1; i <= tot; i++) if (!ignore[i]) {
    putchar(BOXV);
    temp = (int)(planet2[i]/30.0)+1;
    AnsiColor(elemansi[temp-1 & 3]);
    printf("%c%c%c", SIGNAM(temp));
    AnsiColor(-1);
  }
  putchar('\n');
  for (j = 1; j <= total; j++) if (!ignore[j])
    for (k = 1; k <= 4; k++) {
      if (k < 2)
        PrintTab(BOXH, 3);
      else if (k == 2) {
        AnsiColor(objectansi[j]);
        printf("%c%c%c", OBJNAM(j));
      } else {
        temp = (int)(planet1[j]/30.0)+1;
        AnsiColor(elemansi[temp-1 & 3]);
        if (k == 3)
          printf("%2d%c", (int)planet1[j] - (temp-1)*30, DEGR2);
        else
          printf("%c%c%c", SIGNAM(temp));
      }
      if (k > 1)
        AnsiColor(-1);
      for (i = 1; i <= tot; i++) if (!ignore[i]) {
        putchar(k < 2 ? BOXC : BOXV);
        temp = grid->n[i][j];
        if (k > 1)
          AnsiColor(exdisplay & DASHg0 ? elemansi[temp-1 & 3] :
            aspectansi[temp]);
        if (k < 2)
          PrintTab(BOXH, 3);
        else if (k == 2) {
          if (exdisplay & DASHg0)
            printf("%c%c%c", SIGNAM(temp));
          else
            printf("%s", aspectabbrev[temp]);
        } else if (k == 3) {
          if (exdisplay & DASHg0)
            printf("%2d%c", grid->v[i][j]/60, DEGR2);
          else
            if (grid->n[i][j]) {
              if (grid->v[i][j] < 600)
                printf("%c%2d", exdisplay & DASHga ?
                  (grid->v[i][j] < 0 ? 'a' : 's') :
                  (grid->v[i][j] < 0 ? '-' : '+'), abs(grid->v[i][j])/60);
              else
                printf("%3d", abs(temp)/60);
            } else
              printf("   ");
        } else {
          if (grid->n[i][j]) {
            temp = abs(grid->v[i][j])%60;
            printf("%d%d'", temp/10, temp%10);
          } else
            printf("   ");
        }
        AnsiColor(-1);
      }
      putchar('\n');
    }
}


/* Display all aspects between objects in the relationship comparison chart, */
/* one per line, in sorted order based on the total "power" of the aspects,  */
/* as specified with the -r0 -m0 switch combination.                         */

void DisplayAspectRelation()
{
  int pcut = 30000, icut, jcut, phi, ihi, jhi, ahi, p, i, j, k, count = 0;
  real ip, jp;

  while (TRUE) {
    phi = -1;

    /* Search for the next most powerful aspect in the aspect grid. */

    for (i = 1; i <= TOTAL; i++) if (!ignore[i])
      for (j = 1; j <= TOTAL; j++) if (!ignore[j])
        if (k = grid->n[i][j]) {
          ip = i <= OBJECTS ? objectinf[i] : 2.5;
          jp = j <= OBJECTS ? objectinf[j] : 2.5;
          p = (int) (aspectinf[k]*(ip+jp)/2.0*
            (1.0-dabs((real)(grid->v[i][j]))/60.0/aspectorb[k])*1000.0);
          if ((p < pcut || (p == pcut && (i > icut ||
            (i == icut && j > jcut)))) && p > phi) {
            ihi = i; jhi = j; phi = p; ahi = k;
          }
        }
    if (phi < 0)    /* Exit when no less powerful aspect found. */
      break;
    pcut = phi; icut = ihi; jcut = jhi;
    count++;                               /* Display the current aspect. */
    if (interpret)
      InterpretAspectRelation(jhi, ihi);
    else {
      printf("%3d:", count);
      AnsiColor(objectansi[jhi]);
      printf(" %7.7s ", objectname[jhi]);
      k = (int) planet1[jhi]/30;
      AnsiColor(elemansi[k & 3]);
      printf("%c%c%c%c%c", ret1[jhi] >= 0.0 ? '(' : '[', SIGNAM(k+1),
        ret1[jhi] >= 0.0 ? ')' : ']');
      AnsiColor(aspectansi[ahi]);
      printf(" %s with ", aspectabbrev[ahi]);
      k = (int) planet2[ihi]/30.0;
      AnsiColor(elemansi[k & 3]);
      printf("%c%c%c%c%c", ret2[ihi] >= 0.0 ? '(' : '[', SIGNAM(k+1),
        ret2[ihi] >= 0.0 ? ')' : ']');
      AnsiColor(objectansi[ihi]);
      printf(" %s", objectname[ihi]);
      PrintTab(' ', 11-StringLen(objectname[ihi]));
      AnsiColor(-1);
      k = grid->v[ihi][jhi];
      printf("- orb: %c%d,%d%d' - power:%6.2f\n",
        exdisplay & DASHga ? (k < 0 ? 'a' : 's') : (k < 0 ? '-' : '+'),
        abs(k)/60, abs(k)%60/10, abs(k)%60%10, (real) phi/1000.0);
    }
  }
}


/* Display locations of all midpoints between objects in the relationship */
/* comparison chart, one per line, in sorted zodiac order from zero Aries */
/* onward, as specified with the -r0 -m switch combination.               */

void DisplayMidpointRelation()
{
  int mcut = -1, icut, jcut, mlo, ilo, jlo, m, i, j, k, count = 0;

  if (exdisplay & DASHm0) {
    DisplayAspectRelation();
    return;
  }
  while (TRUE) {
    mlo = 21600;

    /* Search for the next closest midpoint farther down in the zodiac. */ 

    for (i = 1; i <= TOTAL; i++) if (!ignore[i])
      for (j = 1; j <= TOTAL; j++) if (!ignore[j]) {
        m = (grid->n[j][i]-1)*30*60 + grid->v[j][i];
        if ((m > mcut || (m == mcut && (i > icut ||
          (i == icut && j > jcut)))) && m < mlo) {
          ilo = i; jlo = j; mlo = m;
        }
      }
    if (mlo >= 21600)    /* Exit when no midpoint farther in zodiac found. */
      break;
    mcut = mlo; icut = ilo; jcut = jlo;
    count++;                               /* Display the current midpoint. */
    printf("%4d: ", count);
    PrintMinute((real) mlo/60.0);
    AnsiColor(objectansi[ilo]);
    printf(" %7.7s ", objectname[ilo]);
    k = (int) planet1[ilo]/30;
    AnsiColor(elemansi[k & 3]);
    printf("%c%c%c%c%c", ret1[ilo] >= 0.0 ? '(' : '[', SIGNAM(k+1),
      ret1[ilo] >= 0.0 ? ')' : ']');
    AnsiColor(WHITE);
    printf(" with ");
    k = (int) planet2[jlo]/30.0;
    AnsiColor(elemansi[k & 3]);
    printf("%c%c%c%c%c", ret2[jlo] >= 0.0 ? '(' : '[', SIGNAM(k+1),
      ret2[jlo] >= 0.0 ? ')' : ']');
    AnsiColor(objectansi[jlo]);
    printf(" %s", objectname[jlo]);
    PrintTab(' ', 11-StringLen(objectname[jlo]));
    AnsiColor(-1);
    printf("-%4d degree span.\n",
      (int) MinDistance(planet1[ilo], planet2[jlo]));
  }
}


/* Calculate any of the various kinds of relationship charts. This involves */
/* reading in and storing the planet and house positions for both charts,   */
/* and then combining them in the main single chart in the proper manner.   */

#define DegToDec(A) Sgn(A)*(floor(dabs(A))+FRACT(dabs(A))*60/100.0)

void CastRelation()
{
  real zon, lon, lat, t1, t2, t;
  int i;

  /* Read in the first chart. */

  InputData(filename);
  zon = X; lon = L5; lat = LA;
  t1 = CastChart(TRUE);
  for (i = 1; i <= SIGNS; i++) {
    house1[i] = house[i];
    inhouse1[i] = inhouse[i];
  }
  for (i = 1; i <= total; i++) {
    planet1[i] = planet[i];
    planetalt1[i] = planetalt[i];
    ret1[i] = ret[i];
  }

  /* Read in the second chart. */

  InputData(filename2);
  Mon = M; Day = D; Yea = Y; Tim = F; Zon = X; Lon = L5; Lat = LA;
  t2 = CastChart(TRUE);
  for (i = 1; i <= SIGNS; i++) {
    house2[i] = house[i];
    inhouse2[i] = inhouse[i];
  }
  for (i = 1; i <= total; i++) {
    planet2[i] = planet[i];
    planetalt2[i] = planetalt[i];
    ret2[i] = ret[i];
  }

  /* Now combine the two charts based on what relation we are doing.   */
  /* For the standard -r synastry chart, use the house cusps of chart1 */
  /* and the planets positions of chart2.                              */

  if (relation <= DASHr)
    for (i = 1; i <= SIGNS; i++)
      house[i] = house1[i];

  /* For the -rc composite chart, take the midpoints of the planets/houses. */

  else if (relation == DASHrc) {
    for (i = 1; i <= total; i++) {
      planet[i] = Midpoint(planet1[i], planet2[i]);
      planetalt[i] = (planetalt1[i]+planetalt2[i])/2.0;
      ret[i] = (ret1[i]+ret2[i])/2.0;
    }
    for (i = 1; i <= SIGNS; i++)
      house[i] = Midpoint(house1[i], house2[i]);

    /* Make sure we don't have any 180 degree errors in house cusp    */
    /* complement pairs, which may happen if the cusps are far apart. */

    for (i = 1; i <= SIGNS; i++)
      if (MinDistance(house[10], Mod(house[i]-(real)(i+2)*30.0)) > 90.0)
        house[i] = Mod(house[i]+180.0);

  /* For the -rm time space midpoint chart, calculate the midpoint time and */
  /* place between the two charts and then recast for the new chart info.   */

  } else if (relation == DASHrm) {
    T = (t1+t2)/2.0;
    t = (T*36525.0)+0.5; JD = floor(t)+2415020.0; F = FRACT(t)*24.0;
    X = (DecToDeg(zon)+DecToDeg(Zon))/2.0; X = DegToDec(X);
    F = DecToDeg(F)-DecToDeg(X); F = DegToDec(F);
    if (F < 0.0) {
      F = DecToDeg(F)+24.0; F = DegToDec(F); JD -= 1.0;
    }
    JulianToMdy(JD, &M, &D, &Y);
    L5 = (DecToDeg(lon)+DecToDeg(Lon))/2.0;
    if (dabs(Lon-lon) > 180.0)
      L5 = Mod(L5+180.0);
    L5 = DegToDec(L5);
    LA = (DecToDeg(lat)+DecToDeg(Lat))/2.0; LA = DegToDec(LA);
    Mon = M; Day = D; Yea = Y; Tim = F; Zon = X; Lon = L5; Lat = LA;
    CastChart(FALSE);

  /* There are a couple of non-astrological charts, which only require the */
  /* number of days that have passed between the two charts to be done.    */

  } else
    JD = floor((dabs(t2-t1)*36525.0)+0.5);
  HousePlace();
}


/* This is a subprocedure of DisplayInDay(). Print the interpretation for */
/* a particular instance of the various exciting events that can happen.  */ 

void InterpretInDay(source, aspect, dest)
int source, aspect, dest;
{
  if (source > OBJECTS || dest > OBJECTS)
    return;

  /* Interpret object changing direction. */

  if (aspect == -2) {
    AnsiColor(objectansi[source]);
    FieldWord("Energy representing"); FieldWord(mindpart[source]);
    FieldWord("will tend to manifest in");
    FieldWord(dest ? "an independent, backward, introverted" :
      "the standard, direct, open");
    FieldWord("manner.");
    FieldWord("");

  /* Interpret object entering new sign. */

  } else if (aspect == -1) {
    AnsiColor(objectansi[source]);
    FieldWord("Energy representing"); FieldWord(mindpart[source]);
    sprintf(string, "will be %s,", description[dest]);
    FieldWord(string);
    sprintf(string, "and it %s.", desire[dest]); FieldWord(string);
    FieldWord("");

  /* Interpret aspect between transiting planets. */

  } else if (aspect > 0 && aspect <= ASPECTI) {
    AnsiColor(aspectansi[aspect]);
    FieldWord("Energy representing"); FieldWord(mindpart[source]);
    sprintf(string, interact[aspect], modifier[1][aspect-1]);
    FieldWord(string);
    sprintf(string, "energies of %s.", mindpart[dest]); FieldWord(string);
    if (therefore[aspect][0]) {
      if (aspect > 1) {
        sprintf(string, "%s.", therefore[aspect]); FieldWord(string);
      } else
        FieldWord("They will affect each other prominently.");
    }
    FieldWord("");
  }
}


/* Search through a day, and print out the times of exact aspects among the  */
/* planets during that day, as specified with the -d switch, as well as the  */
/* times when a planet changes sign or direction. To do this, we cast charts */
/* for the beginning and end of the day, or a part of a day, and do a linear */
/* equation check to see if anything exciting happens during the interval.   */
/* (This is probably the single most complicated procedure in the program.)  */

void DisplayInDay(prog)
int prog;
{
  int time[MAXINDAY], source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY],
    sign1[MAXINDAY], sign2[MAXINDAY], occurcount, division, div,
    i, j, k, s1, s2;
  real Day2, D1, D2, divsiz, d1, d2, e1, e2, f1, f2, g;

  /* If parameter 'prog' is set, look for changes in a progressed chart. */

  division = prog ? 1 : divisions;
  divsiz = 24.0/ (real) division*60.0;

  /* If -d0 in effect, then search through the whole month, day by day. */

  if (exdisplay & DASHdm) {
    D1 = 1.0;
    if (prog && Mon2 == 0.0) {
      Mon2 = 1.0; D2 = 365.0-28.0+(real)DayInMonth(2, (int) Yea2);
    } else D2 = (real)
      DayInMonth((int) (prog ? Mon2 : Mon), (int) (prog ? Yea2 : Yea));
  } else
    D1 = D2 = Day;

  /* Start searching the day or days in question for exciting stuff. */

  for (Day2 = D1; Day2 <= D2; Day2 += 1.0) {
    occurcount = 0;

    /* Cast chart for beginning of day and store it for future use. */

    M = Mon; D = Day2; Y = Yea; F = 0.0; X = Zon; L5 = Lon; LA = Lat;
    if (progress = prog) {
      Jdp = MdyToJulian(Mon2, D, Yea2);
      M = Mon; D = Day; Y = Yea; F = Tim; X = Zon; L5 = Lon; LA = Lat;
    }
    CastChart(TRUE);
    for (i = 1; i <= SIGNS; i++) {
      house2[i] = house[i];
      inhouse2[i] = inhouse[i];
    }
    for (i = 1; i <= total; i++) {
      planet2[i] = planet[i];
      ret2[i] = ret[i];
    }

    /* Now divide the day into segments and search each segment in turn. */
    /* More segments == slower, but slightly better time accuracy.       */

    for (div = 1; div <= division; div++) {

      /* Cast the chart for the ending time of the present segment. The   */
      /* beginning time chart is copied from the previous end time chart. */

      M = Mon; D = Day2; Y = Yea; X = Zon; L5 = Lon; LA = Lat;
      F = 24.0*div/ (real) division;
      if (prog) {
        Jdp = MdyToJulian(Mon2, D+1.0, Yea2);
        M = Mon; D = Day; Y = Yea; F = Tim; X = Zon; L5 = Lon; LA = Lat;
      }
      CastChart(TRUE);
      for (i = 1; i <= SIGNS; i++) {
        house1[i] = house2[i]; inhouse1[i] = inhouse2[i];
        house2[i] = house[i];  inhouse2[i] = inhouse[i];
      }
      for (i = 1; i <= total; i++) {
        planet1[i] = planet2[i]; ret1[i] = ret2[i];
        planet2[i] = planet[i];  ret2[i] = ret[i];
      }

      /* Now search through the present segment for anything exciting. */

      for (i = 1; i <= total; i++) if (!ignore[i] &&
        (prog || i <= THINGS || i > C_HI)) {
        s1 = (int) planet1[i] / 30;
        s2 = (int) planet2[i] / 30;

        /* Does the current planet change into the next or previous sign? */

        if (!ignore[i] && s1 != s2) {
          source[occurcount] = i;
          aspect[occurcount] = -1;
          dest[occurcount] = s2+1;
          time[occurcount] = (int) (MinDistance(planet1[i],
            (real) (ret1[i] >= 0.0 ? s2 : s1) * 30.0) /
            MinDistance(planet1[i], planet2[i])*divsiz) +
            (int) ((real) (div-1)*divsiz);
          sign1[occurcount] = sign2[occurcount] = s1+1;
          occurcount++;
        }

        /* Does the current planet go retrograde or direct? */

        if (!ignore[i] && (ret1[i] < 0.0) != (ret2[i] < 0.0)) {
          source[occurcount] = i;
          aspect[occurcount] = -2;
          dest[occurcount] = ret2[i] < 0.0;
          time[occurcount] = (int) (dabs(ret1[i])/(dabs(ret1[i])+dabs(ret2[i]))
            *divsiz) + (int) ((real) (div-1)*divsiz);
          sign1[occurcount] = sign2[occurcount] = s1+1;
          occurcount++;
        }

        /* Now search for anything making an aspect to the current planet. */

        for (j = i+1; j <= total; j++) if (!ignore[j] &&
          (prog || j <= THINGS || j > C_HI))
          for (k = 1; k <= aspects; k++) {
            d1 = planet1[i]; d2 = planet2[i];
            e1 = planet1[j]; e2 = planet2[j];
            if (MinDistance(d1, d2) < MinDistance(e1, e2)) {
              SwapReal(&d1, &e1);
              SwapReal(&d2, &e2);
            }

            /* We are searching each aspect in turn. Let's subtract the  */
            /* size of the aspect from the angular difference, so we can */
            /* then treat it like a conjunction.                         */

            if (MinDistance(e1, Mod(d1-aspectangle[k])) <
                MinDistance(e2, Mod(d2+aspectangle[k]))) {
              e1 = Mod(e1+aspectangle[k]);
              e2 = Mod(e2+aspectangle[k]);
            } else {
              e1 = Mod(e1-aspectangle[k]);
              e2 = Mod(e2-aspectangle[k]);
            }

            /* Check to see if the aspect actually occurs during our    */
            /* segment, making sure we take into account if one or both */
            /* planets are retrograde or if they cross the Aries point. */

            f1 = e1-d1;
            if (dabs(f1) > 180.0)
              f1 -= Sgn(f1)*DEGREES;
            f2 = e2-d2;
            if (dabs(f2) > 180.0)
              f2 -= Sgn(f2)*DEGREES;
            if (MinDistance(Midpoint(d1, d2), Midpoint(e1, e2)) < 90.0 &&
              Sgn(f1) != Sgn(f2)) {
              source[occurcount] = i;
              aspect[occurcount] = k;
              dest[occurcount] = j;

              /* Horray! The aspect occurs sometime during the interval.   */
              /* Now we just have to solve an equation in two variables to */
              /* find out where the "lines" cross, i.e. the aspect's time. */

              f1 = d2-d1;
              if (dabs(f1) > 180.0)
                f1 -= Sgn(f1)*DEGREES;
              f2 = e2-e1;
              if (dabs(f2) > 180.0)
                f2 -= Sgn(f2)*DEGREES;
              g = (dabs(d1-e1) > 180.0 ?
                (d1-e1)-Sgn(d1-e1)*DEGREES : d1-e1)/(f2-f1);
                time[occurcount] = (int) (g*divsiz) +
                (int) ((real) (div-1)*divsiz);
              sign1[occurcount] = (int) (Mod(planet1[i]+
                Sgn(planet2[i]-planet1[i])*
                (dabs(planet2[i]-planet1[i]) > 180.0 ? -1 : 1)*
                dabs(g)*MinDistance(planet1[i], planet2[i]))/30.0)+1;
              sign2[occurcount] = (int) (Mod(planet1[j]+
                Sgn(planet2[j]-planet1[j])*
                (dabs(planet2[j]-planet1[j]) > 180.0 ? -1 : 1)*
                dabs(g)*MinDistance(planet1[j], planet2[j]))/30.0)+1;
              occurcount++;
            }
          }
      }
    }

    /* After all the aspects, etc, in the day have been located, sort   */
    /* them by time at which they occur, so we can print them in order. */

    for (i = 1; i < occurcount; i++) {
      j = i-1;
      while (j >= 0 && time[j] > time[j+1]) {
        SWAP(source[j], source[j+1]);
        SWAP(aspect[j], aspect[j+1]);
        SWAP(dest[j], dest[j+1]);
        SWAP(time[j], time[j+1]);
        SWAP(sign1[j], sign1[j+1]); SWAP(sign2[j], sign2[j+1]);
        j--;
      }
    }

    /* Finally, loop through and display each aspect and when it occurs. */

    for (i = 0; i < occurcount; i++) {
      s1 = time[i]/60;
      s2 = time[i]-s1*60;
      s1 = Mod12(s1);
      j = (int) Day2;
      if (prog) {
        g = Mon2;
        while (j > (k = DayInMonth((int) g, (int) Yea2))) {
          j -= k;
          g += 1.0;
        }
      }
      printf("%2.0f/%d%d/%4.0f ",
        prog ? g : Mon, j/10, j%10, prog ? Yea2 : Yea);  /* Print date. */
      printf("%2d:%d%d%cm ",
        s1, s2/10, s2%10, time[i] < 12*60 ? 'a' : 'p');  /* Print time. */
      AnsiColor(objectansi[source[i]]);
      if (prog)
        printf("progr ");
      printf("%7.7s", objectname[source[i]]);
      AnsiColor(elemansi[sign1[i]-1 & 3]);
      j = (ret1[source[i]] < 0.0)+(ret2[source[i]] < 0.0);
      printf(" %c%c%c%c%c", j < 1 ? '(' : (j > 1 ? '[' : '<'),
        SIGNAM(sign1[i]), j < 1 ? ')' : (j > 1 ? ']' : '>'));
      if (aspect[i] > 0)
        AnsiColor(aspectansi[aspect[i]]);
      else
        AnsiColor(WHITE);
      if (aspect[i] == -1)
        printf(" --> ");
      else if (aspect[i] == -2)
        printf(" S/%c", dest[i] ? 'R' : 'D');   /* Print a direction change. */
      else
        printf(" %s ", aspectabbrev[aspect[i]]);
      if (aspect[i] == -1) {
        AnsiColor(elemansi[dest[i]-1 & 3]);
        printf("%s", signname[dest[i]]);
        if (source[i] == 1) {
          if (dest[i] == 1)
            printf(" (Vernal Equinox)");      /* If the Sun changes sign, */
          else if (dest[i] == 4)              /* then print out if this   */
            printf(" (Summer Solstice)");     /* is a season change.      */
          else if (dest[i] == 7)
            printf(" (Autumnal Equinox)");
          else if (dest[i] == 10)
            printf(" (Winter Solstice)");
        }
      } else if (aspect[i] > 0) {
        AnsiColor(elemansi[sign2[i]-1 & 3]);
        j = (ret1[dest[i]] < 0.0)+(ret2[dest[i]] < 0.0);
        printf("%c%c%c%c%c ",
          j < 1 ? '(' : (j > 1 ? '[' : '<'), SIGNAM(sign2[i]),
          j < 1 ? ')' : (j > 1 ? ']' : '>'));
        AnsiColor(objectansi[dest[i]]);
        printf("%s", objectname[dest[i]]);
        if (source[i] == 1 && dest[i] == 2) {
          if (aspect[i] <= 3)
            AnsiColor(WHITE);
          if (aspect[i] == 1)
            printf(" (New Moon)");     /* Print out if the present */
          else if (aspect[i] == 2)     /* aspect is a New, Full,   */
            printf(" (Full Moon)");    /* or Half Moon.            */
          else if (aspect[i] == 3)
            printf(" (Half Moon)");
        }
      }
      putchar('\n');
      if (interpret)
        InterpretInDay(source[i], aspect[i], dest[i]);
      AnsiColor(-1);
    }
  }
}


/* This is a subprocedure of DisplayTransit(). Print the interpretation for */
/* a particular transit of a planet to a natal object of a chart.           */ 

void InterpretTransit(source, aspect, dest)
int source, aspect, dest;
{
  if (source <= OBJECTS && dest <= OBJECTS) {
    AnsiColor(aspectansi[aspect]);
    FieldWord("Energy representing"); FieldWord(mindpart[source]);
    sprintf(string, interact[aspect], modifier[1][aspect-1]);
    FieldWord(string);
    sprintf(string, "the person's %s.", mindpart[dest]); FieldWord(string);
    if (therefore[aspect][0]) {
      if (aspect > 1) {
        sprintf(string, "%s.", therefore[aspect]); FieldWord(string);
      } else
        FieldWord("This part of their psyche will be strongly influenced.");
    }
    FieldWord("");
  }
}


/* Search through a month, and print out the times of exact transits where   */
/* planets in the time frame make aspect to the planets in some other chart, */
/* as specified with the -T switch. To do this, we cast charts for the start */
/* and end of the month, or part of the month, and do an equation check for  */
/* aspects to the other base chart during the interval.                      */

void DisplayTransit(prog)
int prog;
{
  real planet3[TOTAL+1], house3[SIGNS+1], ret3[TOTAL+1];
  unsigned time[MAXINDAY];
  int source[MAXINDAY], aspect[MAXINDAY], dest[MAXINDAY], sign[MAXINDAY],
    isret[MAXINDAY], occurcount, div, i, j, k, s1, s2, s3;
  real M1, M2, divsiz, daysiz, d, e1, e2, f1, f2;

  for (i = 1; i <= SIGNS; i++)
    house3[i] = house[i];
  for (i = 1; i <= total; i++) {
    planet3[i] = planet[i];
    ret3[i] = ret[i];
  }
  if (Mon2 == 0.0) {        /* Searching month number zero means to search */
    M1 = 1.0; M2 = 12.0;    /* the whole year instead, month by month.     */
  } else
    M1 = M2 = Mon2;

  /* Start searching the month or months in question for any transits. */

  for (Mon2 = M1; Mon2 <= M2; Mon2 += 1.0) {
    daysiz = (real) DayInMonth((int) Mon2, (int) Yea2)*24.0*60.0;
    divsiz = daysiz/ (real) divisions;

    /* Cast chart for beginning of month and store it for future use. */

    M = Mon2; D = 1.0; Y = Yea2; F = 0.0;
    X = defzone; L5 = deflong; LA = deflat;
    if (progress = prog) {
      Jdp = MdyToJulian(M, D, Y);
      M = Mon; D = Day; Y = Yea; F = Tim; X = Zon; L5 = Lon; LA = Lat;
    }
    CastChart(TRUE);
    for (i = 1; i <= SIGNS; i++)
      house2[i] = house[i];
    for (i = 1; i <= OBJECTS; i++) {
      planet2[i] = planet[i];
      ret2[i] = ret[i];
    }

    /* Divide our month into segments and then search each segment in turn. */

    for (div = 1; div <= divisions; div++) {
      occurcount = 0;

      /* Cast the chart for the ending time of the present segment, and */
      /* copy the start time chart from the previous end time chart.    */

      M = Mon2; Y = Yea2; F = 0.0; X = defzone; L5 = deflong; LA = deflat;
      D = 1.0+(daysiz/24.0/60.0)*div/ (real) divisions;
      if (prog) {
        Jdp = MdyToJulian(M, D, Y);
        M = Mon; D = Day; Y = Yea; F = Tim; X = Zon; L5 = Lon; LA = Lat;
      }
      CastChart(TRUE);
      for (i = 1; i <= SIGNS; i++) {
        house1[i] = house2[i]; house2[i] = house[i];
      }
      for (i = 1; i <= OBJECTS; i++) {
        planet1[i] = planet2[i]; ret1[i] = ret2[i];
        planet2[i] = planet[i];  ret2[i] = ret[i];
      }

      /* Now search through the present segment for any transits. Note that */
      /* stars can be transited, but they can't make transits themselves.   */

      for (i = 1; i <= total; i++) if (!ignore[i])
        for (j = 1; j <= BASE; j++) if (!ignore2[j] &&
          (prog || j <= THINGS || j > C_HI))

          /* Between each pair of planets, check if they make any aspects. */

          for (k = 1; k <= aspects; k++) {
            d = planet3[i]; e1 = planet1[j]; e2 = planet2[j];
            if (MinDistance(e1, Mod(d-aspectangle[k])) <
                MinDistance(e2, Mod(d+aspectangle[k]))) {
              e1 = Mod(e1+aspectangle[k]);
              e2 = Mod(e2+aspectangle[k]);
            } else {
              e1 = Mod(e1-aspectangle[k]);
              e2 = Mod(e2-aspectangle[k]);
            }

            /* Check to see if the present aspect actually occurs during the */
            /* segment, making sure we check any Aries point crossings.      */

            f1 = e1-d;
            if (dabs(f1) > 180.0)
              f1 -= Sgn(f1)*DEGREES;
            f2 = e2-d;
            if (dabs(f2) > 180.0)
              f2 -= Sgn(f2)*DEGREES;
            if (MinDistance(d, Midpoint(e1, e2)) < 90.0 &&
              Sgn(f1) != Sgn(f2) && occurcount < MAXINDAY) {

              /* Ok, we have found a transit. Now determine the time */
              /* and save this transit in our list to be printed.    */

              source[occurcount] = j;
              aspect[occurcount] = k;
              dest[occurcount] = i;
              time[occurcount] = (int) (dabs(f1)/(dabs(f1)+dabs(f2))*divsiz) +
                (int) ((real) (div-1)*divsiz);
              sign[occurcount] = (int) (Mod(
                MinDistance(planet1[j], Mod(d-aspectangle[k])) <
                MinDistance(planet2[j], Mod(d+aspectangle[k])) ?
                d-aspectangle[k] : d+aspectangle[k])/30.0)+1;
              isret[occurcount] = (ret1[j] < 0.0)+(ret2[j] < 0.0);
              occurcount++;
            }
          }

      /* After all transits located, sort them by time at which they occur. */

      for (i = 1; i < occurcount; i++) {
        j = i-1;
        while (j >= 0 && time[j] > time[j+1]) {
          SWAP(source[j], source[j+1]);
          SWAP(aspect[j], aspect[j+1]);
          SWAP(dest[j], dest[j+1]);
          SWAP(time[j], time[j+1]);
          SWAP(sign[j], sign[j+1]);
          SWAP(isret[j], isret[j+1]);
          j--;
        }
      }

      /* Now loop through list and display all the transits. */

      for (i = 0; i < occurcount; i++) {
        k = smartcusp && dest[i] >= C_LO && dest[i] <= C_HI;
        if (k && aspect[i] > 2)
          continue;
        else
          k = k && aspect[i] == 2;
        s1 = time[i]/24/60;
        s3 = time[i]-s1*24*60;
        s2 = s3/60;
        s3 = s3-s2*60;
        printf("%2.0f/%d%d/%4.0f %2d:%d%d%cm ",
          Mon2, (s1+1)/10, (s1+1)%10, Yea2, Mod12(s2),
          s3/10, s3%10, s2 < 12 ? 'a' : 'p');
        AnsiColor(objectansi[source[i]]);
        printf("%s %7.7s", !prog ? "trans" : "progr", objectname[source[i]]);
        j = sign[i];
        AnsiColor(elemansi[j-1 & 3]);
        printf(" %c%c%c%c%c ",
          isret[i] < 1 ? '(' : (isret[i] > 1 ? '[' : '<'), SIGNAM(j),
          isret[i] < 1 ? ')' : (isret[i] > 1 ? ']' : '>'));
        AnsiColor(aspectansi[k ? 1 : aspect[i]]);
        printf("%s ", aspectabbrev[k ? 1 : aspect[i]]);
        j = k ? sign[i] : (int)planet3[dest[i]]/30 + 1;
        AnsiColor(elemansi[j-1 & 3]);
        printf("%c%c%c%c%c ", ret3[dest[i]] >= 0.0 ? '(' : '[',
          SIGNAM(j), ret3[dest[i]] >= 0.0 ? ')' : ']');
        AnsiColor((objectansi[dest[i]]-1 ^ k)+1);
        printf("natal ");
        if (k)
          printf("%dth cusp", dest[i]-15 - (dest[i] < 23));
        else
          printf("%s", objectname[dest[i]]);
        AnsiColor(-1);

        /* Check for a Solar, Lunar, or any other return. */

        if (aspect[i] == 1 && source[i] == dest[i]) {
          AnsiColor(WHITE);
          printf(" (%s Return)", source[i] == 1 ? "Solar" :
            (source[i] == 2 ? "Lunar" : objectname[source[i]]));
        }
        putchar('\n');
        if (interpret)
          InterpretTransit(source[i], aspect[i], dest[i]);
        AnsiColor(-1);
      }
    }
  }
}


/* Print out an ephemeris - the positions of the planets at midnight each */
/* day during a specified month, as done with the -E switch.              */

void DisplayEphemeris()
{
  real M0, M1, M2;
  int daysiz, i, j, k, s, d, m;

  /* If -Ey is in effect, then loop through all months in the whole year. */

  if (exdisplay & DASHEy) {
    M1 = 1.0; M2 = 12.0;
  } else
    M1 = M2 = Mon;

  /* Loop through the month or months in question, printing each ephemeris. */

  for (M0 = M1; M0 <= M2; M0 += 1.0) {
    daysiz = DayInMonth((int) M0, (int) Yea);
    printf("Mo/Dy/Yr");
    for (k = 0, j = 1; j <= total; j++) {
      if (!ignore[j] && (j <= THINGS || j > C_HI)) {
        printf("  %c%c%c%c ", OBJNAM(j), objectname[j][3] != 0 ?
          objectname[j][3] : ' ');
        k++;
        if (column80 && k >= 10)
          j = total;
      }
    }
    putchar('\n');
    for (i = 1; i <= daysiz; i++) {

      /* Loop through each day in the month, casting a chart for that day. */

      M = M0; D = (real) i; Y = Yea;
      F = 0.0; X = defzone; L5 = deflong; LA = deflat;
      CastChart(TRUE);
      printf("%2d/%2d/%2d ", (int) M0, i, ((int) Yea) % 100);
      for (k = 0, j = 1; j <= total; j++)
        if (!ignore[j] && (j <= THINGS || j > C_HI)) {
          AnsiColor(objectansi[j]);
          s = (int) (planet[j]/30.0) + 1;
          d = (int) planet[j] - (s-1)*30;
          m = (int) (FRACT(planet[j])*60.0);
          printf("%2d%s%s%d%c", d, signabbrev[s], m < 10 ? "0" : "", m,
            ret[j] >= 0.0 ? ' ' : '.');
          k++;
          if (column80 && k >= 10)
            j = total;
        }
      putchar('\n');
      AnsiColor(-1);
    }
    if (M0 < M2)
      putchar('\n');
  }
}


/* Display either a biorhythm chart or the number of days that have passed */
/* between two charts, i.e. two types of relationship "charts" that aren't */
/* related in any way to planetary positions, as specified by either the   */
/* -rb or -rd switches, respectively.                                      */

void DisplayRelation()
{
  int i, j;
  real k, l;

  /* If we are calculating the difference between two dates, then display */
  /* the value and return, as with the -rd switch.                        */

  if (relation == DASHrd) {
    printf("%.0f day%s ha%s passed between the dates in the two charts.\n",
     JD, JD != 1.0 ? "s" : "", JD != 1.0 ? "ve" : "s");
    return;
  }

  /* If we are doing a biorhythm (-rb switch), then we'll calculate it for */
  /* someone born on the older date, at the time of the younger date. Loop */
  /* through the week preceeding and following the date in question.       */

  for (JD -= 7.0, i = -7; i <= 7; i++, JD += 1.0) {
    if (i == 0)
      AnsiColor(WHITE);
    else if (i == 1)
      AnsiColor(-1);
    printf("T%c%d Day%c:", i < 0 ? '-' : '+', abs(i), abs(i) != 1 ? 's' : ' ');
    for (j = 1; j <= 3; j++) {
      putchar(' ');
      switch (j) {
      case 1: k = 23.0; AnsiColor(RED);   printf("Physical");     break;
      case 2: k = 28.0; AnsiColor(BLUE);  printf("Emotional");    break;
      case 3: k = 33.0; AnsiColor(GREEN); printf("Intellectual"); break;
      }
      AnsiColor(i ? -1 : WHITE);

      /* The biorhythm formula is below. */

      l = sin((JD/k)*PI*2.0)*100.0;
      printf(" at %c%3.0f%%", l < 0.0 ? '-' : '+', dabs(l));

      /* Print smiley face, medium face, or sad face based on current cycle. */

      printf(" :%c", l > 50.0 ? ')' : (l < -50.0 ? '(' : '|'));
      if (j < 3)
        putchar(',');
    }
    putchar('\n');
  }
}


/* Another important procedure: Display any of the types of (text) charts    */
/* that the user specified they wanted, by calling the appropriate routines. */

void PrintChart(prog)
{
  if (todisplay == 0)          /* Assume the -v chart if user */
    todisplay |= DASHv;        /* didn't indicate anything.   */
  if (todisplay & DASHv) {
    if (relation < DASHrd)
      ChartLocation(FALSE);
    else

      /* If the -rb or -rd relationship charts are in effect, then instead  */
      /* of doing the standard -v chart, print either of these chart types. */

      DisplayRelation();
    if (todisplay - (todisplay & DASHv*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHw) {
    ChartWheel();
    if (todisplay - (todisplay & DASHw*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHg) {
    if (relation != DASHr0) {
      CreateGrid(FALSE);
      ChartGrid(FALSE);
      if (exdisplay & DASHg0) {    /* If -g0 switch in effect, then  */
        putchar('\n');             /* display aspect configurations. */
        DisplayGrands();
      }
    } else {

      /* Do a relationship aspect grid between two charts if -r0 in effect. */

      CreateGridRelation(exdisplay & DASHg0 ? 2 : FALSE);
      DisplayGridRelation();
    }
    if (todisplay - (todisplay & DASHg*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHm) {
    if (!(todisplay & DASHg) || relation == DASHr0)
      CreateGrid(FALSE);
    if (relation != DASHr0) {
      ChartMidpoint();
      if (todisplay - (todisplay & DASHm*2-1))
        printf("\n\n");
    } else {
      CreateGridRelation((exdisplay & DASHm0) == 0);
      DisplayMidpointRelation();
    }
  }
  if (todisplay & DASHZ) {
    ChartHorizon();
    if (todisplay - (todisplay & DASHZ*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHS) {
    ChartSpace();
    if (todisplay - (todisplay & DASHS*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHj) {
    ChartInfluence();
    if (todisplay - (todisplay & DASHj*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHL) {
    ChartAstroGraph();
    if (todisplay - (todisplay & DASHL*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHd) {
    DisplayInDay(prog);
    if (todisplay - (todisplay & DASHd*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHE) {
    DisplayEphemeris();
    if (todisplay - (todisplay & DASHE*2-1))
      printf("\n\n");
  }
  if (todisplay & DASHT)
    DisplayTransit(prog);
}

/* options.c */
