/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is
 * preserved on all copies.
 *
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 */
/*
 * cnv.c - select the read/write function using the file name ( !!! ).
 *
 * Author:      Raul Rivero
 *              Mathematics Dept.
 *              University of Oviedo
 * Date:        Sat Feb 6 1993
 * Copyright (c) 1993, Raul Rivero
 *
 */
 /*
  * The algorithm is not too acuratte, but this is to me a
  * curiosity not a vital part of LUG.
  *
  * If u wanna fix the problems, please do it ( and thank u ).
  */

#include <lug.h>
#include <lugfnts.h>

/*
 * If we need reduce the number of colors, what is the
 * default process ? ...
 */
#define DITHER_INSTEAD_OF_QUANTIZE              FALSE

extern int LUGverbose;

/*
 * Complete file format name.
 */
static char *lug_ff_name[] = {
                        "Compuserve's GIF",
                        "Rayshade's heightfield",
                        "Sun raster",
                        "Portable Bitmap Map",
                        "Portable Grey Map",
                        "Portable Pix Map",
                        "ZSoft's PCX",
                        "Alias's 'pix'",
                        "raw",
                        "rgb",
                        "Wavefront's RLA",
                        "Wavefront's RLB",
                        "Utah Raster Toolkit's RLE",
                        "Silicon Graphics RGB",
                        "True Vision's targa",
                        "Aldus' TIFF",
                        "Aldus' TIFF",
                        "PostScript",
                        "JPEG",
                        "JPEG"
};

/*
 * Ok, we recognize these extensions ... 
 */
static char *lug_ff_ext[] = {
                        ".gif",
                        ".hf",
                        ".im",
                        ".pbm", ".pgm", ".ppm",
                        ".pcx",
                        ".pix",
                        ".raw",
                        ".rgb",
                        ".rla", ".rlb",
                        ".rle",
                        ".sgi",
                        ".tga",
                        ".tif", ".tiff",
                        ".ps",
                        ".jpg", ".jpeg",
                        NULL
};

/*
 * Read file functions.
 */
static int (*read_lug_fnts[])() = {
                        read_gif_file,
                        NULL,
                        NULL,
                        read_pbm_file, read_pbm_file, read_pbm_file,
                        read_pcx_file,
                        read_alias_file,
                        read_raw_file,
                        read_rgb_i_file,
                        read_rla_file,
                        read_rla_file,
#ifdef iRLE
                        read_rle_file,
#else
                        NULL,
#endif  /* iRLE */
#ifdef iSGI
                        read_sgi_file,
#else
                        NULL,
#endif  /* iSGI */
                        read_tga_file,
#ifdef iTIFF
                        read_tiff_file, read_tiff_file,
#else
                        NULL, NULL,
#endif
                        NULL,
#if defined(iJPEG) || defined(iJPEGNEW)
                        read_jpeg_file, read_jpeg_file,
#else
                        NULL, NULL,
#endif
                        NULL
};

/* 
 * Write file functions.
 */
static int (*write_lug_fnts[])() = {
                        write_gif_file,
                        write_hf_file,
                        NULL,
                        write_pbm_file, write_pbm_file, write_pbm_file,
                        write_pcx_file,
                        write_alias_file,
                        write_raw_file,
                        write_rgb_file,
                        write_rla_file,
                        write_rla_file,
#ifdef iRLE
                        write_rle_file,
#else
                        NULL,
#endif  /* iRLE */
#ifdef iSGI
                        write_sgi_file,
#else
                        NULL,
#endif  /* iSGI */
                        write_tga_file,
#ifdef iTIFF
                        write_tiff_file, write_tiff_file,
#else
                        NULL, NULL,
#endif
                        write_ps_file,
#if defined(iJPEG) || defined(iJPEGNEW)
                        write_jpeg_file, write_jpeg_file,
#else
                        NULL, NULL,
#endif
                        NULL
};

/* 
 * Each file formats allows these depths ...
 */ 
static int write_depth_fnts[] = {
                        ONLY_8_PLANES,
                        ONLY_RAW_PLANES,
                        ALL_PLANES,
                        ONLY_BINARY_PLANES, ONLY_8_PLANES, ONLY_24_PLANES,
                        ONLY_8_PLANES,
                        ONLY_24_PLANES,
                        ONLY_RAW_PLANES,
                        ONLY_24_PLANES,
                        ONLY_24_PLANES,
                        ONLY_24_PLANES,
                        ALL_PLANES,
                        ONLY_24_PLANES,
                        ONLY_24_PLANES,
                        ALL_PLANES, ALL_PLANES,
                        ONLY_RAW_PLANES,
                        ALL_PLANES, ALL_PLANES
};


