/****************************************************************************/
/*                                                                          */
/*  VolVis is a volume visualization system for investigating, manipulating */
/*  and rendering geometric and volumetric data.                            */
/*                                                                          */
/*  Copyright (C) 1993 by the Research Foundation of the State University   */
/*                            of New York                                   */
/*                                                                          */
/*  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 1, 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.               */
/*                                                                          */
/*  For information on VolVis, contact us at:                               */
/*                                                                          */
/*                volvis@cs.sunysb.edu                         (email)      */
/*                                                                          */
/*                Lisa Sobierajski & Ricardo Avila             (US Mail)    */
/*                Department of Computer Science                            */
/*                State University of New York at Stony Brook               */
/*                Stony Brook, New York  11794-4400                         */
/*                                                                          */
/****************************************************************************/




/*			File: C_motif_win.c
 *		      Author: Rick Avila & Morita
 *			Date: 03/07/92
 *		 Description: Motif Windowing Routines Of VolVis
 *	Modification History:
 *
 *		Who?		When?		Why?
 *	--------------------------------------------------------------------
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <malloc.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <Xm/Xm.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/BulletinB.h>
#include <Xm/LabelG.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/DrawingA.h>

#include <sys/time.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <Xm/TextF.h>
#include <unistd.h>
#include <pwd.h>
#include <fcntl.h>

#include "C_volvis.h"
#include "MOTIF_windefs.h"
#include "C_fio.h"
#include "C_help.h"

/* Global Variables For Motif Windowing */
extern Widget		vv_toplevel;	/* VolVis toplevel Shell Widget */
extern Widget		fio_bbdialog;	/* File I/O Bulletin Board Dialog */
extern C_WindowDefs	window_defs;
extern C_World		world;
extern C_View		view;
extern C_ImageTable	image_table;

int   		decide_axis();
int   		machine_24_bit();
int   		data_conversion();
void  		make_blank_icon();
void  		set_color_slc_8_bit();
unsigned char 	set_color_img_8_bit();

/*
 *        Procedure Name: get_full_path
 *          Return Value: int
 *       Input Variables: template - pathname
 *                        full_path - pathname
 *      Output Variables: none
 *      Update Variables: full_path
 *      Global Variables: none
 *           Description: get_full_path will complete a path name starting
 *			  with a ~.  The end result is the same as what UNIX
 *			  would have done. 
 */

int get_full_path(template,full_path)
char *template;
char *full_path;
{
  char   *p, *q,*temp;
  struct  passwd     *pwdEntry;
  int	 i,j;

        /*
         *  We're completing a file in a directory.
         *  The directory may be lead by a ~<username> abbreviation.
         *  If that's the case expand it.
         */ 
        if (template[0] == '~') 
	{
            /*
             *  We need to do twiddle directory expansion.
             *  See if it's our directory:
             */
            if (template[1] == '/') 
	    {
		sprintf(full_path,"%s%s",getenv("HOME"),&template[1] );
	    }
            else 
	    {
                /*
                 * It's someone else's user id.
		 */
                for (p= full_path, q= &template[1];
                        ((*p= *q) != '/') && (*p!='\0'); p++, q++);
                *p= 0;
                if (!(pwdEntry= getpwnam(full_path))) 
		/* function returns 0, unable to expand	*/
			return (FALSE);
		sprintf(full_path, "%s%s",pwdEntry->pw_dir,q);
	    }
	}
	else
	    sprintf(full_path,"%s", template);

	return(TRUE);

}/* get_full_path */

/*
 *        Procedure Name: get_extension
 *          Return Value: char *, extension of the file
 *       Input Variables: any file name
 *      Output Variables: none
 *      Update Variables: none
 *      Global Variables: none
 *           Description: get_extension will return the extension of the 
 *			  file name, the '.' character will not be returned
 *
 */
char * get_extension(filename)
char  *filename;
{
  char *extension;

	if ((extension = strrchr(filename,'.')) != NULL)
	    ++extension;

	/* return the extension */
	return(extension);
}


