/* reformat.c
 * Convert a file from some known type to another known type
 * 
 * Peter Webb, Summer 1990
 */

/* Standard include files */

#include <stdio.h>

/* Package include files */

#include "reformat.h"
#include "extern.h"
#include "types.h"
#include "error.h"

/* Global variables */

CvtBlkPtr CvtList = NULL;
char ScratchBuf[BUF_SIZE];
char InputDirectory[FILE_SIZE];
char OutputDirectory[FILE_SIZE];
int PrintInfo = TRUE;
int Debug = FALSE;
char *ProcName;     /* Name of the process (av[0]) */
int CompressHDF = FALSE;
long Width = -1, Height = -1;

/* Static variables */

static char *toFile, *fromFile;
static DataType fromType, toType;

/* Array of function pointers for converting between file types.  Note that 
 * the order of the elements in this static data array is very important,
 * as it will be accessed using variables declared to be DataType, an enum.
 * See types.h for the proper order.  When adding to this array, leave the
 * row representing TIFF as the final entry.
 */

static ErrorCode UsePbmLib();
static ErrorCode UsePgmLib();
static ErrorCode UsePpmLib();

static ErrorFuncPtr cvtFuncs[NUM_TYPES][NUM_TYPES] = {

/* HDF - Don't convert HDF files to any other types yet */

  { NULL, NULL, NULL, NULL, NULL, NULL, NULL },
       
/* FITS */

  { FitsToHDF, NULL, NULL, NULL, NULL, NULL, NULL }, 

/* GIF */

  { GIFToRI8, NULL, NULL, NULL, NULL, NULL, NULL },
  
/* XWD */

  { XWDToRI8, NULL, NULL, NULL, NULL, NULL, NULL },

/* Sun Raster files */

  { UsePpmLib, NULL, NULL, NULL, NULL, NULL, NULL },

/* Raw 8-bit raster images.  No palette in the file. */

  { Raw8ToRI8, NULL, NULL, NULL, NULL, NULL, NULL },

/* TIFF */

  { TiffToRI8, NULL, NULL, NULL, NULL, NULL, NULL },

};

/* PBM functions and associated types. The string is the PBM executable used
 * to do the conversion while the type indicates which type it accepts as
 * input.
 */

static FileCvt PBMTypeMap[] = {
  { "rasttoppm", sunrast },
  { NULL, none },
};

/* Functions for writing out files of a given type */

static ErrorFuncPtr writeFuncs[NUM_TYPES] = {
   WriteHDF, WriteFITS, WriteGIF, WriteXWD, WriteSunrast, WriteRaw8, WriteTIFF
};

/* Do the conversion */

static ErrorCode Convert(from_file, from_type, to_file, to_type)
     char *from_file;
     DataType from_type;
     char *to_file;
     DataType to_type;
{
  ErrorCode error;
  FileInfo file_info;

/* Check parameters */

  if (from_file == NULL || from_file[strlen(from_file)-1] == '/')
    return(err_msg(ReformatConvert, BadInputFile));
  if (to_file == NULL || to_file[strlen(to_file)-1] == '/')
    return(err_msg(ReformatConvert, BadOutputFile));
  if (from_type == none)
    return(err_msg(ReformatConvert, BadInputType));
  if (to_type == none)
    return(err_msg(ReformatConvert, BadOutputType));

/* Do the conversion */

  if (cvtFuncs[(int)from_type][(int)to_type] == NULL)
    err_msg(ReformatFile, NotSupported);
  else
    {
      if (PrintInfo) InfoMsg("Converting data\n");
      file_info.name = to_file;
      file_info.values = (int)CvtNone;
      file_info.file_data = from_type;
      file_info.image = NULL;
      error =
	(*(cvtFuncs[(int)from_type][(int)to_type]))(from_file, &file_info);
      if (error == AllOk)
	{
/* Write the data out to the output file */

	  if (PrintInfo) InfoMsg("Writing output file\n");
	  if (writeFuncs[(int)to_type] == NULL)
	    err_msg(ReformatFile, InternalError);
	  else error = (*(writeFuncs[(int)to_type]))(&file_info);
	}
    }
  if (file_info.image != NULL) free(file_info.image);
  if (PrintInfo) InfoMsg("Done.\n");
  return(error);
}

