/* window.c
 * X-window interface for a file conversion utility.  The utility understands
 * the following data file formats:
 *
 * HDF, TIFF, GIFF, FITS
 *
 * The utility can convert a file of any of these types into an HDF file.  Some
 * effort has also been expended in the development of a more general 
 * conversion utility - i.e. able to convert from any given file type to any
 * other type.
 *
 * The program will run in command-line mode as well, for those who do not
 * have access to X. The command line interface is as follows:
 *
 * reformat -htgf source-file [-htgf] destination-file
 *
 * The single-letter switch preceeding each file indicates the type of the 
 * file.  The switch is mandatory in both places, even though the program could
 * probably try to guess the type of the source file.  This requirement 
 * simplifies the processing in the user interface.  Some types of files may
 * not be able to be converted to all of the other types.  In this case, a
 * warning message will appear, and no action will be taken.
 *
 * There are also several command-line switches that are specific to X. None of
 * the command line options are mandatory.  The default behavior is to bring
 * up the X version of the tool.
 *
 * The X-windows interface is too complex to describe here.  See the 
 * accompaning documentation.  The interface relies heavily on the Athena
 * Toolkit (comes on the X distribution tape).
 *
 * Much of the actual conversion code was taken from various places on the
 * network.  The interface, which collects all of them under one roof, as it
 * were, is the primary contribution of this program.
 *
 * The file contains many direct calls to the X interface.  It will have to
 * be modified extensively should this program be ported to another window
 * system.
 */

/* X include files */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>

/* Widget include files */

#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Text.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Dialog.h>

/* Standard include files */

#include <stdio.h>

/* The bitmap for the icon */

#include "../bitmaps/reformat.bitmap"

#define XA_BITMAPDEPTH 1   /* Bitmaps have depth 1 */

/* Package include files */

#include "window.h"   
#include "options.h"    /* Option table */
#include "types.h"      /* Package-wide type definitions */
#include "error.h"      /* Error codes */
#include "extern.h"     /* External routines and global variables */
#include "reformat.h"   /* Package-wide contants */

/* Global variables */

Display *AppDisplay;   /* Physical device information */
XrmDatabase resourceBase;  /* Fully merged resource data base */
int AppScreen;         /* Which screen on the device */
short can_convert[NUM_TYPES][NUM_TYPES];  /* Is a given conversion possible? */
Visual *visual;
char HelpFile[FILE_SIZE];  /* Name of the help file */
char *InputFiles;   /* List of input files */
char *EmptyList[] = {"", NULL};
int ResetFileOnCd = TRUE;  /* Reset input file when changing directory? */
Widget AppShell;    /* Top-level application shell widget */

/* Static globals (scope restricted to this file) */

/* This is the minimal set of default resources required for the application
 * to run properly.
 */

static char *minDefResources[] = {
  "xreformat.geometry: =500x600\n",
  "*font: 9x15\n",
  "xreformat.minWidth: 500\n",
  "xreformat.minHeight: 600\n",
  NULL
};


static XFontStruct *font_info;
static char *displayName = NULL;    /* Various character strings to hold */
static char *geometry = NULL,        /* values of program parameters */
            *fn = NULL,
            *fc = NULL, *hc = NULL, 
            *bc = NULL;
static char *fontName;
static char geoStr[GEOM_SIZE];            /* Geometry string */
static char iconGeoStr[GEOM_SIZE];        /* Geometry string for icon */
static GC gc;                             /* Graphics context */
static CvtBlkPtr cvtList;                 /* List of conversions */
static XSizeHints sizeHints,              /* For the window */
       iconSizeHints;                     /* For the icon */
static int foreground, background,        /* Pixel values */
           borderColor;  
static int borderWidth;
static Boolean noGUI;               /* Graphical user interface? */
static int MinIconWidth, MinIconHeight, minAppWidth = 500, minAppHeight = 600;

static  Arg argList[MAX_ARGS];
static  int argNum = 0;

/* Write a message to the output window */

