/*
 *  TEX Device Driver  ver 2.00-
 *  copyright 1988, 1989 by TSG, 1990-93 by SHIMA
 *
 *  putdvi.c :
 *      3rd edition
 *
 *	modified for non PC-9801 machines by sempa 1992
 *	very slightly modified against warnings by Oh-Yeah? 25 May 1992
 */

#include <stdio.h>
#define _DEF_STDIO_H_
#include <ctype.h>
#include "dd.h"
#include "err.h"
#include "dviread.h"

#define TO_FLG     '-'
#define OPTION_FLG '-'
#define	TOP_PAGE	0x40
#define	F_PRINTER	0x80

#define min(a,b) ( (a) < (b) ? (a) : (b) )
#define max(a,b) ( (a) > (b) ? (a) : (b) )

BOOL device_open_flag = FALSE;
static int f_even = FALSE;
static int num_scroll = 1;
int unit_pages = 1;
int current_page;
char *f_page_scroll;

extern BOOL dvifile_page;
extern DIMENSION dviout_dimension;

/* bitmap.c */
void bitmap_init(OUTPUT_INFO *out);

/* clrbuf.asm ( or buffer.c ) */
void clear_buf(BUF_INFO *);

/* device.c */
void device_init(DIMENSION *);
void device_end(DIMENSION *);
void device_clear(OUTPUT_INFO *);
NEXT_ACTION device_out(OUTPUT_INFO *, DIMENSION *);

/* pret.c */
void interpret(OUTPUT_INFO *);

/* size.c, prtsize.c */
PIXEL sptopixel(SCALED_PT);
PIXEL vtopixel(SCALED_PT);

/* stack.c */
void stack_rewind(void);

/* p_out() */
void pr_new_page(void);

#ifdef	FDOWN
extern int f_download;

#endif

typedef enum {
	FORWARD, REVERSE
} SearchDirection;

void put_dvi(DVIFILE_INFO *, DIMENSION *, int, char **);
void init_output(OUTPUT_INFO *);
static BOOL print_page(DVIFILE_INFO *, DIMENSION *);
static void set_output_size(DIMENSION *, OUTPUT_INFO *);
static BOOL search_page(int, char **, DIMENSION *);
static int strtopage(char **, DIMENSION *, SearchDirection);

void put_dvi(DVIFILE_INFO *dvi, DIMENSION *dim, int argc, char **argv)
	/* dviファイルをコマンドラインのページ指定に従って出力．
     */
{
	char *tmp;
	int part;
	BOOL do_print;

	ENTER("put_dvi");

	for (tmp = f_page_scroll; *tmp; tmp++) {
		if (*tmp == 'e') {
			f_even = TRUE;
			goto skip_2;
		}
		if (*tmp == 'o') {
skip_2:		num_scroll = (num_scroll > 0) ? 2 : -2;
		}
		else if (*tmp == 'r')
			num_scroll = -num_scroll;
	}

	device_init(dim);
	device_open_flag = TRUE;
	part = 0;

	if (dim->start_page > 0 && dim->start_page <= dim->total_page) {
		if (argc > 2 && *argv[argc - 2] != OPTION_FLG)
			goto repeat;
		dim->prt_type |= TOP_PAGE;
		dim->end_page = dim->total_page;
		print_page(dvi, dim);
	}
	else {
repeat:
#ifdef	FDOWN
		if (f_download) {
			if (f_download == 1) {
				clear_buf(bitmap_buf_pointer);
				fprintf(stderr, "Font counting: ");
			}
			else
				fprintf(stderr, "\n");
		}
#endif
		for (do_print = search_page(argc, argv, dim); do_print;
			 do_print = search_page(argc, NULL, dim)) {
			if ((num_scroll & 1) == 0) {
				if (f_even) {
					if ((dim->start_page & 1) != 0)
						dim->start_page++;
					if ((dim->end_page & 1) != 0)
						dim->end_page--;
				}
				else {
					if ((dim->start_page & 1) == 0)
						dim->start_page++;
					if ((dim->end_page & 1) == 0)
						dim->end_page--;
				}
			}
			if (dim->start_page > dim->end_page)
				continue;
			/* search all page-directions */
			if (
#ifdef	FDOWN
				   f_download != 1 &&
#endif
				   part++)
				pr_new_page();
			if (!print_page(dvi, dim))
				break;
		}
#ifdef	FDOWN
		if (f_download++ == 1) {
			d_resume();
			goto repeat;
		}
#endif
	}

	device_end(dim);
	device_open_flag = FALSE;

	END();
}

