#lang racket/base

; Notepad application
(provide
  make-notepad
  ; Media operations
  notepad-new-media notepad-update-media notepad-delete-media
  )

(require
  racket/port
  racket/string
  "notes.rkt"
  "media.rkt"
  "user.rkt"
  "stored-objects.rkt"
  )

; Definition of a notepad
; A notepad is described by a directory containing the following elements :
; - a 'notepad.db' file, containing the notepad sqlite database
; - a 'media' directory, containing files uploaded by the notepad authors

; The sqlite database contains :
; - a table of users
; - a table of cookies, to manage edition of notepad
; - a table of notes
; - a table of media
; - a table of parent/child relations for notes and media

; Notepad structure
(struct notepad
  (directory ; notepad directory
   repository ; repository for stored objects
  ))

; Create/open a notepad
(define (make-notepad dir)
  (define repo-path (string-append dir "/notepad.db"))
  (define repo (open-repository 'sqlite3 repo-path))
  (user-init-repository repo)
  (note-init-repository repo)
  (media-init-repository repo)
  (notepad
    dir
    repo))

; Media directory
(define (notepad-media-dir np)
  (string-append (notepad-directory np) "/media"))

; Get the type of media
; Return 'image, 'other or #f
(define (notepad-media-type np media)
  (cond
    ( (ormap (lambda (x) (string-suffix? media x)) '(".png" ".jpg" ".gif" ".jpeg" ".svg"))
      "image")
    ( #t
      "other")))

; Save a media
; Takes a filename and an input stream
(define (notepad-new-media np
          #:path path
          #:input-stream in
          #:name name
          #:author author
          #:public? public?)
  (define filepath (string-append (notepad-media-dir np) "/" path))
  (call-with-output-file
    filepath
    (lambda (out)
      (copy-port in out)
      (close-input-port in)
      (new-media
        #:name name
        #:file path
        #:type (notepad-media-type np path)
        #:author author
        #:public? public?))
    #:exists 'truncate/replace))

; Update a media - return #t if there is no error
(define (notepad-update-media np media
          #:path path
          #:name name
          #:author author
          #:public? public?)
  (cond
    ( (or (not path)
          (and path (equal? "" path) (string-contains? path "/"))
          (not name)
          (and name (equal? "" name)))
      ; Return KO
      #f)
    ( #t
      ; Move file
      (when (not (equal? path (media-file media)))
        (define media-dir (notepad-media-dir np))
        (rename-file-or-directory
          (string-append media-dir "/" (media-file media))
          (string-append media-dir "/" path)))
      ; Update metadata
      (update-media media
        #:name name
        #:file path
        #:type (media-type media)
        #:author author
        #:public? public?)
      ; Return OK
      #t)))

; Remove a media
(define (notepad-delete-media np media)
  ; Delete file
  (delete-file (string-append (notepad-media-dir np) "/" (media-file media)))
  ; Delete metadata
  (remove-media media))
