#include <stdio.h>
#include <string.h>
#include "identifiers.h"
#include "qbtypes.h"
#include "makeqb.h"
#include "write_endian.h"

 /* This program is free software. It comes without any warranty, to
 * the extent permitted by applicable law. You can redistribute it
 * and/or modify it under the terms of the Do What The Fuck You Want
 * To Public License, Version 2, as published by Sam Hocevar. See
 * http://sam.zoy.org/wtfpl/COPYING for more details. */

int makeSimpleDataSection(FILE *qbFile, unsigned int sectionType, unsigned int fileId, unsigned int sectionId)
{
	unsigned int pointerNext, reserved = 0;

	fwrite(&sectionType, 4, 1, qbFile);
	fwriteBe(&sectionId, 4, 1, qbFile);
	fwriteBe(&fileId, 4, 1, qbFile);
	
	pointerNext = ftell(qbFile) + 8;
	fwriteBe(&pointerNext, 4, 1, qbFile);
	fwriteBe(&reserved, 4, 1, qbFile);

	return 0;
}

int makeStringSection(FILE *qbFile, unsigned int fileId, unsigned int sectionId, char *string)
{
	makeSimpleDataSection(qbFile, SECTION_STRING, fileId, sectionId); // Data section
	fwrite(string, strlen(string) + 1, 1, qbFile); // Write string + null character
	makePadding(qbFile); // Padding to next dword
	return 0;
}

int makeScriptSection(FILE *qbFile, unsigned int fileId, ScriptInfo *script)
{
	makeSimpleDataSection(qbFile, SECTION_SCRIPT, fileId, script->sectionName);
	fwriteBe(&script->unknownNumber, 4, 1, qbFile);
	fwriteBe(&script->uncompressedSize, 4, 1, qbFile);
	fwriteBe(&script->compressedSize, 4, 1, qbFile);
	fwrite(script->scriptData, script->compressedSize, 1, qbFile);
	makePadding(qbFile);

	return 0;
}

void makePadding(FILE *qbFile)
{
	while((ftell(qbFile) % 4) != 0)
		fputc(0, qbFile);
}


int makeQBKeyArray(FILE *qbFile, int numEntries, unsigned int *entries)
{
	int section = ARRAY_QBKEY, pointerNext;

	fwrite(&section, 4, 1, qbFile);
	fwriteBe(&numEntries, 4, 1, qbFile);

	if (numEntries > 1)
	{
		pointerNext = ftell(qbFile) + 4;
		fwriteBe(&pointerNext, 4, 1, qbFile);
	}

	fwriteBe(entries, 4, numEntries, qbFile);

	return 0;
}

int makeVector(FILE *qbFile, float element1, float element2)
{
	int section = ARRAY_VECTOR;

	fwrite(&section, 4, 1, qbFile);
	fwriteBe(&element1, 4, 1, qbFile);
	fwriteBe(&element2, 4, 1, qbFile);

	return 0;
}

int makeStructDeclaration(FILE *qbFile)
{
	int startPoint, section = STRUCT_INIT, pointerNext;

	startPoint = ftell(qbFile);

	fwrite(&section, 4, 1, qbFile);

	pointerNext = ftell(qbFile) + 4;
	fwriteBe(&pointerNext, 4, 1, qbFile);

	return startPoint;
}

int closeStruct(FILE *qbFile, int structPointer)
{
	linkStruct(qbFile, structPointer, 0);

	return 0;
}

int makeStructSimple(FILE *qbFile, unsigned int structType, unsigned int name, unsigned int value, int pointerLink)
{
	int currentPoint, pointerNext;

	currentPoint = ftell(qbFile);

	linkStruct(qbFile, pointerLink, currentPoint);

	fwrite(&structType, 4, 1, qbFile);
	fwriteBe(&name, 4, 1, qbFile);
	fwriteBe(&value, 4, 1, qbFile);

	pointerNext = ftell(qbFile) + 4;
	fwriteBe(&pointerNext, 4, 1, qbFile);

	return currentPoint;
}

int makeStructFloat(FILE *qbFile, unsigned int name, float value, unsigned int pointerLink)
{
	// Weird hack... >_>
	return makeStructSimple(qbFile, STRUCT_FLOAT, name, *((unsigned int*)&value), pointerLink);
}

int makeStructPointer(FILE *qbFile, unsigned int structType, unsigned int name, unsigned int pointerLink)
{
	return makeStructSimple(qbFile, structType, name, ftell(qbFile) + 16, pointerLink);
}

int makeStructString(FILE *qbFile, unsigned int name, char *string, unsigned int pointerLink)
{
	int pointerStruct;

	pointerStruct = makeStructPointer(qbFile, STRUCT_STRING, name, pointerLink); // String struct

	fwrite(string, strlen(string) + 1, 1, qbFile); // Write string + null character
	makePadding(qbFile); // Padding to next dword

	return pointerStruct;
}

int linkStruct(FILE *qbFile, int structPointer, int newPointer)
{
	int currentPoint, type;

	currentPoint = ftell(qbFile);
	
	fseek(qbFile, structPointer, SEEK_SET);
	fread(&type, 4, 1, qbFile);

	if (type != STRUCT_INIT)
	{
		fseek(qbFile, 8, SEEK_CUR); // Skip name/value
	}

	fwriteBe(&newPointer, 4, 1, qbFile);

	fseek(qbFile, currentPoint, SEEK_SET);

	return 0;
}

int finishQB(FILE *qbFile)
{
	int fileSize = ftell(qbFile);

	fseek(qbFile, 4, SEEK_SET);
	fwriteBe(&fileSize, 4, 1, qbFile);

	return 0;
}