/*
 * cxg_grab - a generic frontend for the cx100 grabber
 *
 * Copyright 1995   rubini@ipvvis.unipv.it (Alessandro Rubini)
 *
 *   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.
 ********/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#include "cxdrv.h"

char *prgname;

/* variables to retain options, set to default values */
int   opt_verbose    =0;
int   opt_lowres     =1;
int   opt_count      =1;
int   opt_step       =0;
int   opt_fc         =0;
int   opt_mem        =0;
int   opt_save       =0;
int   opt_multiple   =0;
char *opt_filename   =NULL;
char *opt_geo        =NULL;
int   opt_pgm        =0;
char *opt_infilename =NULL;
int   opt_quit       =0;

#define VERBOSE(args) if (opt_verbose) fprintf args /* FIXME -- not clean */
#define PERROR(s) fprintf(stderr,"%s: %s: %s\n",prgname,(s),strerror(errno))

/*===================================================================*/
static int usage(char *whofailed)
{
 printf("%s " CXG_RELEASE ", " CXG_RELEASE_TIME "\n",prgname);
#if 0
 if (whofailed)
   {
   printf("Error in the %s specification. Try \"%s -h\".\n",
      whofailed,prgname);
   return 1;
   }
#endif

 printf("Usage: %s <device_name> [options]\n",prgname);
 printf("  Valid options are:\n"
	
	" -v                be verbose on stderr\n"
	" -t                be terse on stderr (default)\n"
	
	" -h                high resolution\n"
	" -l                low resolution (default)\n"
	
	" -c <n>            count: how many images to grab (default 1)\n"
	" -s <n>            step: repeat grabbing every that many frames\n"
	" -f                put the frame counter in pgm headers (if pgm)\n"
	" -M                memory intensive: grab all, save at the end\n"
	" -S                save now previously grabbed frames\n"
	" -m                save a stream of images as multiple files\n"
	" -o <filename>     outputfile radix (default: stdout)\n"
	
	" -g <widxhei+x+y>  specify a geometry\n"
	" -p                output a pgm image\n"
	" -r                output a raw image (default)\n"
	
	" -i <filename>     process an input file (\"-\" = stdin)\n"
	" -q                quit now\n"
	);
 return 1;
 }

