#lang racket/base

; Model and generation of traits
(require
  racket/string
  "../../base-generation/category.rkt"
  "../../lang/english.rkt"
  "../../lang/case.rkt"
  "gender.rkt"
  "species.rkt"
  "geography.rkt")

(provide
  jsexpr->traits-generator
  traits-generate
  trait->string)

; Internally, it's a category generator
(struct traits-generator
  (categories))

(define (jsexpr->traits-generator js)
  (traits-generator
    (jsexpr->category-generator js)))

(define (traits-generate gen)
  (category-generate-dictionary (traits-generator-categories gen)))


; Return the corresponding accessor of gender
(define (gender-accessor name)
  (case (string->symbol name)
    ((title) gender-title)
    ((title-abbreviation) gender-title-abbreviation)
    ((subject) gender-subject)
    ((object) gender-object)
    ((genitive) gender-genitive)
    ((reflexive) gender-reflexive)
    (else (error "Invalid gender attribute: " name))))

; Return the corresponding predicate of species
(define (species-predicate name)
  (case (string->symbol name)
    ((restricted-to-endemic-areas?) species-restricted-to-endemic-areas?)
    ((generable-as-character?) species-generable-as-character?)
    ((citizen?) species-citizen?)
    ((pet?) species-pet?)
    ((wild?) species-wild?)
    ((vegetal?) species-vegetal?)
    ((mimic?) species-mimic?)
    ((mimic-genes-used?) species-mimic-genes-used?)
    (else (error "Invalid species predicate: " name))))

; Interpolate a trait into a string
; Each trait is a list of tokens
; The argument list is:
; trait: the trait to interpolate
; gender: the gender used to interpolate
; wordlist: a dictionary of words to use in interpolation
; nature-generator: a category generator
; species-database: the database of species
; geography-database: the database of geography loacations
(define (trait->string trait gender wordlist nature-generator species-database geography-database)
  ; Interpret a token
  (define (interpret-token token)
    (cond
      ((string? token)
       token)
      ((and (hash? token) (hash-has-key? token 'gender))
       ((gender-accessor (hash-ref token 'gender)) gender))
      ((and (hash? token) (hash-has-key? token 'verb))
       (english:3rd-person-of (hash-ref token 'verb) (gender-plural? gender)))
      ((and (hash? token) (hash-has-key? token 'undefined-article))
       (english:with-undefined-article (interpret-token (hash-ref token 'undefined-article))))
      ((and (hash? token) (hash-has-key? token 'plural))
       (english:plural-of (interpret-token (hash-ref token 'plural))))
      ((and (hash? token) (hash-has-key? token 'word))
       (hash-ref wordlist (string->symbol (hash-ref token 'word))))
      ((and (hash? token) (hash-has-key? token 'species))
       (species-name (species-database-random species-database (species-predicate (hash-ref token 'species)))))
      ((and (hash? token) (hash-has-key? token 'nature))
       (category-generate nature-generator))
      ((and (hash? token) (hash-has-key? token 'location))
       (place-name (geography-random-subplace geography-database "Floraverse")))
      (#t
        (error "Invalid token: " token))
      ))
  (string-append
    (case:upcase-1st
      (string-join
        (map interpret-token trait)
        " "))
    "."))