static int strtopage(char **str_ptr, DIMENSION *dim, SearchDirection dir)
	/* string to integer */
{
	char *ptr;
	int page = 0;
	int i, num;

	ENTER("strtopage");

	ptr = *str_ptr;
	while (isdigit(*ptr))
		page = page * 10 + (*ptr++ - '0');

	*str_ptr = ptr;

	if (dvifile_page) {
		for (i = 1; i < dim->total_page; i++) {
			num = (dir == REVERSE) ? (dim->total_page - i + 1) : i;
			if (dim->page_index[num].number == page)
				RETURN(num);
		}
		error(PROGRAM_STOP, "No such a page : dvifile-page : %d", page);
	}
	RETURN(page);
}

static BOOL search_page(int argc, char **argv, DIMENSION *dim)
	/* search pages directed in command-line from dvi-file */
{
	static char **page_dir = NULL;
	static int count = 0;
	int i;
	char *str;

	ENTER("search_page");

	if (argv != NULL) {
		count = 0;
		for (i = 1; i < argc; i++)
			/* Skip options */
			if (*argv[i] != OPTION_FLG) {
				page_dir = &argv[i];
				count = i;
				break;
			}
		/* Now, 'page_dir' directs ptr-ptr of dvi-filename */
		if (count == argc - 1) {
			/* When no page-directions... */
			dim->start_page = 1;
			dim->end_page = dim->total_page;
			RETURN(TRUE);
		}
	}
	if (++count >= argc)
		/* When all page-directions are over */
		RETURN(FALSE);

	str = *++page_dir;
	dim->start_page = (*str == TO_FLG) ? 1 : strtopage(&str, dim, FORWARD);

	if (*str == '+') {
		dim->prt_type |= TOP_PAGE;
		str++;
		goto skip;
	}
	if (*str++ == TO_FLG)
	  skip:dim->end_page = (*str == '\0') ?
			dim->total_page : strtopage(&str, dim, REVERSE);
	else
		dim->end_page = dim->start_page;
	RETURN(TRUE);
}

static BOOL print_page(DVIFILE_INFO *dvi, DIMENSION *dim)
	/* print pages between start_page and end_page in DIMENSION */
{
	OUTPUT_INFO output;
	BOOL part_printing, do_next_part;
	int page;

#if	defined(J3100) || defined(AX) || defined(DOSV)
	int previous_page = 0, previous_split = 0;

#endif
	BOOL last_part = FALSE;

	ENTER("print_page");

	output.dvifile_ptr = dvi->file_ptr;
	output.print_direction = dim->print_direction;
	output.bitmap_ptr = (HUGE_BUF *)bitmap_buf_pointer->start;

	page = (num_scroll > 0) ? dim->start_page : dim->end_page;

	if ((dim->prt_type & TOP_PAGE) != 0)
		dim->start_page = 1;

	for (;;) {

		if (page < 1 || page > dim->total_page)
			error(WARNING, "No such a page: %d", page);

		output.page_start_offset = (dim->page_index)[page].offset;
		output.page = page;
		output.split = (last_part)?dim->split:1;
		last_part = FALSE;

#if defined(J3100) || defined(AX) || defined(DOSV)
		if ((dviout_dimension.prt_type & F_PRINTER) == 0) {
			fprintf(stderr, "[%d]", output.page);
		}
#endif
		do {
			set_output_size(dim, &output);
			init_output(&output);

			/* initializing */
#ifdef	FDOWN
			if (f_download == 1) {
#ifdef	PC9801
				fprintf(stderr, "[%d]", output.page);
#endif
				interpret(&output);
				part_printing = do_next_part = FALSE;
				goto next_part;
			}
#endif
			clear_buf(bitmap_buf_pointer);
			if ((dviout_dimension.prt_type & F_PRINTER) != 0) {
#if	defined(J3100) || defined(AX) || defined(DOSV)
				if (previous_page != 0) {
					fprintf(stderr, "\x1b" "[;H");
					fprintf(stderr, ((dim->split > 1) ? "[%d-%d]" : "[%d]"),
							previous_page, previous_split);
				}
#endif
				fprintf(stderr, ((dim->split > 1) ? "->[%d-%d]" : "->[%d]"),
						output.page, output.split);
			}
			interpret(&output);
			/* interpret dvi-file */
			device_clear(&output);
#ifdef	PC9801
			fprintf(stderr, ((dim->split > 1) ? "[%d-%d]" : "[%d]"),
					output.page, output.split);
			/* printing the page and split */
#endif
#if	defined(J3100) || defined(AX) || defined(DOSV)
			previous_page = output.page;
			previous_split = output.split;
#endif
			for (;;) {
				part_printing = TRUE;
				do_next_part = FALSE;
				switch (device_out(&output, dim)) {
				  case NextPage:
					  if (unit_pages < 0) {
						  unit_pages = -unit_pages;
						  goto prev_page;
					  }
					  if (page < dim->end_page) {
						  do_next_part = TRUE;
						  page = min(page + unit_pages, dim->end_page);
					  }
					  part_printing = FALSE;
					  break;
				  case PreviousPage:
					  prev_page:if (page > dim->start_page) {
						  do_next_part = TRUE;
						  page = max(page - unit_pages, dim->start_page);
					  }
					  part_printing = FALSE;
					  break;
				  case NextPart:
					  if (output.split < dim->split) {
						  output.split++;
						  do_next_part = TRUE;
					  }
					  else {
						  if (page < dim->end_page ||
							  (dviout_dimension.prt_type & F_PRINTER) == 0) {
							next_part:page += num_scroll;
							  if (page <= dim->end_page
								  && page >= dim->start_page) {
								  do_next_part = TRUE;
								  part_printing = FALSE;
							  }
						  }
					  }
					  break;
				  case PreviousPart:
					  part_printing = TRUE;
					  if (output.split > 1) {
						  do_next_part = TRUE;
						  output.split--;
					  }
					  else{
						  if (page > dim->start_page){
							  page -= num_scroll;
							  if (page <= dim->end_page
								  && page >= dim->start_page) {
								  last_part = do_next_part = TRUE;
								  part_printing = FALSE;
							  }
						  }
					  }
					  break;
				  case NextPageDirection:
					  RETURN(TRUE);
				  case EscapeQuit:
					  RETURN(FALSE);
				}
				unit_pages = 1;
				if (!do_next_part) {
#ifdef FDOWN
					if (f_download != 1)
#endif
						putchar('\007');
					if ((dviout_dimension.prt_type & F_PRINTER) == 0) {
						RETURN(TRUE);
					}
				}
				else
					break;
			}
		} while (part_printing);
#ifdef FDOWN
		if (f_download != 1)
#endif
			pr_new_page();
	}
}

