// 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>

#include "globals.h"
#include "showvideo.h"
#include "memops.h"
#include "sound.h"
#include "debug.h"
#include "errorhandler.h"
#include "drawprimitives.h"

#include "minilzo.h"
#include "bmfconvert.h"
#include "joystick.h"
#include "engine.h"
#ifndef DISABLE_NETWORK
#include "blpstream.h"
#endif // DISABLE_NETWORK
#include "BlinkenMovie.h"
#include "bsscreen.h"

#define IN_LEN 10000000
#define OUT_LEN 10000000

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

void initShowVideo() {
	return;
}


bool showVideo(const char* fname, bool trackergui, bool allowstop) {
    int r;
    lzo_uint in_len;
    lzo_uint out_len = 0;
    lzo_uint new_len;
	Uint32 blinker = 100;
	SDL_RWops* rw;
	SDL_Surface *VIDEO_Surface;
	
	if(enableColor3D) {
		BS_Set3DMode(COLOR3D_NONE);
	}

	char fullfname[MAX_FNAME_LENGTH];
	char infname[MAX_FNAME_LENGTH];
	sprintf(fullfname, "%s", configGetPath(fname));

#ifndef DISABLE_NETWORK
	if (blpport != 0) {
		char blmfname[MAX_FNAME_LENGTH];
		sprintf(blmfname, "%s", configGetPath(fname));
		char *tmpblm = strstr(blmfname, ".bmf");
		if(!tmpblm) {
			printf("Can't prepare BLM video name %s\n", fullfname);
			return false;
		}
		sprintf(tmpblm, "%s", ".blm");
		initBLPMovie(blmfname);
	} ;
#endif // DISABLE_NETWORK

	in_len = IN_LEN;

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

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

	Uint32 fps = 0;
	Uint32 framecount = 0;
	Uint32 currframe = 0;
	bool firstFrame = true;
	Uint32 startticks = 0;
	Uint32 currticks = 0;

	bool running = true;
	while(running) {
		bmftype = bmfReadInt(ifh);
		switch(bmftype) {
			case BMFTYPE_VERSION:
				tmpnum = bmfReadInt(ifh);
				if(tmpnum != BMF_VERSION) {
					DIE(ERROR_BMFVERSION, fullfname);
				}
				break;
			case BMFTYPE_FPS:
				fps = bmfReadInt(ifh);
				//printf("FPS: %d\n", fps);
				break;
			case BMFTYPE_FRAMECOUNT:
				framecount = bmfReadInt(ifh);
				break;
			case BMFTYPE_WIDTH:
				tmpnum = bmfReadInt(ifh);
				if(tmpnum != SCR_WIDTH) {
					DIE(ERROR_BMFWIDTH, fullfname);
				}
				break;
			case BMFTYPE_HEIGHT:
				tmpnum = bmfReadInt(ifh);
				if(tmpnum != SCR_HEIGHT) {
					DIE(ERROR_BMFHEIGHT, fullfname);
				}
				break;
			case BMFTYPE_FILENAME:
				tmpnum = bmfReadInt(ifh);
				if(!fread(infname, tmpnum, 1, ifh)) {
					DIE(ERROR_BMFEOF, fullfname);
				}
				infname[tmpnum] = 0;
				//printf("Next file: %s\n", fname);
				break;
			case BMFTYPE_METAFILE_COMPRESSED:
			case BMFTYPE_METAFILE_UNCOMPRESSED:
				if(strlen(infname) == 0) {
					printf("Got file without filename!!\n");
				}
				in_len = bmfReadInt(ifh);
				if(!fread(in, in_len, 1, ifh)) {
					DIE(ERROR_BMFEOF, fullfname);
				}
				// Metafiles not yet supported, just skip'em
				break;
			case BMFTYPE_FRAME_COMPRESSED:
			case BMFTYPE_FRAME_UNCOMPRESSED:
			case BMFTYPE_SND_COMPRESSED:
			case BMFTYPE_SND_UNCOMPRESSED:
				if(strlen(infname) == 0) {
					printf("Got file without filename!!\n");
				}
				in_len = bmfReadInt(ifh);
				if(!fread(in, in_len, 1, ifh)) {
					DIE(ERROR_BMFEOF, fullfname);
				}

				if(bmftype == BMFTYPE_FRAME_UNCOMPRESSED ||
						bmftype == BMFTYPE_SND_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");
					}

				}

				// HANDLE FILE
				if(bmftype == BMFTYPE_FRAME_COMPRESSED ||
				   bmftype == BMFTYPE_FRAME_UNCOMPRESSED) {
					if(firstFrame) {
						firstFrame = false;
						startticks = BS_GetTicks();
						initFPSCounter();
					}
					currticks = BS_GetTicks();
					// Skip frame if we're too late already
					if(currticks > (startticks + (1000 * currframe) / fps)) {
						printf("Skipping frame %d...\n", currframe);
						currframe++;
						continue;
					}

#ifndef DISABLE_NETWORK
					if (blpport != 0) {
						showBLPMovie();
					} ;
#endif // DISABLE_NETWORK

					while(currticks < (startticks + (1000 * currframe) / fps)) {
						currticks = BS_GetTicks();
						SDL_Delay(1);
#ifndef DISABLE_NETWORK
						if (blpport != 0) {
							showBLPMovie(); // Call again, FPS of BLM might be higher than that of BMF
						} ;
#endif // DISABLE_NETWORK
					} ;
					currframe++;

					rw = SDL_RWFromMem(out, out_len);
					SDL_Surface* temp = IMG_Load_RW(rw, 0);
					if(!temp) {
						DIE(ERROR_IMAGE_READ, fullfname);
					}
					VIDEO_Surface = SDL_DisplayFormat(temp);
					SDL_FreeSurface(temp);

					// Timing: SDL_Delay may not be fine-grained enough, busy-loop here


					if (SDL_MUSTLOCK(VIDEO_Surface))
						if (SDL_LockSurface(VIDEO_Surface) < 0)
							return false;
					if (SDL_MUSTLOCK(gScreen))
						if (SDL_LockSurface(gScreen) < 0)
							return false;

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

					long fc_src_long = (long)VIDEO_Surface->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;
					}

					if(trackergui) {
						blinker = (blinker + 150/fps) % 250;
						if(blinker < 50) {
							blinker = 50;
						}

						Uint32 color = ((Uint32)blinker & 0xff) << 8;
						drawrect(10, 10, 620, 3, color);
						drawrect(10, 10, 3, 40, color);
						drawrect(627, 10, 3, 40, color);

						drawrect(10, 467, 620, 3, color);
						drawrect(10, 427, 3, 40, color);
						drawrect(627, 427, 3, 40, color);

					}

#ifndef CAVAC_RELEASEMODE
					displayFPSCounter();
#endif // NO CAVAC_RELEASEMODE

					// Unlock Surfaces if needed
					if (SDL_MUSTLOCK(gScreen))
						SDL_UnlockSurface(gScreen);
					if (SDL_MUSTLOCK(VIDEO_Surface))
						SDL_UnlockSurface(VIDEO_Surface);
					SDL_FreeSurface(VIDEO_Surface);
					// Tell SDL to update the whole screen
					BS_Flip(gScreen);
					//printf("Displaying %s\n", infname);
					//SDL_Delay(50);
				} else {
					// SOUND
					rw = SDL_RWFromMem(out, out_len);
					soundStartVideoFX(rw);
				}



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

			case BMFTYPE_END_OF_FILE:
				running = false;
				break;

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


		// Poll for events, and handle the ones we care about.
		Uint32 joymove = getJoystickMoves();
		if(allowstop && (joymove & JOYSTICK_JUMP || joymove & JOYSTICK_ACTION)) {
			running = false;
			attracktModeRunning = false;
		}
		SDL_Event event;
		while (SDL_PollEvent(&event))
		{
			switch (event.type)
			{
				case SDL_KEYDOWN:
					break;
				case SDL_KEYUP:
					// If escape is pressed, return (and thus, quit)
					if (allowstop && event.key.keysym.sym != SDLK_ESCAPE) {
						running = false;
						attracktModeRunning = false;

#ifdef ALLOW_BOSSKEY
					} else if (event.key.keysym.sym == SDLK_ESCAPE) {
						exit(0);
#endif // ALLOW_BOSSKEY
					}
					break;
				case SDL_QUIT:
					exit(0);
			}
		}



	}
	soundStopVideoFX();

	fclose(ifh);
#ifndef DISABLE_NETWORK
	if (blpport != 0) {
		deInitBLPMovie();
	} ;
#endif // DISABLE_NETWORK
	return true;

}

void deInitShowVideo() {
	return;
}