int check_magic_num(pathname,filename,filetype,icon)
char  *pathname;
char  *filename;
C_FileType  filetype;
Icon_Info   *icon;
{
  char	fullname[C_MAX_STRING],
	error_msg[C_MAX_STRING];
  int   file_id,
	magic_num;

	sprintf(fullname,"%s/%s", pathname,filename);
	if((file_id = open(fullname, O_RDONLY) ) <= 0 )
        {
	    icon->valid_file = FALSE;
	    sprintf(icon->error_msg, "\n Can Not Open File %s !!!\n",fullname);
            return( C_ERROR );
	}

        read( file_id, &magic_num, sizeof(int) );

        switch ( filetype )
        {
	  case   C_SLICE_FILE:
		if (magic_num !=  C_SLICE_MAGIC)
		{
		    icon->valid_file = FALSE;
                    sprintf(icon->error_msg,"\n Although file %s has an .slc extension, but it is not a valid slice file due to incorrect magic number\n", 
		    fullname);
		    close(file_id);
		    return C_OK;
		}
		break;

	  case C_IMAGE_FILE:
		if (magic_num !=  C_IMAGE_MAGIC)
		{
		    icon->valid_file = FALSE;
                    sprintf(icon->error_msg,"\n Although file %s has an .img extension, but it is not a valid image file due to incorrect magic number\n", 
                    fullname);
		    close(file_id);
		    return C_OK;
		}
		break;

          case C_TEXTURE_FILE:
		if (magic_num != C_TEXTURE_MAGIC)
		{
		    icon->valid_file = FALSE;
                    sprintf(icon->error_msg,"\n Although file %s has an .tex extension, but it is not a valid texture file due to incorrect magic number\n", 
                    fullname);
		    close(file_id);
		    return C_OK;
		}
		break;
	}
	icon->valid_file = TRUE;
	close(file_id);
	return C_OK;
}

/*
 *        Procedure Name: valid_file_name
 *          Return Value: int
 *       Input Variables: filename - any file name
 *			  pathname - pathname
 *			  filetype - the file type
 *			  icon	   - one icon
 *      Output Variables: none
 *      Update Variables: none
 *      Global Variables: none
 *           Description: valid_file_name will check to see if the file ends
 *			  with a extension, it could be slc,img,tex,fun,env
 *
 */

int valid_file_name(pathname, filename,filetype,icon)
char  *pathname;
char  *filename;
C_FileType  filetype;
Icon_Info *icon;
{
  char *extension;
  void	check_magin_num();

	if (filename[0] != '.' )
	/* we should not concern ourselfs with icon files */
	{
	    extension= get_extension(filename);
	    if (extension != NULL)
	    {
		if ((filetype == C_SLICE_FILE) && (strcmp(extension,"slc")==0))
		{
		    check_magic_num(pathname,filename,filetype,icon);
		    return TRUE;
		}
		else if ((filetype == C_TEXTURE_FILE) && 
						(strcmp(extension,"tex")==0))
		{
		    check_magic_num(pathname,filename,filetype,icon);
		    return TRUE;
		}
		else if ((filetype == C_IMAGE_FILE) && 
						(strcmp(extension,"img")==0))
		{
		    check_magic_num(pathname,filename,filetype,icon);
		    return TRUE;
		}
		else if ((filetype == C_FUNCTION_FILE) && 
						(strcmp(extension,"fun")==0))
 		{
	         	return TRUE;
		}
		else if ((filetype == C_ENVIRONMENT_FILE) &&
						(strcmp(extension,"env")==0))
		{
			return TRUE;
		}
		else
			return FALSE;
	    }
	    else
		return FALSE;
	}
	else
	    return FALSE;
}


int machine_24_bit(widget)
Widget	widget;
{
	if (window_defs.depth == 24)
	    return(1);
	else
	    return(0);
}

void set_color_slc_8_bit(filename, image_ptr)
char *filename;
unsigned char *image_ptr;
{
  char *extension;
  unsigned char *temp_image_ptr;
  int i;

	for (i = 0; i< C_ICON_IMAGE_WIDTH * C_ICON_IMAGE_HEIGHT; ++i)
	{
		/* map the image_ptr value to the gray scale in the colormap */
		*(image_ptr + i) = *(image_ptr +i) / 4 
	 				+ window_defs.first_grey_index;		
	}		
}

/*
 *        Procedure Name: make_blank_icon 
 *          Return Value: none  
 *       Input Variables: icon		-  hold information about one icon 
 *      Output Variables: none
 *      Update Variables: icon 
 *      Global Variables: none
 *           Description: This function is called when some thing goes wrong
 *			  during creation of an icon.  An blank icon is created
 *			  with all the values to be zero.
 */

