#include<stdio.h>
#include<stdlib.h>  /* exit() */
#include<stdarg.h>
#include<string.h>

#include "fig.h"
#include "fig_colours.h"
#include "bmp2eps.h"

int obj_max,obj_count=0;
struct pdf_obj *objects;
struct img_obj images;
double text_scale=72.0/80.0;
double default_font_size;

int pg[2]={500,800};
int fontmap[35],default_font;
int flags;
int *xref,cref,pdf_root_obj;
FILE *pdf,*fig; 

void write_pdf_head(char* title);
void write_pdf_tail(double border,int background);
void write_text(char *p);
void write_line(char *p);
void write_spline(char *p);
void write_ellipse(char *p);
void write_arc(char *p);
void read_colour(char *p);
void read_fig_head(FILE *fig);
void help(void);
void latex_clean(void);

int main(int argc, char **argv)
{
  int i,tmp,opt=1,debug=1,nobjs,skip,background=-1;
  char *optp,*file1=0,*file2=0,buff[181],*p,*title;
  double border=0;


  FILE *infile,*outfile;

  xref=malloc(100*sizeof(int));

  obj_max=100;
  objects=malloc(obj_max*sizeof(struct pdf_obj));

  images.dict=0;
  images.next=NULL;
  images.filename=NULL;
  flags=BINARY+PREDICT;
  title=NULL;

  default_font_size=0;
  default_font=0;

  opt=1;
  optp=argv[opt];

  while (opt<argc){
    skip=0;
    switch(*optp){
    case 0:
      opt++;
      optp=argv[opt];
      break;
    case '-':
      while(*(++optp)){
        switch(*optp){
        case 'v':
          debug++;
          break;
	case 'h':
	  help();
	  break;
        case 'b':
          opt++;
          tmp=sscanf(argv[opt],"%lf",&border);
          if (tmp!=1){
	    fprintf(stderr,"Invalid use of -b. -h for usage.\n");
            exit(1);
          }
          skip=1;
          break;
        case 'g':
	  opt++;
	  if ((strlen(argv[opt])!=7)||
	      (sscanf(argv[opt],"#%6x",(unsigned int *)&background)!=1)){
	    fprintf(stderr,"Invalid use of -g. -h for usage.\n");
            exit(1);
          }
	  skip=1;
	  break;
        case 'n':
	  opt++;
          title=argv[opt];
          skip=1;
          break;
        case 'q':
          debug=0;
          break;
        case 's':
          opt++;
          tmp=sscanf(argv[opt],"%lf",&default_font_size);
          if (tmp!=1){
	    fprintf(stderr,"Invalid use of -s. -h for usage.\n");
            exit(1);
          }
          skip=1;
          break;
        case 'F':
          text_scale=1.0;
          break;
        case 'P':
          if (*(optp+1)=='='){
            optp+=2;
            if(sscanf(optp,"%d",&tmp)!=1){
              fprintf(stderr,"Invalid use of -P=\n%s -h for usage\n",
                      argv[0]);
              exit(1);
            }
            if((tmp<0)||(tmp>15)){
              fprintf(stderr,"Invalid use of -P=\n%s -h for usage\n",
                      argv[0]);
              exit(1);
            }
            flags&=(~PREDICT);
            flags|=(tmp<<P_SHIFT);
            while(*(optp+1)) optp++; /* Consume the rest of this argument */
          }
          else flags|=PAGE;
          break;
        case 'V':
          fprintf(stderr,"fig2dev " FIG2DEV_VER " including code from bmp2eps "
                  BMP2EPS_VER " (c) 2012-2015 MJR\n\n");
          exit(0);
        case '7':
          flags&=(~BINARY);
          break;
        default:
          fprintf(stderr,"Invalid option %c.\n%s -h for usage.\n",
                   *optp,argv[0]);
           exit(1);
         }
	if (skip) break;
       }
       opt++;
       optp=argv[opt];
       break;
     default:
       if (!file1) file1=argv[opt];
       else if (!file2) file2=argv[opt];
       else{
         fprintf(stderr,"Unexpected argument %s\n%s -h for usage.\n",
                 argv[opt],argv[0]);
         exit(1);
       }
       opt++;
       optp=argv[opt];
       break;
     }
  }

  flags|=(debug&DEBUG_MASK);

  if (file1){
    infile=fopen(file1,"rb");
    if(!infile){
      fprintf(stderr,"Error, unable to open %s for reading.\n",file1);
      exit(1);
    }
  }
  else
    infile=stdin;

  if (file2){
    outfile=fopen(file2,"wb");
    if(!outfile){
      fprintf(stderr,"Error, unable to open %s for writing.\n",file2);
      exit(1);
    }
  }
  else
    outfile=stdout;

  if (!title) title=file1;
  if (!title) title="stdin";

  /* Check magic */

  fread(buff,1,5,infile);

  if (strncmp(buff,"#FIG ",5)){
    fprintf(stderr,"Error: not a fig file\n");
    exit(1);
  }

  /* Read header */

  read_fig_head(infile);

  /* write PDF header */

  pdf=outfile;
  fig=infile;
  write_pdf_head(title);

  /* Read fig file */

  while(p=fgets(buff,180,infile)){
    //    fprintf(stderr,"Read a line\n");
    i=0;
    while((p[i]==' ')||(p[i]=='\t')) i++;
      switch(p[i]){
      case '6': /* Compound */
      case '-': /* End of compound */
      case '#': /* Comment */
	break;
      case '0': /* Colour */
        read_colour(p);
        break;
      case '1': /* Ellipse */
        write_ellipse(p);
        break;
      case '2': /* Polyline */
	write_line(p);
	break;
      case '3': /* Spline */
	write_spline(p);
	break;
      case '4': /* Text */
	write_text(p);
	break;
      case '5': /* Arc */
        write_arc(p);
        break;
      default:
	fprintf(stderr,"Skipping unexpected item\n");
	break;
      }
  }

  if (!obj_count){
    fprintf(stderr,"Nothing found to write to PDF!\n");
    exit(1);
  }

  write_pdf_tail(border,background);

  /* Finish PDF file with xref table */

  nobjs=cref+1;

  fprintf(pdf,"xref\n0 %d\n0000000000 65535 f \n",nobjs);

  for(i=0;i<nobjs-1;i++) fprintf(pdf,"%010d 00000 n \n",xref[i]);

  fprintf(pdf,"trailer\n<<\n/Size %d\n/Root %d 0 R\n/Info 1 0 R\n>>\n",
	  nobjs,pdf_root_obj);

  fprintf(pdf,"startxref\n%d\n%%%%EOF\n",xref[nobjs-1]);

  fclose(pdf);
  latex_clean();

}

