/* $Id: html-table.cc,v 1.4 1997/04/01 01:02:28 dps Exp $ */
/* Html table layout */
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */
#include <iostream.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif /* HAVE_STRING_H */
#ifdef HAVE_STRINGS_H
#include <strings.h>
#endif /* HAVE_STRINGS_H */
#include "tblock.h"
#include "html-table.h"
#define __EXCLUDE_READER_CLASSES
#include "lib.h"
#ifndef HAVE_ALLOCA_H
extern "C" char *alloca(int);
#else
#include <alloca.h>
#endif /* HAVE_ALLOCA_H */

struct rdata
{
   struct wd_info w;
   const char *data;
};



/* Print row after folding of columns has been done */
static void basic_print_row(int ncols, const struct rdata *cols,
                           int maxw, FILE *out)
{
   const char *s;
   int i, nsp, nz;
   align_t al;
   num_info n;
   tblock output, *outp;

   /* Print the content */
   output.add("<TR>");
   for (i=0; i<ncols; i++)
   {
     output.add("<TD>");

       s=cols[i].data;
       al=cols[i].w.align;
       if (cols[i].w.dp_col>=0)
       {
           n=scan_num(s);
           if (n.dot_pos!=-1)
           {
               nz=cols[i].w.dp_col-n.dot_pos;
               if ((!n.has_sign) && (cols[i].w.has_sign))
               {
                 /*
                   output.add("\\phantom{$-$");
                   if (nz>0)
                   {
                       while (nz--)
                           output.add('0');
                   }
                   output.add("}");
                   */
               }
               else
               {
                   if (n.has_sign)
                       nz++;   // - does not count as a digit.
                   if (nz>0)
                   {
                     /*
                       output.add("\\phantom{");
                       while (nz--)
                           output.add('0');
                       output.add("}");
                       */
                   }
               }
               if (n.has_sign)
               {
                   /* Typeset the sign in math mode */
                   output.add(*s);
                   s++;
               }
               output.add(s);
               if (nsp-cols[i].w.dp_col+n.dot_pos>0
                   && cols[i].w.align!=ALIGN_LEFT)
                   output.add(""); /* was hfill */
               al=ALIGN_DP;
               }
           }

       switch(al)
       {
       case ALIGN_DP:
           break;

       case ALIGN_LEFT:
       case ALIGN_CENTER:
       case ALIGN_RIGHT:
           output.add(s);
           break;

       default:
           fprintf(stderr,"basic_print_row: Invalid alignment\n");
           break;
       }

       output.add(" </TD> "); // Seperate columns
   }
   output.add(" \n");          // converted to \\ \n by word_wrap.
   outp=word_wrap((const char *) output, "\n", "</TR>\n", maxw, 0);
   fputs((const char *) (*outp), out);
   delete(outp);
}

extern tblock *__html_do_map(const char *);
/* Split the elements of a row */
static void print_row(int ncols, const struct rdata *dp, int maxw, FILE *out)
{
   static const char null_string[]={'\0'};
   struct rdata *rd;
   tblock *d;
   int i;

   /* Allocate structures */
   if ((rd=(struct rdata *) alloca(ncols*sizeof(rdata)))==NULL)
   {
       fprintf(stderr, "print_row: fatal alloca failure\n");
       exit(1);
   }

   /* Convert data to *TeX */
   for (i=0; i<ncols; i++)
   {
       rd[i].w=dp[i].w;
       if (dp[i].data==NULL)
       {
           rd[i].data=null_string; // Avoid complication of null in
                                   // basic_print_row
           continue;               // Move on to next item
       }

       d=__html_do_map(dp[i].data);
       if ((rd[i].data=strdup(*d))==NULL)
       {
           fprintf(stderr, "html_table::print_row: fatal alloca failure\n");
           exit(1);
       }
       delete(d);
   }
   basic_print_row(ncols, rd, maxw, out); // Printing the rows is actually
                                          // quite complex.
   for (i=0; i<ncols; i++)
   {
       if (rd[i].data!=null_string)
           free((void *) rd[i].data);  // Free data
   }
}



/* Returns NULL or text message */
const char *html_table::print_table(int wd, FILE *out, const int ruled)
{
   int i,j;
   struct rdata *d;
   const struct col_info *col;

   if ((d=(struct rdata *) alloca(cols*sizeof(struct rdata)))==NULL)
   {
       cerr<<"html_table::print_table alloca failute (fatal)\n";
       return "[Table omitted due to lack of memory]";
   }
   if (cols==0 || rows==0)
   {
       fputs("[empty tabel ignored]\n", out);
       return "[Ignored empty table]";
   }

   for (i=0, col=cdata; col!=NULL; i++, col=col->next)
       d[i].w=find_width(rows, col->data);

   if (ruled)
     fputs("<TABLE BORDER=1>", out);
   else
     fputs("<TABLE>", out);

   for (i=0; i<cols; i++)
   {
       switch(d[i].w.align)
       {
       default:
          cerr<<"Alignment "<<d[i].w.align<<" unsupported\n";
          /* Fall through */

      case ALIGN_LEFT:
        /*        fputc('l', out); */
          break;

      case ALIGN_CENTER:
        /* fputc('c', out); */
          break;

      case ALIGN_RIGHT:
        /* fputc('r', out); */
          break;
      }
   }
   fprintf(out, "\n");

   for (i=0; i<rows; i++)
   {
       for (j=0, col=cdata; col!=NULL; j++, col=col->next)
           d[j].data=(col->data)[i];
       print_row(cols, d, wd, out);
       if (i==0)
           fputs("\\hline\n", out);
   }

   fprintf(out, "</TABLE>\n");
   return NULL;
}

/* Set */
int html_table::set(int c, int r, const char *s)
{
   struct col_info *col;
   int i;

   if (c<0 || c>=cols || r<0 || r>=rows)
   {
       cerr<<"Invalid request to set "<<c<<','<<r<<" in "
           <<cols<<'x'<<rows<<" table (value "<<s<<")\n";
       return 0;
   }

   for (col=cdata, i=0; i<c && col!=NULL; i++, col=col->next) ;
   if (col!=NULL)
   {
       if (col->data[r]!=NULL)
           free((void *) col->data[r]);
       col->data[r]=strdup(s);
   }
   return 1;
}


/* Constructor */
html_table::html_table(int c, int r)
{
   int i, j;
   struct col_info *col, **nptr;

   cols=c;
   rows=r;
   cdata=NULL;                 // Hardenning against cols=0
   for (nptr=&cdata, i=0; i<cols; i++)
   {
       col=new(struct col_info);
       *nptr=col;
       col->next=NULL;
       nptr=&(col->next);
       if ((col->data=
            (const char **) malloc(rows*(sizeof(const char *))))==NULL)
       {
           cerr<<"html_table::constructor: malloc failure (fatal)\n";
           exit(1);
       }
       for (j=0; j<rows; j++)
           (col->data)[j]=NULL;
   }
}

/* Destructor */
html_table::~html_table()
{
   int i;
   struct col_info *col, *nxt;

   for (col=cdata; col!=NULL;)
   {
       for (i=0; i<rows; i++)
           if (col->data[i]==NULL)
               free((void *) col->data[i]);
       nxt=col->next;
       free(col);
       col=nxt;
   }
}