void make_blank_icon(icon)
Icon_Info *icon;
{
  extern void C_error_message();

	printf("ohoh, in make blank icon\n");
	if (machine_24_bit(icon->button))
	/* create a 24 bit blank icon */
	{
	    icon->icon_24_data = (unsigned int *) malloc( C_ICON_IMAGE_WIDTH * 
             			   C_ICON_IMAGE_HEIGHT * sizeof(unsigned int));

	    if (!icon->icon_24_data)
	    /* Can't even allocate space for a blank icon*/
	    {
		C_error_message("Not enough memory even to store \nblank icon data\nSystem must exit !!!\n");
		exit(0);
	    }
	    /* set all values to zero */
	    bzero(icon->icon_24_data, sizeof(unsigned int) * 
			icon->image_info.width * icon->image_info.height);
	}
	else
	/* create a 8 bit icon */
	{
	    icon->icon_8_data = (unsigned char *) malloc(C_ICON_IMAGE_WIDTH * 
	       		          C_ICON_IMAGE_HEIGHT*sizeof(unsigned char *));
	    if (!icon->icon_8_data)
	    /* Can't even allocate space for a blank icon*/
	    {
		C_error_message("Not enough memory even to store\nblank icon data\nSystem must exit !!!\n");
		exit(0);
	    }
	    /* set all values to zero */
	    bzero(icon->icon_8_data, sizeof(unsigned char) * 
			icon->image_info.width * icon->image_info.height);
	}
}

/*
 *        Procedure Name: get_function_header 
 *          Return Value: none  
 *       Input Variables: icon		-  hold information about one icon 
 *			  pathname      -  the pathname function file is 
 *      Output Variables: none
 *      Update Variables: icon 
 *      Global Variables: none
 *           Description: This function will get the header from function
 *			  files.  This information will be saved with icon 
 */

void get_function_header(icon, pathname)
Icon_Info  *icon;
char 	   *pathname;
{
  int read_function_file_header();

  char filename[C_MAX_STRING];
  int  STATUS;
		
	sprintf( filename, "%s/%s", pathname, icon->filename);
			
	/* read the file header */
	STATUS = read_function_file_header(icon, filename);

	/* update the read_in field */
	if (STATUS != C_OK)
	{
		icon->valid_file = FALSE;
		sprintf(icon->error_msg, "\n Could not get header information from file %s\n", icon->filename);
	}
	else
		icon->valid_file = TRUE;		
}

int read_function_file_header(icon, string)
Icon_Info *icon;
char *string;
{    
  FILE *fp;
  char *ptr;
  char temp_fun[C_MAX_STRING];
  char c;

        fp = fopen( string, "r" );
        if ( !fp )
        {
                fclose( fp );
                return C_ERROR;
        }
        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.x_voxels = (int) strtol( string, &ptr, 10 ) + 2;
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.y_voxels = (int) strtol( string, &ptr, 10 ) + 2;
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.z_voxels = (int) strtol( string, &ptr, 10 ) + 2;
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }
        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        if ( ( strcmp( string, "METER" )) == 0 )
        {
                icon->function_info.unit_type = C_METER_UNIT;
        }
        else if ( ( strcmp( string, "MILLIMETER" )) == 0 )
        {
                icon->function_info.unit_type = C_MILLIMETER_UNIT;
        }
        else if ( ( strcmp( string, "MICRON" )) == 0 )
        {
                icon->function_info.unit_type = C_MICRON_UNIT;
        }
        else if ( ( strcmp( string, "INCH" )) == 0 )
        {
                icon->function_info.unit_type = C_INCH_UNIT;
        }
        else if ( ( strcmp( string, "FOOT" )) == 0 )
        {
                icon->function_info.unit_type = C_FOOT_UNIT;
        }
        else
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.x_unit = (float) strtod( string, &ptr ) *
                                    (icon->function_info.x_voxels-1);
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.y_unit = (float) strtod( string, &ptr ) *
                                        (icon->function_info.y_voxels-1);
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.z_unit = (float) strtod( string, &ptr ) *
                                        (icon->function_info.z_voxels-1);
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.fun_x_min = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.fun_x_max = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.fun_y_min = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.fun_y_max = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.fun_z_min = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.fun_z_max = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.map_to_0 = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.map_to_255 = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        icon->function_info.segment_at = (float) strtod( string, &ptr );
        if ( ptr == string )
        {
                fclose( fp );
                return C_ERROR;
        }

        fscanf( fp, "%s", string );
        fscanf( fp, "%s", string );
        if ( ( strcmp( string, "TRUE" )) == 0 )
        {
                icon->function_info.invert_function_value = 1;
        }
        else if ( ( strcmp( string, "FALSE" )) == 0 )
        {
                icon->function_info.invert_function_value = 0;
        }
        else
        {
                fclose( fp );
                return C_ERROR;
        }
	
	sprintf(temp_fun,"");
	sprintf(icon->function_info.function,"");
	while( fscanf( fp, "%s", string) != EOF)
	{
		sprintf(temp_fun,"%s",icon->function_info.function);
		sprintf(icon->function_info.function, "%s %s",
				temp_fun, string);
	}

	fclose( fp );
	return C_OK;
}

