/* libp.c - from pbm utility library part 1  (grossly hacked jpb 1995)

   modifications (everything not in the original libpbm.c) are

   Copyright (C) John Beale 1995 <beale@jump.stanford.edu>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

** ----------------------------------------------------------------
** the original libpbm.c was   Copyright (C) 1988 by Jef Poskanzer
** and contained this notice:
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
** ---------------------------------------------------------------

*/

#include <ctype.h>
#include <stdlib.h>
#include <stdarg.h>
#include <math.h>
#include <string.h>
#include <png.h>
#include "pp.h"

#undef tolower          /* annoying detail required for ANSI compat. */

/* Case-insensitive keyword matcher. */

int
pm_keymatch( char *str, char *keyword, int minchars )
{
    register int len;
    char c1, c2;

    len = strlen( str );
    if ( len < minchars )
	return 0;
    while ( --len >= 0 )
	{

	c1 = *str++;
	c2 = *keyword++;
	if ( c2 == '\0' )
	    return 0;
	if (isupper( c1 ))
	    c1 = tolower( c1 );
	if (isupper( c2 ))
	    c2 = tolower( c2 );
	if ( c1 != c2 )
	    return 0;
	}
    return 1;
    }

void pperror( char* str )
{
  printf("%s",str);
  exit(1);
}

void write_info(FILE *fpout, image_data img)
{
 int i;
    /* print out parameters so we know how we generated this file */

  fprintf(fpout,"# from gforge: -name %s -dim %.2f -power %.2f -mesh %d \n",
	    img.fname, img.dim[0], img.powscale, img.meshsize);
    if (img.peakspec) 
       fprintf(fpout,"# -peak %0.2f %0.2f \n",img.xfrac,img.yfrac);
    fprintf(fpout,"# -seed %d \n",img.rseed);
    
    if (img.adimspec) {
      for (i=1;i<img.d_factors;i++) {
       fprintf(fpout,"# -ad %0.2f %0.2f \n",img.dim[i],img.dscale[i]);
       }
      }
    if (img.craterspec) {
      fprintf(fpout,"# -craters %1.1f %1.2f\n",img.craterdens,img.craterscale);
    }
    if (img.limitspec) {
      fprintf(fpout,"# -limit %1.1e %1.1e\n",img.limit_lo,img.limit_hi);
    }
}

/* --------------------------------------- */
static png_byte *pngrow = NULL;
static png_struct *png_ptr;
static png_info *info_ptr;

int pp_openfile(image_data img)
{
 int temp;
  
 Fmatrix xh;                             /* matlab format header */  
 char mname[80] = "land";

  unsigned char xo, yo;
    unsigned char IDLength;             /* length of Identifier String */
    unsigned char CoMapType;            /* 0 = no map */
    unsigned char ImgType;              /* image type (see below for values) */
    unsigned char Index_lo, Index_hi;   /* index of first color map entry */
    unsigned char Length_lo, Length_hi; /* number of entries in color map */
    unsigned char CoSize;               /* size colormap entry (15,16,24,32) */
    unsigned char X_org_lo, X_org_hi;   /* x origin of image */
    unsigned char Y_org_lo, Y_org_hi;   /* y origin of image */
    unsigned char Width_lo, Width_hi;   /* width of image */
    unsigned char Height_lo, Height_hi; /* height of image */
    unsigned char PixelSize;            /* pixel size (8,16,24,32) */
    int xsize, ysize;


    xsize = img.meshsize;
    ysize = img.meshsize;

    xo = 0; yo = 0;
 
  if ((img.type == PGM) || (img.type == OCT)) {      /* ASCII formats */
    if ((fpout = fopen(img.fname,"w")) == NULL )
	pperror("Couldn't open output file\n"); 
  } else {
    if ((fpout = fopen(img.fname,"wb")) == NULL ) /* don't add CR/LF to file */
       pperror("Couldn't open output file\n");
  }

  if (pp_filetype == TGA)
   {
     /* b0-b7 */
    IDLength = 0; CoMapType = 0; ImgType = 2; Index_lo = 0; Index_hi=0;
    Length_lo = 0; Length_hi = 0; CoSize = 0; X_org_lo = 0; X_org_hi = 0;
    temp = xsize / 256;
    Width_hi = (unsigned char) temp;     /* low and high bytes of x width */
    Width_lo = xsize % 256;
    temp = ysize / 256;
    Height_hi = (unsigned char) temp;
    Height_lo = ysize % 256;
    PixelSize = 24;
    Y_org_lo = 0;
    Y_org_hi = 0;

    fpc(IDLength);
    fpc(CoMapType);
    fpc(ImgType);
    fpc(Index_lo);
    fpc( Index_hi);
    fpc(Length_lo);
    fpc(Length_hi);
    fpc(CoSize);
    fpc(X_org_lo); fpc(X_org_hi);
    fpc(Y_org_lo); fpc(Y_org_hi);
    fpc(Width_lo);
    fpc(Width_hi);              /* file in lo-byte, hi-byte order b12,b13*/
    fpc(Height_lo);
    fpc(Height_hi);    /* ysize b14, b15 */
    fpc(PixelSize);
    fpc((unsigned char) 0x20);        /* descriptor byte b17 */

   }
  else if (pp_filetype == PGM)
    {
      fprintf(fpout,"P2\n");       /* PGM type 2: 16-bit ASCII data */
      write_info(fpout, img);
      fprintf(fpout,"%d %d\n",xsize,ysize);
      fprintf(fpout,"%u\n",MAX_PIXVAL);
    }
  else if (pp_filetype == PG8)
    {
      fprintf(fpout,"P5\n");       /* PGM type 2: 8-bit binary data */
      write_info(fpout, img);

      fprintf(fpout,"%d %d\n",xsize,ysize);
      fprintf(fpout,"255\n");
    }
  else if (pp_filetype == OCT) {     /* Octave ascii format */
      fprintf(fpout,"# name: land\n");
      fprintf(fpout,"# type: matrix\n");
      fprintf(fpout,"# rows: %d\n",ysize);
      fprintf(fpout,"# columns: %d\n",xsize);
    }
  else if (pp_filetype == MAT) {     /* Matlab binary format */
      xh.type = NUM_FMT*1000 + PREC*10;
      xh.mrows = ysize;
      xh.ncols = xsize;
      xh.imagf = 0;
      xh.namelen = strlen(mname) + 1;
      fwrite(&xh, sizeof(Fmatrix),(size_t)1, fpout);
      fwrite(mname,sizeof(char),(size_t)xh.namelen,fpout);
    }
  else if (pp_filetype == PNG)
    {
         /* allocate the necessary structures */
     png_ptr = (png_struct *)malloc(sizeof (png_struct)); 
     if (!png_ptr)
     {
      fclose(fpout);
      exit (1);
     }

     if ( (pngrow = (png_byte *)malloc(2*img.meshsize*sizeof(png_byte)))
               == NULL) {
	     fprintf(stderr,"Memory allocation error");
	     exit(1);
           }

     info_ptr = (png_info *)malloc(sizeof (png_info));
     if (!info_ptr)
     {
      fclose(fpout);
      free(png_ptr);
      exit (1);
     }

     /* set error handling */
     if (setjmp(png_ptr->jmpbuf))
     {
      png_write_destroy(png_ptr);
      fclose(fpout);
      free(png_ptr);
      free(info_ptr);
      /* If we get here, we had a problem reading the file */
      fprintf(stderr,"Had error opening PNG file.\n");
      exit( 1);
     }

     png_info_init(info_ptr);  /* initialize the structures */
     png_write_init(png_ptr);
     png_init_io(png_ptr, fpout);     /* set up the output control */

    /* set the file information here */
     info_ptr->width = xsize;
     info_ptr->height = ysize;
     info_ptr->color_type = PNG_COLOR_TYPE_GRAY;
     info_ptr->bit_depth = 16;
     info_ptr->pixel_depth = 16;
     info_ptr->compression_type = 0;
     info_ptr->filter_type = 0;
     info_ptr->interlace_type = 0; /* non-interlaced */
     info_ptr->valid |= PNG_INFO_sBIT;     /* optional significant bit chunk */
     info_ptr->valid |= PNG_INFO_gAMA;     /* optional gamma chunk */
     info_ptr->gamma = 1.0;

     png_write_info(png_ptr, info_ptr);

    }
  return(0);
} /* end pp_openfile() */


