#lang racket/base

; Renderer of a dungeon generated by Yggdrasil
; A renderer is a function that takes a cell 2d-array and an output stream.
;
; Default renderer: outputs a PNG looking-like maps of Etrian Odyssey
; Uses a tileset and a color to draw grid and walls.

(require
  "../../collection/2d-array.rkt"
  "cell.rkt"
  "../../graphics/image.rkt"
  )

(provide
  make-tile-renderer)

; Tileset
; From image path and tile size
(define (make-tileset path size)
  ; Function to define the tiles from their position
  ; (the sprite bank allows sprites of aribtrary sizes, arbitrary positioned in the image)
  (define (resize lst)
    (map
      (lambda (x)
        (cons
          (car x)
          (append
            (map (lambda (n) (* size n)) (cdr x))
            (list size size))))
      lst))
  ;
  (make-sprite-bank
    path
    (resize
      '((wall 0 0) (path 1 0) (staircase-down 2 0) (staircase-up 3 0)
        (shortcut-EW 0 1) (shortcut-WE 1 1) (shortcut-NS 2 1) (shortcut-SN 3 1)
        (event 0 2) (check 1 2) (chest 2 2) (door 3 2)
        (resource-chop 0 3) (resource-mine 1 3) (resource-take 2 3) (resource-harvest 3 3)))))

; Tile renderer structure
(struct tile-renderer
  (tile-size
   tileset
   grid-color))

; Drawing function
(define (draw-dungeon renderer dungeon output)
  (define pen-grid (make-pen (tile-renderer-grid-color renderer) 1))
  (define pen-wall (make-pen (tile-renderer-grid-color renderer) 3))
  (define cell-size (tile-renderer-tile-size renderer))
  (define image
    (make-image (* (2d-array-width dungeon) cell-size)
                (* (2d-array-height dungeon) cell-size)))
  ; Draw cells by type: path or wall
  (2d-array-for-each/indexes
    dungeon
    (lambda (cell i j)
      (image-draw-sprite!
        image
        (* i cell-size)
        (* j cell-size)
        (tile-renderer-tileset renderer)
        (if (yggdrasil-cell-blocker? cell)
            'wall
            'path))))
  ; Draw the grid
  (2d-array-for-each/indexes
    dungeon
    (lambda (cell i j)
      ; separator between (i,j) and (i+1,j)
      (when (2d-array-inside? dungeon (+ i 1) j)
        (define next-cell (2d-array-ref dungeon (+ i 1) j))
        (image-draw-line!
          image
          (* (+ i 1) cell-size)
          (* j cell-size)
          (* (+ i 1) cell-size)
          (* (+ j 1) cell-size)
          (if (eq? (yggdrasil-cell-type cell) (yggdrasil-cell-type next-cell))
              pen-grid
              pen-wall)))
      ; separator between (i,j) and (i,j+1)
      (when (2d-array-inside? dungeon i (+ j 1))
        (define next-cell (2d-array-ref dungeon i (+ j 1)))
        (image-draw-line!
          image
          (* i cell-size)
          (* (+ j 1) cell-size)
          (* (+ i 1) cell-size)
          (* (+ j 1) cell-size)
          (if (eq? (yggdrasil-cell-type cell) (yggdrasil-cell-type next-cell))
              pen-grid
              pen-wall)))
        ))
  ; Draw the features
  (2d-array-for-each/indexes
    dungeon
    (lambda (cell i j)
      (define feature (yggdrasil-cell-feature cell))
      (when feature
        (image-draw-sprite!
          image
          (* i cell-size)
          (* j cell-size)
          (tile-renderer-tileset renderer)
          feature))))
  ; Save image
  (image-save image output))

;
(define (make-tile-renderer tile-path tile-size grid-color)
  (define renderer
    (tile-renderer
      tile-size
      (make-tileset tile-path tile-size)
      grid-color))
  (lambda (dungeon output)
    (draw-dungeon renderer dungeon output)))
