// BlinkenSisters - Hunt for the Lost Pixels
//     Bringing back the fun of the 80s
//
// (C) 2005-07 Rene Schickbauer, Wolfgang Dautermann
//
// See License.txt for licensing information
//


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef WIN32
#include <direct.h>
#else // NO WIN32
#include <dirent.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>


#include "globals.h"
#include "extractmetabmf.h"
#include "memops.h"
#include "debug.h"
#include "errorhandler.h"

#include "minilzo.h"
#include "bmfconvert.h"
#include "config.h"
#include "drawprimitives.h"
#include "bsscreen.h"

#define IN_LEN 10000000
#define IN_LEN 10000000
#define OUT_LEN 10000000

static unsigned char __LZO_MMODEL in  [ IN_LEN ];
static unsigned char __LZO_MMODEL out [ OUT_LEN ];

SDL_Surface* decrunchingbg = 0;

void initExtractMetaBMF() {
	decrunchingbg = BS_IMG_Load_DisplayFormat(configGetPath("decrunchingbg.png"),DIE_ON_FILE_ERROR);
}


bool extractMetaBMF(char* fname, bool preStartup) {
    int r;
    lzo_uint in_len;
    lzo_uint out_len = 0;
    lzo_uint new_len;

	char infname[MAX_FNAME_LENGTH];
	extractMetaBMFprogress(0, preStartup);

    in_len = IN_LEN;

	FILE* ifh = fopen(fname, "rb");
	if(!ifh) {
		printf("Can't open file %s for input\n", fname);
		return false;
	}
	Uint32 tmpnum;
	Uint32 bmftype;

	// Check magic number
	tmpnum = bmfReadInt(ifh);
	if(tmpnum != BMFTYPE_MAGIC) {
		DIE(ERROR_BMFMAGIC, fname);
	}

	bool running = true;
#ifndef WIN32
    DIR *tmpdir;
#endif
    FILE *ofh;
	while(running) {
		bmftype = bmfReadInt(ifh);
		switch(bmftype) {
			case BMFTYPE_VERSION:
				tmpnum = bmfReadInt(ifh);
				if(tmpnum != BMF_VERSION) {
					if(tmpnum == 1) {
						printf("Warning: Older (compatible) Version1 BMF found - continuing\n");
					} else {
						DIE(ERROR_BMFVERSION, fname);
					}
				}
				break;
			case BMFTYPE_DIR:
				tmpnum = bmfReadInt(ifh);
				if(!fread(infname, tmpnum, 1, ifh)) {
					DIE(ERROR_BMFEOF, fname);
				}
				infname[tmpnum] = 0;
				//printf("Installing directory '%s'\n", configGetPath(infname));
				MKDIR(configGetPath(infname));

				infname[0] = 0;
				break;
			case BMFTYPE_FILENAME:
				tmpnum = bmfReadInt(ifh);
				if(!fread(infname, tmpnum, 1, ifh)) {
					DIE(ERROR_BMFEOF, fname);
				}
				infname[tmpnum] = 0;
				//printf("Next file: %s\n", infname);
				break;
			case BMFTYPE_REGISTER_ADDON:
				tmpnum = bmfReadInt(ifh);
				if(!fread(infname, tmpnum, 1, ifh)) {
					DIE(ERROR_BMFEOF, fname);
				}
				infname[tmpnum] = 0;
				registerAddOn(infname);
				infname[0] = 0;
				break;
			case BMFTYPE_REGISTER_MUSIC:
				tmpnum = bmfReadInt(ifh);
				if(!fread(infname, tmpnum, 1, ifh)) {
					DIE(ERROR_BMFEOF, fname);
				}
				infname[tmpnum] = 0;
				registerMusic(infname);
				infname[0] = 0;
				break;
			case BMFTYPE_REGISTER_POSCAP:
				tmpnum = bmfReadInt(ifh);
				if(!fread(infname, tmpnum, 1, ifh)) {
					DIE(ERROR_BMFEOF, fname);
				}
				infname[tmpnum] = 0;
				registerPosCap(infname);
				infname[0] = 0;
				break;
			case BMFTYPE_METAFILE_COMPRESSED:
			case BMFTYPE_METAFILE_UNCOMPRESSED:
				if(strlen(infname) == 0) {
					printf("Got file without filename!!\n");
					DIE(ERROR_FILE_WRITE, "No filename!");
				} else {
					//printf("Installing file '%s'\n", configGetPath(infname));
				}
				in_len = bmfReadInt(ifh);
				if(!fread(in, in_len, 1, ifh)) {
					DIE(ERROR_BMFEOF, fname);
				}

				if(bmftype == BMFTYPE_METAFILE_UNCOMPRESSED) {
					// No compression, just memcopy to output area
					//printf("Uncompressed file %s with len %lu\n", infname, in_len);
					memcpy(out, in, in_len);
					out_len = in_len;
				} else {

					r = lzo1x_decompress(in,in_len,out,&new_len,NULL);
					if (r == LZO_E_OK) {
						/*
						printf("decompressed %lu bytes back into %lu bytes\n",
							(unsigned long) in_len, (unsigned long) new_len);
						*/

						out_len = new_len;

					}
					else
					{
						/* this should NEVER happen */
						DIE(ERROR_LZO, "decompression failed");
					}

				}

				// Write File
				ofh = fopen(configGetPath(infname), "wb");
				if(!ofh) {
					DIE(ERROR_FILE_WRITE, configGetPath(infname));
				}
				fwrite(out, out_len, 1, ofh);
				fclose(ofh);


				infname[0] = 0; // Delete fname so we don't overwrite
				break;

			case BMFTYPE_END_OF_FILE:
				running = false;
				break;

			default:
				printf("Unknown BMFTYPE %d...\n", bmftype);
				exit(1);
		}
	}

	fclose(ifh);

	return true;

}

