/*
Copyright 2002, 2003 Alexis Guillaume <aguillau@liris.univ-lyon2.fr> for "Laboratoire LIRIS, université Lyon II, France."
Copyright 2002, 2003 David Coeurjolly <dcoeurjo@liris.univ-lyon2.fr> for "Laboratoire LIRIS, université Lyon II, France."

This file is part of voltools.

    voltools 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 2 of the License, or
    (at your option) any later version.

    voltools 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 voltools; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*/

#include <vol.h>
#include "tools.h"

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

#include <unistd.h>


void usage( int errcode = badCommandLine ) {

	fprintf( stderr,
"Usage:\n\
	vol2geom [ -i inputfile ] [ -o outputfile ] [ Options ... ]\n\
		(default stdin and stdout)\n\
	vol2geom basename [ options ... ]\n\
		(converts basename.vol into basename.geom)\n\
	vol2geom -h\n\
		(this help)\n\
\n\
	Options :\n\
		-P : do NOT optimize : draw every voxel instead of only useful surfaces.\n\
\n\
		-r : coefficient for red\n\
		-g : coefficient for green\n\
		-b : coefficient for blue\n\
\n\
		-a : auto color\n\
" );
	exit( errcode );

}

int geomview_write_header(FILE *f);
int geomview_write_unit_cube(FILE *f,int x,int y,int z,int r,int v,int b);
int geomview_write_surfel(FILE *f,int x,int y,int z,int xx,int yy,int zz,int r,int v,int b);


