/* $Id: reader.h,v 1.23 1997/04/17 15:38:19 dps Exp $ */
/* header file for the reader */

#ifndef __w6_reader_h__
#define __w6_reader_h__
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_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 <iostream.h>
#include "tblock.h"
#include "interface.h"
#include "fifo.h"
#include "word6.h"

/* Raw reader output */
typedef enum
{
    CH_PAR=0, CH_FIELD, CH_ROW, CH_SPEC, CH_ENDSPEC, CH_OTHER,
    CH_HDRTN, CH_EOF, CH_PAGE, CH_FOOTNOTE,
    CONTROL_FLAG=(1<<17), PART_FLAG=(1<<18)
} chunk_type;

#define CH_NONL 255
#define CH_SUSPECT 127

/*
 * Anything shorter than in totla this is word abuse an all spec
 * paragraph. This should be kept *very* small.
 */
#define DISPL_TRESHOLD 3
#define PAR_ITEM_SEP_LIMIT 4
#define TEXT_ITEM_SEP_LIMIT 1024

#ifndef __EXCLUDE_READER_CLASSES

struct chunk_rtn
{
    tblock txt;
    int type;
};

/* This class converts raw word 6 into chunks for easier digestion */
class chunk_reader
{
 private:
    tblock text;
    istream *in;		/* Maybe should use istream here */
    const char *tptr;		/* Points to tblock text */
    int type;			/* Type */

    void read_chunk_raw(void);	/* Reads a lot */
 protected:
    struct chunk_rtn read_chunk(void); /* Returns the next bit */

    inline chunk_reader(istream *f)
    {
	tptr=NULL;
	in=f;
    }
    inline ~chunk_reader(void) {}; /* Avoids compiler bug */
};


/*
 * This class interpolates stuff not in the chunks, for example the
 * the start and statistics of tables.
 */
class tok_seq: private chunk_reader
{
    /* Classes used here */
public:
    /* Public token class */
    class tok
    {
    private:
	enum {TABLE=0, TEXT} dtype;

    public:
	enum { TOK_START=0, TOK_END };
	token tokval;
	union
	{
	    struct
	    {
		int rows;
		int cols;
	    } table;
	    const char *d;
	} data;
	int end;

	friend ostream &operator <<(ostream &, const tok *f);
	tok &operator=(const tok &d);

	/* Avoid the need to cast NULL everywhere  for NULL defined as
	   (void *) 0 */
	inline tok(token t, void *d, int e)
	{
	    tokval=t;
	    data.d=(const char *) d;
	    dtype=TEXT;
	    end=e;
	}
	/* Avoid the need to cast NULL everywhere for NULL defined as 0 */
	inline tok(token t, int d, int e)
	{
	    d=d;
	    tokval=t;
	    data.d=(const char *) NULL;
	    dtype=TEXT;
	    end=e;
	}
	/* Avoid the need to cast NULL everywhere for NULL defined as 0L */
	inline tok(token t, long int d, int e)
	{
	    d=d;
	    tokval=t;
	    data.d=(const char *) NULL;
	    dtype=TEXT;
	    end=e;
	}

	inline tok(token t, const char *d, int e)
	{
	    tokval=t;
	    if (d!=NULL)
		data.d=strdup(d);
	    else
		data.d=NULL;
	    dtype=TEXT;
	    end=e;
	}
	inline tok(token t, int c, int r, int e)
	{
	    tokval=t;
	    data.table.rows=r;
	    data.table.cols=c;
	    dtype=TABLE;
	    end=e;
	}
	inline ~tok(void)
	{
	    if (dtype==TEXT && data.d!=NULL)
		free((void *) data.d);
	}
    };


private:
    /* Private class for table information */
    class table_info
    {
    private:
	fifo<tok> toks;

    public:
	int rows;
	int cols;
	int col;

	inline table_info(void)
	{
	    cols=0;
	    col=0;
	    rows=0;
	}

	inline void tok_push(token t, tblock *s)
	{
	    tok *td;
	    td=new(tok)(t, (const char *) (*s), tok::TOK_START);
	    toks.enqueue(td);
	    td=new(tok)(t, (void *) NULL, tok::TOK_END);
	    toks.enqueue(td);
	}

	inline void enqueue(const tok *t)
	{
	    toks.enqueue(t);
	}

	inline void finish(fifo<tok> *out)
	{
	    tok *t;

	    t=new(tok)(T_TABLE, cols, rows, tok::TOK_START);
	    out->enqueue(t);
	    out->transfer(&toks);
	    t=new(tok)(T_TABLE, cols, rows, tok::TOK_END);
	    out->enqueue(t);
	}
	inline ~table_info(void) {} // Avoid compiler bug
    };

private:
    fifo<tok> output;		/* Output with equation cleaned up */
    const tok *saved_tok;
    int done_end;
    table_info *table;
    int rd_token(void);
    const tok *feed_token(void);
    const tok *math_collect(void);

    /* Token pusher */
    inline void tok_push(token t, tblock *s)
    {
	tok *td;
	td=new(tok)(t, (const char *) (*s), tok::TOK_START);
	output.enqueue(td);
	td=new(tok)(t, (void *) NULL, tok::TOK_END);
	output.enqueue(td);
    }

    const tok *eqn_rd_token(void);
	
    /* List handling */
    typedef enum { LIST_BULLET, LIST_ENUMERATE, LIST_ENUM_ALPHA } l_type;
    struct list_info
    {
	struct list_info *next_list;
	l_type list_type;
	int obj_cnt;
	int text_cnt;
	int items;
	union
	{
	    int item_no;
	    int lbullet;
	} ldata;
	fifo<tok_seq::tok> *last_item;
    };
    struct list_info *lp;	/* List pointer */
    fifo<tok> outqueue;		/* Final output (so far...) */
    fifo<tok> *recycled;	/* elements to be processed again */
    struct list_info *list_type(const char *);
    const char *list_check(const char *, struct list_info **);
    const char *l_type_name(const struct list_info *);

 public:


    tok_seq(istream *in):  chunk_reader(in)
    {
	tok *t=new(tok)(T_DOC, "Converted by word2x", tok::TOK_START);
	table=NULL;		/* No table */
	saved_tok=NULL;		/* No saved token */
	lp=NULL;		/* No list */
	recycled=NULL;		/* Nothing recycled */
	done_end=0;

	output.enqueue(t);
    }

    inline void return_toks(fifo<tok> *tp)
    {
	if (recycled==NULL)
	    recycled=new(fifo<tok>);
	recycled->ins_trans(tp);
    }   
    
    inline ~tok_seq(void) {}	// Avoids compiler bug

    const tok *read_token(void);

};
#endif /* __EXCLUDE_READER_CLASSES */
#endif /* __w6_reader_h__ */




