/*
       trf-table.c - table writing functions

       Ugly ugly ugly.
*/

# include       <stdio.h>
# include       <sys/types.h>
# include       "rtf.h"
# include       "rtf2troff.h"


static int      CellBorderLocIndex ();
static int      VCellBorderType ();
static char     *VCellBorderStr ();
static char     *HCellBorderStr ();


/*
       Border type tokens *follow* cell border location specifiers.
*/

void TblAttr ()
{
double  inch = (double) rtfParam / (double) rtfTpi;
int     i, j, loc;

       switch (rtfMinor)
       {
       case rtfCellBordBottom:
       case rtfCellBordTop:
       case rtfCellBordLeft:
       case rtfCellBordRight:
               if (its->nCells >= maxCell)
               {
                       fprintf (stderr,
                               "Borders specified for too many cells\n");
                       break;
               }
               loc = CellBorderLocIndex (rtfMinor);
               /*
                       Get border type tokens until non-type token seen,
                       then route non-type token normally.
               */
               for (;;)
               {
                       (void) RTFGetToken ();
                       if (!RTFCheckCM (rtfControl, rtfParAttr)
                               || (rtfMinor != rtfBorderSingle
                                       && rtfMinor != rtfBorderThick
                                       && rtfMinor != rtfBorderShadow
                                       && rtfMinor != rtfBorderDouble
                                       && rtfMinor != rtfBorderDot
                                       && rtfMinor != rtfBorderHair))
                               break;
                       if (its->nCells < maxCell)
                               its->border[its->nCells][loc] = rtfMinor;
               }
               RTFRouteToken ();       /* send non-border through router */
               break;
       case rtfRowDef:
               its->tableHeader = 0;
               its->nCells = 0;
               its->curCell = 0;
               for (i = 0; i < maxCell; i++)
               {
                       its->cellPos[i] = 0;
                       for (j = 0; j < 4; j++)
                               its->border[i][j] = rtfNoBorderType;
               }
               its->tableLeft = 0;
               its->cellGap = 0;
               break;
       case rtfRowLeft:
               break;
       case rtfRowRight:
               break;
       case rtfRowCenter:
               break;
       case rtfRowGapH:
               its->cellGap = inch;
               break;
       case rtfRowHt:
               break;
       case rtfRowLeftEdge:
               its->tableLeft = inch;
               break;
       case rtfCellPos:
               if (its->nCells >= maxCell)
                       fprintf (f, "max. table row cell count (%d) exceeded\n",
                                                       maxCell);
               else
                       its->cellPos[its->nCells++] = inch;
               break;
       case rtfMergeRngFirst:
               break;
       case rtfMergePrevious:
               break;
       }
}


void BeginTbl ()
{
int     i, n;
double  cwid;
char    *p;

       Flush ();
       FlushState ();
       SaveTblFPV ();          /* save current font, ps, vs */
       fprintf (f, ".TS\n");
       fprintf (f, "center tab(^);\n");
       for (i = 0; i < its->nCells; i++)
       {
               if ((p = VCellBorderStr (VCellBorderType (i))) != NULL)
                       fprintf (f, "%s ", p);
               cwid = its->cellPos[i];
               if (i > 0)
                       cwid -= its->cellPos[i-1];
               cwid -= EnWidth ();
               fprintf (f, "l1w(%gi) ", cwid);
       }
       if ((p = VCellBorderStr (VCellBorderType (its->nCells))) != NULL)
               fprintf (f, "%s ", p);
       fprintf (f, ".\n");
       ++its->tableHeader;

       /* print top borders */
       n = 0;
       for (i = 0; i < its->nCells; i++)
       {
               if (its->border[i][topIndex] != rtfNoBorderType)
                       ++n;
       }
       if (n > 0)
       {
               for (i = 0; i < its->nCells; i++)
               {
                       if (i > 0)
                               fprintf (f, "^");
                       if ((p = HCellBorderStr (its->border[i][topIndex]))
                                                               != NULL)
                               fprintf (f, "%s", p);
               }
               fprintf (f, "\n");
       }
}


void EndTbl ()
{
int     i, n;
char    *p;

       /* print bottom borders */
       n = 0;
       for (i = 0; i < its->nCells; i++)
       {
               if (its->border[i][bottomIndex] != rtfNoBorderType)
                       ++n;
       }
       if (n > 0)
       {
               for (i = 0; i < its->nCells; i++)
               {
                       if (i > 0)
                               fprintf (f, "^");
                       if ((p = HCellBorderStr (its->border[i][bottomIndex]))
                                                               != NULL)
                               fprintf (f, "%s", p);
               }
               fprintf (f, "\n");
       }
       fprintf (f, ".TE\n");   /* this undoes ps/vs... */
       FlushTblFPV ();         /* so redo it.  ugh. */
       FlushState ();
       its->tableHeader = 0;
       its->curCell = 0;
}


/*
       BeginCell() called when first \intbl in row is seen and after
       each \cell; EndCell() called whenever \cell or \row are seen.
       These do nothing if the cell number is greater than would be
       expected given the number of cell positions found in the table
       layout information.  (It *is* possible to find information
       beyond the last cell; Word for Macintosh, at least, seems to put an
       empty cell at the end of each row.)
*/

void BeginCell ()
{
       /* accept cells 0..nCells-1 */
       if (its->curCell < its->nCells)
       {
               Flush ();
               fprintf (f, "T{\n");
               /*FlushState ();*/
               FlushTblFPV ();         /* set up correct font, ps, vs */
       }
       inTable = 1;
}


void EndCell ()
{
       Flush ();
       /* accept cells 0..nCells-1 */
       if (its->curCell < its->nCells)
       {
               fprintf (f, "T}");
       }
       ++its->curCell;
       if (its->curCell < its->nCells)
               fprintf (f, "^");       /* more cells to go */
       else if (its->curCell == its->nCells)
               fprintf (f, "\n");      /* no more cells to go */
       inTable = 0;
}


static int CellBorderLocIndex (loc)
int     loc;
{
       switch (loc)
       {
       case rtfCellBordLeft: return (leftIndex);
       case rtfCellBordRight: return (rightIndex);
       case rtfCellBordTop: return (topIndex);
       case rtfCellBordBottom: return (bottomIndex);
       }
       fprintf (stderr, "CellBorderLocIndex: bad argument (%d)\n", loc);
       exit (1);
}


/*
       Determine vertical border for left of cell i.  Takes into account
       right border of i-1 and left border of i, with the latter taking
       precedence.  Two special cases are handled implicitly in code
       below.  When i = 0, return left border of cell 0.  When i = nCells,
       return right border of cell nCells-1.
*/

static int VCellBorderType (i)
int     i;
{
int     border = rtfNoBorderType;

       if (i >= 0 && i < its->nCells)
               border = its->border[i][leftIndex];
       if (i > 0 && i <= its->nCells && border == rtfNoBorderType)
               border = its->border[i-1][rightIndex];
       return (border);
}


static char *VCellBorderStr (type)
int     type;
{
       switch (type)
       {
       case rtfBorderShadow:
       case rtfBorderThick:
       case rtfBorderDot:
       case rtfBorderHair:
       case rtfBorderSingle: return ("|");
       case rtfBorderDouble: return ("||");
       }
       return (NULL);
}


static char *HCellBorderStr (type)
int     type;
{
       switch (type)
       {
       case rtfBorderShadow:
       case rtfBorderThick:
       case rtfBorderDot:
       case rtfBorderHair:
       case rtfBorderSingle: return ("_");
       case rtfBorderDouble: return ("=");
       }
       return (NULL);
}