#lang racket/base

; Model and generation of elemental affinities
(provide
  ; elements collection functions
  jsexpr->elements
  elements-ref elements-combination-table
  ; Element structure accessors
  element-name element-affinity-description
  element-nouns element-adjectives
  combined-element? combined-element-components
  )

; Element structure
(struct element
  (name
   affinity-description
   nouns
   adjectives))

; Combined element structure
(struct combined-element element
  (components))

; Construction of an Element from a json expression
(define (jsexpr->element js)
  (element
    (hash-ref js 'name)
    (hash-ref js 'affinity-description)
    (hash-ref js 'related-nouns)
    (hash-ref js 'related-adjectives)))

; Construction of a Combined Element from a json expression
(define (jsexpr->combined-element js)
  (define result (hash-ref js 'result))
  (combined-element
    (hash-ref result 'name)
    (hash-ref result 'affinity-description)
    (hash-ref result 'related-nouns)
    (hash-ref result 'related-adjectives)
    (hash-ref js 'components)))

; A collection of elements
(struct elements
  (none
   primary
   secondary
   tertiary
   all
   combination-table))

; From json
(define (jsexpr->elements js)
  (define ret
    (elements
      (jsexpr->element (hash-ref js 'none))
      (map jsexpr->element (hash-ref js 'primary))
      (map jsexpr->combined-element (hash-ref js 'secondary))
      (map jsexpr->combined-element (hash-ref js 'tertiary))
      (make-hash)
      (make-hash)))
  ; Populate the table of all elements
  (define (add-element el)
    (hash-set! (elements-all ret) (element-name el) el))
  (add-element (elements-none ret))
  (for-each add-element (elements-primary ret))
  (for-each add-element (elements-secondary ret))
  (for-each add-element (elements-tertiary ret))
  ; Populate the table of combinations
  (define (add-combinations el)
    (hash-set! (elements-combination-table ret) (combined-element-components el) (element-name el)))
  (for-each add-combinations (elements-secondary ret))
  (for-each add-combinations (elements-tertiary ret))
  ;
  ret)

; Get an element from its name
(define (elements-ref elms name)
  (hash-ref (elements-all elms) name))
