/**********************************************************************
 
	Copyright (C) 2005- Hirohisa MORI <joshua@nichibun.ac.jp>
						Tomohito Nakajima <nakajima@zeta.co.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 "kokudo_tiff.h"
#include "k2m.h"

#include <fstream>
using namespace std;

#define max___(l,r) ((l>r)?l:r)


struct Zuyou{
	char path[512];

	double lt_lon,lb_lon,rt_lon,rb_lon,lt_lat,lb_lat,rt_lat,rb_lat,
		lt_x,lt_y,rt_x,rt_y,lb_x,lb_y,rb_x,rb_y,
		top_horizontal_dot_per_degree,
		bottom_horizontal_dot_per_degree,
		left_vertical_dot_per_degree,
		right_vertical_dot_per_degree;

	BYTE *rawImage;
	int currentOutputLine;
	~Zuyou(){
		delete []rawImage;
	}

	Zuyou(istream &f):rawImage(0){
		f >> path;
		f >> lt_lon;
		f >> lb_lon;
		f >> rt_lon;
		f >> rb_lon;
		f >> lb_lat;
		f >> rb_lat;
		f >> lt_lat;
		f >> rt_lat;
		f >> lt_x;
		f >> lt_y;
		f >> rt_x;
		f >> rt_y;
		f >> lb_x;
		f >> lb_y;
		f >> rb_x;
		f >> rb_y;

		f >> top_horizontal_dot_per_degree;
		f >> bottom_horizontal_dot_per_degree;
		f >> left_vertical_dot_per_degree;
		f >> right_vertical_dot_per_degree;
	}
	
	static void onTiffStripDataCallBack(KokudoTiff *tiff, BYTE *data, ULONG dataLen, void *userParam)
	{
		Zuyou* z = (Zuyou*)userParam;
		z->onTiffStripDataCallBack_(tiff, data, dataLen);
	}

	void onTiffStripDataCallBack_(KokudoTiff *tiff, BYTE *data, ULONG dataLen){
	
		if(rawImage == 0){
			rawImage = new BYTE[tiff->width*tiff->height];
		}
		/*
		int w = tiff->width;
		int h = tiff->height;
		int bpp = tiff->bitPerPixel;
		*/
		memcpy(&rawImage[tiff->width*currentOutputLine], data, dataLen);
		currentOutputLine += dataLen / tiff->width;
	}
	
	void process(double dotPerDegree, onCompleteMapData cb, void *userData){
		if(!*path)
			return;
		
		currentOutputLine = 0;
		KokudoTiff tiff;
		tiff.load(path, this, onTiffStripDataCallBack);
		
		/*
		char outImageFile[512];
		original raw image
		sprintf(outImageFile, "%s.raw", strrchr(path, '/')+1);
		FILE *fpDebug = fopen(outImageFile, "wb");
		fwrite(rawImage, tiff.width*tiff.height, 1, fpDebug); 
		fclose(fpDebug);
		*/
		
		int convWidth = (int)(dotPerDegree * (max___(rt_lon-lt_lon, rb_lon-lb_lon)));
		int convHeight = (int)(dotPerDegree * (max___(lt_lat-lb_lat, rt_lat-rb_lat)));
		
		BYTE *convData = new BYTE[convWidth*convHeight];
		memset(convData, 0, convWidth*convHeight);
		int rawBytePerLine = tiff.width * tiff.bitPerPixel / 8;
		for(int y=0; y<convHeight; ++y){
			
			for(int x=0; x<convWidth; ++x){
				double curVerticalDotPerDegree = x*(right_vertical_dot_per_degree-left_vertical_dot_per_degree)/convWidth + left_vertical_dot_per_degree;
				double verticalMag = curVerticalDotPerDegree / dotPerDegree ;
				
				double curHorizontalDotPerDegree = y*(bottom_horizontal_dot_per_degree-top_horizontal_dot_per_degree)/convHeight + top_horizontal_dot_per_degree;
				double horizontalMag = curHorizontalDotPerDegree / dotPerDegree;
				
				double stcTop = x*(rt_y-lt_y)/tiff.width + lt_y;
				double srcLeft = y*(lb_x-lt_x)/tiff.height + lt_x;
				
				double srcLine = y*verticalMag + stcTop;
				double srcX = (x*horizontalMag) + srcLeft;
				
				convData[(ULONG)(convWidth*y+x)] = rawImage[(ULONG)((rawBytePerLine*srcLine) +  srcX)];
			}
		}
		
		cb(convData, convWidth, convHeight, lt_lon, lt_lat, userData);

		/*
		translated raw image
		sprintf(outImageFile, "%s.conv.raw", strrchr(path, '/')+1);
		FILE *fpDebug = fopen(outImageFile, "wb");
		fwrite(convData, convWidth*convHeight, 1, fpDebug); 
		fclose(fpDebug);
		*/
		
		delete []convData;
		
	}
};


/*
	if(argc<4){
		printf("usage: gbk2m conf_file maps_file out_matrix_file\n");
		return 1;
	}

	double dotPerDegree;
	double minLongitude;
	double maxLongitude;
	double minLatitude;
	double maxLatitude;
*/


int kokudo_loader_init(
	const char *initfile, 
	double *dotPerDegree,
	double *minLongitude,
	double *minLatitude,
	double *maxLongitude,
	double *maxLatitude)
{
	ifstream conf(initfile);
	conf >> *dotPerDegree;
	conf >> *minLongitude;
	conf >> *maxLongitude;
	conf >> *minLatitude;
	conf >> *maxLatitude;
	return 0;
}


int kokudo_loader_load(
	const char *mapsfile,
	double dotPerDegree,
	onCompleteMapData cb,
	void *userData
	){
	
	ifstream fmain(mapsfile);
	while(fmain){
		Zuyou z(fmain);
		z.process(dotPerDegree, cb, userData);
	}
	
	return 0;
}