void fpc(unsigned char c)       /* output a single byte to file */
  {
    fprintf(fpout,"%c",c);
  }

void pp_writerow(image_data img, PTYPE *row)
{
 int i;
 int lcount = 0;      /* num. of pixels per line for PGM ascii */

  if (img.type == PNG) { 
     for(i=0;i<img.meshsize;i++) {
       unsigned int color;
       color = row[i]*MAX_PIXVAL;
       pngrow[2*i] = color >> 8;
       pngrow[2*i + 1] = color % 256;
     }
     png_write_row(png_ptr, pngrow);

  } else if (img.type == PGM) {
    for (i = 0; i < img.meshsize; i++) {
      pp_writepixel(row[i]);
      if (++lcount > 9) {
       lcount = 0;
       pp_writenewline(img.type);  /* break lines into groups of 10 */
      } /* end if ++lcount */
    } /* end for i */
    if (lcount != 0) pp_writenewline(img.type); /* newline for logical row */
  } else {
    for (i = 0; i < img.meshsize; i++)  pp_writepixel(row[i]);
    pp_writenewline(img.type);
  }


} /* end pp_writerow */

void pp_writepixel(PTYPE pf)
{
 unsigned char r,g,b;
 unsigned int p;

 r = 0; g =0; b = 0;
 p = MAX_PIXVAL * pf;

  if (pp_filetype == PGM)
    fprintf(fpout,"%u ",p);
  else if(pp_filetype == PG8)
    fprintf(fpout,"%c",(unsigned char)(p>>8));
  else if(pp_filetype == TGA)    /* TGA pixel order is BGR. R=hi, G=lo */
    {
      r = p >> 8;
      g = p % 256;
  /*    printf("p=%d: %d %d %d\n",p,(int)r,(int)g,(int)b); */
      fprintf(fpout,"%c%c%c",b,g,r);
    }
  else if (pp_filetype == OCT) {
    fprintf(fpout,"%1.5f ",pf);
   }
  else if (pp_filetype == MAT) {
    fwrite(&pf,sizeof(PTYPE),1,fpout);
   }
  else
    { fprintf(stderr,"Gforge - unsupported format error.\n");
      exit(1); }
}

void pp_writenewline(int type)
{  
   if ((type == OCT) || (type == PGM)) 
    { /* newline if ascii data */
     fprintf(fpout,"\n");
    }
 }

int pp_closefile(image_data img)
{
  if(img.type == PNG)
    {
      png_write_end(png_ptr, info_ptr);
      png_write_destroy(png_ptr);
      free(png_ptr);
      free(info_ptr);
    }
  return(fclose(fpout));               /* close the file */
}
