#lang racket/base
(require ffi/unsafe
         "../../syntax.rkt"
         "../../lock.rkt"
         racket/class
         racket/match
         "types.rkt"
         "utils.rkt"
         "widget.rkt"
         "queue.rkt"
         "stddialog.rkt"
         "../common/handlers.rkt"
         "../common/queue.rkt")

(provide 
 (protect-out file-selector))

(define _GtkFileChooserDialog _GtkWidget)
(define _GtkFileChooser (_cpointer 'GtkFileChooser))
(define _GtkFileChooserAction 
  (_enum (list 'open 'save 'select-folder 'create-folder)))

;; FIXME: really there are varargs here, but we don't need them for
;; our purposes
(define-gtk gtk_file_chooser_dialog_new 
  (_fun _string (_or-null _GtkWindow) 
        _GtkFileChooserAction
        _string _GtkResponse
        _string _GtkResponse
        (_or-null _pointer)
        -> _GtkFileChooserDialog))
;; FIXME - should really be _GtkDialog but no subtyping
(define-gtk gtk_dialog_run (_fun _GtkFileChooserDialog -> _int))
;; FIXME ;; these should really be _GtkFileChooser but no subtyping
(define-gtk gtk_file_chooser_get_filename 
  (_fun _GtkFileChooserDialog -> _gpath/free))
(define-gtk gtk_file_chooser_get_filenames
  (_fun _GtkFileChooserDialog -> (_GSList _gpath/free)))
(define-gtk gtk_file_chooser_set_current_name
  (_fun _GtkFileChooserDialog _path -> _void))
(define-gtk gtk_file_chooser_set_current_folder
  (_fun _GtkFileChooserDialog _path -> _void))
(define-gtk gtk_file_chooser_set_do_overwrite_confirmation
  (_fun _GtkFileChooserDialog _gboolean -> _void))
(define-gtk gtk_file_chooser_set_select_multiple
  (_fun _GtkFileChooserDialog _gboolean -> _void))

(define _GtkFileFilter (_cpointer 'GtkFileFilter))
(define-gtk gtk_file_filter_new (_fun -> _GtkFileFilter))
(define-gtk gtk_file_filter_set_name
  (_fun _GtkFileFilter _string -> _void))
(define-gtk gtk_file_filter_add_pattern
  (_fun _GtkFileFilter _string -> _void))

(define-gtk gtk_file_chooser_add_filter
  (_fun _GtkFileChooserDialog _GtkFileFilter -> _void))

(define (file-selector message directory filename 
                       extension ;; always ignored
                       filters style parent)
  (define type (car style)) ;; the rest of `style' is irrelevant on Gtk
  (define dlg (as-gtk-window-allocation
               (gtk_file_chooser_dialog_new 
                message (and parent (send parent get-gtk))
                (case type
                  [(dir) 'select-folder]
                  [(put) 'save]
                  [else 'open])
                "gtk-cancel" 'cancel
                ;; no stock names for "Select"
                (case type
                  [(dir) "Choose"]
                  [(put) "gtk-save"]
                  [(get) "gtk-open"]
                  [(multi) "Choose"])
                'accept
                #f)))
  (when (eq? 'multi type)
    (gtk_file_chooser_set_select_multiple dlg #t))
  (when filename
    (gtk_file_chooser_set_current_name dlg filename))
  (when directory
    (gtk_file_chooser_set_current_folder dlg directory))
  (when (eq? 'put type)
    (gtk_file_chooser_set_do_overwrite_confirmation dlg #t))
  (for ([f (in-list filters)])
    (match f
      [(list name glob)
       (let ([ff (gtk_file_filter_new)]
             [glob (if (equal? glob "*.*") "*" glob)])
         (gtk_file_filter_set_name ff (if (equal? glob "*")
                                          name
                                          (format "~a (~a)" name glob)))
         (gtk_file_filter_add_pattern ff glob)
         (gtk_file_chooser_add_filter dlg ff))]))
  (define ans (and (eq? 'accept (show-dialog dlg))
                   (if (eq? type 'multi)
                       (gtk_file_chooser_get_filenames dlg)
                       (gtk_file_chooser_get_filename dlg))))
  (gtk_widget_destroy dlg)
  ans)

(define-gtk gtk_main_iteration_do (_fun _gboolean -> _gboolean))
