bits 64
default rel

section .text

extern print
global entryPoint

entryPoint:
  push rbp
  mov rbp, rsp

  push rbx
  push r12
  push r13
  sub rsp, 32

  ; rax = reserved for math
  ; rdx = reserved for math

  ; rbx = value of current character of input string
  ; rcx = pointer to current character of input string
  ; r8  = return value for nextNumber
  ; r9  = first dimension
  ; r10 = second dimension
  ; r11 = third dimension
  ; r12 = total wrapping paper required
  ; r13 = total ribbon length required

  xor rdx, rdx
  xor r12, r12
  xor r13, r13

.nextLine:
  call .nextNumber
  mov r9, r8  ; save first dimension to r9
  call .nextNumber
  mov r10, r8 ; save second dimension to r10
  call .nextNumber
  mov r11, r8 ; save third dimension to r11

.sort1:        ; initiate bubble sort of the three dimensions (possible configurations 123; 132; 213; 231; 312; 321)
  cmp r9, r10  ; compare first pair of dimensions
  jb .sort2    ; if they are already sorted, skip ahead (123; 132; 231)
  xchg r9, r10 ; otherwise, swap the first pair (213->123; 312->132; 321->231)
.sort2:
  cmp r10, r11  ; compare last pair of dimensions
  jb .sort3     ; if they are already sorted, skip ahead (123)
  xchg r10, r11 ; otherwise, swap the last pair (132->123; 231->213)
.sort3:
  cmp r9, r10  ; compare first pair of dimensions again in case the smallest number started at the end and was moved to second position
  jb .sortEnd  ; if they are already sorted, skip ahead (123)
  xchg r9, r10 ; otherwise, swap the first pair (213->123)
.sortEnd:      ; at this point, the dimensions are sorted from smallest to largest in registers r9, r10, r11

  mov rax, 2
  mul r9
  mul r10
  add r12, rax ; add 2 * dim1 * dim2 to wrapping paper length

  mov rax, 2
  mul r9
  mul r11
  add r12, rax ; add 2 * dim1 * dim3 to wrapping paper length

  mov rax, 2
  mul r10
  mul r11
  add r12, rax ; add 2 * dim2 * dim3 to wrapping paper length

  mov rax, r9
  mul r10
  add r12, rax ; add square area of smallest side to wrapping paper length

  add r13, r9
  add r13, r9
  add r13, r10
  add r13, r10 ; add smallest perimeter to the ribbon length

  mov rax, r9
  mul r10
  mul r11
  add r13, rax ; add volume of the present to the ribbon length

  movzx rbx, byte [ rcx ] ; read current character
  cmp bl, 0               ; if we have not reached end of string yet,
  jne .nextLine           ; go read the next line

  lea rcx, [ print_wrapping_paper ]
  mov rdx, r12
  call print

  lea rcx, [ print_ribbon_length ]
  mov rdx, r13
  call print

  add rsp, 32
  pop r13
  pop r12
  pop rbx

  leave
  ret

.nextNumber:
  xor r8, r8 ; reset return value to zero

.nextDigit:
  movzx rbx, byte [ rcx ] ; read current character
  inc rcx                 ; move to next character

  cmp bl, '0'
  jb .nonDigitCharacter
  cmp bl, '9'
  ja .nonDigitCharacter

  mov rax, 10
  mul r8      ; shift digit accumulator by one decimal place
  mov r8, rax ; move multiplied result back to digit accumulator

  sub rbx, '0' ; convert ASCII to digit
  add r8, rbx  ; add digit to accumulator

  jmp .nextDigit

.nonDigitCharacter:
  ret ; return from nextNumber calls

section .data

print_wrapping_paper: db `Wrapping paper required: %d\n`, 0
print_ribbon_length:  db `Ribbon length required: %d\n`, 0