#!@GUILE@ \
-e main
!#

;;; fossdem.scm -- Read FOSDEM schedule in iCalendar format.

;; Copyright (C) 2017 Artyom V. Poptsov <poptsov.artyom@gmail.com>
;;
;; 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 3 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.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program.  If not, see <http://www.gnu.org/licenses/>.


;;; Commentary:

;; Read FOSDEM [1] schedule in iCalendar format and print it to stdout in
;; org-mode format.
;;
;; [1] https://fosdem.org/

;;; Code:

(use-modules (ice-9 popen)
             (ice-9 getopt-long)
             ((srfi srfi-1)
              #:select (delete-duplicates fold))
             (srfi srfi-41)             ; streams
             ;; Guile-ICS
             (ics)
             (ics conv)
             (ics type object)
             (ics type property))

;;;


(define %option-spec
  '((help (single-char #\h) (value #f))
    (year (single-char #\y) (value #t))
    (categories (single-char #\c) (value #f))
    (speakers   (single-char #\s) (value #f))))

;;;

(define (print-schedule year)
  "Print FOSDEM schedule in org-mode format to stdout."
  ;; We have to use 'curl' because 'http-get' from (web client) does
  ;; not work with HTTPS.
  (let* ((command (format #f "curl 'https://fosdem.org/~a/schedule/ical'"
                          year))
         (p       (open-input-pipe command)))
    (stream-for-each ics-object->org-mode (ics->stream p))))


;;;

(define (map-uniq proc lst)
  (fold (lambda (elem prev)
          (if (assoc-ref prev elem)
              (assoc-set! prev elem (+ (assoc-ref prev elem) 1))
              (assoc-set! prev elem 1)))
        '()
        (map proc lst)))

(define (query year property-name)
  (let* ((command (format #f "curl 'https://fosdem.org/~a/schedule/ical'"
                          year))
         (p       (open-input-pipe command))
         (ics-object (car (ics->scm p))))
    (fold
     (lambda (component prev)
       (let ((property (ics-object-property-ref component property-name)))
         (if property
             (cons property prev)
             prev)))
     '()
     (ics-object-components ics-object))))

(define (query-properties-value year property-name)
  (map-uniq ics-property-value (query year property-name)))

(define (query-properties-param year property-name param-name)
  (map-uniq (lambda (property)
              (ics-property-parameter-ref property param-name))
            (query year property-name)))

(define (print-list name lst)
  "Print a list LST with a NAME in the org-mode format."
  (format #t "* ~a~%" name)
  (for-each (lambda (elem) (format #t "  - ~a~%" elem)) lst))

(define (print-categories year)
  "Print FOSDEM schedule categories in org-mode format to stdout."
  (print-list "CATEGORIES"
              (map (lambda (elem)
                     (format #f "~a: ~a" (car elem) (cdr elem)))
                   (query-properties-value year "CATEGORIES"))))

(define (print-speakers year)
  "Print FOSDEM schedule speakers in org-mode format to stdout."
  (print-list "SPEAKERS" (map car (query-properties-param year "ATTENDEE"
                                                          'CN))))


;;;

(define (current-year)
  "Get current year."
  (+ 1900 (tm:year (localtime (current-time)))))

(define (print-help-and-exit)
  (display "\
Usage: fosdem [options]

Options:
  --help, -h                 Print this message and exit.
  --year, -y <year>          Set year (current year is used by default.)
  --categories, -c           Print talk categories.
")
  (exit 0))


;;; Entry point.

(define (main args)
  (setlocale LC_ALL "")
  (let* ((options      (getopt-long args %option-spec))
         (help-needed? (option-ref options 'help #f))
         (year         (option-ref options 'year (current-year)))
         (categories?  (option-ref options 'categories #f))
         (speakers?    (option-ref options 'speakers   #f)))
    (when help-needed?
      (print-help-and-exit))
    (cond
     (categories?
      (print-categories year))
     (speakers?
      (print-speakers year))
     (else
      (print-schedule year)))))

;;;

;; Local Variables:
;; Mode: Scheme
;; End:

;;; fosdem.scm ends here.
