#include "SOMPCompress.h"

#include "HPTime.h"

#include <conio.h>

enum {nothing,compress, decompress};

// erster wert ist hier immer default
int g_piCBS[]	= {1024,256,16,-1};			// codebook size
int g_piClS[]	= {5,3,2,8,-1};				// cluster size
float g_pfTDF[]	= {1,-1,-1};				// train to distance factor
float g_pfDDF[]	= {.8,-1,-1};				// distance decrease factor
int g_pbLinear[] = {1,0,-1};

char g_pszColors[][20]={"#ffffff","#ffafaf","#afffaf","#afafff"};

int checkFiletype(const char *szFilename){
	if(strlen(szFilename) < 4)
		return nothing;

	if(!strcmp(&szFilename[strlen(szFilename)-4],".bmp"))
		return compress;
	if(!strcmp(&szFilename[strlen(szFilename)-4],".vqp"))
		return decompress;

	return nothing;
}

char *withoutPath(char *szText){
	char *szp = szText + sizeof(char) * (strlen(szText) - 1);

	while(*szp != '\\' && *szp != '/' && szp > szText){
		szp--;
	}
	
	return szp;
}

void couthelp(void){
	//cout <<withoutPath("c:\\test\\test.bmp")<<endl;
	int i;
	cout << "S0MP|cCompress (c) 2004 Johannes Lampel"<<endl<<endl;
	cout << "----------- usage of spcc -----------" << endl;
	cout << endl << "switch value default descr" << endl;
	cout << "-cb x [10]\tsize of codebook ( 2 ^ x )"<<endl;
	cout << "-ds x [0.9]\tdistance factor decrement. should be between 0.8 and 0.99,"<<endl;
	cout << "\t\tsometimes maybe 0.7. lower is faster"<<endl;
	cout << "-cs x [5]\tcluster size : cluster should be x*x in size" << endl;
	cout << "-qu x [1]\tquality of pattern : 1 is best, bigger is faster, lower quality" << endl;
	cout << "-nl  \t\tuse a square SOM [default]" << endl;
	cout << "-l   \t\tuse a linear SOM" << endl;
	cout << "-a   \t\tcompress this picture several times with different settings" << endl;
	cout << "\t\tthe settings are:" << endl;
	cout << "\t\t- codebook    : ";for(i=0;g_piCBS[i]>0;i++)cout<<g_piCBS[i]<<" ";cout << endl;
	cout << "\t\t- clustersize : ";for(i=0;g_piClS[i]>0;i++)cout<<g_piClS[i]<<" ";cout << endl;
	cout << "\t\t- training end: ";for(i=0;g_pfTDF[i]>0;i++)cout<<g_pfTDF[i]<<" ";cout << endl;
	cout << "\t\t- dfac dec    : ";for(i=0;g_pfDDF[i]>0;i++)cout<<g_pfDDF[i]<<" ";cout << endl;
	cout << endl << "(c) Johannes Lampel 2004" << endl;
	cout << "press any key to continue" << endl;
	getch();
}

