PUSHS "Printer Variables", WRAM0[PRINTER_VARS_START]
vTooBusyForPrinter: db ; one if we're too busy to use the async thread for printer stuff
vPrinterState: db ; options: NONE, READY, ERROR, FULL, PRINTING
vPreviousPrinterState: db
def PS_NONE equ 0
def PS_READY equ 1
def PS_ERROR equ 2
def PS_FULL equ 3
def PS_PRINTING equ 4
vPrinterReturnValue: dw
vPrinterReturnValuePrevious: dw
vPrinterReturnValueChanged: db
vBuildingByte: dw
vPrinterIsReady: db

vPrinterRow: db
print vPrinterRow
vPrinterStart: db
POPS

CheckForPrinter:
  ld a, $F
  ld hl, ZEROES
  ld bc, 0
  call SendPacket
  ret


SendPacket:
  ; a should be the command byte
  ; hl shoulld point at data to send
  ; bc should be the length of data
  ; squashes de for the checksum.
  push af
  
  ld a, $88
  call SendByte
  ld a, $33
  call SendByte
  pop af
  ld d, 0
  ld e, a ; the checksum always starts with a vallue of whatever the command is 
  call SendByte
  ld a, $00 
  call SendByte
  ld a, c 
  call SendByte
  ld a, b
  call SendByte
  
  ld a, e
  add a, b
  ld e, a 
  ld a, d
  adc a, 0
  ld d, a 
  
  ld a, e
  add a, c 
  ld e, a 
  ld a, d 
  adc a, 0
  ld d, a
  
  ld a, b
  or a, c 
  jp z, .doneWithByteLoop
.byteLoop
  ld a, [hl]
  add a, e
  ld e, a 
  ld a, d
  adc a, 0
  ld d, a 
  
  ld a, [hl+]
  call SendByte
  dec bc
  ld a, b
  or a, c 
  jp nz, .byteLoop
.doneWithByteLoop
  
  ld a, e
  call SendByte
  
  ld a, d
  call SendByte
  
  ld a, $00
  call SendByte
  ld [vPrinterReturnValue], a 

  ld a, $00
  call SendByte
  ld [vPrinterReturnValue+1], a 
  
  call UpdatePrinterStatus
  ret

UpdatePrinterStatus:
;vPrinterState: db ; options: NONE, READY, ERROR, FULL, PRINTING
  ld a, PS_NONE
  ld [vPrinterState], a 
  ld a, [vPrinterReturnValue]
  cp a, $81
  ret nz ; if the alive byte isn't $81, return with PS_NONE
  
  ld a, PS_ERROR
  ld [vPrinterState], a 
  ld a, [vPrinterReturnValue+1]
  and a, $F0
  ret nz ; if the top nibble is non-zero, there's some error
  
  ld a, PS_FULL
  ld [vPrinterState], a 
  ld a, [vPrinterReturnValue+1]
  bit 2, a 
  ret nz ; if the FULL bit iis set then it's full\
  
  ld a, PS_PRINTING
  ld [vPrinterState], a 
  ld a, [vPrinterReturnValue+1]
  bit 1, a 
  ret nz ; if the printing bit is set then it's printing
  
  ld a, PS_READY
  ld [vPrinterState], a 
  ret ; if we didn't find any of the bits we check for, it's good to go


PrepNetwork:
  ld a, 0 
  ld [vPrinterStart], a 
  
  ld a, PS_NONE
  ld [vPreviousPrinterState], a 
  
  ld hl, rSC
  set 0, [hl] 
  ret 

SendByte:
; waits until the thing is free, then sends the byte in a. puts the receiived
; byte in a anad returns.
  push hl
  
  ld hl, rSC
  
  .waitForFree
    bit 7, [hl]
    jp nz, .waitForFree
  
  ld [rSB], a
  
  set 7, [hl] ; request transfer 
  
  .waitForResponse
    bit 7, [hl]
    jp nz, .waitForResponse
  
  ld a, [rSB]
  
  pop hl
  ret 
  
KickOffPrintJob:
  ld a, 1 
  ld [vBlocked], a 
  
  ld a, 1
  ld [vPrinterStart],a
  ld a, 0 
  ld [vPrinterRow], a

  call CardPrintPrep  
  call CardUpdate

  ret
  
RunPrintJob:
  ld a, [vPrinterStart]
  cp a, 0
  ret z
  
  ld a, [vPrinterRow] ; printer row holds the row of printing we're on; this
  ; combines the tile row of the card + borders and also when to wait for printing
  ; to finish. also later we use the register for 'whetther it's a row of the card'
  bit 0, a ; on even numbered printer rows just jump to the "wait for printable"
  ; routine. this should increase the printer row only if the printer is ready
  ; and return.
  jp z, WaitForPrintable
  
  cp a, 1 ; if the print row is 1, then we want the top border
  jp nz, :+
    call PlanTopRow
    call BuildRow
    set 7, a ; set bit 7 as a flaag thatt we've already taken one of these branches.
  :
  cp a, 35 ; if the print row is 35, we want the bottom border
  jp nz, :+
    call PlanBottomRow
    call BuildRow
    set 7, a 
  :
  cp a, 37 ; if the row is 37, we want to clear the buffer and reset
  jp nz, :+
    call ClearBuffer
    
    ld a, 0 
    ld [vBlocked], a 
    ld [vPrinterStart],a
    ld [vPrinterRow], a
    ld a, 1 
    ld [vPrinterIsReady], a
    
    ret ; don't finish sending the print if we're cleaning up.
  :
  bit 7, a ; if this bit was set by one of the previous branches, then
  ; we aren't drawing a row; otherwise the rest of a holds the printer row for
  ; a card row to draw
  jp nz, :+
    res 7, a ; get rid of that "drawing a row" bit
    srl a ; divide by two to get rid of the "drawing or waiting" bit
    dec a ; subtract one to get the row index into card space
    
    call PlanRowA
    call BuildRow
    
    ld b, 8 ; pre-increment so that when we pre-decrement in the loop later it works
    sla a 
    sla a 
    sla a
    add a, 24 ; multiply by 8 and add 24 to get from card tile space to sprite space
    add a, b ; start from the bottom row of these tiles, a*8 + 7
    ld c, a ; c holds the current scanline we're looking at for this inner loop
    .addSpriteLinesLoop
      dec c 
      
      ld a, c
      ld [vCurrentScanline], a
      call AddSpritesToLine
  
      dec b
      jp nz, .addSpriteLinesLoop
    .doneAddSpriteLinesLoop
  :
  
  call DoubleTheBuffer
  call PrintTheBuffer
  ld a, [vPrinterRow]
  inc a 
  ld [vPrinterRow], a
  ret
  
