////////////////////////////////////////////////////////////////////////////
//
//  Crytek Tool Source File.
//  Copyright (C), Crytek Studios, 2006.
// -------------------------------------------------------------------------
//  Created:     05/05/2006 by Matthew Jack
//  Compilers:   Visual Studio.NET
//  Description: Flexible checksum tool
//  Notes:			 Must link setargv.obj for wildcards
// -------------------------------------------------------------------------
//  History:	05/05/2006 Copied Timur's crc32 code from the Editor, 
//
////////////////////////////////////////////////////////////////////////////


#define _CRT_SECURE_NO_DEPRECATE

#include <stdio.h>
#include <string.h>
#include <conio.h>

#include "crc32.h"
#include "CryCheck.h"


using std::vector;

FilePatternList excludeList;

FilePatternList::FilePatternList(void) : maxPatterns(1024)
{
	nPatterns = 0;
	pattern = new char *[maxPatterns];
}

FilePatternList::~FilePatternList(void)
{
	for (int i=0; i<nPatterns; i++) delete[] pattern[i];
	delete[] pattern;
	nPatterns = 0;
}

bool FilePatternList::match( const char * filename) 
{
	int nLength = (int) strlen(filename);
	for (int i=0; i<nPatterns; i++) {
		printf("Matching: %s\n",pattern[i]);
		// Check just the tails of the strings, so that paths are ignored
		int offset = nLength - (int) strlen(pattern[i]);
		if (offset < 0) continue; // Too short to match
		const char *tail = &filename[offset];
		if ( 0 == _stricmp(pattern[i],tail) ) return true;  // Ignoring case
	}
	return false;
}

bool FilePatternList::addFromFile( const char * filename) 
{
	FILE *fp = fopen(filename,"rt");
	if (!fp) return false;

	const int buffSize = 512;
	char buffer[buffSize];
	while (nPatterns < maxPatterns && fscanf_s(fp, "%s", &buffer, buffSize) > 0) {
		//printf("%s\n", buffer);
		pattern[nPatterns++] = _strdup(buffer);   // Allow me to take joy in using strdup, since CryMemory is absent
	}
	fclose(fp);
	if (nPatterns == maxPatterns) {
		printf("Max number of file patterns was reached\n");
		return false;
	}
	return true;
}




int main( int argc, char * argv[]) 
{
	// Main buffer
	const int buffSize = 1024*1024;
	char *buffer = new char[buffSize];
	
	// Work thru option args
	int i;
	bool verbose = false;
	for (i=1; i<argc && '-' == argv[i][0]; i++) {
		if (verbose) printf("Argument: %s\n",argv[i]);

		if ( strlen(argv[i]) > 1 ) {
			// An option
			if (verbose) printf("Option: %s\n",argv[i]);

			if ('e' == argv[i][1]) {
				// Specifying an exclude list
				if (argc > ++i) {
					if (verbose) printf("Exclude file: %s\n", argv[i]);
					if (! excludeList.addFromFile(argv[i])) {
						printf("Couldn't read exclude file\n");
						return 1;
					}
				} else {
					printf("Must give a filename for exclude list\n");
					return 1;
				}

			} else if ('v' ==argv[i][1]) {
				verbose = true;

			} else {
				// Other option...
				printf("Unrecognised option: %s\n",argv[i]);
				return 1;
			}
		}
	}

	int nFiles = 0;
	for( ; i<argc ;i++ ){
		if (excludeList.match(argv[i])) {
			printf("Excluded: %s\n",argv[i]);
			continue;
		}

		if (verbose) printf("Checking: %s\n",argv[i]);
		
		// Actually CRC-32 a file
		FILE * fp = fopen(argv[i],"rb");
		if (!fp) {
			printf("Could not open file\n");
			continue;
		}

		int bytesRead;
		int totalBytesRead = 0;
		unsigned int crc = 0xFFFFFFFF;
		do{
			bytesRead = (int) fread(buffer, sizeof(char), buffSize, fp);
			totalBytesRead += bytesRead;
			crc = Crc32Gen::GetCRC32(buffer, bytesRead, crc);
			// MUST xor here, because the function was not designed for chaining CRCed blocks
			crc ^= 0xFFFFFFFF;
		} while (bytesRead == buffSize);
		
		// Apply final xor as per spec
		crc ^= 0xFFFFFFFF;

		printf("%-30s   CRC-32 = %08lx, size = %d bytes\n", argv[i], crc, totalBytesRead); 
		fclose(fp);
		
	}
	
	// If no files given, we assume wildcard
	if (0 == nFiles) {
	}

	delete[] buffer;
	return 0;
}