; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 2 of the License, or
; (at your option) any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
; GNU General Public License for more details.

; This script reads in a data file containing a list of 
; badge styles and people's names. For each person listed
; in the file, a PNG file is produced incorporating the 
; specified style.

; Each line of the data file either defines a style:
;   STYLE # "/full/path/to/stylefile.xcf"
; or a person's name in quotes (preceded by the style #):
;   # "Fred Flintstone"
;
; The style files should preferably be in XCF format because the topmost
; layer (typically transparent, but can contain a template for the text)
; of the image is used to determine the location and size of the text
; of the person's name (this layer is otherwise ignored). The name text
; is centered within the bounds of this topmost layer.
;
; Comments may be placed in the style file using the typical Scheme
; convention (ie, starting with a semi-colon and extending to the end of
; the line.
;
(define (sg-create-badges filename font fontsize% color)
  ;; Perform a crude search for the largest font that will fit within
  ;; the cell (this algorithm could be better!)
  ;
  (define (calc-fontsize text font fontsize% width height)
    (let* (
        (fontsize 6) ;; minimum possible fontsize
        (extents nil)
        (last-extents nil)
        (last-fontsize 3)
        (adjust 2)        
        )
      (set! extents (gimp-text-get-extents-fontname text fontsize PIXELS font))
      (set! width (* width fontsize% 0.01))
      (set! height (* height fontsize% 0.01))
      (while (and (<> last-fontsize fontsize) (not (equal? extents last-extents)))
        (if (or (> (car extents) width) (> (cadr extents) height))
          (begin 
            (set! fontsize last-fontsize)
            (set! adjust (+ (* (- adjust 1) 0.5) 1))
            )
          (begin
            (set! last-extents extents)
            (set! last-fontsize fontsize)
            )
          )
        (set! fontsize (truncate (* fontsize adjust)))
        (set! extents (gimp-text-get-extents-fontname text fontsize PIXELS font))
        )
      (max fontsize 6)
      )
    )
    
  ;; center-align layer with a base-layer
  (define (center-align base-layer layer)
    (let* (
        (anchor-x (car (gimp-drawable-offsets base-layer)))
        (anchor-y (cadr (gimp-drawable-offsets base-layer)))
        (width (car (gimp-drawable-width base-layer)))
        (height (car (gimp-drawable-height base-layer)))
        )
      (set! anchor-x (+ anchor-x (/ width 2)))
      (set! anchor-y (+ anchor-y (/ height 2)))
      (let* (
            (ref-x (car (gimp-drawable-offsets layer)))
            (ref-y (cadr (gimp-drawable-offsets layer)))
            (orig-x ref-x)
            (orig-y ref-y)
            (offset-x 0)
            (offset-y 0)
            )
        (set! width (car (gimp-drawable-width layer)))
        (set! height (car (gimp-drawable-height layer)))
        (set! ref-x (+ ref-x (/ width 2)))
        (set! ref-y (+ ref-y (/ height 2)))
        (set! offset-x (+ orig-x (- anchor-x ref-x)))
        (set! offset-y (+ orig-y (- anchor-y ref-y)))
        (gimp-layer-set-offsets layer offset-x offset-y)
        )
      )
    )
  ;; return a list of visible layers
  ;
  (define (visible-layers image)
    (let* (
        (layer's (vector->list (cadr (gimp-image-get-layers image))))
        (viewable's nil)
        )
      (while (pair? layer's)
        (when (= (car (gimp-drawable-get-visible (car layer's))) TRUE)
          (set! viewable's (cons (car layer's) viewable's))
          )
        (set! layer's (cdr layer's))
        )
      (unless (null? viewable's)
        (reverse viewable's)
        )
      )
    )
  (define (create-badge-layer image stylefile name font fontsize%)
    (let* (
        (visible's (visible-layers image))
        (layer's (vector->list (cadr (gimp-file-load-layers RUN-NONINTERACTIVE image stylefile))))
        (frame-layer (car layer's))
        (layer 0)
        (fontsize 0)
        (name-layer 0)
        )
      (set! layer's (reverse (cdr layer's)))
      (map (lambda (x) (gimp-drawable-set-visible x FALSE)) visible's)
      (map (lambda (x) (gimp-image-add-layer image x 0)) layer's)
      (set! layer (car (gimp-image-merge-visible-layers image EXPAND-AS-NECESSARY)))
      (gimp-image-add-layer image frame-layer 0)
      (set! fontsize (calc-fontsize name 
                                    font 
                                    fontsize% 
                                    (car (gimp-drawable-width frame-layer))
                                    (car (gimp-drawable-height frame-layer))
                                    ))
      (set! name-layer (car (gimp-text-fontname image -1 0 0 name 0 TRUE fontsize PIXELS font)))
      (center-align frame-layer name-layer)
      (gimp-image-remove-layer image frame-layer)
      (set! layer (car (gimp-image-merge-visible-layers image EXPAND-AS-NECESSARY)))
      (map (lambda (x) (gimp-drawable-set-visible x TRUE)) visible's)
      )
    )
    
  ;; ----------------------------------------------------------------------
  ;; Main processing start here
  ;
  (let* (
      (image (car (gimp-image-new 10 10 RGB)))
      (STYLE 0) ; "Keyword" indicating that line specifies a style # and stylefile
      (style-files (make-vector 0)) ; vector to store styles
      (inport (open-input-file filename))
      (object (read inport))
      (style-num 0)
      (name "")
      (tmp-vector 0)
      )
    (gimp-image-undo-disable image)
    (gimp-context-push)
    (gimp-context-set-foreground color)
    (while (not (eof-object? object))
      (set! style-num (eval object))
      (if (> style-num 0)
        (begin
          (set! name (read inport))
          (unless (eof-object? name)
            (create-badge-layer image 
                                (vector-ref style-files (- style-num 1))
                                name 
                                font 
                                fontsize%)
            (gimp-image-resize-to-layers image)
            )
          )
        (begin
          (set! style-num (read inport))
          (set! name (read inport))
          (if (> style-num (vector-length style-files))
            (begin
              (set! tmp-vector (make-vector style-num))
              (set! style-num (- style-num 1))
              (vector-set! tmp-vector style-num name)
              (set! style-num (vector-length style-files))
              (while (> style-num 0)
                (set! style-num (- style-num 1))
                (vector-set! tmp-vector  style-num (vector-ref style-files style-num))
                )
              (set! style-files tmp-vector)
              )
            (vector-set! style-files (- style-num 1) name)
            )
          )
        )
      (set! object (read inport))
      )
    (sg-mosaicize image (car (gimp-image-get-active-layer image)))
    (gimp-image-undo-enable image)
    (gimp-context-pop)
    (close-input-port inport)
    (gimp-display-new image)
    )
  )
                
        
(script-fu-register "sg-create-badges"
 "Create badges..."
 "Create badges based on file of names"
 "Saul Goode"
 "Saul Goode"
 "12/6/2009"
 ""
 SF-FILENAME    "Data file" "Badges/example.data"
 SF-FONT "Font" "Sans Bold"
 SF-ADJUSTMENT "Font Size (% of maximum)" '( 80 0 100 1 10 0 1)
 SF-COLOR "Color" '(0 0 0)
 )
(script-fu-menu-register "sg-create-badges"
  "<Image>/File"
  )