int main(int iArgs, char **ppArgs){
	int i,iType;
	CSOMPCompress test;
	char szName[80];
	float fTrainTo = .6;
	bool bAnalyse = false;

	test.m_iPatternQuality = 1;
	test.m_bLinear = false;
	/*test.m_iClusterSize = 5;
	test.m_iCodeBookSize = 256;
	test.m_dDistPFactor = .7;*/

	if(iArgs == 1)
		couthelp();

	for(i=1; i < iArgs; i++){
		if(ppArgs[i][0] == '-'){		// it's a switch
			if(!strcmp(ppArgs[i],"-h")
				||!strcmp(ppArgs[i],"--help")){
					couthelp();
					continue;
				}
				if(!strcmp(ppArgs[i],"-cb")){
					if(i+1<iArgs){
						i++;
						int iCodebook;
						sscanf(ppArgs[i],"%i",&iCodebook);
						g_piCBS[0] = 1<<iCodebook;
						continue;
					}
				}
				if(!strcmp(ppArgs[i],"-ds")){
					if(i+1<iArgs){
						i++;
						float fFactor;
						sscanf(ppArgs[i],"%f",&fFactor);
						g_pfDDF[0] = fFactor;
						continue;
					}
				}
				if(!strcmp(ppArgs[i],"-cs")){
					if(i+1<iArgs){
						i++;
						int iCluster;
						sscanf(ppArgs[i],"%i",&iCluster);
						g_piClS[0] = iCluster;
						continue;
					}
				}
				if(!strcmp(ppArgs[i],"-qu")){
					if(i+1<iArgs){
						i++;
						int iQuality;
						sscanf(ppArgs[i],"%i",&iQuality);
						test.m_iPatternQuality = iQuality;
						continue;
					}
				}
				if(!strcmp(ppArgs[i],"-nl")){
					g_pbLinear[0] = false;
					continue;
				}
				if(!strcmp(ppArgs[i],"-l")){
					g_pbLinear[0] = true;
					continue;
				}
				if(!strcmp(ppArgs[i],"-a")){
					bAnalyse = true;
					continue;
				}
		}
		iType = checkFiletype(ppArgs[i]);
		if(iType == decompress){
			g_HPTime.markTick();
			test.loadCPicture(ppArgs[i]);
			sprintf(szName,"%s.bmp",ppArgs[i]);
			test.saveBMP(szName);

			/*cout << test.image_bmp->sizeX <<" - "<< test.image_bmp->sizeY << endl;
			cout << test.m_iClusterSize << endl;
			cout << test.m_iCodeBookSize << endl;
			char test[80];
			cin >> test;*/
		}
		else if(iType == compress){
			int iCodebookIndex;
			int iClusterSIndex;
			int iDTrainTo;
			int iDDistDecF;
			int iLinearIndex;
			// if we are in analyse mode, loop thru all possibilities, otherwise just take the first entries from
			// the respective arrays
			for(iCodebookIndex = 0; bAnalyse ? (g_piCBS[iCodebookIndex] > 0):(!iCodebookIndex); iCodebookIndex ++){
				test.m_iCodeBookSize = g_piCBS[iCodebookIndex];
				for(iClusterSIndex = 0; bAnalyse ? (g_piClS[iClusterSIndex] > 0):(!iClusterSIndex); iClusterSIndex ++){
					test.m_iClusterSize = g_piClS[iClusterSIndex];
					for(iDTrainTo = 0; bAnalyse ? (g_pfTDF[iDTrainTo] > 0):(!iDTrainTo); iDTrainTo ++){
						fTrainTo = g_pfTDF[iDTrainTo];
						for(iDDistDecF = 0; bAnalyse ? (g_pfDDF[iDDistDecF] > 0):(!iDDistDecF); iDDistDecF ++){
							test.m_dDistPFactor = g_pfDDF[iDDistDecF];
							for(iLinearIndex = 0; bAnalyse ? (g_pbLinear[iLinearIndex] >= 0):(!iLinearIndex); iLinearIndex ++){
							test.m_bLinear = g_pbLinear[iLinearIndex];

							g_HPTime.markTick();
							cout << "--------------------------------------------------------"<<endl;
							cout << "-- Welcome to S0MP|cCompress (c) 2004 Johannes Lampel --"<<endl;
							cout << "--------------------------------------------------------"<<endl;
							cout << "loading "<<ppArgs[i]<< endl;
							test.loadBMP(ppArgs[i]);
							test.calcStats();
							cout <<"Entropy : "<< test.m_dEntropy << endl;
							cout <<"Sigma   : "<< test.m_dSigma << endl;
							cout << "AV("<<test.m_dAv[0] << " - "<< test.m_dAv[1] << " - "<< test.m_dAv[2]<<")" << endl;
							if(!bAnalyse){
								sprintf(szName,"%s.vqp",ppArgs[i]);
							}
							else{
								sprintf(szName,"%s-cb%i%scl%idtt%.1fddf%.1f.vqp",ppArgs[i],test.m_iCodeBookSize,test.m_bLinear?"l":"s",test.m_iClusterSize,fTrainTo,test.m_dDistPFactor);
							}
							cout << "init som" << endl;
							test.initSOM();
							cout << "creating pattern" << endl;
							test.createPattern();
							cout << "(codebook:"<<test.m_iCodeBookSize<<"|cluster:"<<test.m_iClusterSize<<"|fdtt:"<<fTrainTo<<"|fddf"<<test.m_dDistPFactor<<"topology:"<<(test.m_bLinear?"linear":"square")<<","<<test.m_pPattern->GetNumP()<<"p)\n";
							cout << "compressing ..." << endl;
							test.compressFull(fTrainTo);
							cout << "saving compressed file : " << szName << endl;
							test.saveCPicture(szName);
							cout << "compression took "<<g_HPTime.getElapsed_d() << " seconds"<<endl;

							FILE *fhdlog,*fhdtest;
							char szFilename[300],*szp;

							strcpy(szFilename,test.m_szBMPSource);
							szp = szFilename + strlen(szFilename)*sizeof(char);
							while(*szp != '\\' && *szp != '/' && szp > szFilename){
								*szp = 0;
								szp--;
							}

							strcat(szFilename,"vqp-log.html");

							fhdtest = fopen(szFilename,"r");
							if(!fhdtest){
								// no logfile there yet
								fhdlog = fopen(szFilename,"w");
								fprintf(fhdlog,"<html><head><title>Logfile for compressing files using vector quantization by training a SOM</title></head><body>");
								fprintf(fhdlog,"<table border=1><tr><th>time<th>dimension of image<th>file<th>Entropy<th>Sigma of pic<th>compression quality<th>number of pattern<th>topology<th>distance factor decrease");
								fprintf(fhdlog,"<th>training end<th>retrain<th>clustersize<th>codebooksize<th>bpp<th>sigma<th>output file size [kB]<th>input file size [kB]<th>ratio<th>time elapsed");
								fclose(fhdlog);
							}
							else
								fclose(fhdtest);

							fhdlog = fopen(szFilename,"a");

							if(fhdlog){
								time_t time_now;
								time_now = time(0);

								float fSize = log(test.getCodebookSize())/log(2)
									*(float)test.image_bmp->sizeX*(float)test.image_bmp->sizeY
									/(float)test.m_iClusterSize/(float)test.m_iClusterSize + (float)test.getCodebookSize()*3.*8.
									*(float)test.m_iClusterSize*(float)test.m_iClusterSize;

								float fBitPPixel = fSize / float(test.image_bmp->sizeX*test.image_bmp->sizeY);

								fSize/=8;
								float fOSize = test.image_bmp->sizeX*test.image_bmp->sizeY*3;
								float fRatio = fOSize/fSize;
								fSize/=1024;
								fOSize /= 1024;

								fprintf(fhdlog,"<tr>");
								fprintf(fhdlog,"<td>%s",asctime(localtime(&time_now)));
								fprintf(fhdlog,"<td>%li,%li",test.image_bmp->sizeX,test.image_bmp->sizeY);
								fprintf(fhdlog,"<td><a href=\"%s\">%s</a> <a href=\"%s\">vqp</a> <a href=\"%s.bmp\">vqp.bmp</a>",withoutPath(test.m_szBMPSource),withoutPath(test.m_szBMPSource),withoutPath(szName),withoutPath(szName));
								cout << test.m_szBMPSource << endl;
								cout << szName << endl;
								cout << withoutPath(szName) << endl;
								fprintf(fhdlog,"<td>%.2lf",test.m_dEntropy);
								fprintf(fhdlog,"<td>%.2lf",test.m_dSigma);
								fprintf(fhdlog,"<td>%i",test.m_iPatternQuality);
								fprintf(fhdlog,"<td>%li",test.m_pPattern->GetNumP());
								fprintf(fhdlog,"<td bgcolor=\"%s\">%s",g_pszColors[iLinearIndex],test.m_bLinear?"linear":"square");
								fprintf(fhdlog,"<td bgcolor=\"%s\">%.2f",g_pszColors[iDDistDecF],test.m_dDistPFactor);
								fprintf(fhdlog,"<td bgcolor=\"%s\">%.2f",g_pszColors[iDTrainTo],fTrainTo);
								fprintf(fhdlog,"<td>%.1f",test.m_fRetrainFactor);
								fprintf(fhdlog,"<td bgcolor=\"%s\">%i",g_pszColors[iClusterSIndex],test.m_iClusterSize);
								fprintf(fhdlog,"<td bgcolor=\"%s\">%i",g_pszColors[iCodebookIndex],test.m_iCodeBookSize);
								fprintf(fhdlog,"<td>%.2f",fBitPPixel);
								fprintf(fhdlog,"<td>%lf",sqrt(test.m_dErrorAll / double((test.image_bmp->sizeX/test.m_iClusterSize*test.m_iClusterSize)*(test.image_bmp->sizeY/test.m_iClusterSize*test.m_iClusterSize))));
								fprintf(fhdlog,"<td>%.0f",fSize);
								fprintf(fhdlog,"<td>%.0f",fOSize);
								fprintf(fhdlog,"<td>%.2f",fRatio);
								fprintf(fhdlog,"<td>%.2lf",g_HPTime.getElapsed_d());

								fclose(fhdlog);
								cout << "------------------ END OF COMPRESSION ------------------\n\n"<<endl;
								char **tempp = new char *[2];
								tempp[0] = new char[255];
								tempp[1] = new char[255];
								strcpy(tempp[0],ppArgs[0]);
								strcpy(tempp[1],szName);
								if(bAnalyse)main(2,(char**)tempp);
								delete []tempp[0];
								delete []tempp[1];
								delete []tempp;
							}
						}
						}
					}
				}
			}
		}
		else{
			cout << "that's no file I know how to open" << endl;
		}
	}
}