/*
 *    Procedure Name: resize_image 
 *      Return Value: int	- if resizing was ok 
 *   Input Variables: icon 	- the icon structure
 * 		      max_ptr   - one slice of a volume   
 *		      x_axis    - the width of the slice
 *		      y_axis    - the height of the slice
 *  Output Variables: none
 *  Update Variables: icon 
 *  Global Variables: none
 *       Description: This function will resize a slice which was x_axis by
 *		      y_axis to C_ICON_IMAGE_HEIGHT by C_ICON_IMAGE_WIDTH.
 *		      its a proportional which means that the ratio of the 
 *		      x_axis and y_axis will not be changed.  The space left
 *		      will be set to zero to accommadate the new size. 
 */

int resize_image(icon, max_ptr, x_axis, y_axis)
Icon_Info *icon;
C_Voxel_8bit  *max_ptr;
int x_axis;
int y_axis;
{
  extern void C_error_message();

  unsigned int	*temp_24_icon_ptr;
  unsigned char *temp_8_icon_ptr;
  unsigned char	*temp_max_ptr;
  unsigned char *square_ptr;

  char		temp_msg[C_MAX_STRING];
  float		total_x, 
		last_x, 
		gap, 
		total_y=0, 
		last_y = 0;

  int 		i, j, k, x, y, h=0,
		temp,index_max;

	if (x_axis > y_axis)
	/* if the slice's x axis is greater than its y axis */
	{
	    square_ptr = (unsigned char *)malloc(x_axis * x_axis * 
						    sizeof(unsigned char));
	    /* add padding to top and bottom of the slice to make it a
		plane with x_axis equal to y_axis.  The new size if x_axis
  		by x_axis 
	    */

	    j=0;
	    for(i=0;i<x_axis * x_axis; ++i)
	    {
		if ( (i < (x_axis-y_axis)/2 * x_axis )  || 
				(i > ((x_axis-y_axis)/2 + y_axis) * x_axis)  )
		/* if we are adding padding */
		    *(square_ptr + i) = NULL;
		else
		/* just copy the value */
		{
		    *(square_ptr + i) = *(max_ptr + j);
		    j++;
		}
	    }
	    y_axis = x_axis;
	    free(max_ptr);
      	    max_ptr = square_ptr;

        }
	else  if (x_axis <  y_axis )
	/* if the X axis is less than y axis */
	{
	    square_ptr = (unsigned char *)malloc(y_axis * y_axis *
						      sizeof(unsigned char));
	    /* add padding to left and right side of the slice to make it a 
		plane with X_axis equal to y axis, the new size if y_axis
		by y_axis
	    */

	    j=0;
	    for(i = 0; i < y_axis * y_axis; ++i)
	    {
		if ( ((i % y_axis) < (y_axis-x_axis)/2 +1) ||
			    ((i % y_axis) > (y_axis-x_axis)/2 + x_axis) )
		/* if we are adding padding */
		    *(square_ptr + i) = NULL;
		else
		/* just copy the value */
		{
		    *(square_ptr + i)= *(max_ptr + j);
		    j++;
		}
	    }
	    x_axis = y_axis;

	    free(max_ptr);
            max_ptr = square_ptr;
	}

	if (machine_24_bit(icon->button))
	{
	    icon->icon_24_data = (unsigned int *)malloc(C_ICON_IMAGE_HEIGHT * 
							C_ICON_IMAGE_WIDTH  *
							sizeof(unsigned int));
	    if (!icon->icon_24_data)
	    {
		C_error_message("Not Enough Memory To Store Icon File !!");
		return( C_ERROR );    
	    }
	}
	else
	{
	    icon->icon_8_data = (C_Voxel_8bit *)malloc(C_ICON_IMAGE_HEIGHT * 
						       C_ICON_IMAGE_WIDTH);
	    if (!icon->icon_8_data)
	    {
		sprintf( temp_msg, 
			"Not enough memory to find  maximum projection");
		C_error_message( temp_msg );
		return( C_ERROR );	  
	    }
	}
	
	/* choose which ever value is smaller, C_ICON_IMAGE_HEIGHT or y_axis */
	if (y_axis < C_ICON_IMAGE_HEIGHT)
	    temp = y_axis;
	else
	    temp = C_ICON_IMAGE_HEIGHT;

	temp_max_ptr = max_ptr;
	i = 0;

	for(y = 0; y < temp; ++y)
	{
	    if (x_axis <= C_ICON_IMAGE_WIDTH)
	    /* if the x axis is less than C_ICON_IMAGE_WIDTH */
	    {
		k = 0; total_x = 0; last_x = 0;

		/* gap is how much we should add */
		gap = (float)C_ICON_IMAGE_WIDTH/(float) x_axis;

		for ( x = 0; x < x_axis; x++ )
		{
		    total_x += gap;
		    if (machine_24_bit(icon->button))
			icon->icon_24_data[i++] = ( *temp_max_ptr << 16) + 
						  ( *temp_max_ptr << 8)  +
						  *temp_max_ptr;
		    else
			icon->icon_8_data[i++] = *temp_max_ptr;

		    k++;
		    index_max = (int) (total_x) - (int) (last_x) -1;
		    for(j=0; j< index_max; ++j)
		    /* add the same value index_max time in to the array */
		    { 
			if (machine_24_bit(icon->button))
			    icon->icon_24_data[i++] = ( *temp_max_ptr << 16) + 
						      ( *temp_max_ptr << 8)  +
						      *temp_max_ptr;
			else
			    icon->icon_8_data[i++] = *temp_max_ptr;

			k++;
		    }
		    last_x = total_x;	
		    temp_max_ptr++;
		}
		
		/* if we are not quite at C_ICON_IMAGE_WIDTH, add padding */
		while (k++ < C_ICON_IMAGE_WIDTH)
		    if (machine_24_bit(icon->button))
			icon->icon_24_data[i++] = NULL;
		    else
			icon->icon_8_data[i++] = NULL;
	    }
	    else
	    /* x axis is greater than C_ICON_IMAGE_WIDHT */
	    {
		total_x = 0;last_x = 0;k=0;
		/* gap is the space to skip */
		gap = (float) x_axis / (float) C_ICON_IMAGE_WIDTH;

		for ( x = 0; x < C_ICON_IMAGE_WIDTH; x++ )
		{
		    total_x += gap;
		    if (machine_24_bit(icon->button))
			icon->icon_24_data[i++] = ( *temp_max_ptr << 16) + 
						  ( *temp_max_ptr << 8)  +
						  *temp_max_ptr;
		    else
			icon->icon_8_data[i++] = *temp_max_ptr;

		    temp_max_ptr++;
		    k++;
		    index_max = (int) (total_x) - (int) (last_x) - 1;
		    for(j=0;j< index_max; j++)
		    /* we should skip index_max number of elements in array */
		    { 
			temp_max_ptr++;
			k++;
		    }
		    last_x = total_x;
		}

		/* make sure start of the next row is correct */
		while (k++ < x_axis)
		    temp_max_ptr++;
	    }

	    /* after one row */
	    if (y_axis <= C_ICON_IMAGE_HEIGHT)
	    {
		/* gap is how much rows we should add */
		gap = (float)C_ICON_IMAGE_HEIGHT/  (float) y_axis;

		total_y += gap;
		h++;
		index_max = (int) (total_y) - (int) (last_y) - 1;

		for(j=0;j< index_max; ++j)
		/* add index_max number of rows */
		{ 
		    for (k=0;k<C_ICON_IMAGE_WIDTH;++k)
			if (machine_24_bit(icon->button))
			    icon->icon_24_data[i++] = 
				    icon->icon_24_data[i-C_ICON_IMAGE_WIDTH];
			else
			    icon->icon_8_data[i++] =
				    icon->icon_8_data[i-C_ICON_IMAGE_WIDTH];
		    h++;
		}
		last_y = total_y;	
	    }
	    else
	    {
		if (h < y_axis)
		{
		    /* gap is how much we should skip */
		    gap = (float) y_axis / (float) C_ICON_IMAGE_HEIGHT;
		    total_y += gap;
		    h++;
		    index_max = (int) (total_y) - (int) (last_y) - 1;

		    for(j=0;j< index_max; j++)
		    { 
			temp_max_ptr += x_axis;
			h++;
		    }
		    last_y = total_y;
		}
	    }
	}/* end of for loop */

	/* add rows at bottom of the image if necessary */
	while (h++ < C_ICON_IMAGE_HEIGHT)
	    for (k=0;k<C_ICON_IMAGE_WIDTH;++k)
		if (machine_24_bit(icon->button))
		    icon->icon_24_data[i++] = 
				      icon->icon_24_data[i-C_ICON_IMAGE_WIDTH];
		else
		    icon->icon_8_data[i++] =
			      icon->icon_8_data[i-C_ICON_IMAGE_WIDTH];
	return(C_OK);
}


