/*--------------------------------------------------------------
	PR-list to postscript converter  prlst2ps  v1.8
		Written  by H.Goto, Aug.  1994
		Modified by H.Goto, Feb.  1997
		Modified by H.Goto, Sept. 1997
		Modified by H.Goto, Nov.  1997
		Modified by H.Goto, Aug.  1998
		E-Mail: hgot@ecip.tohoku.ac.jp
--------------------------------------------------------------*/

/*--------------------------------------------------------------------
  Copyright (C) 1994-1997  Hideaki Goto

        All Rights Reserved

  Permission to use, copy, modify, and distribute this software and
  its documentation for any purpose is hereby granted without fee,
  provided that (i) the above copyright notice and this permission
  notice appear in all copies and in supporting documentation, (ii)
  the name of the author, Hideaki Goto, may not be used in any
  advertising or otherwise to promote the sale, use or other
  dealings in this software without prior written authorization
  from the author, (iii) this software may not be used for
  commercial products without prior written permission from the
  author, and (iv) the notice of the modification is specified in
  case of that the modified copies of this software are distributed.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
  THE AUTHOR WILL NOT BE RESPONSIBLE FOR ANY DAMAGE CAUSED BY THIS
  SOFTWARE.
--------------------------------------------------------------------*/


#define		DefaultRuleBWID	64
#define		HT_AngleRes	1024

#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<math.h>

#include	"ufilep.h"
#include	"stdps.h"




/*------------------------------------------------------
	postscript file export class
------------------------------------------------------*/

class PSEXP {
    private:
	FILE		*fp;
    public:
	int		open(FILE *fp);
	int		line(int x0,int y0,int x1,int y1,int width);
	int		linemark(int bwid,int x,int y,int a);
	int		boxfill(int x0,int y0,int width,int height);
	int		box(int x0,int y0,int width,int height);
//	int		stickfill(int x0,int y0,int width,int height,double angle);
	int		stick(int x0,int y0,int width,int height,double angle);
	int		close(void);
			PSEXP(void);
};


PSEXP :: PSEXP(void){
	fp = stdout;
}


int PSEXP :: open(FILE *fp){
	PSEXP :: fp = fp;
	stdps_setsize("A4");
	return( stdps_header(fp) );
}


int PSEXP :: line(int x0,int y0,int x1,int y1,int width){
	fprintf(fp,"%d setlinewidth\n",width);
	fprintf(fp,"newpath %d %d moveto %d %d lineto  stroke\n",x0,y0,x1,y1);
	return(0);
}


int PSEXP :: linemark(int bwid,int x,int y,int a){
	int	x1,y1,x2,y2;
	x1 = x - (bwid /2);
	x2 = x + (bwid /2);
	y1 = y + a * (bwid /2) / HT_AngleRes;
	y2 = y - a * (bwid /2) / HT_AngleRes;
	line(x1,y1,x2,y2,3);
	return(0);
}


int PSEXP :: boxfill(int x0,int y0,int width,int height){
	if ( (width == 0) || (height == 0) )  return(0);
	fprintf(fp,"%d %d %d %d filledbox\n",x0,y0,width,height);
	return(0);
}


int PSEXP :: box(int x0,int y0,int width,int height){
	if ( (width == 0) || (height == 0) )  return(0);
	fprintf(fp,"%d %d %d %d framebox\n",x0,y0,width,height);
	return(0);
}


int PSEXP :: stick(int x0,int y0,int width,int height,double angle){
	double	x,y;
	double	c,s;
	double	w,d;
	if ( (width == 0) || (height == 0) )  return(0);
	c = cos(angle);
	s = sin(angle);
	w = (double)width /2;
	d = (double)height /2;
	x =  c * w + s * (-d);
	y = -s * w + c * (-d);
	fprintf(fp,"newpath %f %f moveto\n",x + (double)x0,y + (double)y0);
	x =  c * w + s * d;
	y = -s * w + c * d;
	fprintf(fp,"        %f %f lineto\n",x + (double)x0,y + (double)y0);
	x =  c * (-w) + s * d;
	y = -s * (-w) + c * d;
	fprintf(fp,"        %f %f lineto\n",x + (double)x0,y + (double)y0);
	x =  c * (-w) + s * (-d);
	y = -s * (-w) + c * (-d);
	fprintf(fp,"        %f %f lineto\n",x + (double)x0,y + (double)y0);
	fprintf(fp,"        closepath stroke\n");
	return(0);
}


