/*
 * pswrap - put a prologue and epilogue around a postscript file
 */
#include <stdio.h>
#include <math.h>
#include <sys/types.h>
#include <sys/time.h>

int ps_box_size = 10000; /* the diagram is assumed to be in a 10000x10000 box */
char *title = "standard input";
int font_size = 200;
int font_size_set = 0;
float x_pos = 1;	/* prfloating size and position, in inches */
float y_pos = 1;
float x_size = 6;
float y_scale = 1;
int x_pack;
int y_pack;
float page_bottom = 1;
float page_height = 9; /* from bottom, the date will go just above this */
float page_margin = 1;
float page_width  = 6; /* from margin */
int n_diagrams = 0;
int do_date = 1;
char *diag[100];
char *my_name;
char *user;
char *date;

char *options_description[] = {
"-nodate	: don't display the date",
"-fontsize N	: set the fontsize used in the diagrams",
"-y_scale S	: set the ratio height:width",
  NULL
};


int error(void *s,
          void *p)

{
  char str[200];
  sprintf(str,"%s: %s\n",my_name,s);
  fprintf(stderr,str,p);
  exit(1);
}

int main(int argc ,
         char *argv[] )

{
  struct timeval tv;
  struct timezone tz;
  gettimeofday(&tv,&tz);
  date = ctime(&tv.tv_sec);
  my_name = argv[0];
  process_options(argv);
  find_best_packing();
  print_diagrams();
}

int print_diagrams(void)

{
  char **p = diag;
  float x,y;
  int i,j;
  y = page_bottom + page_height - x_size*y_scale;
  x = page_margin;
  /* font size gets smaller as drawing boxes get smaller, but not unreadable */
  if (!font_size_set) font_size = (sqrt(x_size)*ps_box_size)/81.65;
  header();
  i = j = 0;
  while (*p) {
    printf("%% file: %s of %d, position %g %g, scale %g %g\n",*p,n_diagrams,x,y,x_size,x_size*y_scale);
    printf("save 72 72 scale %g %g translate\n",x,y);
    printf("%g %g scale save\n",x_size,x_size*y_scale);
    printf("1 %d div 1 %d div scale\n",ps_box_size,ps_box_size);
    printf("[] 0 setdash 1 setlinewidth\n");
    cat(*p);
    printf("restore restore\n");
    /* fprintf(stderr,"i=%d x_pack=%d j=%d y_pack=%d\n",i,x_pack,j,y_pack); */
    if (++i<x_pack) {
      x += x_size;
    } else {
      j++;
      i = 0;
      y -= y_scale*x_size;
      x = page_margin;
    }
    p++;
  }
  trailer();
}

int cat(char *file )

{
  FILE *f;
  int c;
  extern char *sys_errlist[];
  extern int errno;
  if (!strcmp("-",file))
    f=stdin;
  else
    f=fopen(file,"r");
  if (f==NULL) {
    fprintf(stderr,"%s: can't open \"%s\": %s\n",my_name,file,sys_errlist[errno]);
  } else {
    while ((c=getc(f))!=EOF) putchar(c);
  }
}

int header(void)

