// File: thanoskoutr[P]Chip-8-Emulator/main.cpp
// Function: main
int main (int argc, char **argv)
{
	/* Initialize the Chip8 system and load the game into the memory */
	if(argc < 2)
	{
	  printf("No ROM given...\n");
		return 1;
	}

	// First we need to start up SDL, and make sure it went ok
	if (SDL_Init(SDL_INIT_VIDEO) != 0)
	{
		logSDLError(std::cout, "SDL_Init");
		return 1;
	}
	// Now create a window with title "Hello World" at 100, 100 on the screen with w:640 h:480 and show it
	// Setup our window and renderer
	SDL_Window *window = SDL_CreateWindow(argv[1], SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, Screen_Width, Screen_Height, SDL_WINDOW_RESIZABLE);
	if (window == nullptr)
	{
		logSDLError(std::cout, "CreateWindow");
		return 1;
	}

	// Create a renderer that will draw to the window, -1 specifies that we want to load whichever
	// video driver supports the flags we're passing
	// Flags: SDL_RENDERER_ACCELERATED: We want to use hardware accelerated rendering
	// 				SDL_RENDERER_PRESENTVSYNC: We want the renderer's present function (update screen) to be
	// 				synchronized with the monitor's refresh rate
	SDL_Renderer *renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
	if (renderer == nullptr)
	{
		logSDLError(std::cout, "CreateRenderer");
		cleanup(window);
		SDL_Quit();
		return 1;
	}

	// To use a hardware accelerated texture for rendering we can create one
	SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
	if (texture == nullptr)
	{
		cleanup(texture, renderer, window);
		logSDLError(std::cout, "CreateTexture");
		SDL_Quit();
		return 1;
	}

	// Create a mapping of SDL keyboard symbols to CHIP-8 keypad codes
	std::unordered_map<int,unsigned char> keymap
	{
		{SDLK_1, 0x1}, {SDLK_2, 0x2}, {SDLK_3, 0x3}, {SDLK_4, 0xC},
		{SDLK_q, 0x4}, {SDLK_w, 0x5}, {SDLK_e, 0x6}, {SDLK_r, 0xD},
		{SDLK_a, 0x7}, {SDLK_s, 0x8}, {SDLK_d, 0x9}, {SDLK_f, 0xE},
		{SDLK_z, 0xA}, {SDLK_x, 0x0}, {SDLK_c, 0xB}, {SDLK_v, 0xF},
		{SDLK_ESCAPE, -1}
	};


  // Temporary pixel buffer for updating texture
  uint32_t pixels[2048];

  // Load Application
  if (chip8.loadApplication(argv[1]) != 0) // initialization included
	{
		std::cout << "Failed to Load Application" << std::endl;
		return 1;
	}

	// Our event structure
	SDL_Event e;
	// For tracking if we want to quit
	bool quit = false;

  // Emulation loop
	while (!quit)
	{
    chip8.emulateCycle();

		// Read any SDL events that occured
		while (SDL_PollEvent(&e))
		{
			//If user closes the window
			if (e.type == SDL_QUIT)
				quit = true;

			// If user presses any key
			if (e.type == SDL_KEYDOWN)
      {
        // If user presses ESC we exit
        if (e.key.keysym.sym == SDLK_ESCAPE)
          quit = true;
        else
        {
          // find if valid is key pressed and set to 1
          auto pressed_key = keymap.find(e.key.keysym.sym);
          if (pressed_key != keymap.end())
          {
            printf ("Pressed Key: 0x%X\n", pressed_key->first);
            printf ("Mapped to: 0x%X\n", pressed_key->second);
            chip8.key[pressed_key->second] = 1;
          }

        }
      }

      // If user releases any key
      if (e.type == SDL_KEYUP)
      {
        // find if valid is key pressed and set to 0
        auto released_key = keymap.find(e.key.keysym.sym);
        if (released_key != keymap.end())
        {
          printf ("Released Key: 0x%X\n", released_key->first);
          printf ("Mapped to: 0x%X\n", released_key->second);
          chip8.key[released_key->second] = 0;
        }

      }
		}

    // If draw occurred, redraw SDL screen
    if(chip8.drawFlag)
 	 {
     chip8.drawFlag = false;

     // Store pixels in temporary buffer
     for (int i = 0; i < SCREEN_SIZE; ++i)
     {
       unsigned char pixel = chip8.gfx[i];
       pixels[i] = (0x00FFFFFF * pixel) | 0xFF000000;
     }
     // Update SDL texture
     SDL_UpdateTexture(texture, NULL, pixels, SCREEN_WIDTH* sizeof(Uint32));
     // First clear the renderer
     SDL_RenderClear(renderer);
     // Draw the texture
     SDL_RenderCopy(renderer, texture, NULL, NULL);
     // Update the screen
     SDL_RenderPresent(renderer);
 	 }

   // Sleep to slow down emulation speed
   // std::this_thread::sleep_for(std::chrono::microseconds(1200));
   SDL_Delay(100/60);

	}

	// Clean up our objects and quit
	cleanup(renderer, window);
	SDL_Quit();

	return 0;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x2280, %rsp           # imm = 0x2280
movl $0x0, -0x4(%rbp)
movl %edi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
cmpl $0x2, -0x8(%rbp)
jge 0x39b9
leaq 0x3803(%rip), %rdi      # 0x71a9
movb $0x0, %al
callq 0x2060
movl $0x1, -0x4(%rbp)
jmp 0x411b
movl $0x20, %edi
callq 0x2210
cmpl $0x0, %eax
je 0x3a56
leaq -0x31(%rbp), %rdi
movq %rdi, -0x2228(%rbp)
callq 0x2390
movq -0x2228(%rbp), %rdx
leaq 0x37d0(%rip), %rsi      # 0x71ba
leaq -0x30(%rbp), %rdi
callq 0x4130
jmp 0x39f5
movq 0x65d4(%rip), %rdi      # 0x9fd0
leaq -0x30(%rbp), %rsi
callq 0x38f0
jmp 0x3a07
leaq -0x30(%rbp), %rdi
callq 0x2130
leaq -0x31(%rbp), %rdi
callq 0x2290
movl $0x1, -0x4(%rbp)
jmp 0x411b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3a48
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x30(%rbp), %rdi
callq 0x2130
leaq -0x31(%rbp), %rdi
callq 0x2290
jmp 0x4127
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movl $0x2fff0000, %edx       # imm = 0x2FFF0000
movl $0x280, %ecx            # imm = 0x280
movl $0x1e0, %r8d            # imm = 0x1E0
movl $0x20, %r9d
movl %edx, %esi
callq 0x2070
movq %rax, -0x50(%rbp)
cmpq $0x0, -0x50(%rbp)
jne 0x3b14
leaq -0x71(%rbp), %rdi
movq %rdi, -0x2230(%rbp)
callq 0x2390
movq -0x2230(%rbp), %rdx
leaq 0x371b(%rip), %rsi      # 0x71c3
leaq -0x70(%rbp), %rdi
callq 0x4130
jmp 0x3ab3
movq 0x6516(%rip), %rdi      # 0x9fd0
leaq -0x70(%rbp), %rsi
callq 0x38f0
jmp 0x3ac5
leaq -0x70(%rbp), %rdi
callq 0x2130
leaq -0x71(%rbp), %rdi
callq 0x2290
movl $0x1, -0x4(%rbp)
jmp 0x411b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3b06
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x70(%rbp), %rdi
callq 0x2130
leaq -0x71(%rbp), %rdi
callq 0x2290
jmp 0x4127
movq -0x50(%rbp), %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
movl $0x6, %edx
callq 0x2050
movq %rax, -0x80(%rbp)
cmpq $0x0, -0x80(%rbp)
jne 0x3be3
leaq -0xa1(%rbp), %rdi
movq %rdi, -0x2238(%rbp)
callq 0x2390
movq -0x2238(%rbp), %rdx
leaq 0x3679(%rip), %rsi      # 0x71d0
leaq -0xa0(%rbp), %rdi
callq 0x4130
jmp 0x3b65
movq 0x6464(%rip), %rdi      # 0x9fd0
leaq -0xa0(%rbp), %rsi
callq 0x38f0
jmp 0x3b7a
leaq -0xa0(%rbp), %rdi
callq 0x2130
leaq -0xa1(%rbp), %rdi
callq 0x2290
movq -0x50(%rbp), %rdi
callq 0x41e0
callq 0x2080
movl $0x1, -0x4(%rbp)
jmp 0x411b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3bd2
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0xa0(%rbp), %rdi
callq 0x2130
leaq -0xa1(%rbp), %rdi
callq 0x2290
jmp 0x4127
movq -0x80(%rbp), %rdi
movl $0x16362004, %esi       # imm = 0x16362004
movl $0x1, %edx
movl $0x40, %ecx
movl $0x20, %r8d
callq 0x23b0
movq %rax, -0xb0(%rbp)
cmpq $0x0, -0xb0(%rbp)
jne 0x3cce
movq -0xb0(%rbp), %rdi
leaq -0x80(%rbp), %rsi
leaq -0x50(%rbp), %rdx
callq 0x4210
leaq -0xd1(%rbp), %rdi
movq %rdi, -0x2240(%rbp)
callq 0x2390
movq -0x2240(%rbp), %rdx
leaq 0x3594(%rip), %rsi      # 0x71df
leaq -0xd0(%rbp), %rdi
callq 0x4130
jmp 0x3c59
movq 0x6370(%rip), %rdi      # 0x9fd0
leaq -0xd0(%rbp), %rsi
callq 0x38f0
jmp 0x3c6e
leaq -0xd0(%rbp), %rdi
callq 0x2130
leaq -0xd1(%rbp), %rdi
callq 0x2290
callq 0x2080
movl $0x1, -0x4(%rbp)
jmp 0x411b
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
jmp 0x3cbd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0xd0(%rbp), %rdi
callq 0x2130
leaq -0xd1(%rbp), %rdi
callq 0x2290
jmp 0x4127
leaq 0x3597(%rip), %rsi      # 0x726c
leaq -0x1a8(%rbp), %rdi
movq %rdi, -0x2250(%rbp)
movl $0x88, %edx
callq 0x21d0
movq -0x2250(%rbp), %rax
movq %rax, -0x120(%rbp)
movq $0x11, -0x118(%rbp)
leaq -0x1ab(%rbp), %rdi
movq %rdi, -0x2248(%rbp)
callq 0x4250
movq -0x2248(%rbp), %rcx
movq -0x120(%rbp), %rsi
movq -0x118(%rbp), %rdx
movq %rsp, %rax
movq %rcx, (%rax)
xorl %eax, %eax
movl %eax, %ecx
leaq -0x110(%rbp), %rdi
leaq -0x1a9(%rbp), %r8
leaq -0x1aa(%rbp), %r9
callq 0x4270
jmp 0x3d54
leaq -0x1ab(%rbp), %rdi
callq 0x42d0
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rsi
leaq 0x64ed(%rip), %rdi      # 0xa25c
callq 0x26e0
movl %eax, -0x2254(%rbp)
jmp 0x3d7c
movl -0x2254(%rbp), %eax
cmpl $0x0, %eax
je 0x3e0c
movq 0x623e(%rip), %rdi      # 0x9fd0
leaq 0x3454(%rip), %rsi      # 0x71ed
callq 0x2230
movq %rax, -0x2260(%rbp)
jmp 0x3da7
movq -0x2260(%rbp), %rdi
movq 0x620b(%rip), %rsi      # 0x9fc0
callq 0x2270
jmp 0x3dbc
movl $0x1, -0x4(%rbp)
movl $0x1, -0x21b4(%rbp)
jmp 0x410f
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x1ab(%rbp), %rdi
callq 0x42d0
jmp 0x4127
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x40(%rbp)
movl %eax, -0x44(%rbp)
leaq -0x110(%rbp), %rdi
callq 0x43e0
jmp 0x4127
movb $0x0, -0x21f1(%rbp)
movb -0x21f1(%rbp), %al
xorb $-0x1, %al
testb $0x1, %al
jne 0x3e24
jmp 0x40e8
leaq 0x6431(%rip), %rdi      # 0xa25c
callq 0x28c0
jmp 0x3e32
jmp 0x3e34
leaq -0x21f0(%rbp), %rdi
callq 0x2120
movl %eax, -0x2264(%rbp)
jmp 0x3e48
movl -0x2264(%rbp), %eax
cmpl $0x0, %eax
je 0x4014
cmpl $0x100, -0x21f0(%rbp)   # imm = 0x100
jne 0x3e6a
movb $0x1, -0x21f1(%rbp)
cmpl $0x300, -0x21f0(%rbp)   # imm = 0x300
jne 0x3f48
cmpl $0x1b, -0x21dc(%rbp)
jne 0x3e8f
movb $0x1, -0x21f1(%rbp)
jmp 0x3f46
leaq -0x21dc(%rbp), %rsi
leaq -0x110(%rbp), %rdi
callq 0x42f0
movq %rax, -0x2270(%rbp)
jmp 0x3eab
movq -0x2270(%rbp), %rax
movq %rax, -0x2200(%rbp)
leaq -0x110(%rbp), %rdi
callq 0x4350
movq %rax, -0x2208(%rbp)
leaq -0x2200(%rbp), %rdi
leaq -0x2208(%rbp), %rsi
callq 0x4320
testb $0x1, %al
jne 0x3ee5
jmp 0x3f44
leaq -0x2200(%rbp), %rdi
callq 0x4380
movl (%rax), %esi
leaq 0x330e(%rip), %rdi      # 0x7208
xorl %eax, %eax
callq 0x2060
jmp 0x3f03
leaq -0x2200(%rbp), %rdi
callq 0x4380
movzbl 0x4(%rax), %esi
leaq 0x3301(%rip), %rdi      # 0x721b
xorl %eax, %eax
callq 0x2060
jmp 0x3f23
leaq -0x2200(%rbp), %rdi
callq 0x4380
movzbl 0x4(%rax), %eax
movl %eax, %ecx
leaq 0x6320(%rip), %rax      # 0xa25c
movb $0x1, 0x801(%rax,%rcx)
jmp 0x3f46
jmp 0x3f48
cmpl $0x301, -0x21f0(%rbp)   # imm = 0x301
jne 0x400f
leaq -0x21dc(%rbp), %rsi
leaq -0x110(%rbp), %rdi
callq 0x42f0
movq %rax, -0x2278(%rbp)
jmp 0x3f74
movq -0x2278(%rbp), %rax
movq %rax, -0x2210(%rbp)
leaq -0x110(%rbp), %rdi
callq 0x4350
movq %rax, -0x2218(%rbp)
leaq -0x2210(%rbp), %rdi
leaq -0x2218(%rbp), %rsi
callq 0x4320
testb $0x1, %al
jne 0x3fae
jmp 0x400d
leaq -0x2210(%rbp), %rdi
callq 0x4380
movl (%rax), %esi
leaq 0x3269(%rip), %rdi      # 0x722c
xorl %eax, %eax
callq 0x2060
jmp 0x3fcc
leaq -0x2210(%rbp), %rdi
callq 0x4380
movzbl 0x4(%rax), %esi
leaq 0x3238(%rip), %rdi      # 0x721b
xorl %eax, %eax
callq 0x2060
jmp 0x3fec
leaq -0x2210(%rbp), %rdi
callq 0x4380
movzbl 0x4(%rax), %eax
movl %eax, %ecx
leaq 0x6257(%rip), %rax      # 0xa25c
movb $0x0, 0x801(%rax,%rcx)
jmp 0x400f
jmp 0x3e34
testb $0x1, 0x6241(%rip)      # 0xa25c
je 0x40d7
movb $0x0, 0x6234(%rip)      # 0xa25c
movl $0x0, -0x221c(%rbp)
cmpl $0x800, -0x221c(%rbp)   # imm = 0x800
jge 0x4088
movslq -0x221c(%rbp), %rcx
leaq 0x6210(%rip), %rax      # 0xa25c
movb 0x1(%rax,%rcx), %al
movb %al, -0x221d(%rbp)
movzbl -0x221d(%rbp), %eax
imull $0xffffff, %eax, %ecx   # imm = 0xFFFFFF
orl $0xff000000, %ecx       # imm = 0xFF000000
movslq -0x221c(%rbp), %rax
movl %ecx, -0x21b0(%rbp,%rax,4)
movl -0x221c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x221c(%rbp)
jmp 0x4032
movq -0xb0(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
leaq -0x21b0(%rbp), %rdx
movl $0x100, %ecx            # imm = 0x100
callq 0x21a0
jmp 0x40a6
movq -0x80(%rbp), %rdi
callq 0x2220
jmp 0x40b1
movq -0x80(%rbp), %rdi
movq -0xb0(%rbp), %rsi
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rdx
callq 0x22d0
jmp 0x40ca
movq -0x80(%rbp), %rdi
callq 0x2090
jmp 0x40d5
jmp 0x40d7
movl $0x1, %edi
callq 0x2180
jmp 0x40e3
jmp 0x3e13
movq -0x80(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x43b0
jmp 0x40f7
callq 0x2080
jmp 0x40fe
movl $0x0, -0x4(%rbp)
movl $0x1, -0x21b4(%rbp)
leaq -0x110(%rbp), %rdi
callq 0x43e0
movl -0x4(%rbp), %eax
addq $0x2280, %rsp           # imm = 0x2280
popq %rbp
retq
movq -0x40(%rbp), %rdi
callq 0x2380