/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	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.

**********************************************************************/


#include	<stdio.h>
#include	<stdlib.h>
#include	<fcntl.h>
#include	"r64.h"
#include	"ppm_types.h"

PPM_INFO ppm;
char * target;

#define TEST_LEN 1000

void
mem_test(char * str)
{
int i;
char ** t;
	printf("START %s\n",str);
	fflush(stdout);
	t = malloc(sizeof(char*)*TEST_LEN);
	for ( i = 0 ; i < TEST_LEN ; i ++ )
		t[i] = malloc(i+1);
	for ( i = 0 ; i < TEST_LEN ; i ++ )
		free(t[i]);
	free(t);
	printf("END %s\n",str);
}

unsigned char
adjust_max(unsigned int max,unsigned int col)
{
unsigned int cc;
	cc = col*255/max;
	if ( cc > 255 )
		cc = 255;
	return cc;
}

void
ppm2r64(char ** argv)
{
R64_FILE * f;
int w,h;
unsigned char*  col;
unsigned char c[3],cc;
int step;
	printf("convert %s(ppm) to %s(r64)\n",argv[1],argv[2]); 
	ppm.pi_fd = open(argv[1],O_RDONLY);
	if ( ppm.pi_fd < 0 ) {
		fprintf(stderr,"cannot open the file \"%s\"\n",
			argv[1]);
		exit(1);
	}
	read_header(&ppm);
	if ( strcmp(ppm.pi_type,"P4") == 0 ) {
		fprintf(stderr,"not support the  format P4\n");
		exit(1);
	}
	if ( strcmp(ppm.pi_type,"P5") == 0 )
		step = 1;
	else	step = 3;
	f = r64_open_file(argv[2],O_RDWR|O_TRUNC|O_CREAT,0644,'P',
		ppm.pi_width,ppm.pi_height);
	if ( f == 0 ) {
		fprintf(stderr,"R64 %i\n",r64_error);
		perror("system ");
		exit(1);
	}
	r64_ctl(f,R64_SET_RCTYPE,RC_NEAR);
	lseek(ppm.pi_fd,ppm.pi_offset,SEEK_SET);
	col = malloc(ppm.pi_width*3);
	for ( h = 0 ; h < ppm.pi_height ; h ++ ) {
		printf("h = %i/%i   \r",h,ppm.pi_height);
		fflush(stdout);
		read(ppm.pi_fd,col,ppm.pi_width*step);
		for ( w = 0 ; w < ppm.pi_width ; w ++ ) {
			switch ( step ) {
			case 1:
				cc = adjust_max(ppm.pi_max,col[w]);
				c[0] = cc;
				c[1] = cc;
				c[2] = cc;
				break;
			case 3:
				c[0] = adjust_max(ppm.pi_max,col[3*w]);
				c[1] = adjust_max(ppm.pi_max,col[3*w+1]);
				c[2] = adjust_max(ppm.pi_max,col[3*w+2]);
				break;
			}
			r64_set(f,w,h,0,c);
		}
	}
	printf("\nEND\n");
	r64_close_file(f);
	close(ppm.pi_fd);
	free(col);
}

void
new_level(int levels)
{
int lev;
R64_FILE * f;
	printf("make multi levels of details\n");
	f = r64_open_file(target,O_RDWR,0644,'P',0,0);
	if ( f == 0 ) {
		fprintf(stderr,"r64 error: %i\n",r64_error);
		perror("system ");
		exit(1);
	}
	for ( lev = 0 ; r64_check_level(f,lev) ; lev ++ );
	lev --;
	printf("from level %i\n",lev);
	if ( lev < 0 ) {
		fprintf(stderr,"broken file :: %s\n",target);
		exit(1);
	}
	if ( levels > 0 ) {
		for ( ; levels ; levels -- , lev ++ ) {
			r64_flush(f);
			if ( r64_new_level(f,lev) < 0 ) {
				fprintf(stderr,"r64 error: %i\n",r64_error);
				perror("system ");
				exit(1);
			}
		}
	}
	else {
		for ( ; ; lev ++ ) {
			r64_flush(f);
			if ( r64_new_level(f,lev) == 0 )
				continue;
			if ( r64_error == E_NOLEV )
				break;
			fprintf(stderr,"r64 error: %i\n",r64_error);
			perror("system ");
			exit(1);
		}
	}
	r64_close_file(f);
}

int rect_size = 256;

void
r642cr(char * from,char * to)
{
int lev;
R64_FILE * f;
	printf("make compressed rectangle (CR)\n");
	f = r64_open_file(from,O_RDONLY,0644,'P',0,0);
	if ( f == 0 ) {
		fprintf(stderr,"r64 error: %i\n",r64_error);
		perror("system ");
		exit(1);
	}
	if ( cr_write_file(to,0644,rect_size,f) < 0 ) {
		fprintf(stderr,"r64 error: %i\n",r64_error);
		perror("system ");
		exit(1);
	}
	r64_close_file(f);
}

void
ppm_type(char * filename)
{
	ppm.pi_fd = open(filename,O_RDONLY);
	if ( ppm.pi_fd < 0 ) {
		fprintf(stderr,"cannot open the file \"%s\"\n",
			filename);
		exit(1);
	}
	read_header(&ppm);
	printf("%s %i %i %i\n",
		ppm.pi_type,
		ppm.pi_width,
		ppm.pi_height,
		ppm.pi_max);
}

int
main(int argc,char ** argv)
{
int c;
	check_endian(); 
	r64_init();
	for ( c = 1 ; c < argc ; ) {
		if ( strcmp(argv[c],"-ppmtype") == 0 ) {
			ppm_type(argv[c+1]);
			c += 2;
		}
		else if ( strcmp(argv[c],"-pr") == 0 ) {
			if ( c+2 >= argc ) {
				fprintf(stderr,
					"too few argment for -pr\n");
				exit(1);
			}
			ppm2r64(&argv[c]);
			target = argv[c+2];
			c += 3;
		}
		else if ( strcmp(argv[c],"-l") == 0 ) {
			c++;
			if ( c >= argc )
				new_level(0);
			else if ( argv[c][0] == '-' ) {
				new_level(0);
				c ++;
			}
			else {
				new_level(atoi(argv[c]));
				c++;
			}
		}
		else if ( strcmp(argv[c],"-t") == 0 ) {
			c++;
			if ( c >= argc ) {
				fprintf(stderr,"too few argments for -t\n");
				exit(1);
			}
			target = argv[c];
			c++;
		}
		else if ( strcmp(argv[c],"-crsize") == 0 ) {
			c ++;
			if ( c >= argc ) {
				fprintf(stderr,"too few argments for -t\n");
				exit(1);
			}
			rect_size = atoi(argv[c]);
			if ( rect_size != 256 &&
				rect_size != 128 &&
				rect_size != 64 ) {
				fprintf(stderr,"invalid rectsize\n",
					rect_size);
				exit(1);
			}
			c ++;
		}
		else if ( strcmp(argv[c],"-cr") == 0 ) {
			c ++;
			if ( c >= argc ) {
				fprintf(stderr,"too few argments for -cr\n");
				exit(1);
			}
			if ( target == 0 ) {
				fprintf(stderr,"target is required\n");
				exit(1);
			}
			r642cr(target,argv[c]);
			c ++;
		}
		else {
			fprintf(stderr,"invalid command \"%s\"\n",
				argv[c]);
			exit(1);
		}
	}
	exit(0);
}
