/*
 * Fade To Black engine rewrite
 * Copyright (C) 2006-2012 Gregory Montoir (cyx@users.sourceforge.net)
 */

#include "file.h"

bool g_isDemo = false;
static int _fileLanguage;
static int _fileVoice;
static const char *_fileDataPath;
static bool _exitOnError = true;

static void fileMakeFilePath(const char *fileName, int fileType, int fileLang, char *filePath) {
	static const char *dataDirsTable[] = { "DATA", "DATA/SOUND", "TEXT", "VOICE" };
	static const char *langDirsTable[] = { "US", "FR", "GR", "SP", "IT" };

	if (fileType == kFileType_RUNTIME) {
		sprintf(filePath, "%s/", _fileDataPath);
	} else {
		assert(fileType >= 0 && fileType < ARRAYSIZE(dataDirsTable));
		sprintf(filePath, "%s/%s/", _fileDataPath, dataDirsTable[fileType]);
	}
	switch (fileLang) {
	case kFileLanguage_SP:
	case kFileLanguage_IT:
		if (fileType == kFileType_TEXT) {
			assert(fileLang >= 0 && fileLang < ARRAYSIZE(langDirsTable));
			strcat(filePath, langDirsTable[fileLang]);
			strcat(filePath, "/");
		}
		fileLang = _fileVoice;
		break;
	}
	if (fileType == kFileType_TEXT || fileType == kFileType_VOICE) {
		assert(fileLang >= 0 && fileLang < ARRAYSIZE(langDirsTable));
		strcat(filePath, langDirsTable[fileLang]);
		strcat(filePath, "/");
	}
	strcat(filePath, fileName);
}

static FILE *fileOpenIntern(const char *fileName, int fileType) {
	char filePath[512];

	fileMakeFilePath(fileName, fileType, _fileLanguage, filePath);
	char *p = strrchr(filePath, '/');
	if (p) {
		++p;
	} else {
		p = filePath;
	}
	stringToUpperCase(p);
	FILE *fp = fopen(filePath, "rb");
	if (!fp) {
		stringToLowerCase(p);
		fp = fopen(filePath, "rb");
	}
	if (!fp && fileType == kFileType_TEXT) {
		fp = fileOpenIntern(fileName, kFileType_DATA);
	}
	return fp;
}

bool fileExists(const char *fileName, int fileType) {
	FILE *fp = fileOpenIntern(fileName, fileType);
	if (fp) {
		fclose(fp);
	}
	return fp != 0;
}

bool fileInit(int language, int voice, const char *dataPath) {
	_fileLanguage = language;
	_fileVoice = voice;
	_fileDataPath = dataPath;
	bool ret = fileExists("player.ini", kFileType_DATA);
	if (ret) {
		g_isDemo = fileExists("ddtitle.cin", kFileType_DATA);
	}
	debug(kDebug_FILE, "fileInit() dataPath '%s' isDemo %d", _fileDataPath, g_isDemo);
	return ret;
}

FILE *fileOpen(const char *fileName, int *fileSize, int fileType, bool errorIfNotFound) {
	if (g_isDemo) {
		if (fileType == kFileType_VOICE) {
			return 0;
		} else if (fileType == kFileType_TEXT) {
			fileType = kFileType_DATA;
		}
	}
	FILE *fp = fileOpenIntern(fileName, fileType);
	if (!fp) {
		if (errorIfNotFound) {
			error("Unable to open '%s'", fileName);
		} else {
			warning("Unable to open '%s'", fileName);
		}
		return 0;
	}
	fseek(fp, 0, SEEK_END);
	if (fileSize) {
		*fileSize = ftell(fp);
	}
	fseek(fp, 0, SEEK_SET);
	return fp;
}

void fileClose(FILE *fp) {
	fclose(fp);
}

void fileRead(FILE *fp, void *buf, int size) {
	int count = fread(buf, size, 1, fp);
	if (count != 1) {
		if (_exitOnError && ferror(fp)) {
			error("I/O error on reading %d bytes", size);
		}
	}
}

uint8_t fileReadByte(FILE *fp) {
	uint8_t b;
	fileRead(fp, &b, 1);
	return b;
}

uint16_t fileReadUint16LE(FILE *fp) {
	uint8_t buf[2];
	fileRead(fp, buf, 2);
	return READ_LE_UINT16(buf);
}

uint32_t fileReadUint32LE(FILE *fp) {
	uint8_t buf[4];
	fileRead(fp, buf, 4);
	return READ_LE_UINT32(buf);
}

uint32_t fileGetPos(FILE *fp) {
	return ftell(fp);
}

void fileSetPos(FILE *fp, uint32_t pos, int origin) {
	static const int originTable[] = { SEEK_CUR, SEEK_SET };
	if (origin >= ARRAYSIZE(originTable)) {
		error("Invalid file seek origin", origin);
	} else {
		int r = fseek(fp, pos, originTable[origin]);
		if (r != 0 && _exitOnError) {
			error("I/O error on seeking to offset %d", pos);
		}
	}
}

int fileEof(FILE *fp) {
	return feof(fp);
}