read_lug_file( name, bitmap )
char *name;
bitmap_hdr *bitmap;
{
  ifunptr read_file;

  /*
   * Get the correct funtion to read that file ( please, remember
   * tha we use the file extension and this is not perfect ).
   */
  read_file = get_readlug_function( name );

  /* Ok, do it. */
  read_file( name, bitmap );
}


write_lug_file( name, bitmap )
char *name;
bitmap_hdr *bitmap;
{
  ifunptr write_file;
  int new_depth;
  int dither_flag = DITHER_INSTEAD_OF_QUANTIZE;

  /* Get the output file type */
  new_depth = get_depth_writelug_function( name );

  /*
   * If the target file format doesn't allow the number of planes
   * we have then we need convert the source image.
   */
  if ( !new_depth || bitmap->depth == new_depth ) {
    /* Ok, all right */
    write_file = get_writelug_function( name );
    write_file( name, bitmap );
  }else{
    /* Ooppss!, different # of colors */
    bitmap_hdr out;

    switch ( new_depth ) {
      case  ONLY_BINARY_PLANES:
                fprintf( stderr, "Converting to bi-level format.\n" );
                error( 99 );
                break;
      case  ONLY_RAW_PLANES:
                to_raw_bw( bitmap, &out );
                write_file = get_writelug_function( name );
                write_file( name, &out );
                break;
      case  ONLY_8_PLANES:
                if ( dither_flag ) {
                  dither_image( bitmap, &out, 6, (double) 1.0 );
                }else {
                  VPRINTF( stderr, "Quantizing\n" );
                  quantize( bitmap, &out, 256 );
                }
                write_file = get_writelug_function( name );
                write_file( name, &out );
                break;
      case ONLY_24_PLANES:
                to24( bitmap, &out );
                write_file = get_writelug_function( name );
                write_file( name, &out );
                break;
      default:
                fprintf( stderr, "Conversion error, unkown target depth\n" );
                exit( 1 );
    }
    freebitmap( &out );
  }
}

ifunptr get_readlug_function( str )
char *str;
{
  ifunptr ptr;
  int value;

  /* Get the correct function for reading */
  if ( !(ptr = read_lug_fnts[ value = get_index_function(str) ]) ) {
    /* Ooops!, no reader */
    fprintf( stderr, "%s reader not linked during the compilation process\n",
                     lug_ff_name[ value ] );
    error( 99 );
  }

  VPRINTF( stderr, "Reading %s using the %s reader ...\n",
           str, lug_ff_name[value] );

  return ptr;
}

ifunptr get_writelug_function( str )
char *str;
{
  ifunptr ptr;
  int value;

  /* Get the correct function for writing */
  if ( !(ptr = write_lug_fnts[ value = get_index_function(str) ]) ) {
    /* Ooops !, no writer */
    fprintf( stderr, "%s writer not linked during the compilation process\n",
                     lug_ff_name[ value ] );
    error( 99 );
  }

  VPRINTF( stderr, "Writing %s using the %s writer ...\n",
           str, lug_ff_name[value] );

  return ptr;
}

get_depth_writelug_function( str )
char *str;
{
  /* Return the correct depth of that specific file format */
  return write_depth_fnts[ get_index_function(str) ];
}

get_index_function( str )
char *str;
{
  char dup[132];
  char *ptr;
  int len = strlen( str );
  int indexx;

  /* Duplicates the string */
  strcpy( dup, str );

  /* Check if exists the '.Z' extension ( and discard it ) */
  if ( dup[len-2] == '.' && dup[len-1] == 'Z' )
    dup[len-2] = 0;

  while ( ptr = strrchr( dup, '.' ) ) {
    /*
     * If the extension exists then we return the index
     * to the read/write function else continue ( and
     * disard the extension ).
     */
    if ( (indexx = get_real_index_function( ptr )) != -1 )
      return indexx;
    else ptr[0] = 0;
  }

  return DEFAULT_FORMAT;
}

get_real_index_function( str )
char *str;
{
  register int i = 0;

  while ( lug_ff_ext[i] ) {
    if ( strstr( str, lug_ff_ext[i] ) )
      return i;
    i++;
  }

  return -1;
}