int PSEXP :: close(void){
	return( stdps_end(fp) );
}




/*------------------------------------------------------
	Message class
------------------------------------------------------*/

class MSG {
    public:
	void		usage(void);
	void		switcherr(void);
	void		readerr(char *name);
	void		writeerr(char *name);
	void		nonsupported(char *name);
	void		memoryover(void);
};
    	
    	
void MSG :: usage(void){		// Display Usage
	puts("prlst2ps  v1.8,  Copyright (C) 1994-1998 Hideaki Goto ");
	puts("Usage : prlst2ps [-options] in_file|stdin ");
	puts("		-fill    : fill rectangle ");
	puts("		-stick   : stick display mode ");
	puts("		-lseg    : line-segment display mode ");
	puts("		-lslen N : line-segment length (Def.=64) ");
	puts("		-quiet   : suppress messages");
}


void MSG :: switcherr(void){
	puts("Switch error.");
}


void MSG :: readerr(char *name){
	printf("Can't read %s.\n",name);
}


void MSG :: writeerr(char *name){
	printf("Can't write %s.\n",name);
}


void MSG :: nonsupported(char *name){
	printf("Non-supported file %s.\n",name);
}


void MSG :: memoryover(void){
	puts("Not enough memory.");
}




/*------------------------------------------------------
	Argument / Option class
------------------------------------------------------*/

class ARGS {
    private:
	char		*fpath[16];
	int		fpcount;
    	int		sw_verbose;
	int		sw_vertical;
	int		sw_list;
	int		sw_fill;
	int		sw_mode;
	int		sw_rbwid;
    public:
	int		scanargv(int ac,char **av);
	int		SWverbose(void) {  return sw_verbose; }
	int		SWvertical(void) {  return sw_vertical; }
	int		SWlist(void) {  return sw_list; }
	int		SWfill(void) {  return sw_fill; }
	int		SWmode(void) {  return sw_mode; }
	int		SWrbwid(void) {  return sw_rbwid; }
	char		*infile(void);
	char		*outfile(void);
			ARGS(void);
};


ARGS :: ARGS(void){
	sw_verbose = -1;
	sw_vertical = 0;
	sw_list = 0;
	sw_fill = 0;
	sw_mode = 0;
	sw_rbwid = DefaultRuleBWID;
}


int ARGS :: scanargv(int ac,char **av){
	int	i1,err,skip;
	char	*sw;
	fpcount = err = 0;
	skip = 0;
	--ac;  if( ac >= 16 )  ac = 16;
	for( i1 = 0 ; i1 < ac ; ++i1 ){
		if( skip ){  skip = 0;  continue;  }
		if( *( sw = av[i1+1] ) == '-' ){
			++sw;
			if( 0 == strcmp(sw,"list") ){
				sw_list = -1;
				continue;
			}
			if( 0 == strcmp(sw,"fill") ){
				sw_fill = -1;
				continue;
			}
			if( 0 == strcmp(sw,"stick") ){
				sw_mode = 2;
				continue;
			}
			if( 0 == strcmp(sw,"lseg") ){
				sw_mode = 1;
				continue;
			}
			if( 0 == strcmp(sw,"vert") ){
				sw_vertical = -1;
				continue;
			}
			if( 0 == strcmp(sw,"quiet") ){
				sw_verbose=0;
				continue;
			}
			if( 0 == strcmp(sw,"verbose") ){
				sw_verbose = -1;
				continue;
			}
			if( 0 == strcmp(sw,"lslen") ){
				if((i1+1)<ac){
					sw_rbwid = atoi(av[i1+2]);
					skip = -1;
					continue;
				}
				else{   err = -1;  break;  }
			}
		 	err = -1;  break;
		}
		else{	fpath[fpcount++] = av[i1+1];
		}
	}
	return(err);
}