void init_output(OUTPUT_INFO *output)
{
	fseek(output->dvifile_ptr, output->page_start_offset, SEEK_SET);
	/* ページの先頭に持っていく．*/
	stack_rewind();
	bitmap_init(output);
	current_page = output->page;
}

static void set_output_size(DIMENSION *dim, OUTPUT_INFO *out)
{
	PIXEL header_depth;
#ifndef	NNSZ
	extern BOOL f_use_new_size_option;
#endif
	ENTER("set_output");

	header_depth = vtopixel((SCALED_PT)HEADER_DEPTH);

#ifndef	NNSZ
	if (f_use_new_size_option) {
		if (out->print_direction == HORIZONTAL) {
			out->h_0 = -dim->x_offset;
			out->width = dim->buf_width;
			out->v_0 = (out->split - 1) * dim->buf_height;
			out->height = min(dim->buf_height, dim->text_height - out->v_0);
			out->v_0 -= dim->y_offset;
		}
		else {
			out->h_0 = (out->split - 1) * dim->buf_width;
			out->width = min(dim->buf_width, dim->text_height - out->h_0);
			out->h_0 -= dim->y_offset;
			out->v_0 = -dim->x_offset;
			out->height = dim->buf_height;
		}
	}
	else
#endif
		{
		header_depth = vtopixel((SCALED_PT)HEADER_DEPTH);

		if (out->print_direction == HORIZONTAL) {
			out->h_0 = -dim->x_offset;
			out->width = dim->buf_width;
			out->v_0 = (out->split - 1) * dim->buf_height;
			out->height = min(dim->buf_height, dim->text_height - out->v_0);
			out->v_0 -= header_depth + dim->y_offset;
		}
		else {
			out->h_0 = (out->split - 1) * dim->buf_width;
			out->width = min(dim->buf_width, dim->text_width - out->h_0);
			out->h_0 -= dim->y_offset;
			out->v_0 = -header_depth - dim->x_offset;
			out->height = dim->buf_height;
		}
	}

	out->byte_width = (out->width + 7) / 8;
	out->byte_height = (out->height + 7) / 8;

	END();
}

/* end of file : putdvi.c */