/*
 *    Procedure Name: image_conversion
 *      Return Value: none
 *
 *   Input Variables: icon  - the icon structure
 *
 *  Output Variables: none
 *  Update Variables: none
 *  Global Variables: none
 *       Description: This function distributes the conversion of the original
 *                    data and send information data into the data conversion
 *		      function.
 */

int image_conversion(icon,texture_data,image_data)
Icon_Info     *icon;
C_VolTexture  *texture_data;
C_Image        image_data;
{
  int 	code;
  char	*extension;
  int	STATUS;

	extension = get_extension(icon->filename);
	if (strcmp(extension, "slc") == 0) 
	{
	    /*
	    * conversion for the slice data
	    */
	    code = decide_axis(	icon->slice_info.x_voxels, 
				icon->slice_info.y_voxels, 
			       	icon->slice_info.z_voxels );
	    if (code == C_XY_Z)
		STATUS = data_conversion(icon->slice_info.y_voxels, 
				icon->slice_info.x_voxels, 
		 		icon->slice_info.z_voxels,
				icon, texture_data, image_data);
	    else 
	    {
		if (code == C_XZ_Y)
		    STATUS = data_conversion(icon->slice_info.z_voxels, 
				icon->slice_info.x_voxels, 
		     		icon->slice_info.y_voxels,
				icon , texture_data, image_data);
		else
		    STATUS = data_conversion(icon->slice_info.z_voxels, 
				icon->slice_info.y_voxels, 
		     		icon->slice_info.x_voxels,
				icon , texture_data, image_data);
	    }
	}

	else if (strcmp(extension, "tex") == 0) 
	{
	    /*
	    * conversion for the texture data
	    */
	    
	    code = decide_axis(icon->texture_info.xres, 
			      icon->texture_info.yres,icon->texture_info.zres);


	    if (code == C_XY_Z)
		STATUS = data_conversion(icon->texture_info.yres, 
			   icon->texture_info.xres, icon->texture_info.zres,
			   icon, texture_data,image_data);
	    else 
	    {
		if (code == C_XZ_Y)
		    STATUS = data_conversion(icon->texture_info.zres, 
			      icon->texture_info.xres, icon->texture_info.yres,
			      icon,texture_data,image_data);
		else
		    STATUS = data_conversion(icon->texture_info.zres, 
			      icon->texture_info.yres,icon->texture_info.xres,
			      icon,texture_data,image_data);
	    }
	}
	else
	{
            /*
            * conversion for the image data
            */

	    STATUS = data_conversion(icon->image_info.height, 
	     icon->image_info.width, 0,icon,texture_data, image_data);
	}

	return(STATUS);
}