void extractMetaBMFprogress(Uint32 progress, bool preStartup) {

     // Avoid compiler warning about unused argument  FIXME
     progress = 0;

	if(preStartup) {
		return;
	}
	// Lock Surface if needed
	if (SDL_MUSTLOCK(gScreen))
		if (SDL_LockSurface(gScreen) < 0)
			return;

	if (SDL_MUSTLOCK(decrunchingbg))
		if (SDL_LockSurface(decrunchingbg) < 0)
			return;


	Uint32 bigpitch = gScreen->pitch;
	Uint32 bigpitchBG = decrunchingbg->pitch;

	long fc_src_long = (long)decrunchingbg->pixels;
	long fc_dst_long = (long)gScreen->pixels;

	for(Uint32 j=0; j < SCR_HEIGHT; j++) {
		fc_src = (fastcopy *)fc_src_long;
		fc_dest = (fastcopy *)fc_dst_long;
		*fc_dest = *fc_src;
		fc_dst_long += bigpitch;
		fc_src_long += bigpitchBG;
	}

	/*
	// Progress BG
	blend_darkenRect(20, 250, 600, 50, 0x00a0a0a0);

	// Progress bar
	if(percent) {
		drawrect(20, 250, percent*6, 50, 0x909090);
	}

	// Progress outline
	drawrect(20, 250, 600, 1, 0xd0d0d0);
	drawrect(20, 250, 1, 50, 0xd0d0d0);
	drawrect(20, 300, 600, 1, 0xd0d0d0);
	drawrect(619, 250, 1, 50, 0xd0d0d0);
	*/


	// Unlock Surface if needed
	if (SDL_MUSTLOCK(decrunchingbg))
		SDL_UnlockSurface(decrunchingbg);
	if (SDL_MUSTLOCK(gScreen))
		SDL_UnlockSurface(gScreen);
	BS_Flip(gScreen); /* Update whole screen */
}


void deInitExtractMetaBMF() {
	SDL_FreeSurface(decrunchingbg);
	decrunchingbg = 0;
}

