// File: TNanukem[P]chip8-emulator/emulator.cpp
// Function: emulator::emulate(int, char**)
void emulator::emulate(int argc, char** argv){
    chip8 Chip8;
	display Display;

	// Intializes the Chip8 system and loads the game into memory
	Chip8.initialize();
	std::string load;

	// Handling the game input from command line
	if(argc >= 2)
		load = std::string("roms/") + argv[1];
	else load = std::string("roms/PONG");
	Chip8.loadGame(load);

	// Graphical System Initialization
	Display.displayInit();

	// Loading the audio file
	SDL_AudioSpec wavSpec;
	uint32_t wavLength;
	uint8_t *wavBuffer;

	SDL_LoadWAV("music/sound.wav", &wavSpec, &wavBuffer, &wavLength);

	// Opening the audio device
	SDL_AudioDeviceID deviceId = SDL_OpenAudioDevice(NULL, 0, &wavSpec, NULL, 0);

	// For the FPS count
	clock_t before = clock();
	double frameCount = 0;

	while(1){			// Emulation loop

		SDL_Event event;

		// Event loop -> This is what controls the keyboard inputs
		while(SDL_PollEvent(&event)){
			if(event.type == SDL_QUIT)		// Closes the window when the user clicks on the close button
				return;

			// Structure that pauses the game when the user presses the spacebar
			if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_SPACE){
				printf("Game Paused\n");

				std::this_thread::sleep_for(std::chrono::milliseconds(800));
				while(1){
					SDL_PollEvent(&event);
					if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_SPACE)
						break;
				}
				printf("Unpausing Game\n");
			}

			// Selects the load/save state SaveStateSlot
			if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_F1){
				if(SaveStateSlot == 3)
					SaveStateSlot = 0;
				else
					SaveStateSlot++;
				printf("Selected SaveStateSlot %d\n", SaveStateSlot);
			}

			// Saves the game on the selected SaveStateSlot
			if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_F2){
				printf("Saving the game on SaveStateSlot %d\n", SaveStateSlot);
				saveGame(SaveStateSlot, &Chip8, load);
			}

			// Loads the game from the selected SaveStateSlot
			if(event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_F3){
				printf("Loading the game from SaveStateSlot %d\n", SaveStateSlot);
				Chip8 = loadGame(SaveStateSlot, &Chip8, load);
			}

			// All the pressed keys options
			if(event.type == SDL_KEYUP){
				if(event.key.keysym.sym == SDLK_1)	Chip8.keyboard[0] = 0;
				if(event.key.keysym.sym == SDLK_2)	Chip8.keyboard[1] = 0;
				if(event.key.keysym.sym == SDLK_3)	Chip8.keyboard[2] = 0;
				if(event.key.keysym.sym == SDLK_4)	Chip8.keyboard[3] = 0;
				if(event.key.keysym.sym == SDLK_q)	Chip8.keyboard[4] = 0;
				if(event.key.keysym.sym == SDLK_w)	Chip8.keyboard[5] = 0;
				if(event.key.keysym.sym == SDLK_e)	Chip8.keyboard[6] = 0;
				if(event.key.keysym.sym == SDLK_r)	Chip8.keyboard[7] = 0;
				if(event.key.keysym.sym == SDLK_a)	Chip8.keyboard[8] = 0;
				if(event.key.keysym.sym == SDLK_s)	Chip8.keyboard[9] = 0;
				if(event.key.keysym.sym == SDLK_d)	Chip8.keyboard[10] = 0;
				if(event.key.keysym.sym == SDLK_f)	Chip8.keyboard[11] = 0;
				if(event.key.keysym.sym == SDLK_z)	Chip8.keyboard[12] = 0;
				if(event.key.keysym.sym == SDLK_x)	Chip8.keyboard[13] = 0;
				if(event.key.keysym.sym == SDLK_c)	Chip8.keyboard[14] = 0;
				if(event.key.keysym.sym == SDLK_v)	Chip8.keyboard[15] = 0;
			}

			// All the release keys options
			if(event.type == SDL_KEYDOWN){
				if(event.key.keysym.sym == SDLK_1)	Chip8.keyboard[0] = 1;
				if(event.key.keysym.sym == SDLK_2)	Chip8.keyboard[1] = 1;
				if(event.key.keysym.sym == SDLK_3)	Chip8.keyboard[2] = 1;
				if(event.key.keysym.sym == SDLK_4)	Chip8.keyboard[3] = 1;
				if(event.key.keysym.sym == SDLK_q)	Chip8.keyboard[4] = 1;
				if(event.key.keysym.sym == SDLK_w)	Chip8.keyboard[5] = 1;
				if(event.key.keysym.sym == SDLK_e)	Chip8.keyboard[6] = 1;
				if(event.key.keysym.sym == SDLK_r)	Chip8.keyboard[7] = 1;
				if(event.key.keysym.sym == SDLK_a)	Chip8.keyboard[8] = 1;
				if(event.key.keysym.sym == SDLK_s)	Chip8.keyboard[9] = 1;
				if(event.key.keysym.sym == SDLK_d)	Chip8.keyboard[10] = 1;
				if(event.key.keysym.sym == SDLK_f)	Chip8.keyboard[11] = 1;
				if(event.key.keysym.sym == SDLK_z)	Chip8.keyboard[12] = 1;
				if(event.key.keysym.sym == SDLK_x)	Chip8.keyboard[13] = 1;
				if(event.key.keysym.sym == SDLK_c)	Chip8.keyboard[14] = 1;
				if(event.key.keysym.sym == SDLK_v)	Chip8.keyboard[15] = 1;
			}
		}

		// Calls the next cycle, fetching, decoding and executing the next instruction in the memory
		Chip8.nextCycle();

		if(Chip8.drawFlag){

			// SDL_SetRenderDrawColor(render, 0x00, 0x00, 0x00, 0xFF);
			// SDL_RenderClear(render);
			// int changeLine = 0;
			// int changeColumn = 0;
			//
			// for(int i = 0; i < 32*64; i++){
			// 	if((i % 64) == 0){
			// 		changeLine += 9;
			// 		changeColumn = 0;
			// 	}
			// 	if(Chip8.display[i] == 1){
			// 		SDL_Rect fillRect = {changeColumn, changeLine, 10, 10};
			// 		SDL_SetRenderDrawColor(render, 0x00, 0xFF, 0x00, 0xFF);
			// 		SDL_RenderFillRect(render, &fillRect);
			// 	}
			// 	changeColumn += 9;
			// }
			// SDL_RenderPresent(render);

			Chip8.drawFlag = false;
			Display.displayDraw(Chip8.display);

			frameCount++;
			clock_t now = clock();
			float time = 100*(float)(now-before)/CLOCKS_PER_SEC;

			//printf("%f\n", time);
			// If a second has passed, update the FPS
			if(time >= 1.0){
				char title[255];

				snprintf(title, 255, "Chip8 Emulator - FPS: %3.3f", frameCount);
				Display.changeWindowName(title);
				before = now;
				frameCount = 0;
			}
		}
		if(Chip8.playSound)
			playSound(deviceId, wavBuffer, wavLength);
			Chip8.playSound = false;

		std::this_thread::sleep_for(std::chrono::milliseconds(1));
	}

	// Free every SDL structure allocated
	Display.displayDestroy();

	SDL_CloseAudioDevice(deviceId);
	SDL_FreeWAV(wavBuffer);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x63c0, %rsp           # imm = 0x63C0
