#include <stdio.h>
#include <allegro.h>

#include "structs.h"
#include "text.h"
#include "common.h"
#include "obj01.h"



char PlayDemo(signed char d){
	char demo_players;
	char demo_flags;
	//int demo_size;
	int i;
	
	if(frame != 1){
		return 1;	// temporary
	}
	
	if(!titlecard_sequence_end){
		return 1;
	}
	
	if(demo_mode == 1){
		if(DemoPosition == 0 && DemoFile == NULL){
			DemoFile = fopen(demo_file_list[d], "rb");
			#ifdef ENABLE_SRAM_LOG_ANALYSIS
			SRAMFile = fopen(sram_file_list[d], "rb");
			#endif
			if(DemoFile != NULL){
				fseek(DemoFile, 0, SEEK_END);
				demo_size = ftell(DemoFile);
				#ifdef ENABLE_SRAM_LOG_ANALYSIS
				fseek(SRAMFile, 0, SEEK_END);
				sram_size = ftell(SRAMFile);
				#endif
				if(demo_size >= 6){
					if(demodata) free(demodata);
					demodata = (char *)malloc(demo_size);
					fseek(DemoFile, 0, SEEK_SET);
					
					fread(demodata, 1, demo_size, DemoFile);
					
					fclose(DemoFile);
					DemoFile = 0;
					DemoPosition = 6;
					
					#ifdef ENABLE_SRAM_LOG_ANALYSIS
					if(sramdata) free(sramdata);
					sramdata = (char *)malloc(sram_size);
					fseek(SRAMFile, 0, SEEK_SET);
					
					fread(sramdata, 1, sram_size, SRAMFile);
					
					fclose(SRAMFile);
					SRAMFile = 0;
					SRAMPosition = 4;
					#endif
				}
				else{
					allegro_message("\"%s\" not found!", demo_file_list[d]);
					demo_mode = 0;
					fclose(DemoFile);
					DemoFile = 0;
					demo_size = 0;
					
					#ifdef ENABLE_SRAM_LOG_ANALYSIS
					if(SRAMFile)
						fclose(SRAMFile);
					SRAMFile = 0;
					sram_size = 0;
					#endif
					
					return -1;
				}
			}
			else{
				//allegro_message("No demo data for \"%s\"!", demo_file_list[d]);
				//demo_mode = 0;
				demo_number++;
				demo_number %= 10;
				
				#ifdef ENABLE_SRAM_LOG_ANALYSIS
				if(SRAMFile)
					fclose(SRAMFile);
				#endif
				
				return -1;
			}
		}
		
		if(DemoPosition==6){
			demo_players = (demodata[0] & 3) + 1;
			demo_flags = demodata[0] >> 4;
			DemoCount = *(unsigned short *)(&demodata[2]);
			zone = demodata[4];
			act = demodata[5] & 7;
			stage = (demodata[5] >> 4) & 3;
			
			#ifdef ENABLE_SRAM_LOG_ANALYSIS
			SRAMCount = *(unsigned short *)(&sramdata[0]);
			SRAMCount = (SRAMCount >> 8) | (SRAMCount << 8);
			sram_start = *(unsigned short *)(&sramdata[2]);
			sram_start = (sram_start >> 8) | (sram_start << 8);
			SRAMPosition = 4;
			#endif
			
			if(demo_flags & 1){
				for(i=0; i < demo_players; i++){
					// demodata[6+(i*5)] is the character
					p->x_pos = (demodata[7+(i*5)] << 8) + demodata[8+(i*5)];
					p->y_pos = (demodata[9+(i*5)] << 8) + demodata[10+(i*5)];
				}
				DemoPosition += (i*5);
			}
			else{
				for(i=0; i < demo_players; i++){
					// demodata[6+i] is the character
					;
				}
				DemoPosition += i;
			}
			
			ResetSound();
			
			LoadZone(&z, zone_file_list[zone]);
			InitDraw(&z);
			AllocateObjects(&z);
			CreateBlockLayout(&z);
			
			// SET UP THE CELL DATA
			num_of_cells = z.FILTERCOMPOSITE[0];
			num_of_filters = z.FILTERCOMPOSITE[1];
			cells_ptr = *(short *)&z.FILTERCOMPOSITE[2];
			filters_ptr = *(short *)&z.FILTERCOMPOSITE[4];
			bg_rgb_color = *(short *)&z.FILTERCOMPOSITE[6];
			filter_a = z.FILTERCOMPOSITE[8];
			filter_b = z.FILTERCOMPOSITE[9];
			filter_a_speed = z.FILTERCOMPOSITE[10];
			filter_b_speed = z.FILTERCOMPOSITE[11];
			
			cell_data = (CELL*)(&z.FILTERCOMPOSITE[cells_ptr]);
			
			for(i=0; i < 4; i++){
				player[i] = init_player;
				
				player[i].x_pos = z.Act[act].Stage[stage].StartX[0];
				player[i].y_pos = z.Act[act].Stage[stage].StartY[0];
				player[i].Camera_X_pos = p->x_pos - (screen_resolution_x >> 1);
				player[i].Camera_Y_pos = p->y_pos - (screen_resolution_y >> 1) + 0x10;
				player[i].Camera_Min_X_pos = z.Act[act].Stage[stage].LevelXL;
				player[i].Camera_Max_X_pos = z.Act[act].Stage[stage].LevelXR;
				player[i].Camera_Min_Y_pos = z.Act[act].Stage[stage].LevelYT;
				player[i].Camera_Max_Y_pos = z.Act[act].Stage[stage].LevelYB;
				player[i].Camera_Max_Y_pos_now = z.Act[act].Stage[stage].LevelYB;
				player[i].Camera_Y_pos_bias = 0x60;
				
				player[i].render_flags |= 0x80;
				
				player[i].Ring_count = 0;
			}
			Timer_minute = 0;
			Timer_second = 0;
			Timer_millisecond = 0;
			
			titlecard_sequence_end = 0;
			
			strcpy(TextBuffer, "ProSonic - ");
			strcat(TextBuffer, z.LevelName1);
			strcat(TextBuffer, " ZONE");
			set_window_title(TextBuffer);
			
			RunFunction(4);
		}
		
		else if(DemoPosition > 6){
			if(DemoCount <= DemoFadeDelay*24 && DemoCount % DemoFadeDelay == 0){
				fade_count -= 4;
			}
			if(DemoCount > 1){		// Do not make this 0
				p->CtrlInput = demodata[DemoPosition];
				DemoPosition++;
				DemoCount--;
				
				#ifdef ENABLE_SRAM_LOG_ANALYSIS
				//if(ticCounterL >= sram_start){
					sram_master_key = sramdata[SRAMPosition];
					SRAMPosition++;
					SRAMCount--;
					for(i=0; i < 8; i++){
						sram_segment_key[i] = 0;
						if(sram_master_key & (0x80 >> i)){
							sram_segment_key[i] = sramdata[SRAMPosition];
							SRAMPosition++;
							SRAMCount--;
						}
					}
					for(i=0; i < 8; i++){
						for(n=0; n < 8; n++){
							if(sram_segment_key[i] & (0x80 >> n)){
								sram_frame[(i << 3) + n] = sramdata[SRAMPosition];
								SRAMPosition++;
								SRAMCount--;
							}
						}
					}
				//}
				#endif
			}
			if(DemoCount == 1){		// Do not make this 0
				DemoPosition = 0;
				demo_mode = 0;
				free(demodata);
				demodata = 0;
				demo_size = 0;
				demo_number++;
				DemoFile = 0;
				if(demo_number >= 3)
					demo_number = 0;
				
				#ifdef ENABLE_SRAM_LOG_ANALYSIS
				SRAMPosition = 0;
				if(sramdata)
					free(sramdata);
				sram_size = 0;
				SRAMFile = 0;
				#endif
			}
		}
	}
	
	return 0;
}



