/* $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;
    }
}



