/*
======================================================================
files.c

Ernie Wright  17 Apr 05
MSVC 4.0
====================================================================== */

#include "qv.h"
#include <commdlg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <lwhost.h>


static LWDirInfoFunc *dirinfo;


/*
======================================================================
initFileReq()

Initialize LW's Directory Info global, used to find the "Output"
directory and to search for QV's config file.
====================================================================== */

int initFileReq( GlobalFunc *global )
{
   dirinfo = global( LWDIRINFOFUNC_GLOBAL, GFUSE_TRANSIENT );
   return ( dirinfo != NULL );
}


/* used internally to store saver names and default filename extensions */

typedef struct { char *name, *ext; } Saver;


/*
======================================================================
free_savers()

Free memory allocated by get_savers().  Don't free the first two
names, since those are the string literals for QV's internal formats,
and don't free the extensions, since those point into the memory
allocated for the name field.
====================================================================== */

static void free_savers( Saver *saver )
{
   int i;

   if ( saver ) {
      for ( i = 2; saver[ i ].name; i++ )
         free( saver[ i ].name );
      free( saver );
   }
}


/*
======================================================================
split_name()

Split a LW image saver name into a description and a default filename
extension, and save the parts in a Saver record.  By convention, the
extension is at the end of the saver name in parentheses.  If it's not
there, the extension is stored as "*".
====================================================================== */

static void split_name( Saver *saver, const char *name )
{
   char *p, *q;

   saver->name = malloc( strlen( name ) + 1 );
   strcpy( saver->name, name );

   p = strrchr( saver->name, '(' );
   if ( !p ) {
      saver->ext = "*";
      return;
   }

   *p = 0;
   ++p;
   if ( *p == '.' ) ++p;
   q = strrchr( p, ')' );
   if ( q ) *q = 0;
   saver->ext = p;
}


/*
======================================================================
get_savers()

Create an array of saver names and default filename extensions.  The
first two entries are for QV's built-in BMP and IFF savers.  The rest
are supplied by saverFormatName(), which calls LW's Image Utility
global to get the saver names.

The names are used in the list of available file formats displayed to
the user in the file dialog.  The extensions are used in the file
dialog's filter string, and to supply an extension when the user
doesn't.
====================================================================== */

static Saver *get_savers( void )
{
   Saver *saver;
   int count, i;

   count = saverFormatCount();
   saver = calloc( count + 3, sizeof( Saver ));

   saver[ 0 ].name = "QV BMP";
   saver[ 0 ].ext = "bmp";
   saver[ 1 ].name = "QV IFF";
   saver[ 1 ].ext = "iff";

   for ( i = 0; i < count; i++ )
      split_name( &saver[ i + 2 ], saverFormatName( i ));

   return saver;
}


/*
======================================================================
find_saver()

Find the saver name in the Saver array and return its index.  If the
name isn't in the array, index 0 is returned.
====================================================================== */

static int find_saver( Saver *saver, char *name )
{
   int i;

   for ( i = 0; saver[ i ].name; i++ )
      if ( !strcmp( saver[ i ].name, name ))
         return i;
   return 0;
}


/*
======================================================================
build_filter()

Given a Saver array, build a string that can be used as the file
format filter string in a Win32 OPENFILENAME.

The format of the string is

   Format Name (.ext)\0*.ext\0...

for each file format.  The first string is the description displayed
to the user in the "Files of Type" dropdown list.  The second is the
filename extension used to filter the filenames in the files list.
The string contains as many description/filter pairs as there are
file formats in the Saver array, and is terminated by a second 0 byte.
====================================================================== */

static char *build_filter( Saver *saver )
{
   int i, size = 1;
   char *filter, *p;

   /* find the string length */

   for ( i = 0; saver[ i ].name; i++ )
      size += strlen( saver[ i ].name )
           + 2 * strlen( saver[ i ].ext ) + 10;

   /* create the filter string */

   filter = malloc( size );
   p = filter;
   for ( i = 0; saver[ i ].name; i++ ) {
      size = sprintf( p, "%s (.%s)%c*.%s%c",
         saver[ i ].name,
         saver[ i ].ext, '\0',
         saver[ i ].ext, '\0' );
      p += size;
   }

   return filter;
}


/*
======================================================================
FileRequest()

Allow the user to specify a filename and image format.

ARGUMENTS
   hwnd           parent window
   iname          image name

RESULTS
   Displays the standard Windows file dialog.  If the user cancels the
   dialog, the function returns NULL.  Otherwise, a QVFileReq is
   filled and returned.

The initial path is the path of the most recently saved file.  If no
file has been saved yet, we call LW's Directory Info to get the path
for the current "Output" directory.  If that doesn't exist, the path
string is empty, and the resulting initial path is the current working
directory, usually LW's content directory.

The initial filename is the 'iname' argument.  If this name contains
an extension, it's removed.  Typically 'iname' is the filename most
recently used to save the current image, or a default name constructed
for the image (like "Untitled4") if it hasn't been saved yet.

The initial image format is the format of the most recently saved
file.  If no file has been saved yet, the default format is the first
one in the list (QV's internal BMP saver).

The list of available image savers is rebuilt each time FileRequest()
is called, since this list could change while QV is running (although
it typically won't), so in order to remember the last format used, we
can't just remember a saver index.  We remember the saver name and get
the index by finding it in the current saver list.  If the saver has
disappeared for some reason, the initial format is again QV's internal
BMP saver.

If the user doesn't supply a filename extension, the extension for the
selected image format is appended to the filename.  By convention, the
default extension for LW's plug-in savers is at the end of the format
name, in parentheses.  If this is missing, no extension is added to
the filename.

The saver index returned in the QVFileReq is negative for the internal
savers (-2 for BMP, -1 for IFF) or the (nonnegative) index used by
LW's Image Utility global.
====================================================================== */