void RecordDemo(signed char d){
	char demo_players;
	char demo_flags;
	int i;
	
	if(frame != 1) return;	// temporary
	
	if(!titlecard_sequence_end) return;
	
	d &= 0xF;
	
	if(demo_mode == 2){
		if(DemoPosition == 0 && DemoFile == NULL){
			DemoFile = fopen(demo_file_list[d], "w+b");
			if(DemoFile != NULL){
				demo_size = 6;
				if(demodata) free(demodata);
				demodata = (char *)malloc(demo_size);
				DemoPosition = 6;
				DemoCount = 0;
			}
			else{
				allegro_message("No demo data!");
				demo_mode = 0;
			}
		}
		
		if(DemoPosition==6){
			demodata[0] = 0;	// 000000pp		(players)
			demodata[1] = 0;	// 00000000		(unused!)
			demodata[4] = zone;	// zzzzzzzz		(zone)
			demodata[5] = (stage << 4) + act;	// 00ss0aaa		(stage/act)
			
			DemoPosition++;
			demodata = (char *)realloc(demodata, DemoPosition);
			demodata[6] = 0;
			
			LoadZone(&z, zone_file_list[zone]);
			InitDraw(&z);
			AllocateObjects(&z);
			CreateBlockLayout(&z);
			
			// SET UP THE CELL DATA
			num_of_cells = z.FILTERCOMPOSITE[0];
			num_of_filters = z.FILTERCOMPOSITE[1];
			cells_ptr = *(short *)&z.FILTERCOMPOSITE[2];
			filters_ptr = *(short *)&z.FILTERCOMPOSITE[4];
			bg_rgb_color = *(short *)&z.FILTERCOMPOSITE[6];
			filter_a = z.FILTERCOMPOSITE[8];
			filter_b = z.FILTERCOMPOSITE[9];
			filter_a_speed = z.FILTERCOMPOSITE[10];
			filter_b_speed = z.FILTERCOMPOSITE[11];
			
			cell_data = (CELL*)(&z.FILTERCOMPOSITE[cells_ptr]);
			
			for(i=0; i < 4; i++){
				player[i] = init_player;
				
				player[i].x_pos = z.Act[act].Stage[stage].StartX[0];
				player[i].y_pos = z.Act[act].Stage[stage].StartY[0];
				player[i].Camera_X_pos = p->x_pos - (screen_resolution_x >> 1);
				player[i].Camera_Y_pos = p->y_pos - (screen_resolution_y >> 1) + 0x10;
				player[i].Camera_Min_X_pos = z.Act[act].Stage[stage].LevelXL;
				player[i].Camera_Max_X_pos = z.Act[act].Stage[stage].LevelXR;
				player[i].Camera_Min_Y_pos = z.Act[act].Stage[stage].LevelYT;
				player[i].Camera_Max_Y_pos = z.Act[act].Stage[stage].LevelYB;
				player[i].Camera_Max_Y_pos_now = z.Act[act].Stage[stage].LevelYB;
				player[i].Camera_Y_pos_bias = 0x60;
				
				player[i].Ring_count = 0;
			}
			Timer_minute = 0;
			Timer_second = 0;
			Timer_millisecond = 0;
			
			titlecard_sequence_end = 0;
			
			RunFunction(4);
		}
		
		else if(DemoPosition > 6){
			DemoPosition++;
			DemoCount++;
			demodata = (char *)realloc(demodata, DemoPosition);
			demodata[DemoPosition-1] = p->CtrlInput;
		}
	}
	
	else if(demo_mode == 3){
		*(short *)(&demodata[2]) = DemoCount;
		//for(DemoPosition=0; DemoPosition < DemoCount + 6; DemoPosition++)
		//	fwrite(&demodata[DemoPosition], 1, 1, DemoFile);
		fwrite(demodata, 1, DemoCount + 6, DemoFile);
		
		DemoPosition = 0;
		demo_mode = 0;
		free(demodata);
		demodata = 0;
		demo_size = 0;
		fclose(DemoFile);
		DemoFile = 0;
	}
}
