/* pspager.c */

#include "ps_package.h"
#include "pspager.h"
#ifdef AMIGA
#include <utilities.h>
#include <getopt.h>
#else
#include "utilities.h"
#include "getopt.h"
#endif
#include <string.h>
#include <sys/stat.h>


/* preprocessor symbols */

#define UNTITLED   "Untitled"
#define PSP_ADOBE  "psp_adobe.ps"
#define PSP_SETUP  "psp_setup.ps"

#define PAGE_LIMIT_BBE   56
#define PAGE_LIMIT_SAT2  74
#define PAGE_LIMIT_SAT4  70


/* global data */

static char *fileName = NULL;
static time_t fileTime;
static int pageNo;
static char satFonts[] = "Helvetica Helvetica-Bold Courier";
static char bbeFonts[] = "Courier-Bold Courier";


/* postscript generation functions */

static void Print1PerPage(void)
{
  char *ln,dateStr[40],timeStr[40];
  int i,j,y;

  strftime(dateStr,40,"%A, %d. %B %Y",localtime(&fileTime));
  strftime(timeStr,40,"%X Uhr",localtime(&fileTime));

  ln = PSNextLine();
  for(i=0; i<pageNo; i++) {
    /* print page skeleton */
    printf("%%%%Page: %d %d\n"
      "%%%%BeginPageSetup\n"
      "initializepage\n"
      "(pspager; page: %d of %d)setjob\n"
      "%%%%EndPageSetup\n"
      "gS 0 0 552 730 rC\n"
      "5 16 :M\n"
      "f1_9 sf\n"
      ".609(%s)A\n"
      "470 16 :M\n"
      "1.434 .143(Page %d of %d)J\n"
      "5 27 :M\n"
      "2.466 .247(%s)J\n"
      "463 27 :M\n"
      "2.981 .298(%s)J\n"
      "5 38.25 -.25 .25 547.25 38 .25 5 38 @a\n"
      "5 40.25 -.25 .25 547.25 40 .25 5 40 @a\n"
      "1 G\n"
      "0 0 0 0 rC\n"
      "0 0 0 0 rF\n"
      "-1 0 1 12 rF\n"
      "gR\n"
      "1 G\n"
      "gS 16 49 531 672 rC\n"
      "16 49 531 672 rF\n"
      "15 49 532 12 rF\n"
      "16 58 :M\n"
      "0 G\n"
      "f3_9 sf\n",
      i+1,i+1,i+1,pageNo,fileName,i+1,pageNo,dateStr,timeStr);

    /* print pane contents */
    for(j=0,y=58; j<PAGE_LIMIT_BBE && ln && ln[0]!='\f'; j++) {
      if(j > 0) {
        printf("16 %d 531 12 rF\n", y-9);
        if(ln[0] == '\0') {
          y += 12;
          ln = PSNextLine();
          continue; /* don't print anything for empty lines */
        }
        printf("16 %d :M\n0 G\n", y);
      }
      printf("(%s)S\n1 G\n",ln);
      y += 12;
      ln = PSNextLine();
    }

    /* skip rest of pane at form feed */
    if(ln && ln[0]=='\f')
      ln++;
    printf("endp\n");
  }
}


static void Print2PerPage(void)
{
  char *ln,*userStr,dateStr[80];
  int i,j,x,xc,y,m,d;
  static const char * const pnSetup[2] = {
                "0  18 385 518 rC\n"   "1  23 :M\n" "f2_7 sf\n",
    "gR\n" "gS 395  18 386 518 rC\n" "396  23 :M\n" "f2_7 sf\n"
  };
  static const struct { int x,y; } pnCoords[2] = {
    { 1, 23 }, { 396, 23 }
  };

  if(!(userStr = getenv("USER")))
    userStr = "Nobody";
  strftime(dateStr,80,"%d.%m %y@%H:%M by ",localtime(&fileTime));
  strcat(dateStr,userStr);

  /* estimate a x position for title */
  m = strlen(fileName);
  xc = m>7 ? 368-(m-7)*6 : 368+(7-m)*6;

  ln = PSNextLine();
  for(i=0; i<pageNo; i++) {
    m = i & 1;
    /* print page skeleton every four panes*/
    if(m == 0) {
      d = i >> 1;
      printf("%%%%Page: %d %d\n"
        "%%%%BeginPageSetup\n"
        "initializepage\n"
        "(pspager; page: %d of %d)setjob\n"
        "%%%%EndPageSetup\n"
        "gS 0 0 781 538 rC\n"
        "0 0 215 13 rC\n"
        "1 10 :M\n"
        "f0_12 sf\n"
        ".815 .082(%s)J\n"
        "gR\n"
        "gS 0 0 781 538 rC\n"
        /*"%d 10 :M\n"*/
        "f1_12 sf\n"
        "390 (%s) stringwidth pop 2 div sub 10 :M\n"
        ".0(%s)A\n"
        "774 10 :M\n"
        "f0_12 sf\n"
        "(%d)S\n"
        "0 13.25 -.25 .25 781.25 13 .25 0 13 @a\n"
        "-.25 -.25 390.25 538.25 .25 .25 390 13 @b\n",
        d+1,d+1,d+1,pageNo,dateStr,fileName,fileName,d+1); /*xc*/
    }

    /* setup current pane */
    x = pnCoords[m].x;
    y = pnCoords[m].y;
    printf("%s",pnSetup[m]);

    /* print pane contents */
    for(j=0; j<PAGE_LIMIT_SAT2 && ln && ln[0]!='\f'; j++) {
      printf("%d %d :M\n(%s)S\n",x,y,ln);
      y += 7;
      ln = PSNextLine();
    }

    /* skip rest of pane at form feed */
    if(ln && ln[0]=='\f')
      ln++;

    /* print end of page after each second pane */
    if(m==1 || !ln)
      printf("endp\n");
  }
}