movq %rdi, -0x8(%rbp)
movl %esi, -0xc(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x6388(%rbp)
leaq -0x3068(%rbp), %rdi
callq 0x4b80
leaq -0x3068(%rbp), %rdi
callq 0x2640
leaq -0x30a0(%rbp), %rdi
callq 0x2350
cmpl $0x2, -0xc(%rbp)
jl 0x413a
leaq -0x30e1(%rbp), %rdi
movq %rdi, -0x6390(%rbp)
callq 0x23f0
movq -0x6390(%rbp), %rdx
leaq 0x207a(%rip), %rsi      # 0x610a
leaq -0x30e0(%rbp), %rdi
callq 0x49b0
jmp 0x409e
movq -0x18(%rbp), %rax
movq 0x8(%rax), %rdx
leaq -0x30c0(%rbp), %rdi
leaq -0x30e0(%rbp), %rsi
callq 0x4ba0
jmp 0x40bb
leaq -0x30a0(%rbp), %rdi
leaq -0x30c0(%rbp), %rsi
callq 0x2310
leaq -0x30c0(%rbp), %rdi
callq 0x2190
leaq -0x30e0(%rbp), %rdi
callq 0x2190
leaq -0x30e1(%rbp), %rdi
callq 0x2280
jmp 0x41b9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30f0(%rbp)
movl %eax, -0x30f4(%rbp)
jmp 0x4129
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30f0(%rbp)
movl %eax, -0x30f4(%rbp)
leaq -0x30e0(%rbp), %rdi
callq 0x2190
leaq -0x30e1(%rbp), %rdi
callq 0x2280
jmp 0x48bd
leaq -0x3119(%rbp), %rdi
movq %rdi, -0x6398(%rbp)
callq 0x23f0
movq -0x6398(%rbp), %rdx
leaq 0x1fb5(%rip), %rsi      # 0x6110
leaq -0x3118(%rbp), %rdi
callq 0x49b0
jmp 0x4169
leaq -0x30a0(%rbp), %rdi
leaq -0x3118(%rbp), %rsi
callq 0x2310
leaq -0x3118(%rbp), %rdi
callq 0x2190
leaq -0x3119(%rbp), %rdi
callq 0x2280
jmp 0x41b9
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30f0(%rbp)
movl %eax, -0x30f4(%rbp)
leaq -0x3119(%rbp), %rdi
callq 0x2280
jmp 0x48bd
leaq -0x3140(%rbp), %rdi
leaq -0x30a0(%rbp), %rsi
callq 0x2150
jmp 0x41ce
leaq -0x3068(%rbp), %rdi
leaq -0x3140(%rbp), %rsi
callq 0x2760
jmp 0x41e3
leaq -0x3140(%rbp), %rdi
callq 0x2190
leaq -0x3080(%rbp), %rdi
callq 0x3870
jmp 0x41fd
leaq 0x1f16(%rip), %rdi      # 0x611a
leaq 0x1e35(%rip), %rsi      # 0x6040
callq 0x2140
movq %rax, -0x63a0(%rbp)
jmp 0x4219
movq -0x63a0(%rbp), %rdi
movl $0x1, %esi
leaq -0x3160(%rbp), %rdx
leaq -0x3170(%rbp), %rcx
leaq -0x3164(%rbp), %r8
callq 0x2100
jmp 0x4241
xorl %r8d, %r8d
movl %r8d, %ecx
leaq -0x3160(%rbp), %rdx
movq %rcx, %rdi
movl %r8d, %esi
callq 0x2300
movl %eax, -0x63a4(%rbp)
jmp 0x4261
movl -0x63a4(%rbp), %eax
movl %eax, -0x3174(%rbp)
callq 0x21a0
movq %rax, -0x3180(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x3188(%rbp)
jmp 0x4286
jmp 0x4288
leaq -0x31c0(%rbp), %rdi
callq 0x2180
movl %eax, -0x63a8(%rbp)
jmp 0x429c
movl -0x63a8(%rbp), %eax
cmpl $0x0, %eax
je 0x476a
cmpl $0x100, -0x31c0(%rbp)   # imm = 0x100
jne 0x4306
leaq -0x30a0(%rbp), %rdi
callq 0x2190
addq $0x63c0, %rsp           # imm = 0x63C0
popq %rbp
retq
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30f0(%rbp)
movl %eax, -0x30f4(%rbp)
jmp 0x48bd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30f0(%rbp)
movl %eax, -0x30f4(%rbp)
leaq -0x3140(%rbp), %rdi
callq 0x2190
jmp 0x48bd
cmpl $0x300, -0x31c0(%rbp)   # imm = 0x300
jne 0x4399
cmpl $0x20, -0x31ac(%rbp)
jne 0x4399
leaq 0x1e04(%rip), %rdi      # 0x612a
xorl %eax, %eax
callq 0x2080
jmp 0x432f
movl $0x320, -0x31cc(%rbp)   # imm = 0x320
leaq -0x31c8(%rbp), %rdi
leaq -0x31cc(%rbp), %rsi
callq 0x4ca0
jmp 0x434e
leaq -0x31c8(%rbp), %rdi
callq 0x4bf0
jmp 0x435c
jmp 0x435e
jmp 0x4360
leaq -0x31c0(%rbp), %rdi
callq 0x2180
jmp 0x436e
cmpl $0x300, -0x31c0(%rbp)   # imm = 0x300
jne 0x4385
cmpl $0x20, -0x31ac(%rbp)
jne 0x4385
jmp 0x4387
jmp 0x435e
leaq 0x1da9(%rip), %rdi      # 0x6137
xorl %eax, %eax
callq 0x2080
jmp 0x4397
jmp 0x4399
cmpl $0x300, -0x31c0(%rbp)   # imm = 0x300
jne 0x440a
cmpl $0x4000003a, -0x31ac(%rbp) # imm = 0x4000003A
jne 0x440a
movq -0x6388(%rbp), %rax
movzbl 0x3068(%rax), %eax
cmpl $0x3, %eax
jne 0x43d4
movq -0x6388(%rbp), %rax
movb $0x0, 0x3068(%rax)
jmp 0x43ea
movq -0x6388(%rbp), %rax
movb 0x3068(%rax), %cl
addb $0x1, %cl
movb %cl, 0x3068(%rax)
movq -0x6388(%rbp), %rax
movzbl 0x3068(%rax), %esi
leaq 0x1d48(%rip), %rdi      # 0x6147
xorl %eax, %eax
callq 0x2080
jmp 0x4408
jmp 0x440a
cmpl $0x300, -0x31c0(%rbp)   # imm = 0x300
jne 0x44c6
cmpl $0x4000003b, -0x31ac(%rbp) # imm = 0x4000003B
jne 0x44c6
movq -0x6388(%rbp), %rax
movzbl 0x3068(%rax), %esi
leaq 0x1d23(%rip), %rdi      # 0x6162
xorl %eax, %eax
callq 0x2080
jmp 0x4448
movq -0x6388(%rbp), %rax
movb 0x3068(%rax), %al
movb %al, -0x63a9(%rbp)
leaq -0x31f0(%rbp), %rdi
leaq -0x30a0(%rbp), %rsi
callq 0x2150
jmp 0x4470
movq -0x6388(%rbp), %rdi
movb -0x63a9(%rbp), %al
movzbl %al, %esi
leaq -0x3068(%rbp), %rdx
leaq -0x31f0(%rbp), %rcx
callq 0x3ae0
jmp 0x4495
leaq -0x31f0(%rbp), %rdi
callq 0x2190
jmp 0x44c6
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30f0(%rbp)
movl %eax, -0x30f4(%rbp)
leaq -0x31f0(%rbp), %rdi
callq 0x2190
jmp 0x48bd
cmpl $0x300, -0x31c0(%rbp)   # imm = 0x300
jne 0x45a1
cmpl $0x4000003c, -0x31ac(%rbp) # imm = 0x4000003C
jne 0x45a1
movq -0x6388(%rbp), %rax
movzbl 0x3068(%rax), %esi
leaq 0x1c8c(%rip), %rdi      # 0x6187
xorl %eax, %eax
callq 0x2080
jmp 0x4504
movq -0x6388(%rbp), %rax
movb 0x3068(%rax), %al
movb %al, -0x63aa(%rbp)
leaq -0x6260(%rbp), %rdi
leaq -0x30a0(%rbp), %rsi
callq 0x2150
jmp 0x452c
movq -0x6388(%rbp), %rsi
movb -0x63aa(%rbp), %al
movzbl %al, %edx
leaq -0x6240(%rbp), %rdi
leaq -0x3068(%rbp), %rcx
leaq -0x6260(%rbp), %r8
callq 0x3d30
jmp 0x4558
leaq -0x3068(%rbp), %rdi
leaq -0x6240(%rbp), %rsi
movl $0x304e, %edx           # imm = 0x304E
callq 0x2220
leaq -0x6260(%rbp), %rdi
callq 0x2190
jmp 0x45a1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x30f0(%rbp)
movl %eax, -0x30f4(%rbp)
leaq -0x6260(%rbp), %rdi
callq 0x2190
jmp 0x48bd
cmpl $0x301, -0x31c0(%rbp)   # imm = 0x301
jne 0x4683
cmpl $0x31, -0x31ac(%rbp)
jne 0x45be
movb $0x0, -0x2c(%rbp)
cmpl $0x32, -0x31ac(%rbp)
jne 0x45cb
movb $0x0, -0x2b(%rbp)
cmpl $0x33, -0x31ac(%rbp)
jne 0x45d8
movb $0x0, -0x2a(%rbp)
cmpl $0x34, -0x31ac(%rbp)
jne 0x45e5
movb $0x0, -0x29(%rbp)
cmpl $0x71, -0x31ac(%rbp)
jne 0x45f2
movb $0x0, -0x28(%rbp)
cmpl $0x77, -0x31ac(%rbp)
jne 0x45ff
movb $0x0, -0x27(%rbp)
cmpl $0x65, -0x31ac(%rbp)
jne 0x460c
movb $0x0, -0x26(%rbp)
cmpl $0x72, -0x31ac(%rbp)
jne 0x4619
movb $0x0, -0x25(%rbp)
cmpl $0x61, -0x31ac(%rbp)
jne 0x4626
movb $0x0, -0x24(%rbp)
cmpl $0x73, -0x31ac(%rbp)
jne 0x4633
movb $0x0, -0x23(%rbp)
cmpl $0x64, -0x31ac(%rbp)
jne 0x4640
movb $0x0, -0x22(%rbp)
cmpl $0x66, -0x31ac(%rbp)
jne 0x464d
movb $0x0, -0x21(%rbp)
cmpl $0x7a, -0x31ac(%rbp)
jne 0x465a
movb $0x0, -0x20(%rbp)
cmpl $0x78, -0x31ac(%rbp)
jne 0x4667
movb $0x0, -0x1f(%rbp)
cmpl $0x63, -0x31ac(%rbp)
jne 0x4674
movb $0x0, -0x1e(%rbp)
cmpl $0x76, -0x31ac(%rbp)
jne 0x4681
movb $0x0, -0x1d(%rbp)
jmp 0x4683
cmpl $0x300, -0x31c0(%rbp)   # imm = 0x300
jne 0x4765
cmpl $0x31, -0x31ac(%rbp)
jne 0x46a0
movb $0x1, -0x2c(%rbp)
cmpl $0x32, -0x31ac(%rbp)
jne 0x46ad
movb $0x1, -0x2b(%rbp)
cmpl $0x33, -0x31ac(%rbp)
jne 0x46ba
movb $0x1, -0x2a(%rbp)
cmpl $0x34, -0x31ac(%rbp)
jne 0x46c7
movb $0x1, -0x29(%rbp)
cmpl $0x71, -0x31ac(%rbp)
jne 0x46d4
movb $0x1, -0x28(%rbp)
cmpl $0x77, -0x31ac(%rbp)
jne 0x46e1
movb $0x1, -0x27(%rbp)
cmpl $0x65, -0x31ac(%rbp)
jne 0x46ee
movb $0x1, -0x26(%rbp)
cmpl $0x72, -0x31ac(%rbp)
jne 0x46fb
movb $0x1, -0x25(%rbp)
cmpl $0x61, -0x31ac(%rbp)
jne 0x4708
movb $0x1, -0x24(%rbp)
cmpl $0x73, -0x31ac(%rbp)
jne 0x4715
movb $0x1, -0x23(%rbp)
cmpl $0x64, -0x31ac(%rbp)
jne 0x4722
movb $0x1, -0x22(%rbp)
cmpl $0x66, -0x31ac(%rbp)
jne 0x472f
movb $0x1, -0x21(%rbp)
cmpl $0x7a, -0x31ac(%rbp)
jne 0x473c
movb $0x1, -0x20(%rbp)
cmpl $0x78, -0x31ac(%rbp)
jne 0x4749
movb $0x1, -0x1f(%rbp)
cmpl $0x63, -0x31ac(%rbp)
jne 0x4756
movb $0x1, -0x1e(%rbp)
cmpl $0x76, -0x31ac(%rbp)
jne 0x4763
movb $0x1, -0x1d(%rbp)
jmp 0x4765
jmp 0x4288
leaq -0x3068(%rbp), %rdi
callq 0x2870
jmp 0x4778
testb $0x1, -0x1c(%rbp)
je 0x4865
movb $0x0, -0x1c(%rbp)
leaq -0x2050(%rbp), %rsi
leaq -0x3080(%rbp), %rdi
callq 0x39c0
jmp 0x479b
movsd 0x194d(%rip), %xmm0     # 0x60f0
addsd -0x3188(%rbp), %xmm0
movsd %xmm0, -0x3188(%rbp)
callq 0x21a0
movq %rax, -0x6268(%rbp)
movq -0x6268(%rbp), %rax
subq -0x3180(%rbp), %rax
cvtsi2ss %rax, %xmm1
movss 0x1922(%rip), %xmm0     # 0x60fc
mulss %xmm1, %xmm0
movss 0x1912(%rip), %xmm1     # 0x60f8
divss %xmm1, %xmm0
movss %xmm0, -0x626c(%rbp)
movss -0x626c(%rbp), %xmm0
cvtss2sd %xmm0, %xmm0
movsd 0x18ea(%rip), %xmm1     # 0x60f0
ucomisd %xmm1, %xmm0
jb 0x4863
movsd -0x3188(%rbp), %xmm0
leaq 0x1994(%rip), %rdx      # 0x61af
leaq -0x6370(%rbp), %rdi
movq %rdi, -0x63b8(%rbp)
movl $0xff, %esi
movb $0x1, %al
callq 0x23b0
movq -0x63b8(%rbp), %rsi
leaq -0x3080(%rbp), %rdi
callq 0x3990
jmp 0x484a
movq -0x6268(%rbp), %rax
movq %rax, -0x3180(%rbp)
xorps %xmm0, %xmm0
movsd %xmm0, -0x3188(%rbp)
jmp 0x4865
testb $0x1, -0x1b(%rbp)
je 0x4887
movl -0x3174(%rbp), %edi
movq -0x3170(%rbp), %rsi
movl -0x3164(%rbp), %edx
callq 0x3fe0
jmp 0x4885
jmp 0x4887
movb $0x0, -0x1b(%rbp)
movl $0x1, -0x637c(%rbp)
leaq -0x6378(%rbp), %rdi
leaq -0x637c(%rbp), %rsi
callq 0x4ca0
jmp 0x48aa
leaq -0x6378(%rbp), %rdi
callq 0x4bf0
jmp 0x48b8
jmp 0x4284
leaq -0x30a0(%rbp), %rdi
callq 0x2190
movq -0x30f0(%rbp), %rdi
callq 0x23e0
nopw %cs:(%rax,%rax)
nop