/*
 *    Procedure Name: decide_axis
 *      Return Value: int   - the result is 1 if z_axis is the smallest value
 *			    - the result is 2 if x_axis is the smallest value
 *			    - the result is 3 if y_axis is the smallest value
 *   Input Variables: int   - x_axis
 *                    int   - y_axis
 *                    int   - z_axis
 *  Output Variables: none
 *  Update Variables: none
 *  Global Variables: none
 *       Description: This function decides which axis has the smallest value,
 *		      and returns the correct code.        
 */
int decide_axis(x_axis,y_axis,z_axis)
int x_axis;
int y_axis;
int z_axis;
{
	if (x_axis > y_axis) 
	{
	    if (y_axis > z_axis)
		return C_XY_Z;
	    else
	    {
		if (x_axis > z_axis)
			return C_XZ_Y;
		else
			return C_XZ_Y;
	    }
	} 
	else
	{
	    if (z_axis > y_axis)
		return C_YZ_X;
	    else
	    {
		if (z_axis > x_axis)
		    return C_YZ_X;
		else
		    return C_XY_Z;
	    }
	}
}

/*
 *    Procedure Name: data_coversion
 *      Return Value: 
 *   Input Variables:  	j_max    - the  y_axis in the image
 *                     	i_max    - the  x_axis in the image
 *                     	k_max    - the  z_axis in the image 
 *  Output Variables:  	none
 *  Update Variables:  	none
 *  Global Variables:  	none
 *  Description     :  	This function converts 3 dimensional data (x,y,z) into 2
 *                     	dimensional data, where j_axis, from the input becomes
 *		       	y axis in the resulting image; i_axis, from the input 
 *			becomes x axis in the resulting image; and z_axis 
 *			calculates its average value, the result is data of 
 *	 		the image in a 2 dimensional data set with an 100 by 
 *			100 unit. In the conversion, the y axis, for every 
 *			step j (0-99) the j value added by delta 
 *			( j_max / VERTICAL_PLOT ) and is added by save_diff_j
 *			(the decimal value before rounded down into floor) and
 *                     	get the floor value of it.
 *                     	The important trick in this function is the decimal  
 *			value before we rounded down to the floor is saved 
 *			(save_diff_j) then it is used for the new j value of 
 *	    		the next step, so we can have a better approximation of  *			this algorithm.
 *
 */