void registerAddOn(char *regStr) {
	char regLines[100][1000];
	memset(regLines, 0, sizeof(regLines));
	FILE* fh;
	char line[1000];
	char *tmp;
	Uint32 cnt = 0;
	bool found = false;
	fh = fopen(configGetPath("addons.dat"), "r");
	if(fh) {
		while(fgets(line, sizeof(line), fh)) {
			// Remove Comments and newline characters
			while((tmp = strchr(line, '\n'))) {
				*tmp = 0;
			}
			while((tmp = strchr(line, '\r'))) {
				*tmp = 0;
			}
			while((tmp = strchr(line, '#'))) {
				*tmp = 0;
			}

			if(line[0] == '\0') {
				// Ignore remark or empty line
				continue;
			}
			sprintf(regLines[cnt], "%s", line);
			cnt++;
		}
		fclose(fh);

		for(Uint32 i = 0; i < cnt; i++) {
			if(strcmp(regStr, regLines[i]) == 0) {
				found = true;
			}
		}
	}

	if(!found) {
		sprintf(regLines[cnt], "%s", regStr);
		cnt++;

		fh = fopen(configGetPath("addons.dat"), "w");
		if(!fh) {
			DIE(ERROR_FILE_WRITE, configGetPath("addons.dat"));
		}
		for(Uint32 i = 0; i < cnt; i++) {
			fprintf(fh, "%s\r\n", regLines[i]);
		}
		fclose(fh);
	}
	return;
}

void registerMusic(char *regStr) {
	char regLines[100][1000];
	memset(regLines, 0, sizeof(regLines));
	FILE* fh;
	char line[1000];
	char *tmp;
	Uint32 cnt = 0;
	bool found = false;
	fh = fopen(configGetPath("playersounds.dat"), "r");
	if(fh) {
		while(fgets(line, sizeof(line), fh)) {
			// Remove Comments and newline characters
			while((tmp = strchr(line, '\n'))) {
				*tmp = 0;
			}
			while((tmp = strchr(line, '\r'))) {
				*tmp = 0;
			}
			while((tmp = strchr(line, '#'))) {
				*tmp = 0;
			}

			if(line[0] == '\0') {
				// Ignore remark or empty line
				continue;
			}
			sprintf(regLines[cnt], "%s", line);
			cnt++;
		}
		fclose(fh);

		for(Uint32 i = 0; i < cnt; i++) {
			if(strcmp(regStr, regLines[i]) == 0) {
				found = true;
			}
		}
	}

	if(!found) {
		sprintf(regLines[cnt], "%s", regStr);
		cnt++;

		fh = fopen(configGetPath("playersounds.dat"), "w");
		if(!fh) {
			DIE(ERROR_FILE_WRITE, configGetPath("playersounds.dat"));
		}
		for(Uint32 i = 0; i < cnt; i++) {
			fprintf(fh, "%s\r\n", regLines[i]);
		}
		fclose(fh);
	}
	return;
}

void registerPosCap(char *regStr) {
	char regLines[100][1000];
	memset(regLines, 0, sizeof(regLines));
	FILE* fh;
	char line[1000];
	char *tmp;
	Uint32 cnt = 0;
	bool found = false;
	fh = fopen(configGetPath("poscaps.dat"), "r");
	if(fh) {
		while(fgets(line, sizeof(line), fh)) {
			// Remove Comments and newline characters
			while((tmp = strchr(line, '\n'))) {
				*tmp = 0;
			}
			while((tmp = strchr(line, '\r'))) {
				*tmp = 0;
			}
			while((tmp = strchr(line, '#'))) {
				*tmp = 0;
			}

			if(line[0] == '\0') {
				// Ignore remark or empty line
				continue;
			}
			sprintf(regLines[cnt], "%s", line);
			cnt++;
		}
		fclose(fh);

		for(Uint32 i = 0; i < cnt; i++) {
			if(strcmp(regStr, regLines[i]) == 0) {
				found = true;
			}
		}
	}

	if(!found) {
		sprintf(regLines[cnt], "%s", regStr);
		cnt++;

		fh = fopen(configGetPath("playersounds.dat"), "w");
		if(!fh) {
			DIE(ERROR_FILE_WRITE, configGetPath("playersounds.dat"));
		}
		for(Uint32 i = 0; i < cnt; i++) {
			fprintf(fh, "%s\r\n", regLines[i]);
		}
		fclose(fh);
	}
	return;
}
