// File: /workspace/github_cpp_makefile_star2_O2/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 0x2d5c
leaq 0x1542(%rip), %rdi      # 0x4297
callq 0x22e0
jmp 0x2da5
movq %rsi, %r14
pushq $0x20
popq %rdi
callq 0x21e0
testl %eax, %eax
je 0x2dbc
leaq 0x1475(%rip), %rsi      # 0x41e7
leaq 0xa0(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x316c
movq 0x3245(%rip), %rdi      # 0x5fd0
leaq 0xa0(%rsp), %rsi
callq 0x2ce8
leaq 0xa0(%rsp), %rdi
callq 0x2100
pushq $0x1
popq %rbx
movl %ebx, %eax
addq $0x20a8, %rsp           # imm = 0x20A8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x8(%r14), %rdi
pushq $0x20
popq %r9
movl $0x2fff0000, %esi       # imm = 0x2FFF0000
movl $0x2fff0000, %edx       # imm = 0x2FFF0000
movl $0x280, %ecx            # imm = 0x280
movl $0x1e0, %r8d            # imm = 0x1E0
callq 0x2070
movq %rax, 0x18(%rsp)
testq %rax, %rax
je 0x2eb5
pushq $-0x1
popq %rsi
pushq $0x6
popq %rdx
movq %rax, %rdi
callq 0x2050
movq %rax, 0x28(%rsp)
testq %rax, %rax
je 0x2ee7
pushq $0x1
popq %rbx
pushq $0x40
popq %rcx
pushq $0x20
popq %r8
movq %rax, 0x10(%rsp)
movq %rax, %rdi
movl $0x16362004, %esi       # imm = 0x16362004
movl %ebx, %edx
callq 0x2320
movq %rax, 0x20(%rsp)
testq %rax, %rax
je 0x2f2d
leaq 0x146d(%rip), %rsi      # 0x42a8
leaq 0xa0(%rsp), %r15
movl $0x88, %edx
movq %r15, %rdi
callq 0x21b0
leaq 0x128(%rsp), %rdx
leaq 0xe(%rsp), %rax
movq %rax, (%rsp)
leaq 0x30(%rsp), %rdi
leaq 0x68(%rsp), %r8
leaq 0xf(%rsp), %r9
movq %r15, %rsi
xorl %ecx, %ecx
callq 0x3338
movq 0x8(%r14), %rsi
leaq 0x3387(%rip), %r15      # 0x620c
movq %r15, %rdi
callq 0x254a
testl %eax, %eax
je 0x2f82
movq 0x3134(%rip), %rdi      # 0x5fd0
leaq 0x1377(%rip), %rsi      # 0x421a
callq 0x2200
movq %rax, %rdi
callq 0x2110
jmp 0x3118
leaq 0x1334(%rip), %rsi      # 0x41f0
leaq 0xa0(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x316c
movq 0x30fb(%rip), %rdi      # 0x5fd0
leaq 0xa0(%rsp), %rsi
callq 0x2ce8
jmp 0x2d98
leaq 0x130f(%rip), %rsi      # 0x41fd
leaq 0xa0(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x316c
movq 0x30c9(%rip), %rdi      # 0x5fd0
leaq 0xa0(%rsp), %rsi
callq 0x2ce8
leaq 0xa0(%rsp), %rdi
callq 0x2100
movq 0x18(%rsp), %rdi
callq 0x31a7
jmp 0x2f78
leaq 0x28(%rsp), %rsi
leaq 0x18(%rsp), %rdx
xorl %edi, %edi
callq 0x31b1
leaq 0x12c7(%rip), %rsi      # 0x420c
leaq 0xa0(%rsp), %rdi
leaq 0x30(%rsp), %rdx
callq 0x316c
movq 0x3072(%rip), %rdi      # 0x5fd0
leaq 0xa0(%rsp), %rsi
callq 0x2ce8
leaq 0xa0(%rsp), %rdi
callq 0x2100
callq 0x2080
jmp 0x2da5
leaq 0x7c(%rsp), %r12
xorl %r14d, %r14d
leaq 0x68(%rsp), %r13
leaq 0x30(%rsp), %rbp
testb $0x1, %r14b
jne 0x3102
movq %r15, %rdi
callq 0x2692
xorl %r14d, %r14d
movq %r13, %rdi
callq 0x2130
testl %eax, %eax
je 0x307c
movl 0x68(%rsp), %eax
cmpl $0x100, %eax            # imm = 0x100
sete %cl
orb %cl, %r14b
cmpl $0x300, %eax            # imm = 0x300
jne 0x3025
movb $0x1, %cl
cmpl $0x1b, 0x7c(%rsp)
je 0x301e
movq %rbp, %rdi
movq %r12, %rsi
callq 0x376a
movq %rax, %rbx
testq %rax, %rax
je 0x301b
movl 0x8(%rbx), %esi
leaq 0x1240(%rip), %rdi      # 0x4235
xorl %eax, %eax
callq 0x2060
movzbl 0xc(%rbx), %esi
leaq 0x1241(%rip), %rdi      # 0x4248
xorl %eax, %eax
callq 0x2060
movzbl 0xc(%rbx), %eax
movb $0x1, 0x801(%rax,%r15)
movl %r14d, %ecx
movl 0x68(%rsp), %eax
movl %ecx, %r14d
cmpl $0x301, %eax            # imm = 0x301
jne 0x2fa9
movq %rbp, %rdi
movq %r12, %rsi
callq 0x376a
movq %rax, %rbx
testq %rax, %rax
je 0x2fa9
movl 0x8(%rbx), %esi
leaq 0x1208(%rip), %rdi      # 0x4259
xorl %eax, %eax
callq 0x2060
movzbl 0xc(%rbx), %esi
leaq 0x11e5(%rip), %rdi      # 0x4248
xorl %eax, %eax
callq 0x2060
movzbl 0xc(%rbx), %eax
movb $0x0, 0x801(%rax,%r15)
jmp 0x2fa9
cmpb $0x1, 0x3189(%rip)      # 0x620c
jne 0x30f5
movb $0x0, 0x3180(%rip)      # 0x620c
xorl %eax, %eax
cmpq $0x800, %rax            # imm = 0x800
je 0x30b0
movzbl 0x1(%rax,%r15), %ecx
negl %ecx
orl $0xff000000, %ecx       # imm = 0xFF000000
movl %ecx, 0xa0(%rsp,%rax,4)
incq %rax
jmp 0x308e
movq 0x20(%rsp), %rdi
xorl %esi, %esi
leaq 0xa0(%rsp), %rdx
movl $0x100, %ecx            # imm = 0x100
callq 0x2190
movq 0x10(%rsp), %rdi
callq 0x21f0
movq 0x28(%rsp), %rdi
movq %rdi, 0x10(%rsp)
movq 0x20(%rsp), %rsi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0x2250
movq 0x10(%rsp), %rdi
callq 0x2090
pushq $0x1
popq %rdi
callq 0x2170
jmp 0x2f94
leaq 0x18(%rsp), %rsi
movq 0x10(%rsp), %rdi
callq 0x31d2
callq 0x2080
xorl %ebx, %ebx
leaq 0x30(%rsp), %rdi
callq 0x31e4
jmp 0x2da8
jmp 0x3139
jmp 0x314b
jmp 0x3156
jmp 0x3139
jmp 0x314b
jmp 0x314b
jmp 0x3139
jmp 0x314b
jmp 0x3156
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
callq 0x2100
jmp 0x3163
movq %rax, %rbx
jmp 0x3163
jmp 0x3156
jmp 0x3156
jmp 0x3156
movq %rax, %rbx
leaq 0x30(%rsp), %rdi
callq 0x31e4
movq %rbx, %rdi
callq 0x2300
nop