int data_conversion(j_axis,i_axis,k_axis,icon, texture_data, image_data)
int i_axis;
int j_axis;
int k_axis;
Icon_Info *icon;
C_VolTexture  *texture_data;
C_Image        image_data;

{
  extern void C_error_message();
  extern C_Byte *C_dither_image_8bit();

  C_Image  	*image;
  int 		i,j,k,                /* counter */
   		kk,                   /* counter for pointer to the icon data */
   		i_calc=0, j_calc=0,   /* i and j coordinate after calculation */
   		prev_i=0, prev_j=0,   /*original coordinate of the data */

   		maximum		= 0,
		minimum		= 65535,
  	 	maximum_red	= 0,
		maximum_green	= 0,
		maximum_blue	= 0,
  	 	minimum_red  	= 65535,  
		minimum_green 	= 65535,
		minimum_blue	= 65535,

    		temporal_red, 
		temporal_green, 
		temporal_blue, 
		temporal;

  float 	save_diff_i=0.0, save_diff_j=0.0,
	 	delta_i=(float) i_axis / (float) C_ICON_IMAGE_WIDTH, 
        	delta_j=(float) j_axis / (float) C_ICON_IMAGE_HEIGHT;

  char 		*extension;

	extension = get_extension(icon->filename);

	if (machine_24_bit(icon->button))
	{
	    icon->icon_24_data = (unsigned int *) malloc(C_ICON_IMAGE_WIDTH *
				   C_ICON_IMAGE_HEIGHT * sizeof(unsigned int));
	    if (!icon->icon_24_data)
	    {
		C_error_message("Not enough memory to store icon data! \n");
		return C_ERROR;
	    }
	}
	else
	{
	    icon->icon_8_data = (unsigned char *) malloc(C_ICON_IMAGE_WIDTH * 
                                C_ICON_IMAGE_HEIGHT * sizeof(unsigned char));
	    if (!icon->icon_8_data)
	    {
		C_error_message("Not enough memory to store icon data! \n"); 
		return C_ERROR;
	    }

	    image = ( C_Image *) malloc(sizeof(C_Image) );

	    image->width = C_ICON_IMAGE_WIDTH;
	    image->height = C_ICON_IMAGE_HEIGHT;
	    image->depth = 3;

	    image->red = (C_Byte *) malloc(C_ICON_IMAGE_WIDTH *
				C_ICON_IMAGE_HEIGHT * sizeof(C_Byte));
	    if (!image->red)
	    {
		C_error_message("Not enough memory to store icon data! \n");
                return C_ERROR;
	    }	

            image->green = (C_Byte *) malloc(C_ICON_IMAGE_WIDTH *
                                C_ICON_IMAGE_HEIGHT * sizeof(C_Byte));
            if (!image->green)
            {
                C_error_message("Not enough memory to store icon data! \n");
                return C_ERROR;
            }   

            image->blue = (C_Byte *) malloc(C_ICON_IMAGE_WIDTH *
                                C_ICON_IMAGE_HEIGHT * sizeof(C_Byte));
            if (!image->blue)
            {
                C_error_message("Not enough memory to store icon data! \n");
                return C_ERROR;
            }   

	}

	for (j=0,kk=0; j<C_ICON_IMAGE_HEIGHT; j++) 
	{
	    if (j == 0) j_calc = 0;
	    else
	    {
		j_calc = (int) (save_diff_j + prev_j + delta_j);
		save_diff_j = (save_diff_j + prev_j + delta_j) - j_calc;
	    }

	    prev_j = j_calc;

	    for (i=0; i<C_ICON_IMAGE_WIDTH; i++) 
	    {
		if (i==0) i_calc = 0;
		else
		{
		    i_calc = (int) (save_diff_i + prev_i + delta_i);
		    save_diff_i = (save_diff_i + prev_i + delta_i) - i_calc;
		}

		prev_i = i_calc;

		maximum         = 0;
            	minimum         = 65535;

            	maximum_red     = 0;
            	maximum_green   = 0;
            	maximum_blue    = 0;

            	minimum_red     = 65535;
            	minimum_green   = 65535;
            	minimum_blue    = 65535;

		/*
		  * conversion for the maximum value
		  *
		*/
		for (k=0; k<k_axis; k++) 
		{
		    if (strcmp(extension,"tex") == 0)
		    {
		      /* convert texture or image data */
			temporal_red = *(texture_data->red   + k * j_axis *
					  i_axis + prev_j * i_axis + prev_i );
			temporal_green = *(texture_data->green + k * j_axis *
					  i_axis + prev_j * i_axis + prev_i );
			temporal_blue  = *(texture_data->blue  + k * j_axis *
					  i_axis + prev_j * i_axis + prev_i );

			if (temporal_red   > maximum_red)   
				maximum_red   = temporal_red;
			if (temporal_green > maximum_green) 
				maximum_green = temporal_green;
			if (temporal_blue  > maximum_blue)   
				maximum_blue  = temporal_blue;
		    }
		}

		if (strcmp(extension,"tex") == 0)
		/* texture data file */
		{
		    if (machine_24_bit(icon->button))
			icon->icon_24_data[kk++] = (maximum_blue << 16) +
					(maximum_green << 8) + (maximum_red);
		    else
		    {
		 	image->red[kk]   = (unsigned char ) maximum_red;
			image->green[kk] = (unsigned char ) maximum_green;
			image->blue[kk]  = (unsigned char ) maximum_blue; 	
			kk++;
		    }
		}
		else
		/* image data file */
		{

		    if (machine_24_bit(icon->button))
			icon->icon_24_data[kk++] = 
			    (*(image_data.blue+prev_j*i_axis+prev_i) << 16) +
			    (*(image_data.green+ prev_j* i_axis+ prev_i) << 8)+
			    (*(image_data.red+ prev_j* i_axis +prev_i));
		    else
		    {
			image->red[kk]   = 
				*(image_data.red   + prev_j * i_axis + prev_i);
			image->green[kk] = 
				*(image_data.green + prev_j * i_axis + prev_i);
			image->blue[kk]  = 
				*(image_data.blue  + prev_j * i_axis + prev_i);
			kk++;
		    }
		}
	    }
	}

	if (!machine_24_bit(icon->button))
	{
	    /* call the dither function to dither the 8 bit image data */
	    icon->icon_8_data = C_dither_image_8bit( image );
	    free(image->red);
	    free(image->blue);
	    free(image->green);
	    free(image);
	}

	if (strcmp(extension,"tex") == 0)
	{
	    free(texture_data->green);
	    free(texture_data->red);
	    free(texture_data->blue);
	    free(texture_data);
	}
	else
	{
	    if (strcmp(extension, "img") == 0)
	    {
		free(image_data.red);
		free(image_data.green);
		free(image_data.blue);
	    }
	}

	return C_OK ;
}

C_Byte *decode_8bit_data( in_ptr, size, SUCCESS )
C_Byte		*in_ptr;
int		size;
int		SUCCESS;
{
  extern void C_error_message();

  register C_Byte  *curr_ptr;
  register C_Byte  *decode_ptr;
  register C_Byte  *return_ptr;
  register C_Byte  current_value;
  register C_Byte  remaining;

	curr_ptr = in_ptr;

	decode_ptr = return_ptr = (C_Byte *) malloc( size * sizeof(C_Byte) );
	if (!return_ptr){
	    C_error_message("Can't not allocate memory for image component\n");
	    SUCCESS = FALSE;
	}
	else 
		SUCCESS = TRUE;

	while ( 1 )
	{
		current_value = *(curr_ptr++);

		if ( !(remaining = (current_value & 0x7f)) )
			break;

		if ( current_value & 0x80 )
		{
			while ( remaining-- )
				*(decode_ptr++) = *(curr_ptr++);
		}
		else
		{
			current_value = *(curr_ptr++);
			while ( remaining-- )
				*(decode_ptr++) = current_value;
		}	
		
	}

	return return_ptr;
}