{
  printf("%%!PS-Adobe-1.0\n");
  printf("%%%%Creator: pswrap\n");
  printf("%%%%For: %s\n",getenv("USER"));
  printf("%%%%CreationDate: %s",date);
  printf("%%%%Title: diagrams\n");
  printf("%%%%Pages: (atend)\n");
  printf("%%%%DocumentFonts: (atend)\n");
  printf("/inches { 72 mul } def\n");
  printf("/cm { 28.34646 mul } def\n");
  printf("%% xy xy xy xy\n");
  printf("/sqfill {\n");
  printf("    newpath\n");
  printf("    moveto\n");
  printf("    lineto\n");
  printf("    lineto\n");
  printf("    lineto\n");
  printf("    closepath\n");
  printf("    gsave\n");
  printf("    polygray setgray\n");
  printf("    fill\n");
  printf("    grestore\n");
  printf("    0 setgray\n");
  printf("    stroke\n");
  printf("} def\n");
  printf("%% xy xy xy\n");
  printf("/trfill {\n");
  printf("    newpath\n");
  printf("    moveto\n");
  printf("    lineto\n");
  printf("    lineto\n");
  printf("    closepath\n");
  printf("    gsave\n");
  printf("    polygray setgray\n");
  printf("    fill\n");
  printf("    grestore\n");
  printf("    0 setgray\n");
  printf("    stroke\n");
  printf("} def    \n");
  printf("/sq {\n");
  printf("    newpath\n");
  printf("    moveto\n");
  printf("    lineto\n");
  printf("    lineto\n");
  printf("    lineto\n");
  printf("    closepath\n");
  printf("    0 setgray\n");
  printf("    stroke\n");
  printf("} def\n");
  printf("/tr {\n");
  printf("    newpath\n");
  printf("    moveto\n");
  printf("    lineto\n");
  printf("    lineto\n");
  printf("    closepath\n");
  printf("    0 setgray\n");
  printf("    stroke\n");
  printf("} def\n");
  printf("/label {\n");
  printf("    %d mul\n",font_size);
  printf("    dup\n");
  printf("    0 lt { %d add } if\n",ps_box_size);
  printf("    exch\n");
  printf("    %d mul\n",font_size);
  printf("    dup\n");
  printf("    0 lt { %d add } if\n",ps_box_size);
  printf("    exch\n");
  printf("    moveto\n");
  printf("    show\n");
  printf("} def\n");
  printf("/text {\n");
  printf("    moveto\n");
  printf("    show\n");
  printf("} def\n");
  printf("%%%%EndProlog\n");
  printf("gsave\n");
  printf("/Courier findfont\n");
  printf("%d scalefont setfont\n",font_size);
}

int trailer(void)

{
  printf("showpage\n");
  printf("grestore\n");
  printf("%%%%Trailer\n");
  printf("%%%%DocumentFonts: Courier\n");
  printf("%%%%Pages: 1\n");
}

int process_options(char *argv[] )

{
  char *p;
  while (p = *(++argv)) {
    if (*p == '-') {
      p++;
      if (prefix(p,"ps_scale")) {
	if (!*(++argv)) error("Expected box size after '-%s'",p);
	ps_box_size = atoi(*argv);
      } else if (prefix(p,"nodate")) {
	do_date = 0;
      } else if (prefix(p,"fontsize")) {
	if (!*(++argv)) error("Expected number after '-%s'",p);
	font_size = atoi(*argv);
	font_size_set = 1;
      } else if (prefix(p,"yscale")) {
	if (!*(++argv)) error("Expected scale factor after '-%s'",p);
	y_scale = atof(*argv);
      } else {
	error("Bad argument: '%s'",p);
      }
    } else {
      diag[n_diagrams++] = *argv;
    }
  }
  if (n_diagrams==0) {
    diag[n_diagrams++] = "-";
  }
}

int find_best_packing(void)

{
  int n = n_diagrams;
  float max_size=0;
  float y_size;
  int max_size_x_pack=0;
  int max_size_y_pack=0;
  for (x_pack=1;x_pack<=n;x_pack++) {
    x_size = page_width/x_pack;
    y_pack = n/x_pack;
    if (n % x_pack) y_pack++;
    y_size = page_height/y_pack;
    if (y_size<x_size*y_scale) x_size = y_size/y_scale;
    if (x_size > max_size) {
      max_size = x_size;
      max_size_x_pack = x_pack;
      max_size_y_pack = y_pack;
    }
  }
  x_pack = max_size_x_pack;
  y_pack = max_size_y_pack;
  x_size = max_size;
  if ((x_pack+1)*x_size <= page_width) x_pack++;
}

/*
 * return 1 if prefix is an unambigous prefix of the option 'word'
 */

int prefix(char *prefix ,
           char *word )

{
  int matches,len;
  char **option;
  len = strlen(prefix);
  if (strncmp(prefix,word,len)) return 0;
  if (strlen(word) == len) return 1;
  /* we've got a prefix match, check for ambiguity */
  matches = 0;
  option = options_description;
  while (*option) {
    if (option[0][0]=='-' && !strncmp(prefix,option[0]+1,len))
      matches++;
    option++;
  }
  if (matches==1) return 1;
  else return 0;
}

int print_options(void)

{
  char **p = options_description;
  while (*p) printf("%s\n",*p++);
}