void WriteOutputMsg(str)
  char *str;
{
  XawTextBlock text_blk;
  XawTextPosition start;
  int i;

/* Make the output window writeable */

  argNum = 0;
  XtSetArg(argList[argNum], XtNeditType, XawtextAppend); argNum++;
  XtSetValues(MsgOut, argList, argNum);

/* Set up the text block */

  text_blk.ptr = str;
  text_blk.firstPos = 0;
  text_blk.length = i = strlen(str);
  text_blk.format = FMT8BIT;

  start = XawTextGetInsertionPoint(MsgOut);

  XawTextReplace(MsgOut, start, start+i, &text_blk);

  XawTextSetInsertionPoint(MsgOut, start+i);

  XFlush(XtDisplay(MsgOut));  /* Do it now! */

/* Prevent the user from typing into the window */

  argNum = 0;
  XtSetArg(argList[argNum], XtNeditType, XawtextRead); argNum++;
  XtSetValues(MsgOut, argList, argNum);
}

/* Query the resource databases to determine the values of various parameters.
 * Set the parameters.
 */

ErrorCode SetUpWithDefaults()
{
  char *str_type[ST_SIZE];           /* Strings describing resource types */
  char buffer[20];
  char filename[FILE_SIZE];
  long flags;
  XrmValue value;
  int x, y;
  unsigned int width, height;
  XColor screen_def;
  unsigned int font_width, 
               font_height;          /* Font dimensions */

/* If the user is not interested in a graphical user interface, don't bother
 * getting the resources related to the GUI.  Default is to bring up the GUI.
 */

  if ((XrmGetResource(resourceBase, "xreformat.noGUI",
		      "XReformat.NoGUI", str_type, &value)) == True)
    if (strncmp("Yes", value.addr, (int) value.size) == 0 ||
	strncmp("yes", value.addr, (int) value.size) == 0)
      noGUI = True;
    else noGUI = False;
  else noGUI = False;

  if (noGUI == True) return;

/* Input directory - defaults to current directory */

  if ((XrmGetResource(resourceBase, "xreformat.inputdir",
		      "XReformat.InputDir", str_type, &value)) == True)
    strcpy(InputDirectory, value.addr);
  else strcpy(InputDirectory, CUR_DIR(filename));

/* Output directory - defaults to current directory */

  if ((XrmGetResource(resourceBase, "xreformat.outputdir",
		      "XReformat.OutputDir", str_type, &value)) == True)
    strcpy(OutputDirectory, value.addr);
  else strcpy(OutputDirectory, CUR_DIR(filename));

/* Window geometry */

  if ((XrmGetResource(resourceBase, "xreformat.geometry",
		      "XReformat.geometry", str_type, &value)) == True)
    (void) strncpy(geoStr, value.addr, (int) value.size);
  else
    {
      err_msg(SetUpWithDB, NoDBGeom);
      strcpy(geoStr, DEF_GEOM);
    }
  
  XParseGeometry(geoStr, &x, &y, &width, &height);

/*  sizeHints.x = x;
  sizeHints.y = y; */
  sizeHints.width = width;
  sizeHints.height = height;
  sizeHints.flags = PPosition | PSize;

/* Get the minimum width and height */

  if ((XrmGetResource(resourceBase, "xreformat.minWidth",
		      "XReformat.Width", str_type, &value)) == True)
    sizeHints.min_width = (int) atoi(value.addr);
  else
    {
      err_msg(SetUpWithDB, NoGeomMin);
      sizeHints.min_width = minAppWidth;
    }

  if ((XrmGetResource(resourceBase, "xreformat.minHeight",
		      "XReformat.Height", str_type, &value)) == True)
    sizeHints.min_height = (int) atoi(value.addr);
  else
    {
      err_msg(SetUpWithDB, NoGeomMin);
      sizeHints.min_height = minAppHeight;
    }

  sizeHints.flags |=  PMinSize;

/*  argNum = 0;
  XtSetArg(argList[argNum], XtNminHeight, sizeHints.min_height); argNum++;
  XtSetArg(argList[argNum], XtNminWidth, sizeHints.min_width); argNum++;
  XtSetValues(AppShell, argList, argNum);
*/
/* Icon geometry */

  if (XrmGetResource(resourceBase, "xreformat.iconGeometry",
		     "XReformat.IconGeometry", str_type, &value)== True)
    (void) strncpy(iconGeoStr, value.addr, (int) value.size);
  else iconGeoStr[0] = NULL;

  XParseGeometry(iconGeoStr, &x, &y, &width, &height);

  MinIconWidth = 40;
  MinIconHeight = 40;

  iconSizeHints.x = x; 
  iconSizeHints.y = y;
  iconSizeHints.width = width;
  iconSizeHints.height = height;
  iconSizeHints.flags = PPosition | PSize | PMinSize;
  iconSizeHints.min_width = MinIconWidth;
  iconSizeHints.min_height = MinIconHeight;

/* Forground color */

  if (XrmGetResource(resourceBase, "xreformat.foreground",
		     "XReformat.Foreground", str_type, &value)== True)
    {
      (void) strncpy(buffer, value.addr, (int) value.size);
      if (XParseColor(AppDisplay, DefaultColormap(AppDisplay, AppScreen),
		      buffer, &screen_def) == 0)
	{
	  err_msg(SetUpWithDB, BadFGColor);
	  foreground = BlackPixel(AppDisplay, AppScreen);
	}
      else
	{
	  if (visual->class == StaticGray)
	    foreground = BlackPixel(AppDisplay, AppScreen);
	  else if (XAllocColor(AppDisplay, DefaultColormap(AppDisplay,
							   AppScreen),
			       &screen_def) == 0)
	    {
	      err_msg(SetUpWithDB, CantAllocColor);
	      foreground = BlackPixel(AppDisplay, AppScreen);
	    }
	  else foreground = screen_def.pixel;
	}
    }
  else foreground = BlackPixel(AppDisplay, AppScreen);

/* Background color */

  if (XrmGetResource(resourceBase, "xreformat.background",
		     "XReformat.Background", str_type, &value)== True)
    {
      (void) strncpy(buffer, value.addr, (int) value.size);
      if (XParseColor(AppDisplay, DefaultColormap(AppDisplay, AppScreen),
		      buffer, &screen_def) == 0)
	{
	  err_msg(SetUpWithDB, BadBGColor);
	  background = WhitePixel(AppDisplay, AppScreen);
	}
      else
	{
	  if (visual->class ==StaticGray)
	    background = WhitePixel(AppDisplay, AppScreen);
	  else if (XAllocColor(AppDisplay, DefaultColormap(AppDisplay,
							   AppScreen),
			       &screen_def) == 0)
	    {
	      err_msg(SetUpWithDB, CantAllocColor);
	      background = WhitePixel(AppDisplay, AppScreen);
	    }
	  else background = screen_def.pixel;
	}
    }
  else  background = WhitePixel(AppDisplay, AppScreen);

/* One last check to make sure the colors are different! */

  if (background == foreground)
    {
      background = WhitePixel(AppDisplay, AppScreen);
      foreground = BlackPixel(AppDisplay, AppScreen);
    }

/* Font */

  if (XrmGetResource(resourceBase, "xreformat.font", "XReformat.Font",
		     str_type, &value) == True)
    fontName = strsave(value.addr);
  else
    {
      err_msg(SetUpWithDB, NoFont);
      fontName = strsave(DEF_FONT);
    }

/* Load and query the font */

  font_info = XLoadQueryFont(AppDisplay, fontName);

/* Border color */

  if (XrmGetResource(resourceBase, "xreformat.borderColor",
		     "XReformat.BorderColor", str_type, &value)== True)
    {
      (void) strncpy(buffer, value.addr, (int) value.size);
      if (XParseColor(AppDisplay, DefaultColormap(AppDisplay, AppScreen), buffer, 
		      &screen_def) == 0)
	{
	  err_msg(SetUpWithDB, BadBDColor);
	  borderColor = BlackPixel(AppDisplay, AppScreen);
	}
      else
	{
	  if (visual->class == StaticGray)
	    borderColor = BlackPixel(AppDisplay, AppScreen);
	  else if (XAllocColor(AppDisplay, DefaultColormap(AppDisplay, AppScreen),
			       &screen_def) == 0)
	    {
	      err_msg(SetUpWithDB, CantAllocColor);
	      borderColor = BlackPixel(AppDisplay, AppScreen);
	    }
	  else borderColor = screen_def.pixel;
	}
    }
  else borderColor = WhitePixel(AppDisplay, AppScreen);

/* Border width */

  if (XrmGetResource(resourceBase, "xreformat.borderWidth",
		     "XReformat.BorderWidth", str_type, &value)== True)
    borderWidth = atoi(value.addr);
  else borderWidth = BORDER_WIDTH;

/* Done */

  return(AllOk);
}