int main( int argc, char **argv ) {

	char *file_in = "";
	char *file_out = "/dev/stdout";

	bool optimize = true;
	double coeff_red = 1.0, coeff_green = 1.0, coeff_blue =1.0;
	bool auto_color = false;

	int curoption;

	// Fast syntax : vol2geom basename
/*	if (argc == 2 && argv[1][0] != '-') {
		file_in = (char *)malloc( strlen( argv[1] ) + 4 + 1 );
		file_out = (char *)malloc( strlen( argv[1] ) + 4 + 1 );
		assert( file_in != NULL && file_out != NULL );
		// safe
		strcpy( file_in, argv[1] );
		strcpy( file_out, argv[1] );
		strcat( file_in, ".vol" );
		strcat( file_out, ".geom" );
	} else {
*/		while ((curoption = getopt( argc, argv, "i:o:hPr:g:b:a" )) != -1) {
			switch (curoption) {
				case 'i':
					file_in = optarg;
					break;
				case 'o':
					file_out = optarg;
					break;
				case 'P':
					optimize = false;
					break;
				case 'h':
					usage( noError );
					break;
				case 'r':
					coeff_red = atof( optarg );
					break;
				case 'g':
					coeff_green = atof( optarg );
					break;
				case 'b':
					coeff_blue = atof( optarg );
					break;
				case 'a':
					auto_color = true;
					break;
			}
		}
		if (optind != argc) {
			if (optind == argc - 1) {
				file_in = (char *)malloc( strlen( argv[optind] ) + 4 + 1 );
				file_out = (char *)malloc( strlen( argv[optind] ) + 4 + 1 );
				assert( file_in != NULL && file_out != NULL );
				// safe
				strcpy( file_in, argv[optind] );
				strcpy( file_out, argv[optind] );
				strcat( file_in, ".vol" );
				strcat( file_out, ".geom" );
			} else {
				usage();
			}
		}
//	}

	Vol vin( file_in );
	if (!vin.isOK()) {
		fprintf( stderr, "Cannot open %s\n", file_in );
		return badInputFile;
	}
	
	FILE *fout = fopen( file_out, "w" );

	if (fout == NULL) {
		fprintf( stderr, "cannot open file %s for writing !\n", file_out );
		return badOutputFile;
	}
	
	int r = 0;
	r += geomview_write_header( fout );

	int maxs[] = { 0, 0, 0 };
	int mins[] = { vin.sizeX(), vin.sizeY(), vin.sizeZ() };
	int diffs[3];
	
	vin.setVolumeCenter( vin.sizeX()/2, vin.sizeY()/2, vin.sizeZ()/2 );
	voxel alpha = vin.alpha();

	if (auto_color) {
		for (int i = 0; i < vin.sizeX(); ++i) {
			for (int j = 0; j < vin.sizeY(); ++j) {
				for (int k = 0; k < vin.sizeZ(); ++k) {
					if (vin( i, j, k ) != alpha) {
						if (i < mins[0]) mins[0] = i;
						if (i > maxs[0]) maxs[0] = i;
					
						if (j < mins[1]) mins[1] = j;
						if (j > maxs[1]) maxs[1] = j;
	
						if (k < mins[2]) mins[2] = k;
						if (k > maxs[2]) maxs[2] = k;
					}
				}
			}
		}
		diffs[0] = maxs[0] - mins[0];
		diffs[1] = maxs[1] - mins[1];
		diffs[2] = maxs[2] - mins[2];
	}

	int cr = 0, cg = 0, cb = 0;
	
	maxs[0] = vin.sizeX();
	maxs[1] = vin.sizeY();
	maxs[2] = vin.sizeZ();
	
	for (int i = 0; i < maxs[0]; ++i) {
		if (auto_color)
			cr = (int)(((255*i)/diffs[0])*coeff_red);
		
		for (int j = 0; j < maxs[1]; ++j) {
			if (auto_color)
				cg = (int)(((255*j)/diffs[1])*coeff_green);
				
			for (int k = 0; k < maxs[2]; ++k) {
				voxel color = vin( i, j, k );
				if (auto_color)	{
					cb = (int)(((255*k)/diffs[2])*coeff_blue);
				} else {
					cr = (int)(color*coeff_red);
					cg = (int)(color*coeff_green);
					cb = (int)(color*coeff_blue);
				}
						
				if (color != alpha) {
					if (!optimize) {
						geomview_write_unit_cube( fout, i, j, k, cr, cg, cb );
					} else {
						// draw surfels when necessary (todo)
						if (i == 0 || vin( i - 1, j, k ) == alpha)
							r += geomview_write_surfel( fout, i - 1, j, k, i, j, k, cr, cg, cb );
						if (j == 0 || vin( i, j - 1 , k ) == alpha)
							r += geomview_write_surfel( fout, i, j - 1, k, i, j, k, cr, cg, cb );
						if (k == 0 || vin( i, j, k - 1 ) == alpha) 
							r += geomview_write_surfel( fout, i, j, k - 1, i, j, k, cr, cg, cb );
						if (i == maxs[0] - 1 || vin( i + 1, j, k ) == alpha)
							r += geomview_write_surfel( fout, i, j, k, i + 1, j, k, cr, cg, cb );
						if (j == maxs[1] - 1 || vin( i, j + 1, k ) == alpha)
							r += geomview_write_surfel( fout, i, j, k, i, j + 1, k, cr, cg, cb );
						if (k == maxs[2] - 1 || vin( i, j, k + 1 ) == alpha)
							r += geomview_write_surfel( fout, i, j, k, i, j, k + 1, cr, cg, cb );
					}
				}
					
			}
		}
	}
	
	r += geomview_write_unit_cube( fout, maxs[0] - 1, 0, 0, 0xFF, 0, 0 );
	r += geomview_write_unit_cube( fout, 0, maxs[1] - 1, 0, 0, 0xFF, 0 );
	r += geomview_write_unit_cube( fout, 0, 0, maxs[2] - 1, 0, 0, 0xFF );
	r += geomview_write_unit_cube( fout, 0, 0, 0, 0xFF, 0xFF, 0xFF );
	
	int exit_code = 0;
	if (r != 0) {
		fprintf( stderr, "%d error occured ... sorry !\n", r );
		exit_code = badOutputFile;
	}
	if (fclose( fout ) != 0) {
		perror( "can't close file " );
		exit_code = badOutputFile;
	}

	return exit_code;
}

int geomview_write_header(FILE *f)
{
  return fprintf(f,"LIST\n") != 5;
}