PlanTopRow:
  ; draw the top of a card as tile ids in buffer one
  ld hl, CardBrowse.UITilemap
  ld bc, 10
  ld de, BUFFER_ONE
  call CopyRange ; copy tiles for the top row to the first buffer
  ret
PlanRowA: ; a should be which row of a tile map we should draw
  push af
  
  ld de, BUFFER_ONE
  
  ld a, $0b
  ld [de], a
  inc de

  call FindCardTileMap ; now hl points at the beginning of the tile map
  
  pop af
  push af
  
  sla a
  sla a
  sla a ; multiply row number by 8 for the stride of the tile map
  ld b, 0
  ld c, a ; advance to the row we're looking for.
  add hl, bc
  ld b, 8
  :
    ld a, [hl+] 
    ld [de], a 
    inc de
    dec b
    jp nz, :-
  
  ld a, $0c
  ld [de], a 
  
  pop af
  
  ret
PlanBottomRow:
  ; draw the bottom of a card as tile ids in buffer one
  ld hl, CardBrowse.UITilemap + 20*17 ;
  ld bc, 10
  ld de, BUFFER_ONE
  call CopyRange ; copy tiles for the top row to the first buffer
  ret
  
BuildRow:
  ; assuming buffer one contains a sequence of ten tile IDs
  ; this writes the tile data for each of those tiles sequentially into BUFFER_TWO
  push af
  ld hl, BUFFER_ONE
  ld de, BUFFER_TWO
  ld c, 10
  .loop
    push bc
    ld a, [hl+] ; fetch a tile ID
    push hl
    ld hl, UITiles
    cp a, 26
    jp c, :+
      ; if the tile id is greater than 26, then we need to fetch from the card data
      sub a, 26 ; and undo the offset encoded into the tile map
      call FindCardKeyTiles
    :
    call FindTileData
    ; now hl points to tile data, de points to a spot in buffer 2
    ld bc, 16
    call CopyRange
    pop hl
    pop bc
    dec c
    jp nz, .loop
  pop af
  ret
DoubleTheBuffer:
  ld hl, BUFFER_TWO
  ld de, BUFFER_ONE
  
  ld a, 10
  .topHalfLoop
    push hl
    push af
    call WriteTopHalfDoubledTile
    pop af
    pop hl
    ld bc, 16
    add hl, bc
    dec a 
    jp nz, .topHalfLoop
    
  ld hl, BUFFER_TWO
  ld a, 10
  .bottomHalfLoop
    push hl
    push af
    ld bc, 8
    add hl, bc
    call WriteTopHalfDoubledTile
    pop af
    pop hl
    ld bc, 16
    add hl, bc
    dec a 
    jp nz, .bottomHalfLoop
  
  ret
PrintTheBuffer:
  call ClearBuffer
  
  ld a, 4 ; fill buffer
  ld hl, BUFFER_ONE
  ld bc, $280
  call SendPacket
  
  call SendEmpty
  
  call SendPrint
  ret


WaitForPrintable:
  ld a, $F
  ld hl, ZEROES
  ld bc, 0
  call SendPacket
  
   ; NONE, READY, ERROR, FULL, PRINTING
   
  ld a, [vPrinterState]
  cp a, PS_PRINTING
  ret z
  cp a, PS_ERROR
  ret z
  cp a, PS_NONE
  ret z
  
  call ClearBuffer
  
  ld a, [vPrinterState]
  cp a, PS_FULL
  ret z
  
  ld a, [vPrinterRow]
  inc a 
  ld [vPrinterRow], a 
  
  ret


SendEmpty:
  ld a, 4
  ld hl, ZEROES
  ld bc, 0
  call SendPacket
  ret
  

SendPrint:
  call SendEmpty

  ld hl, BUFFER_ONE
  ld a, 1 ; number of sheets
  ld [hl+], a
  ld a, $00 ; margins
  ld [hl+], a 
  ld a, $e4 ; palette
  ld [hl+], a 
  ld a, $7f ; exposure
  ld [hl+], a 
  
  ld a, 2 ; print
  ld hl, BUFFER_ONE
  ld bc, 4
  call SendPacket
  ret
  
  
ClearBuffer:
  ld a, $1
  ld hl, ZEROES
  ld bc, 0
  call SendPacket
  
  ret