// File: /workspace/github_cpp_makefile_star2_O1/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x20a8, %rsp           # imm = 0x20A8
cmpl $0x1, %edi
jg 0x2e50
leaq 0x1435(%rip), %rdi      # 0x427b
callq 0x22d0
jmp 0x310b
movq %rsi, %r14
movl $0x20, %edi
callq 0x21c0
testl %eax, %eax
je 0x2ec2
leaq 0xb0(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x1357(%rip), %rsi      # 0x41cb
leaq 0x1358(%rip), %rdx      # 0x41d3
leaq 0xa0(%rsp), %rdi
callq 0x3466
movq 0x3141(%rip), %rdi      # 0x5fd0
leaq 0xa0(%rsp), %rsi
callq 0x2d74
movq 0xa0(%rsp), %rdi
cmpq %r14, %rdi
je 0x310b
movq 0xb0(%rsp), %rsi
incq %rsi
callq 0x2210
jmp 0x310b
movq 0x8(%r14), %rdi
movl $0x2fff0000, %esi       # imm = 0x2FFF0000
movl $0x2fff0000, %edx       # imm = 0x2FFF0000
movl $0x280, %ecx            # imm = 0x280
movl $0x1e0, %r8d            # imm = 0x1E0
movl $0x20, %r9d
callq 0x2080
movq %rax, 0x18(%rsp)
testq %rax, %rax
je 0x2ff8
movq %rax, %rdi
movl $0xffffffff, %esi       # imm = 0xFFFFFFFF
movl $0x6, %edx
callq 0x2060
testq %rax, %rax
je 0x3038
movq %rax, %rbx
movq %rax, %rdi
movl $0x16362004, %esi       # imm = 0x16362004
movl $0x1, %edx
movl $0x40, %ecx
movl $0x20, %r8d
callq 0x2320
movq %rax, 0x20(%rsp)
testq %rax, %rax
je 0x30a1
movq %rbx, 0x28(%rsp)
leaq 0x1343(%rip), %rsi      # 0x428c
leaq 0xa0(%rsp), %r15
movl $0x88, %edx
movq %r15, %rdi
callq 0x21a0
leaq 0x128(%rsp), %rdx
leaq 0x16(%rsp), %rax
movq %rax, (%rsp)
leaq 0x30(%rsp), %rdi
leaq 0x68(%rsp), %r8
leaq 0x17(%rsp), %r9
movq %r15, %rsi
xorl %ecx, %ecx
callq 0x34f6
movq 0x8(%r14), %rsi
leaq 0x3279(%rip), %r15      # 0x620c
movq %r15, %rdi
callq 0x254a
testl %eax, %eax
movq 0x28(%rsp), %r14
je 0x3124
movq 0x3021(%rip), %rbx      # 0x5fd0
leaq 0x1248(%rip), %rsi      # 0x41fe
movl $0x1a, %edx
movq %rbx, %rdi
callq 0x2240
movq (%rbx), %rax
addq -0x18(%rax), %rbx
movq %rbx, %rdi
movl $0xa, %esi
callq 0x21e0
movsbl %al, %esi
movq 0x2fef(%rip), %rdi      # 0x5fd0
callq 0x2050
movl $0x1, %ebx
movq %rax, %rdi
callq 0x2130
jmp 0x336e
leaq 0xb0(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x11c9(%rip), %rsi      # 0x41d4
leaq 0x11ce(%rip), %rdx      # 0x41e0
leaq 0xa0(%rsp), %rdi
callq 0x3466
movq 0x2faa(%rip), %rdi      # 0x5fd0
leaq 0xa0(%rsp), %rsi
callq 0x2d74
jmp 0x2e9c
leaq 0xb0(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x1196(%rip), %rsi      # 0x41e1
leaq 0x119d(%rip), %rdx      # 0x41ef
leaq 0xa0(%rsp), %rdi
callq 0x3466
movq 0x2f6a(%rip), %rdi      # 0x5fd0
leaq 0xa0(%rsp), %rsi
callq 0x2d74
movq 0xa0(%rsp), %rdi
cmpq %r14, %rdi
je 0x3090
movq 0xb0(%rsp), %rsi
incq %rsi
callq 0x2210
movq 0x18(%rsp), %rdi
testq %rdi, %rdi
je 0x3106
callq 0x2040
jmp 0x3106
leaq 0x18(%rsp), %rsi
movq %rbx, %rdi
callq 0x33cd
leaq 0xb0(%rsp), %r14
movq %r14, -0x10(%r14)
leaq 0x112f(%rip), %rsi      # 0x41f0
leaq 0x1135(%rip), %rdx      # 0x41fd
leaq 0xa0(%rsp), %rdi
callq 0x3466
movq 0x2ef4(%rip), %rdi      # 0x5fd0
leaq 0xa0(%rsp), %rsi
callq 0x2d74
movq 0xa0(%rsp), %rdi
cmpq %r14, %rdi
je 0x3106
movq 0xb0(%rsp), %rsi
incq %rsi
callq 0x2210
callq 0x2090
movl $0x1, %ebx
movl %ebx, %eax
addq $0x20a8, %rsp           # imm = 0x20A8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x68(%rsp), %r12
movl $0x1, %ebx
leaq 0x10f7(%rip), %r13      # 0x422c
xorl %ebp, %ebp
testb $0x1, %bpl
jne 0x335a
movq %r15, %rdi
callq 0x2708
movq %r12, %rdi
callq 0x2120
testl %eax, %eax
je 0x32da
movl 0x68(%rsp), %eax
cmpl $0x100, %eax            # imm = 0x100
movzbl %bpl, %r14d
cmovel %ebx, %r14d
cmpl $0x300, %eax            # imm = 0x300
jne 0x321f
movslq 0x7c(%rsp), %rcx
movb $0x1, %bpl
cmpq $0x1b, %rcx
je 0x3222
movq 0x30(%rsp), %rdi
movq 0x38(%rsp), %r8
movq %rcx, %rax
xorl %edx, %edx
divq %r8
movq %rdx, %rsi
movq (%rdi,%rdx,8), %rdx
movl $0x0, %eax
testq %rdx, %rdx
je 0x31e2
movq (%rdx), %r9
movq %rdx, %rax
cmpl 0x8(%r9), %ecx
je 0x31e2
movq %r9, %r10
movq (%r9), %r9
testq %r9, %r9
je 0x31e0
movslq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
movl $0x0, %eax
cmpq %rsi, %rdx
jne 0x31e2
movq %r10, %rax
cmpl %edi, %ecx
jne 0x31b6
jmp 0x31e2
xorl %eax, %eax
testq %rax, %rax
je 0x31ec
movq (%rax), %rbp
jmp 0x31ee
xorl %ebp, %ebp
testq %rbp, %rbp
je 0x321f
movl 0x8(%rbp), %esi
leaq 0x101c(%rip), %rdi      # 0x4219
xorl %eax, %eax
callq 0x2070
movzbl 0xc(%rbp), %esi
movq %r13, %rdi
xorl %eax, %eax
callq 0x2070
movzbl 0xc(%rbp), %eax
movb $0x1, 0x801(%rax,%r15)
movl %r14d, %ebp
cmpl $0x301, 0x68(%rsp)      # imm = 0x301
jne 0x3149
movslq 0x7c(%rsp), %rcx
movq 0x30(%rsp), %rdi
movq 0x38(%rsp), %r8
movq %rcx, %rax
xorl %edx, %edx
divq %r8
movq %rdx, %rsi
movq (%rdi,%rdx,8), %rdx
movl $0x0, %eax
testq %rdx, %rdx
je 0x3290
movq (%rdx), %r9
movq %rdx, %rax
cmpl 0x8(%r9), %ecx
je 0x3290
movq %r9, %r10
movq (%r9), %r9
testq %r9, %r9
je 0x328e
movslq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
movl $0x0, %eax
cmpq %rsi, %rdx
jne 0x3290
movq %r10, %rax
cmpl %edi, %ecx
jne 0x3264
jmp 0x3290
xorl %eax, %eax
testq %rax, %rax
je 0x329a
movq (%rax), %r14
jmp 0x329d
xorl %r14d, %r14d
testq %r14, %r14
je 0x3149
movl 0x8(%r14), %esi
leaq 0xf8c(%rip), %rdi       # 0x423d
xorl %eax, %eax
callq 0x2070
movzbl 0xc(%r14), %esi
movq %r13, %rdi
xorl %eax, %eax
callq 0x2070
movzbl 0xc(%r14), %eax
movb $0x0, 0x801(%rax,%r15)
jmp 0x3149
cmpb $0x1, 0x2f2b(%rip)      # 0x620c
movq 0x28(%rsp), %r14
jne 0x334b
movb $0x0, 0x2f1d(%rip)      # 0x620c
xorl %eax, %eax
movzbl 0x1(%rax,%r15), %ecx
negl %ecx
orl $0xff000000, %ecx       # imm = 0xFF000000
movl %ecx, 0xa0(%rsp,%rax,4)
incq %rax
cmpq $0x800, %rax            # imm = 0x800
jne 0x32f1
movq 0x20(%rsp), %rdi
xorl %esi, %esi
leaq 0xa0(%rsp), %rdx
movl $0x100, %ecx            # imm = 0x100
callq 0x2180
movq %r14, %rdi
callq 0x21d0
movq %r14, %rdi
movq 0x20(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2230
movq %r14, %rdi
callq 0x20a0
movl $0x1, %edi
callq 0x2160
jmp 0x3137
leaq 0x18(%rsp), %rsi
movq %r14, %rdi
callq 0x33cd
callq 0x2090
xorl %ebx, %ebx
leaq 0x30(%rsp), %rdi
callq 0x33ec
jmp 0x3110
jmp 0x338f
jmp 0x33b1
jmp 0x33b8
jmp 0x338f
jmp 0x33b1
jmp 0x33b1
jmp 0x338f
jmp 0x33b1
jmp 0x33b8
movq %rax, %rbx
movq 0xa0(%rsp), %rdi
cmpq %r14, %rdi
je 0x33c5
movq 0xb0(%rsp), %rsi
incq %rsi
callq 0x2210
jmp 0x33c5
movq %rax, %rbx
jmp 0x33c5
jmp 0x33b8
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
callq 0x33ec
movq %rbx, %rdi
callq 0x2300