/*
# mrcImageMeanFreePathCalc : $Revision$  
# $Date$ 
# Created by $Author$
# Usage : mrcImageMeanFreePathCalc
# Attention
#   $Loccker$
#  	$State$ 
#
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>                  
#define GLOBAL_DECLARATION
#include "../inc/config.h"

#define DEBUG
#include "genUtil.h"
#include "mrcImage.h"
#include "Memory.h"

typedef struct lmrcImageMeanFreePathCalcInfo {
	int  N;
	int* countWhite;
	int* countBlack;
	int* countWhiteEdge;
	int* countBlackEdge;
	double averageWhite;
	double averageBlack;
	double averageWhiteEdge;
	double averageBlackEdge;
} lmrcImageMeanFreePathCalcInfo;

typedef enum lmrcImageMeanFreePathCalcMode {
	MeanFreePathCalcModeAlongZaxis=0,
} lmrcImageMeanFreePathCalcMode;

extern void lmrcImageMeanFreePathCalcPrint(FILE* fpt, lmrcImageMeanFreePathCalcInfo* linfo, lmrcImageMeanFreePathCalcMode mode);
extern void lmrcImageMeanFreePathCalc(mrcImage* in, lmrcImageMeanFreePathCalcInfo* linfo, lmrcImageMeanFreePathCalcMode mode);
extern void lmrcImageMeanFreePathCalcAlongZaxis(mrcImage* in, lmrcImageMeanFreePathCalcInfo* linfo, lmrcImageMeanFreePathCalcMode  mode);

extern void lmrcImageMeanFreePathCalcModePrint(FILE* fpt);

int
main(int argc, char* argv[]) 
{
	mrcImageMeanFreePathCalcInfo info;
	lmrcImageMeanFreePathCalcInfo linfo;
	mrcImage in;

	init0(&info);
    argCheck(&info, argc, argv);
    init1(&info);

	DEBUGPRINT("Program Start\n");

	mrcFileRead(&in, info.In, "in main", 0);

	lmrcImageMeanFreePathCalc(&in, &linfo, info.mode);

	lmrcImageMeanFreePathCalcPrint(info.fptOut, &linfo, info.mode);

	exit(EXIT_SUCCESS);
}

void
additionalUsage()
{
	fprintf(stderr, "----- Additional Usage -----\n");
	lmrcImageMeanFreePathCalcModePrint(stderr);
}


void
lmrcImageMeanFreePathCalcModePrint(FILE* fpt)
{
	fprintf(fpt, "%d: AlongZ-axis\n", MeanFreePathCalcModeAlongZaxis);
}

void
lmrcImageMeanFreePathCalc(mrcImage* in, lmrcImageMeanFreePathCalcInfo* linfo, lmrcImageMeanFreePathCalcMode mode)
{
	switch(mode) {
		case MeanFreePathCalcModeAlongZaxis: {
			lmrcImageMeanFreePathCalcAlongZaxis(in, linfo, mode);
			break;
		}
		default: {
			fprintf(stderr, "Not supported mode: %d\n", mode);
			exit(EXIT_FAILURE);
			break;
		}
	}

}

void
lmrcImageMeanFreePathCalcPrint(FILE* fpt, lmrcImageMeanFreePathCalcInfo* linfo, lmrcImageMeanFreePathCalcMode mode)
{
	int i;
	for(i=0; i<=linfo->N; i++) {
		fprintf(fpt, "%4d %6d %6d %6d %6d %6.3f %6.3f %6.3f %6.3f\n", 
			i,
			linfo->countWhite[i], linfo->countBlack[i],
			linfo->countWhiteEdge[i], linfo->countBlackEdge[i],
			linfo->countWhite[i]/(double)linfo->countWhite[0]*100, linfo->countBlack[i]/(double)linfo->countBlack[0]*100,
			linfo->countWhiteEdge[i]/(double)linfo->countWhiteEdge[0]*100, linfo->countBlackEdge[i]/(double)linfo->countBlackEdge[0]*100);
	}
}


void
lmrcImageMeanFreePathCalcAlongZaxis(mrcImage* in, lmrcImageMeanFreePathCalcInfo* linfo, lmrcImageMeanFreePathCalcMode mode)
{
	int* countBlack;
	int* countWhite; 
	int* countBlackEdge; 
	int* countWhiteEdge; 
	int x, y, z;
	int flagEdge;
	double data;
	double prevData;
	int lengthWhite;
	int lengthBlack;
	int i;
	
	countBlack     = memoryAllocate(sizeof(int)*(in->HeaderN.z+1), "in lmrcImageMeanFreePathCalc");
	countWhite     = memoryAllocate(sizeof(int)*(in->HeaderN.z+1), "in lmrcImageMeanFreePathCalc");
	countBlackEdge = memoryAllocate(sizeof(int)*(in->HeaderN.z+1), "in lmrcImageMeanFreePathCalc");
	countWhiteEdge = memoryAllocate(sizeof(int)*(in->HeaderN.z+1), "in lmrcImageMeanFreePathCalc");

	linfo->countBlack = countBlack;
	linfo->countWhite = countWhite;
	linfo->countBlackEdge = countBlackEdge;
	linfo->countWhiteEdge = countWhiteEdge;
	linfo->N = in->HeaderN.z;

	for(y=0; y<in->HeaderN.y; y++) {
	for(x=0; x<in->HeaderN.x; x++) {
		flagEdge = 1;
		lengthWhite = 0;
		lengthBlack = 0;
	
		// Start
		mrcPixelDataGet(in, x, y, 0, &data, mrcPixelRePart, mrcPixelHowNearest);
		if(0<data) {
			countWhiteEdge[0]++;		
			lengthWhite++;
		} else {
			countBlackEdge[0]++;
			lengthBlack++;
		}
		prevData = data;

		// Interval
		for(z=1; z<in->HeaderN.z-1; z++) {
			mrcPixelDataGet(in, x, y, z, &data, mrcPixelRePart, mrcPixelHowNearest);
			if(0<prevData) {
				if(0<data) { // White continue
					if(flagEdge) {
						countWhiteEdge[0]++;
					} else {
						countWhite[0]++;
					}
					lengthWhite++;
				} else {     // White -> Black
					if(flagEdge) {
						countWhiteEdge[lengthWhite]++;	
						flagEdge=0;
					} else {
						countWhite[lengthWhite]++;
					}
					countBlack[0]++;
					lengthWhite=0;			
					lengthBlack++;
				}
			} else {
				if(0<data) { // Black -> White 
					if(flagEdge) {
						countBlackEdge[lengthBlack]++;	
						flagEdge=0;
					} else {
						countBlack[lengthBlack]++;
					}
					countWhite[0]++;
					lengthBlack=0;
					lengthWhite++;
				} else {    // Black continue
					if(flagEdge) {
						countBlackEdge[0]++;	
					} else {
						countBlack[0]++;	
					}
					lengthBlack++;			
				}
			}
			prevData = data;
		}

		// End
		mrcPixelDataGet(in, x, y, in->HeaderN.z-1, &data, mrcPixelRePart, mrcPixelHowNearest);

		if(0<prevData) {
			if(0<data) { // White continue
				lengthWhite++;
				countWhiteEdge[lengthWhite]++;	
				countWhiteEdge[0]++;
			} else {     // White -> Black
				if(flagEdge) {
					countWhiteEdge[lengthWhite]++;
				} else {
					countWhite[lengthWhite]++;
				}
				countBlackEdge[1]++;	
				countBlackEdge[0]++;
			}
		} else {
			if(0<data) { // Black -> White 
				if(flagEdge) {
					countBlackEdge[lengthBlack]++;	
				} else {
					countBlack[lengthBlack]++;
				}
				countWhiteEdge[1]++;	
				countWhiteEdge[0]++;
			} else {    // Black continue
				lengthBlack++;
				if(flagEdge) {
					countBlackEdge[lengthBlack]++;	
					countBlackEdge[0]++;	
				} else {
					countBlack[lengthBlack]++;
					countBlack[0]++;	
				}
			}
		}
	}
	}

	linfo->averageWhite = linfo->averageBlack = 0; 
	linfo->averageWhiteEdge = linfo->averageBlackEdge = 0; 
	for(i=0; i<=linfo->N; i++) {
		linfo->averageWhite	+= linfo->countWhite[i];			
		linfo->averageBlack += linfo->countBlack[i];			
	}

}
