/**********************************************************************
 
	Copyright (C) 2005- 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	"k2m.h"


//#define KIBAN2MATRIX_DUMMY

#ifdef KIBAN2MATRIX_DUMMY

#define MATRIX MATRIX_DUMMY
#define MATRIX_NODE MATRIX_NODE_DUMMY

typedef struct{
	FILE *fp[8];
	char file[8][512];
	INTEGER64 width;
	INTEGER64 height;
}MATRIX_DUMMY;

typedef struct{
	unsigned char mem[128*128];
	MATRIX_DUMMY *m;
	INTEGER64 top;
	INTEGER64 left;
	FILE *fp;
}MATRIX_NODE_DUMMY;

#define matrix_open_kiban matrix_open_kiban_dummy
MATRIX* matrix_open_kiban_dummy(char * filename,INTEGER64 x,INTEGER64 y)
{
	int i;
	MATRIX_DUMMY *m;
	m = (MATRIX_DUMMY *)malloc(sizeof(*m));
	m->width = x;
	m->height = y;
	for(i=0; i<8; ++i){
		sprintf(m->file[i], "%s_%d.raw", filename, i);
		m->fp[i] = fopen(m->file[i], "w+b");
		fseek(m->fp[i], (long)(x*y-1), SEEK_SET);
		fwrite("\0", 1, 1, m->fp[i]);
	}
	return m;
}

#define get_matrix_node_channel get_matrix_node_channel_dummy
void *
get_matrix_node_channel_dummy(int * errp,MATRIX_NODE ** np,
		MATRIX * m,INTEGER64 * dim_code,
		int ch,int type,int access,
		MATRIX_ALLOC_VECTOR_PARAM * vp)
{
	MATRIX_NODE_DUMMY *d;
//	FILE *fp;
	int n = 0;
	INTEGER64 y;
	d = (MATRIX_NODE_DUMMY*)calloc(sizeof(*d),1);
	d->m = m;
	d->left = dim_code[1];
	d->top = dim_code[2];
	d->fp = m->fp[ch];
	for(y=d->top; y<d->top+128; ++y){
		fseek(d->fp, (long)(m->width*y+d->left), SEEK_SET);
		fread(&d->mem[128*n], 128, 1, d->fp);
		n++;
	}
	
	*np = (MATRIX_NODE *)d;
	
	return d->mem;
}

#define k_ix k_ix_dummy
unsigned char k_ix_dummy_c;
unsigned char *
k_ix_dummy(void * v,int x,int y){
	return &((unsigned char*)v)[y*128+x];
}

#define matrix_node_channel_unlock matrix_node_channel_unlock_dummy
void
matrix_node_channel_unlock_dummy(MATRIX_NODE * n,int flags)
{
	INTEGER64 y;
	MATRIX_NODE_DUMMY *d;
	int line;
	d = (MATRIX_NODE_DUMMY *)n;
	
	line=0;
	for(y=d->top; y<d->top+128; ++y){
		fseek(n->fp, (long)(d->m->width*y+d->left), SEEK_SET);
		fwrite(&d->mem[128*line], 128, 1, n->fp);
		line++;
	}
	free(d);
}

#define unlock_node unlock_node_dummy
void  unlock_node_dummy(MATRIX_NODE * n,MATRIX_TOKEN * t){}

#define matrix_peano_trigger matrix_peano_trigger_dummy
void matrix_peano_trigger_dummy(
	MATRIX * m,
	INTEGER64 * dc_start,
	INTEGER64 * dc_end,
	int _access)
{
}

#define close_matrix close_matrix_dummy
void
close_matrix_dummy(MATRIX * m)
{
	int i;
	for(i=0; i<8; ++i){
		fclose(m->fp[i]);
	}
	free(m);
}

#endif /* end of KIBAN2MATRIX_DUMMY */



typedef struct{
	MATRIX *m;
	double dot_per_degree;
	double top_latitude;
	double left_longitude;
}CALLBACK_PARAM;