#ifdef XGUI

/* Called when user gives permission to write over an existing file */

static void YesCallback(widget, client_data, call_data)
     Widget widget;
     XtPointer client_data;
     XtPointer call_data;
{
  ErrorCode error;

/* Get rid of the damn file, then do the conversion. */

  DFR8restart();
  DFSDrestart();
  if (unlink(toFile) != 0)
    err_msg(ReformatFile, FileSystemError);
  else Convert(fromFile, fromType, toFile, toType);

/* Get rid of the widget */

  XtPopdown((Widget)client_data);
}

static void NoCallback(widget, client_data, call_data)
     Widget widget;
     XtPointer client_data;
     XtPointer call_data;
{
  err_msg(ReformatFile, NoOverWrite);
  XtPopdown((Widget)client_data);
}

#endif

/* Dispatch file conversion */

ErrorCode Reformat(from_file, from_type, to_file, to_type)
  char *from_file;
  DataType from_type;
  char *to_file;
  DataType to_type;
{
  ErrorCode error;

/* Check the parameters */

  if (from_file == NULL)
    return(err_msg(ReformatFile, BadInputFile));
  if (to_file == NULL)
    return(err_msg(ReformatFile, BadOutputFile));
  if (from_type == none)
    return(err_msg(ReformatFile, BadInputType));
  if (to_type == none)
    return(err_msg(ReformatFile, BadOutputType));

/* Check to see if the output file already exists.  Ask for permission to
 * overwrite it.
 */


#ifndef XGUI

  if (!OverWrite(to_file))
    return(err_msg(ReformatFile, NoOverWrite));

  return( Convert(from_file, from_type, to_file, to_type) );

#else

  if (FileExists(to_file))
    {
      toType = to_type;
      fromType = from_type;
      toFile = to_file;
      fromFile = from_file;
      FileOverWriteMsg(ScratchBuf, to_file);
      CreateConfirmBox(AppShell, YesCallback, NoCallback, ScratchBuf);
      return(AllOk);
    }
  else
    {
      error = Convert(from_file, from_type, to_file, to_type);
      return(error);
    }

#endif

}

/* Given a file type, determine if it has an associated PBM conversion routine,
 * and return the name of that routine.
 */

static char *LookupPBM(data)
     DataType data;
{
  int i = 0;

  while (PBMTypeMap[i].t != none)
    {
      if (data == PBMTypeMap[i].t) return(PBMTypeMap[i].str);
      i++;
    }
  return(NULL);
}
  
/* Determine the type of the input file, call the appropriate pbm routine. */

static ErrorCode UsePbmLib(theName, theInfo)
     char *theName;
     FileInfo *theInfo;
{
  char buf[BUF_SIZE];
  char *t, temp[FILE_SIZE], temp2[FILE_SIZE];
  ErrorCode error;

/* Convert the file to Portable Bitmap Format. */

  t = NewTempFile();
  if ((error = FullInputPath(t, temp)) != AllOk) return(error);
  sprintf(buf, "%s/pbm/%s %s > %s", PBM, LookupPBM(theInfo->file_data),
	  theName, temp);
  if (PrintInfo) InfoMsg("Converting to Portable Bitmap Format\n");
  system(buf);
  
/* Now convert to an X window dump */

  t = NewTempFile();
  if ((error = FullInputPath(t, temp2)) != AllOk) return(error);
  sprintf(buf, "%s/pbm/pbmtoxwd %s > %s", PBM, temp, temp2);
  if (PrintInfo) InfoMsg("Converting to X Window Dump\n");
  system(buf);

/* Finally, convert to HDF */
   
  if (PrintInfo) InfoMsg("Converting to HDF\n");
  error = (*(cvtFuncs[(int)xwd][(int)hdf]))(temp2, theInfo);
  unlink(temp);
  unlink(temp2);
  return(error);
}