void read_fig_head(FILE *fig){
  /* Assume have read first five characters */
  char buff[81],*p;
  int i,debug;
  int land=0;
  int ver_maj,ver_min;
  int head_lines;

  debug=flags&DEBUG_MASK;

  fgets(buff,180,fig); /* Read version number */
  sscanf(buff,"%d.%d",&ver_maj,&ver_min);

  head_lines=8;
  if ((ver_maj==3)&&(ver_min==1)) head_lines=4;

  /* We now simply wish to discard 8 header lines */

  p=buff;
  for(i=0;i<head_lines;i++){
    //    fprintf(stderr,"Read a line of header\n");
    p=fgets(buff,180,fig);
    if (!p){
      fprintf(stderr,"Error reading fig header\n");
      exit(1);
    }
    while (p&&(p[0]=='#')) p=fgets(buff,180,fig); /* Skip comments */
    switch(i){
    case 0:
      if (!strncmp(buff,"Landscape",9)) land=1;
      break;
    case 3:
      if (debug>1) fprintf(stderr,"Page is %s",buff);
      if (!strncmp(buff,"Letter",6)) {pg[0]=612;pg[1]=792;}
      else if (!strncmp(buff,"Legal",5)) {pg[0]=612;pg[1]=1008;}
      else if (!strncmp(buff,"Tabloid",7)) {pg[0]=792;pg[1]=1224;}
      else if (!strncmp(buff,"A5",2)) {pg[0]=420;pg[1]=595;}
      else if (!strncmp(buff,"A4",2)) {pg[0]=595;pg[1]=842;}
      else if (!strncmp(buff,"A3",2)) {pg[0]=842;pg[1]=1190;}
      else if (!strncmp(buff,"A2",2)) {pg[0]=1190;pg[1]=1684;}
      else if (!strncmp(buff,"A1",2)) {pg[0]=1684;pg[1]=2384;}
      else if (!strncmp(buff,"A0",2)) {pg[0]=2384;pg[1]=3370;}
      else if (!strncmp(buff,"B5",2)) {pg[0]=516;pg[1]=729;}
      else if (flags&PAGE)
	fprintf(stderr,"Warning: unsupported page size\n");
      break;
    }
  }
  if (land) {i=pg[0];pg[0]=pg[1];pg[1]=i;}
}

void help(void){
  printf("usage: fig2pdf [options] input output\n\n"
	 " -F         font sizes are in pt, not 1/80\"\n"
         " -P         MediaBox from page size, not calculated bounding box\n"
         " -P=n       define which PNG predictors to use\n"
         " -b width   add border to bounding box (pt)\n"
         " -g #rrggbb set backround colour (in hex)\n"
         " -n txt     set title of PDF file\n"
         " -q         be quiet\n"
         " -v         be verbose (debugging)\n"
         " -V         print version and exit\n"
         " -7         produce 7 bit ASCII output (debugging)\n\n"
	 "(c) 2012-2015 MJR\n");
  exit(0);
}