static void Print4PerPage(void)
{
  char *ln,*userStr,dateStr[80];
  int i,j,x,xc,y,m,d;
  static const char * const pnSetup[4] = {
                "0  18 271 355 rC\n"   "1  22 :M\n" "f2_5 sf\n",
    "gR\n" "gS 281  18 271 355 rC\n" "282  22 :M\n" "f2_5 sf\n",
    "gR\n" "gS   0 376 271 355 rC\n"   "1 380 :M\n" "f2_5 sf\n",
    "gR\n" "gS 281 376 271 355 rC\n" "282 380 :M\n" "f2_5 sf\n"
  };
  static const struct { int x,y; } pnCoords[4] = {
    { 1, 22 }, { 282, 22 }, { 1, 380 }, { 282, 380 }
  };

  if(!(userStr = getenv("USER")))
    userStr = "Nobody";
  strftime(dateStr,80,"%d.%m %y@%H:%M by ",localtime(&fileTime));
  strcat(dateStr,userStr);

  /* estimate a x position for title */
  m = strlen(fileName);
  xc = m>10 ? 233-(m-10)*6 : 233+(10-m)*6;

  ln = PSNextLine();
  for(i=0; i<pageNo; i++) {
    m = i % 4;
    /* print page skeleton every four panes*/
    if(m == 0) {
      d = i/4;
      printf("%%%%Page: %d %d\n"
        "%%%%BeginPageSetup\n"
        "initializepage\n"
        "(pspager; page: %d of %d)setjob\n"
        "%%%%EndPageSetup\n"
        "gS 0 0 552 730 rC\n"
        "0 0 215 13 rC\n"
        "1 10 :M\n"
        "f0_12 sf\n"
        ".907 .091(%s)J\n"
        "gR\n"
        "gS 0 0 552 730 rC\n"
        "f1_12 sf\n"
        /*"%d 10 :M\n"*/
        "276 (%s) stringwidth pop 2 div sub 10 :M\n"
        ".0(%s)A\n"
        "537 10 :M\n" /*545 10 for normal printers*/
        "f0_12 sf\n"
        "(%d)S\n"
        "0 13.25 -.25 .25 552.25 13 .25 0 13 @a\n"
        "-.25 -.25 276.25 730.25 .25 .25 276 13 @b\n"
        "0 371.25 -.25 .25 552.25 371 .25 0 371 @a\n",
        d+1,d+1,d+1,pageNo,dateStr,fileName,fileName,d+1); /*xc*/
    }

    /* setup current pane */
    x = pnCoords[m].x;
    y = pnCoords[m].y;
    printf("%s",pnSetup[m]);

    /* print pane contents */
    for(j=0; j<PAGE_LIMIT_SAT4 && ln && ln[0]!='\f'; j++) {
      printf("%d %d :M\n(%s)S\n",x,y,ln);
      y += 5;
      ln = PSNextLine();
    }

    /* skip rest of pane at form feed */
    if(ln && ln[0]=='\f')
      ln++;

    /* print end of page every four panes */
    if(m==3 || !ln)
      printf("endp\n");
  }
}


int main(int argc, char *argv[])
{
  static void (*actionFunc)(void);
  char *fontNames;
  Orientation orient;
  struct stat fs;
#ifdef AMIGA
  struct tm *ft;
#endif
  enum { eCurDate, eModifDate } prtDate;
  FILE *fp;
  int ch;

  /* assume 2 per page, use modification date */
  actionFunc = NULL;
  fontNames = satFonts;
  orient = eLandscape;
  prtDate = eModifDate;

  /* parse options */
  while((ch = getopt(argc,argv,"f:d124")) != EOF)
    switch(ch) {
      case '1':
        PSDefSymbol("PSP_1_PER_PAGE");
        actionFunc = Print1PerPage;
        fontNames = bbeFonts;
        orient = ePortrait;
        break;
      case '2':
        PSDefSymbol("PSP_2_PER_PAGE");
        actionFunc = Print2PerPage;
        fontNames = satFonts;
        orient = eLandscape;
        break;
      case '4':
        PSDefSymbol("PSP_4_PER_PAGE");
        actionFunc = Print4PerPage;
        fontNames = satFonts;
        orient = ePortrait;
        break;
      case 'f':
        fileName = optarg; /* input file specification */
        break;
      case 'd':
        prtDate = eCurDate; /* current date instead of modification date */
        break;
      default:
        ; /*nothing to do*/
    }

  if(!actionFunc) {
    PSDefSymbol("PSP_2_PER_PAGE");
    actionFunc = Print2PerPage;
  }

  /* setup global data */
  if(fileName) {
    if(stat(fileName,&fs) < 0)
      FatalExit("cannot locate input file");
#ifdef AMIGA
    ft = localtime(&fs.st_mtime);
    ft->tm_hour += 6;  /* bug in SAS/C function fstat() - 6 hours too late */
    fs.st_mtime = mktime(ft);
#endif
    if(!(fp = fopen(fileName,"r")))
      FatalExit("cannot open input file");
    fileTime = prtDate==eModifDate ? fs.st_mtime : time(NULL);
  }
  else {
    fp = stdin;
    fileName = UNTITLED;
    fileTime = time(NULL);
  }

  /* read input data and print postscript source */
  pageNo = PSReadFile(fp);
  PSPrintHdr(fileName,fileTime,pageNo,fontNames,orient);
  PSInclFile(TackOn(PSP_LIBDIR,PSP_SETUP));
  PSUndefAll();
  (*actionFunc)();
  PSPrintEnd();
  PSFreeFile();
  if(fp != stdin)
    fclose(fp);

  return 0;
}