/* Determine the type of the input file, call the appropriate pgm routine. */

static ErrorCode UsePgmLib(theName, theInfo)
     char *theName;
     FileInfo *theInfo;
{
  char buf[BUF_SIZE];
  char *t, temp[FILE_SIZE], temp2[FILE_SIZE];
  ErrorCode error;

/* Convert the file to Portable Graymap Format. */

  t = NewTempFile();
  if ((error = FullInputPath(t, temp)) != AllOk) return(error);
  sprintf(buf, "%s/pgm/%s %s > %s", PBM, LookupPBM(theInfo->file_data),
	  theName, temp);
  InfoMsg("Converting to Portable Graymap Format\n");
  system(buf);
  
/* Now convert to FITS */

  t = NewTempFile();
  if ((error = FullInputPath(t, temp2)) != AllOk) return(error);
  InfoMsg("Converting to FITS\n");
  sprintf(buf, "%s/pgm/pgmtofits %s > %s", PBM, temp, temp2);
  system(buf);

/* Finally, convert to HDF */
   
  InfoMsg("Converting to HDF\n");
  error = (*(cvtFuncs[(int)fits][(int)hdf]))(temp2, theInfo);
  unlink(temp);
  unlink(temp2);
  return(error);
}

/* Determine the type of the input file, call the appropriate ppm routine. */

static ErrorCode UsePpmLib(theName, theInfo)
     char *theName;
     FileInfo *theInfo;
{
  char buf[BUF_SIZE];
  char *t, temp[FILE_SIZE], temp2[FILE_SIZE];
  ErrorCode error;

/* Convert the file to Portable Pixmap Format. */

  t = NewTempFile();
  if ((error = FullInputPath(t, temp)) != AllOk) return(error);
  sprintf(buf, "%s/ppm/%s %s > %s\n", PBM, LookupPBM(theInfo->file_data),
	  theName, temp);
  if (PrintInfo) InfoMsg("Converting to Portable Pixmap Format\n");
  system(buf);
  
/* Now convert to GIF */

  t = NewTempFile();
  if ((error = FullInputPath(t, temp2)) != AllOk) return(error);
  sprintf(buf, "%s/ppm/ppmtogif %s > %s\n", PBM, temp, temp2);
  if (PrintInfo) InfoMsg("Converting to GIF\n");
  system(buf);

/* Finally, convert to HDF */
   
  if (PrintInfo) InfoMsg("Converting to HDF\n");
  error = (*(cvtFuncs[(int)gif][(int)hdf]))(temp2, theInfo);
  unlink(temp);
  unlink(temp2);
  return(error);
}

#ifndef XGUI

/* Main routine for the non-X version */

main(ac, av)
  int ac;
  char *av[];
{
  CvtBlkPtr cvt_list;

  ProcName = av[0];

/* Parse the command line */

  if (ac > 1)
    {
      ParseOptions(&ac, av);

      cvt_list = NewCvtBlk();
      if (cvt_list == NULL)
	{
	  err_msg(Main, NoMemory);
	  return;
	}
      
      ParseConversion(&ac, av, cvt_list);

/* Preform the operation */

      if (FROM_FILE(cvt_list) == NULL || TO_FILE(cvt_list) == NULL ||
	  FROM_TYPE(cvt_list) == none || TO_TYPE(cvt_list) == none) usage();

      Reformat(FROM_FILE(cvt_list), FROM_TYPE(cvt_list), TO_FILE(cvt_list),
	       TO_TYPE(cvt_list));
    }
  else usage();
}

#endif