int geomview_write_unit_cube(FILE *f,int x,int y,int z,int r,int v,int b)
{
  fprintf(f,"{ OFF\n");
  fprintf(f,"8 6 12\n");
  /* On ecrit les 8 sommets */
  fprintf(f,"%f %f %f\n",x-0.5,y-0.5,z-0.5);
  fprintf(f,"%f %f %f\n",x+0.5,y-0.5,z-0.5);
  fprintf(f,"%f %f %f\n",x+0.5,y-0.5,z+0.5);
  fprintf(f,"%f %f %f\n",x-0.5,y-0.5,z+0.5);
  fprintf(f,"%f %f %f\n",x-0.5,y+0.5,z+0.5);
  fprintf(f,"%f %f %f\n",x+0.5,y+0.5,z+0.5);
  fprintf(f,"%f %f %f\n",x+0.5,y+0.5,z-0.5);
  fprintf(f,"%f %f %f\n",x-0.5,y+0.5,z-0.5);
  fprintf(f,"\n");
  /* et les faces... */
  fprintf(f,"4 0 1 2 3 %d %d %d\n",r,v,b);
  fprintf(f,"4 1 6 5 2 %d %d %d\n",r,v,b);
  fprintf(f,"4 6 5 4 7 %d %d %d\n",r,v,b);
  fprintf(f,"4 4 3 0 7 %d %d %d\n",r,v,b);
  fprintf(f,"4 0 1 6 7 %d %d %d\n",r,v,b);
  fprintf(f,"4 3 2 5 4 %d %d %d\n",r,v,b);
  return fprintf(f,"}\n\n") != 3;
}

int geomview_write_surfel(FILE *f,int x,int y,int z,int xx,int yy,int zz,int r,int v,int b)
{
  float dec;
  float tiny=0.00001;
  
  if (x-xx!=0)
    {
      if (x-xx==1)
    dec=-0.5-tiny;
      else
    dec=0.5+tiny;
      fprintf(f,"{ OFF\n");
      fprintf(f,"4 1 4\n");
      /* On ecrit les 4 sommets */
      fprintf(f,"%f %f %f\n",x+dec,y-0.5,z-0.5);
      fprintf(f,"%f %f %f\n",x+dec,y+0.5,z-0.5);
      fprintf(f,"%f %f %f\n",x+dec,y+0.5,z+0.5);
      fprintf(f,"%f %f %f\n",x+dec,y-0.5,z+0.5);
      fprintf(f,"\n");
      /* et la face... */
      fprintf(f,"4 0 1 2 3 %d %d %d\n",r,v,b);
      return fprintf(f,"}\n\n") != 3;
    }
  if (y-yy!=0)
    {
      if (y-yy==1)
    dec=-0.5-tiny;
      else
    dec=0.5+tiny;                                                                             
      fprintf(f,"{ OFF\n");                                                                   
      fprintf(f,"4 1 4\n");                                                                   
      /* On ecrit les 4 sommets */                                                            
      fprintf(f,"%f %f %f\n",x-0.5,y+dec,z-0.5);                                              
      fprintf(f,"%f %f %f\n",x+0.5,y+dec,z-0.5);                                              
      fprintf(f,"%f %f %f\n",x+0.5,y+dec,z+0.5);                                              
      fprintf(f,"%f %f %f\n",x-0.5,y+dec,z+0.5);                                              
      fprintf(f,"\n");                                                                        
      /* et la face... */                                                                     
      fprintf(f,"4 0 1 2 3 %d %d %d\n",r,v,b);                                                
      return fprintf(f,"}\n\n") != 3;                                                              
    }                                                                                         
  if (z-zz!=0)                                                                                
    {                                                                                         
      if (z-zz==1)                                                                            
    dec=-0.5-tiny;                                                                            
      else                                                                                    
    dec=0.5+tiny;                                                                             
      fprintf(f,"{ OFF\n");                                                                   
      fprintf(f,"4 1 4\n");                                                                   
      /* On ecrit les 4 sommets */                                                            
      fprintf(f,"%f %f %f\n",x-0.5,y-0.5,z+dec);                                              
      fprintf(f,"%f %f %f\n",x+0.5,y-0.5,z+dec);                                              
      fprintf(f,"%f %f %f\n",x+0.5,y+0.5,z+dec);                                              
      fprintf(f,"%f %f %f\n",x-0.5,y+0.5,z+dec);                                              
      fprintf(f,"\n");                                                                        
      /* et la face... */                                                                     
      fprintf(f,"4 0 1 2 3 %d %d %d\n",r,v,b);                                                
      return fprintf(f,"}\n\n") != 3;                                                              
    }                               

	return 1;
}