char * ARGS :: infile(void){
	if ( fpcount < 1 )  return( "" );
	return( fpath[0] );
}


char * ARGS :: outfile(void){
	if ( fpcount < 2 )  return( "/dev/null" );
	return( fpath[1] );
}




/*------------------------------------------------------
	Main routine
------------------------------------------------------*/

struct d4pac	d4p;
struct d8pac	d8p;

int main(int ac,char **av){
	ARGS		ARGS;
	MSG		MSG;
	D8LOAD		D8LD;
	PSEXP		PSEXP;
	int		retcode;
	int		rects;
	double		cpi;
	cpi = atan(1) / 45;

	if ( ac < 2 ){
		MSG.usage();
		exit(0);
	}
	if ( 0 != ARGS.scanargv(ac,av) ){
		MSG.switcherr();
		exit(1);
	}

	retcode = D8LD.open(ARGS.infile());
	switch ( retcode ){
	  case 0:	break;
	  case -3:	MSG.nonsupported(ARGS.infile());  exit(2);
	  case -4:	MSG.memoryover();  exit(3);
	  default:	MSG.readerr(ARGS.infile());  exit(2);
	}

	D8LD.rewind();
	PSEXP.open(stdout);
	rects = 0;
	switch ( ARGS.SWmode() ){
	    case 0:
		while ( 0 == D8LD.getdata(&d8p) ){
			if ( d8p.d8_data[0] == 0 && d8p.d8_data[1] == 0 \
			  && d8p.d8_data[2] == 0 && d8p.d8_data[3] == 0 ) \
				continue;

			if ( ARGS.SWfill() ){
				PSEXP.boxfill(d8p.d8_data[0],d8p.d8_data[1], \
						d8p.d8_data[2],d8p.d8_data[3]);
			}
			else{	PSEXP.box(d8p.d8_data[0],d8p.d8_data[1], \
						d8p.d8_data[2],d8p.d8_data[3]);
			}
			++rects;
		}
		break;
	    case 1:
		while ( 0 == D8LD.getdata(&d8p) ){
			if ( d8p.d8_data[0] == 0 && d8p.d8_data[1] == 0 \
			  && d8p.d8_data[2] == 0 && d8p.d8_data[3] == 0 ) \
				continue;

			PSEXP.linemark(ARGS.SWrbwid(), \
				d8p.d8_data[0],d8p.d8_data[1],d8p.d8_data[2]);
			++rects;
		}
		break;
	    case 2:
		while ( 0 == D8LD.getdata(&d8p) ){
			if ( d8p.d8_data[0] == 0 && d8p.d8_data[1] == 0 \
			  && d8p.d8_data[2] == 0 && d8p.d8_data[3] == 0 ) \
				continue;

			if ( ARGS.SWfill() ){
/*				PSEXP.stickfill(d8p.d8_data[0],d8p.d8_data[1], \
					d8p.d8_data[2],d8p.d8_data[3], \
					(double)d8p.d8_data[4] * cpi / 100);
*/			}
			else{	PSEXP.stick(d8p.d8_data[0],d8p.d8_data[1], \
					d8p.d8_data[2],d8p.d8_data[3], \
					(double)d8p.d8_data[4] * cpi / 100);
			}
			++rects;
		}
		break;
	}
	PSEXP.close();

	D8LD.close();

	if ( ARGS.SWverbose() ){
		switch ( ARGS.SWmode() ){
		    case 0:
			fprintf(stderr,"Total %d rectangles.\n",rects);
			break;
		    case 1:
			fprintf(stderr,"Total %d line segments.\n",rects);
			break;
		    case 2:
			fprintf(stderr,"Total %d sticks (rectangles).\n",rects);
			break;
		}
	}

	return(0);
}