/*
This callback is called on load each 'zuyou' tiff file.
*/
void on_complete_map_data_callback_using_node_interface(unsigned char *data, int width, int height, double longitude, double latitude, void *userData)
{
CALLBACK_PARAM *param;
INTEGER64 dim_code[3];
MATRIX *m;
double dot_per_degree;
INTEGER64 map_left;
INTEGER64 map_top;
int x;
int y;
INTEGER64 node_left;
INTEGER64 node_top;
INTEGER64 node_right;
INTEGER64 node_bottom;
int err;
int i,j,k;
MATRIX_NODE * n;
void * ch_data;
int x_node_count,y_node_count;
int node_xmin,node_xmax,node_xmin_;
int node_ymin,node_ymax,node_ymin_;

printf("on_complete_map_data_callback_using_node_interface called width=%d height=%d longitude=%f latitude=%f\n",
		width, height, longitude, latitude);

	param = (CALLBACK_PARAM*)userData;
	m = param->m;
	dot_per_degree = param->dot_per_degree;
	
	map_left = (INTEGER64)(dot_per_degree * (longitude - param->left_longitude));
	map_top = (INTEGER64)(dot_per_degree * (param->top_latitude - latitude));
	
	node_left = (map_left / 128) * 128 ;
	node_top = (map_top / 128) * 128 ;
	
	node_right = (((map_left + width)+127) / 128) * 128;
	node_bottom = (((map_top + height)+127) / 128) * 128;
	
	x_node_count = (int)((node_right-node_left)/128);
	y_node_count = (int)((node_bottom-node_top)/128);
	node_xmin_ = (int)(map_left % 128);
	node_ymin_ = (int)(map_top % 128);

printf("x_node_count=%d y_node_count=%d \n", x_node_count, y_node_count);

	for(i=0; i<y_node_count; ++i){
		for(j=0; j<x_node_count; ++j){
printf("process node x=%08d y=%08d\r", j, i);

			dim_code[0] = 0;
			dim_code[1] = node_left + 128 * j;
			dim_code[2] = node_top + 128 * i;
			
			if(j==0){
				node_xmin = node_xmin_;
			}
			else{
				node_xmin = 0;
			}
			if(i==0){
				node_ymin = node_ymin_;
			}
			else{
				node_ymin = 0;
			}
			
			if(j==x_node_count-1){
				node_xmax = (int)((width - (128-(map_left%128)) ) % 128);
			}
			else{
				node_xmax = 128;
			}
			
			if(i==y_node_count-1){
				node_ymax =	(int)((height - (128-(map_top%128)) ) % 128);
			}
			else{
				node_ymax =	128;
			}

//ss_printf("PT-1\n");
			wait_matrix_mode(m);
//ss_printf("PT-2\n");
			n = 0;			
			err = 0;
			ch_data = get_matrix_node_channel(&err,
				&n, m, &dim_code[0], 
				16, GN_TREE, GN_LIST_CREATE, 0);
//ss_printf("ERR-1 %i\n",err);
			if ( n ) {
				matrix_node_channel_unlock(n,0);
				unlock_node(n,0);
			}
			err = 0;
			n = get_matrix_node_wait(&err,m,
				&dim_code[0],
				GN_LIST_CREATE);
//ss_printf("ERR-2 %i\n",err);
			if ( err ) {
				er_panic("A\n");
			}

			for(k=0; k<8; ++k){
				ch_data = get_matrix_node_channel(&err,
					&n, m, &dim_code[0], 
					k+16, GN_NODE, GN_NODE, 0);

				for(y=node_ymin; y<node_ymax; ++y){
					for(x=node_xmin; x<node_xmax; ++x){
						int src_x,src_y;
						src_y = (int)(i*128+y-node_ymin_);
						src_x = (int)(j*128+x-node_xmin_);
						*k_ix(ch_data, x, y) = (data[(int)(src_y*width+src_x)] & (1<<k)) ? 255 : 0;
					}
				}
				
				/* write lock wo kaijo NF_DIRTY=dirty bit wo tateru */
				matrix_node_channel_unlock(n,NF_DIRTY);
				
			}

			unlock_node(n,0);
		}
	}
}


void write_pixel_(INTEGER64 *position, unsigned char data)
{
int i;
unsigned char d[8];
	for(i=0; i<8; ++i){
		d[i] = (data & (1<<i)) ? 255 : 0;
	}
	write_pixel(position, d);
}

void on_complete_map_data_callback_using_write_pixel(
	unsigned char *data, int width, int height, double longitude, double latitude, void *userData)
{
CALLBACK_PARAM *param;
double dot_per_degree;
INTEGER64 map_left;
INTEGER64 map_top;
INTEGER64 position[3];
int x,y;

printf("on_complete_map_data_callback_using_write_pixel called longitude=%f latitude=%f width=%d height=%d\n", longitude, latitude, width, height);

	param = (CALLBACK_PARAM*)userData;
	dot_per_degree = param->dot_per_degree;
	
	map_left = (INTEGER64)(dot_per_degree * (longitude - param->left_longitude));
	map_top = (INTEGER64)(dot_per_degree * (param->top_latitude - latitude));
	
	position[0] = 0;
	
	for(y=0; y<height; ++y){
printf("writing line %d \r", y);
		for(x=0; y<width; ++x){
			position[1] = x+map_left;
			position[2] = y+map_top;
			write_pixel_(position, data[y*width+x]);
		}
	}
}


int
_main(int argc, char *argv[])
{
INTEGER64 dc_start[3];
INTEGER64 dc_end[3];
MATRIX * m;

CALLBACK_PARAM param;
double dot_per_degree,min_longitude,max_longitude,min_latitude,max_latitude;
INTEGER64 matrix_width,matrix_height;


	minimum_matrix_init(argc,argv); 

	if(argc<4){
		printf("usage: kiban2matrix conf_file maps_file out_matrix_file\n");
		printf("call this program by kiban2matrix.pl\n");
		return 1;
	}
	
	kokudo_loader_init(argv[1], &dot_per_degree, &min_longitude, &min_latitude, &max_longitude, &max_latitude);
	
	matrix_width = (INTEGER64)(dot_per_degree * (max_longitude - min_longitude));
	matrix_height = (INTEGER64)(dot_per_degree * (max_latitude - min_latitude));
	matrix_width = ((matrix_width+127) / 128) * 128;
	matrix_height = ((matrix_height+127) / 128) * 128;

	/* File wo open */
	m = matrix_open_kiban(argv[3], matrix_width, matrix_height);
	
	
	/* Kakikomu Han'i wo settei */
	dc_start[0] = 0;	/* Zero ni kotei */
	dc_start[1] = 0;
	dc_start[2] = 0;

	dc_end[0] = 0;		/* Zero ni kotei */
	dc_end[1] = matrix_width;
	dc_end[2] = matrix_height;
	

	param.m = m;
	param.dot_per_degree = dot_per_degree;
	param.top_latitude = max_latitude;
	param.left_longitude = min_longitude;
	
	kokudo_loader_load(argv[2], dot_per_degree, 
		on_complete_map_data_callback_using_write_pixel
		/*on_complete_map_data_callback_using_node_interface*/, &param);
	

	/* kakikonda Han'i ni file making no trigger wo kakeru */
	flush_write_pixel();
	matrix_peano_trigger(m,
		&dc_start[0],
		&dc_end[0],
		MI_EDIT_1_BT);

	/* file no close */
	/* file making to synclonize saremasu. */
	close_matrix(m);

	return 0;
}