QVFileReq *FileRequest( HWND hwnd, char *iname )
{
   static char
      name[ 260 ],
      path[ 260 ],
      node[ 260 ],
      sname[ 128 ];
   static QVFileReq freq;

   Saver *saver;
   char *filter, *p;
   const char *dir;
   int findex, result;
   OPENFILENAME ofn = { 0 };


   /* if path is empty, try to put something useful in it by asking the
      LW Directory Info global for the path to the "Output" directory */

   if ( !path[ 0 ] )
      if ( dir = dirinfo( "Output" ))
         strcpy( path, dir );

   /* initialize node and name with the image name argument */

   strcpy( name, iname );
   if ( p = strrchr( name, '.' ))
      *p = 0;
   strcpy( node, name );

   /* get the list of saver names and filename extensions */

   saver = get_savers();
   filter = build_filter( saver );

   /* find the index of the previously used saver */

   findex = find_saver( saver, sname );

   /* initialize the OPENFILENAME */

   ofn.lStructSize     = sizeof( OPENFILENAME );
   ofn.hwndOwner       = hwnd;
   ofn.lpstrFilter     = filter;
   ofn.nFilterIndex    = findex + 1;
   ofn.lpstrFile       = name;
   ofn.nMaxFile        = sizeof( name );
   ofn.lpstrFileTitle  = node;
   ofn.nMaxFileTitle   = sizeof( node );
   ofn.lpstrInitialDir = path;
   ofn.lpstrTitle      = "Save QV image buffer";
   ofn.Flags           = OFN_EXPLORER | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY
                       | OFN_NOCHANGEDIR;

   result = GetSaveFileName( &ofn );

   /* if result != 0, the user pressed OK */

   if ( result ) {
      findex = ofn.nFilterIndex - 1;
      strcpy( path, name );
      path[ ofn.nFileOffset ] = 0;
      strcpy( sname, saver[ findex ].name );

      /* add the filename extension, if there isn't one */

      if ( !strchr( node, '.' ) && saver[ findex ].ext[ 0 ] != '*' ) {
         strcat( name, "." );
         strcat( name, saver[ findex ].ext );
         strcat( node, "." );
         strcat( node, saver[ findex ].ext );
      }

      /* set the values of the QVFileReq */

      freq.filename = name;
      freq.title    = node;
      freq.type     = findex - 2;
   }

   free( filter );
   free_savers( saver );
   return result ? &freq : NULL;
}


/*
======================================================================
findConfigFile()

Try to locate a config file.

INPUTS
   hinst          module instance handle (module is e.g. LW or qv.p)
   cfgname        the name of the config file (no path)
   buf            stores the config file's pathname
   bufsize        size of buf in bytes

RESULTS
   Returns TRUE if successful, otherwise FALSE.

Searches for the config first in the current directory, then in the
"Settings" directory returned by the LW Directory Info global, then in
the directory associated with the USERPROFILE environment variable,
and finally in the directory in which the module associated with the
instance handle resides.
====================================================================== */

int findConfigFile( HINSTANCE hinst, char *cfgname, char *buf, int bufsize )
{
   FILE *fp;
   const char *dir;
   char *p;
   int i;


   strcpy( buf, cfgname );
   fp = fopen( buf, "rb" );

   if ( !fp ) {
      dir = dirinfo( "Settings" );
      if ( dir && dir[ 0 ] ) {
         sprintf( buf, "%s%c%s", dir, '\\', cfgname );
         fp = fopen( buf, "rb" );
      }
   }

   if ( !fp ) {
      dir = getenv( "USERPROFILE" );
      if ( dir && dir[ 0 ] ) {
         sprintf( buf, "%s%c%s", dir, '\\', cfgname );
         fp = fopen( buf, "rb" );
      }
   }

   if ( !fp ) {
      GetModuleFileName( hinst, buf, bufsize );
      p = strrchr( buf, '\\' );
      if ( !p ) p = strrchr( buf, '/' );
      if ( !p ) {
         if ( i = strlen( buf )) {
            buf[ i ] = '\\';
            p = &buf[ i ];
         }
         else p = buf - 1;
      }
      strcpy( p + 1, cfgname );
      fp = fopen( buf, "rb" );
   }

   if ( fp ) {
      fclose( fp );
      return 1;
   }

   return 0;
}
