// dice.cpp : 
// Implementation file for di[c]e recognition project
// EE 4367 / EE 5367
// Spring 2000
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
#include <mmsystem.h>		//Needed for PlaySound
#include <process.h>
#include "pgmfile.h"
#include "pgmfileOperations.h"
#include "ImageOps.h"
//#include "findblob.h"			// From Cody
//#include "resolvequiv.h"		// From Chris
#include "dice.h"


//Main program
int main(int argc, char* argv[]){

	char *pOutBinFile = NULL;
	char *pOutDebugFile = NULL;

	if(argc < 2){
		printUsage();
		return 0;
	}//if

	if(argc > 2)
		pOutBinFile = argv[2];

	if(argc > 3)
		pOutDebugFile = argv[3];


	Cpgmfile pfile;
	printf("\nReading input file [%s]...", argv[1]);
	if(pfile.readFile(argv[1]) < 0){				//Read in the file...
		printf("\n*** Error reading file %s...aborting!\n", argv[1]);
		return -1;
	}//if
	printf("finished.\n");

	unsigned char **pBuf;
	unsigned char **pBlobMat1;
	unsigned char **pBlobMat2;
	unsigned char **pBMat;
	int iWidth = pfile.getWidth();
	int iHeight = pfile.getHeight();

	pBuf = (unsigned char**)malloc(sizeof(unsigned char*)*iHeight);			//Alloc matrix for data
	pBlobMat1 = (unsigned char**)malloc(sizeof(unsigned char*)*iHeight);	//Alloc matrix for blob data
	pBlobMat2 = (unsigned char**)malloc(sizeof(unsigned char*)*iHeight);	//Alloc matrix for blob data
	for(int i=0;i<iHeight;i++){
		pBuf[i] = (unsigned char*)malloc(sizeof(unsigned char)*iWidth);
		pBlobMat1[i] = (unsigned char*)malloc(sizeof(unsigned char)*iWidth);
		pBlobMat2[i] = (unsigned char*)malloc(sizeof(unsigned char)*iWidth);
		memset(pBlobMat1[i], 0, sizeof(unsigned char)*iWidth);
		memset(pBlobMat2[i], 0, sizeof(unsigned char)*iWidth);
	}//for

	pfile.getData(pBuf, iWidth, iHeight);

	int iMaxGrayVal = pfile.getMaxGrayVal();

	printf("Converting image to binary...");
	CpgmfileOperations::AdjustContrast(pfile, iMaxGrayVal/2);	/* Make the thing binary...*/
	printf("finished.\n");

	if(pOutBinFile){
		printf("Writing binary file to disk: [%s]\n", pOutBinFile);
		int rc = pfile.writeFile(pOutBinFile);
		if(rc < 0)
			printf("Error:  Binary output file not written...");
	}//if
	
	pfile.getData(pBuf, iWidth, iHeight);

	int iCt = LAST_LABEL - FIRST_LABEL;
	int iBlobCt1, iBlobCt2;
	
	pBMat = (unsigned char**)malloc(sizeof(unsigned char*)*iCt);		//Alloc matrix for equivs
	for(i=0;i<iCt;i++){
		pBMat[i] = (unsigned char*)malloc(sizeof(unsigned char)*iCt);
		memset(pBMat[i], 0, sizeof(unsigned char)*iCt);
	}//for

	//////////////////////////

	printf("Performing blob analysis...");
	iBlobCt1 = ImageOps::doBlob(pBuf, iWidth, iHeight, pBlobMat1, pBMat, &iCt);
	if(iBlobCt1<0){
		printf(" *** ERROR! (Will try to continue anyway...)\n");
		if(iBlobCt1 == ERROR_LABELMAX)
			printf("*** Too many equivalence labels...\n");
	}//if
	else{
		printf("finished.\n");
		printf("There are %d blob regions with possible equivalencies...\n", iBlobCt1);
	}
	ImageOps::debugOutputBlobMatrix(pOutDebugFile, pBlobMat1, iWidth, iHeight, pBMat, iCt);
	printf("Resolving equivalencies...");
	iBlobCt1 = ImageOps::resolvEquiv(pBlobMat1, iWidth, iHeight, pBMat, &iCt);
	printf("finished.\nThere are %d distinct blob regions\n", iBlobCt1);
	ImageOps::debugOutputBlobMatrix(pOutDebugFile, pBlobMat1, iWidth, iHeight, pBMat, iCt);

	///////////////////////

	printf("Inverting image...");
	CpgmfileOperations::Invert(pfile);
	printf("done.\n");
	pfile.getData(pBuf, iWidth, iHeight);
	iCt = LAST_LABEL - FIRST_LABEL;
	printf("Performing blob analysis...");
	iBlobCt2 = ImageOps::doBlob(pBuf, iWidth, iHeight, pBlobMat2, pBMat, &iCt);
	if(iBlobCt2 < 0){
		printf(" *** ERROR! (Will try to continue anyway...)\n");
		if(iBlobCt2 == ERROR_LABELMAX)
			printf("*** Too many equivalence labels...\n");
	}//if
	else{
		printf("finished.\n");
		printf("There are %d blob regions with possible equivalencies...\n", iBlobCt2);
	}
	ImageOps::debugOutputBlobMatrix(pOutDebugFile, pBlobMat2, iWidth, iHeight, pBMat, iCt);
	printf("Resolving equivalencies...");
	iBlobCt2 = ImageOps::resolvEquiv(pBlobMat2, iWidth, iHeight, pBMat, &iCt);
	printf("finished.\nThere are %d distinct blob regions\n", iBlobCt2);
	ImageOps::debugOutputBlobMatrix(pOutDebugFile, pBlobMat2, iWidth, iHeight, pBMat, iCt);
	
	printf("\nWithout any safety checks...the roll might be a %d...\n", iBlobCt2-1);

	//////////////////////////

	printf("\nPerforming blob area analysis...");
	int *pAreas = (int*)malloc((iBlobCt1+iBlobCt2)*sizeof(int));
	int *pSorts = (int*)malloc((iBlobCt1+iBlobCt2)*sizeof(int));
	for(i=0;i<iBlobCt1;i++){
		pAreas[i] = ImageOps::getBlobArea(pBlobMat1, iWidth, iHeight, FIRST_LABEL+i);
	}//for
	for(i=iBlobCt1;i<iBlobCt1+iBlobCt2;i++){
		pAreas[i] = ImageOps::getBlobArea(pBlobMat2, iWidth, iHeight, FIRST_LABEL+i-iBlobCt1);
	}//for

	
	//Poor sorting algorithm to sort blob areas:
	for(i=0;i<iBlobCt1+iBlobCt2;i++){
		int ind = 0;
		for(int j=0;j<iBlobCt1+iBlobCt2;j++){
			if( pAreas[j] > pAreas[ind]){
				ind = j;
			}
		}//for
		pSorts[i] = pAreas[ind];
		pAreas[ind] = -1;
	}//for
	

	//Note: At this point, pSorts[0] is bkgnd, pSorts[1] is die face, and dots start at pSorts[3]
	iCt=1;			//We should have at least 1 dot
	for(i=2;i<iBlobCt1+iBlobCt2-1;i++){
		//See if next area is "close" (within 30%) of this one...
		if( abs(pSorts[i+1] - pSorts[i]) < (pSorts[i] * 0.30))
			iCt++;				//If it is, we have another dot
		else
			break;				//Otherwise, we're done counting
	}//for
	printf("done.\n");

	if((iCt > 1) && (iCt < 7))
		printf("\n  *** The die is a %d ***\n", iCt);
	else{
		printf("\n  *** Error: Invalid dot count detected.");
		printf("\n  ***        Be sure you are using a 6-sided die!");
	}//else

	switch(iCt){
	case 1:
		PlaySound(TEXT("1wav"), (HMODULE)GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
		break;
	case 2:
		PlaySound(TEXT("2wav"), (HMODULE)GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
		break;
	case 3:
		PlaySound(TEXT("3wav"), (HMODULE)GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
		break;
	case 4:
		PlaySound(TEXT("4wav"), (HMODULE)GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
		break;
	case 5:
		PlaySound(TEXT("5wav"), (HMODULE)GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
		break;
	case 6:
		PlaySound(TEXT("6wav"), (HMODULE)GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
		break;
	default:
		PlaySound(TEXT("UNKNOWNWAV"), (HMODULE)GetModuleHandle(NULL), SND_RESOURCE | SND_SYNC);
		break;
	}//switch


	//Free up the memory allocated
	free(pAreas);
	free(pSorts);
	for(i=0;i<iHeight;i++){
		free(pBuf[i]);
		free(pBlobMat1[i]);
		free(pBlobMat2[i]);
	}//for

	for(i=0;i<LAST_LABEL - FIRST_LABEL;i++){
		free(pBMat[i]);
	}

	free(pBuf);
	free(pBlobMat1);
	free(pBlobMat2);
	free(pBMat);

	return 0;

}//main


void printUsage(){
	printf("\n Usage:\n\n");
	printf("  dice.exe die1.pgm [die2.pgm debug.txt] \n\n");
	printf("  where    die1.pgm     - Input file to process\n");
	printf("           die2.pgm     - Optional output binary file\n");
	printf("           debug.txt    - Optional text file for debugging information\n");
	printf("                          (DISABLED due to program changes)\n\n");
	printf("  Note: Parameter order is relevant\n");
}//printUsage function 