/*===================================================================*/
int main(int argc, char **argv)
{
char options[]="vthlc:s:MSmo:g:pri:q";
int i, opt, fd;

int chg_res=1, chg_name=0, chg_inname=0, chg_pgm=0, chg_geo=0;


char ofname[128]; int ofnamelen=0; int filecount=0;
FILE *fout=stdout, *fin=stdin;
Cxg_Roi *roiptr=NULL;
int maxsize;

  prgname=argv[0];

  if (argc<2)
    exit(usage("commandline"));

  if ((fd=open(argv[1],O_RDWR))<0)
    { PERROR(argv[1]); exit(1); }
  
  maxsize=opt_lowres?256:512;

  while ((opt = getopt(argc, argv, options)) != -1)
    {

    switch (opt) /* most of them don't do anything, so "continue;" the loop */
      {
      case 'v': opt_verbose=1; continue;
      case 't': opt_verbose=0; continue;
      
      case 'h': opt_lowres=0; chg_res++; continue;
      case 'l': opt_lowres=1; chg_res++; continue;

      case 'c': opt_count=atoi(optarg); continue;
      case 's': opt_step=atoi(optarg); continue;
      case 'f': opt_fc=1; continue;
      case 'M': opt_mem=1; continue;

      case 'S': opt_save=1; break; /* save all */

      case 'm': opt_multiple=1; continue;
      case 'o': opt_filename=optarg; chg_name++; continue;

      case 'g': opt_geo=optarg; chg_geo++; break; /* grab */
      case 'p': opt_pgm=1; chg_pgm++; continue;
      case 'r': opt_pgm=0; chg_pgm++; continue;

      case 'i': opt_infilename=optarg; chg_inname++; continue;
      case 'q': opt_save=1; opt_quit=1; break; /* save and quit */

      default:
          exit(usage(NULL));
      }

/*
 * Here we are, one or more options has been identifiled, now process it
 */
    if (Cxg_RamPage(fd,CXG_AUTODETECT)<0)
      { PERROR("Cxg_RamPage"); exit(1); }

    if(chg_res) /* set resolution - the first time it is true */
      {
      static char geolow[]="256x256+0+0";
      static char geohigh[]="512x512+0+0";
      chg_res=0;
      VERBOSE((stderr,"Chg resolution to %s\n",opt_lowres ? "low" : "high"));
      if (Cxg_LowRes(fd,opt_lowres)<0)
	{ PERROR("Cxg_LowRes"); exit(1); }
      maxsize = opt_lowres?256:512;
      if (!roiptr && !chg_geo)
	{
	chg_geo++; /* provide default */
	opt_geo= opt_lowres ? geolow : geohigh;
	}		
      }
    
    if (chg_name) /* save to file(s) */
      {
      chg_name=0;
      strcpy(ofname,opt_filename);
      ofnamelen=strlen(ofname);
      if (fout)
	{
	fclose(fout);
	fout=NULL;
	}
      chg_name=0;
      }
    
    if (chg_geo) /* FIXME -- should use a list of rois to cycle with */
      {
      chg_geo=0;
      if (roiptr) /* FIXME -- memory-intensive won't work */
	{
	if (roiptr->xtra.data) free(roiptr->xtra.data);
	free(roiptr);
	}
      if (!roiptr) roiptr=malloc(sizeof(Cxg_Roi));
      if (!roiptr) { PERROR("malloc()"); exit(1); }
      if (sscanf(opt_geo,"%hdx%hd+%hd+%hd",
		 &roiptr->wid,&roiptr->hei,&roiptr->x,&roiptr->y)!=4)
	{
	fprintf(stderr,"%s: Wrong geometry: \"%s\"\n",prgname,opt_geo);
	exit(1);
	}
      if ((roiptr->hei+roiptr->y>maxsize) || (roiptr->wid+roiptr->x>maxsize))
	{  /* FIXME -- resol may have changed */
        fprintf(stderr,"%s: Out of bounds: \"%s\"\n",prgname,opt_geo);
        exit(1);
        }
      roiptr->xtra.data=malloc(roiptr->wid*roiptr->hei);
      if (!roiptr->xtra.data) { PERROR("malloc()"); exit(1); }
      roiptr->count=1;
      }
    
    if (chg_inname) /* read from file */
      {
      chg_inname=0;
      if (fin)
        fclose(fin);
      fopen(opt_infilename,"r");
      if (!fin)
	{ PERROR(opt_infilename); exit(1); }
      }
    
    if (opt_multiple && !ofname)
      {
      fprintf(stderr,"%s: Can't save to multiple unnamed files\n",prgname);
      exit(1);
      }
    
/* What is not supported, yet */
    
    if (opt_mem)
      fprintf(stderr,"%s: memory intensive not supported, yet\n",prgname);
    if (opt_fc)
      fprintf(stderr,"%s: field counter not supported, yet\n",prgname);
    if (opt_step)
      fprintf(stderr,"%s: step choice is not supported, yet\n",prgname);
    
    /*
     * Hey, setup is done...
     */
    
    VERBOSE((stderr,"Going to grab...\n"));
    
    for (i=0; i<opt_count; i++)
      {
      VERBOSE((stderr,"\tregion %dx%d+%d+%d\n",
	       roiptr->wid,roiptr->hei,roiptr->x,roiptr->y));
      
      if (Cxg_GetRegion(fd,roiptr)<0)
	{ PERROR("Cxg_GetRegion"); continue; }
      
      if (opt_multiple)
	{
	if (fout) fclose(fout);
	sprintf(ofname+ofnamelen,".%03d",i);
	fout=fopen(ofname,"w");
	if (!fout) { PERROR(ofname); continue; }
	}
      else
	if (!fout)
	  {
	  fout=fopen(ofname,"w");
	  if (!fout) { PERROR(ofname); continue; }
	  }
      
      if (opt_pgm)
	fprintf(fout,"P5\n%d %d\n255\n",roiptr->wid,roiptr->hei);
      fwrite(roiptr->xtra.data,1,roiptr->wid*roiptr->hei,fout);
      }
    
    } /* while(getopt) */

return 0;
}