/* A version of this exists in X11R4, but is not present in the R3 libraries.
 * Initialize the Xt toolkit, create the application context, open the 
 * display, and create the application shell.
 */

Widget AppInitialize(context, class, opt_tbl, num_opts, argc, argv, fallback,
                     args, num_args)
  XtAppContext *context;
  String class;
  XrmOptionDescList opt_tbl;
  Cardinal num_opts;
  Cardinal *argc;
  String *argv;
  String *fallback;
  ArgList args;
  Cardinal num_args;
{

/* Initialize the Xt toolkit */

  XtToolkitInitialize();

/* Create the application context. */

  *context = XtCreateApplicationContext();

/* Open the display, initialize it and add it to the application context.
 * display is a global variable.
 */

  AppDisplay = XtOpenDisplay(*context, NULL, NULL, class, opt_tbl, num_opts,
			     argc, argv);

/* Now create and return the application shell */

  return( XtAppCreateShell(NULL, class, applicationShellWidgetClass,
			   AppDisplay, args, num_args) );
}

#ifdef XGUI

/* Main routine - initialization, and lots of it, you bet. */

void main(ac, av)
  int ac;
  char *av[];
{
  int i;
  XtAppContext context;
  CvtBlkPtr cvt_list;
  XtTranslations dialog_tbl;
  char *input_files;

/* Set the process name */

  ProcName = av[0];

/* Set the help file */

  sprintf(HelpFile, "%s/%s", ROOT_DIR, HELP_FILE);

/* Set up the Athena toolkit.  This routine does quite a bit of work.  It 
 * calls: XtToolkitInitialize, XtCreateApplicationContext, XtOpenDisplay,
 * XtAppCreateShell.  The ac and av variables are modified - any options
 * recognized from the options table are added to the resource database
 * and then removed.  Any strings left in av after this call represent a
 * conversion operation.
 */

  AppShell = AppInitialize(&context, APP_CLASS, options, NUM_OPTIONS,
			   &ac, av, NULL, NULL, 0);

/* Get the database associated with this display */

  resourceBase = XtDatabase(AppDisplay);

/* Because there may not be an application resource file available, the
 * minimal set of resources needed to make the application work must be
 * specified.  I tried the ...SetFallbackResources routine here, but it
 * didn't work.
 */

  i = 0;
  while (minDefResources[i] != NULL)
    XrmPutLineResource(&resourceBase, minDefResources[i++]);

/* Check to see if there was a conversion operation specified on the 
 * command line.
 */

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

/* Set some global variables - they must have values before InitWidgets and
 * SetUpWithDefaults are called.
 */

  AppScreen = DefaultScreen(AppDisplay);
  visual = DefaultVisual(AppDisplay, AppScreen);

/* Now that a gargantuan amount of initialization has been done, do some more.
 * Read the resource database for parameter values.
 */

  SetUpWithDefaults();

/* If the user doesn't want a GUI, just do the specified conversion */

  if (noGUI == True)
    {
      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));
      exit(0);
    }

/* Scan the input directory and construct a NULL terminated array of strings
 * of the file names.
 */

  ScanDir(InputDirectory, &input_files, FALSE);
  if (input_files == NULL)
    InputFiles = EmptyList[0];
  else InputFiles = input_files;

i=0;
while (*(input_files+i) != NULL)
  printf("file: %s\n", *(input_files+i++));

/* The application uses a viewport widget and several dialog box and 
 * command widgets.  Create these and add them to the application shell.
 * Realize and map the widgets.
 */

  InitWidgets(context, dialog_tbl, AppShell, sizeHints, font_info,
	      input_files, InputDirectory, OutputDirectory);

/* Set the min width and height for the application.  The shell must NOT
 * resize to dimensions smaller than those specified here.
 */

  XSetNormalHints(AppDisplay, XtWindow(AppShell), &sizeHints);

/* Use default Athena event loop */

  XtAppMainLoop(context);

}
#endif
