#lang racket/base
(require racket/class
         ffi/unsafe
         ffi/unsafe/objc
         "../../syntax.rkt"
         "types.rkt"
         "utils.rkt"
         "cg.rkt"
         "window.rkt"
         "procs.rkt"
         "liquid-glass.rkt")

(provide 
 (protect-out panel%
              panel-mixin

              FrameView
              frame-black
              frame-white))

(import-class NSView NSGraphicsContext)

(define-objc-class RacketPanelView NSView
  #:mixins (KeyMouseTextResponder CursorDisplayer)
  [wxb])

(define frame-black (if liquid-glass? 0.7 0))
(define frame-white (if liquid-glass? 0.5 0.8))

(define-objc-class FrameView NSView 
  []
  (-a #:async-apply (box (void))
      _void (drawRect: [_NSRect r])
      (let ([wob? (white-on-black-panel-scheme?)]
            [ctx (tell NSGraphicsContext currentContext)])
        (tellv ctx saveGraphicsState)
        (let ([cg (tell #:type _CGContextRef ctx graphicsPort)]
              [r (tell #:type _NSRect self bounds)])
          (cond
            [wob?
             (CGContextSetRGBFillColor cg 0 0 0 1.0)
             (CGContextSetRGBStrokeColor cg frame-white frame-white frame-white 1.0)]
            [else
             (CGContextSetRGBFillColor cg 1.0 1.0 1.0 1.0)
             (CGContextSetRGBStrokeColor cg frame-black frame-black frame-black 1.0)])
          (CGContextAddRect cg r)
          (CGContextStrokePath cg))
        (tellv ctx restoreGraphicsState))))

(define (panel-mixin %)
  (class %
    (inherit register-as-child on-new-child
             is-window-enabled? get-cocoa)

    (define lbl-pos 'horizontal)
    (define children null)

    (super-new)
    
    (define/public (get-label-position) lbl-pos)
    (define/public (set-label-position pos) (set! lbl-pos pos))

    (define/public (adopt-child p)
      ;; in atomic mode
      (send p set-parent this))

    (define/override (fix-dc)
      (super fix-dc)
      (for ([child (in-list children)])
        (send child fix-dc)))

    (define/override (hide-children)
      (for ([child (in-list children)])
        (send child hide-children)))

    (define/override (show-children)
      (for ([child (in-list children)])
        (send child show-children)))

    (define/override (fixup-locations-children)
      (for ([child (in-list children)])
        (send child fixup-locations-children)))
    
    (define/override (paint-children)
      (for ([child (in-list children)])
        (send child paint-children)))

    (define/override (children-accept-drag on?)
      (for ([child (in-list children)])
        (send child child-accept-drag on?)))

    (define/override (enable-window on?)
      (super enable-window on?)
      (let ([on? (and on? (is-window-enabled?))])
        (for ([child (in-list children)])
          (send child enable-window on?))))
    
    (define/override (set-size x y w h)
      (super set-size x y w h)
      (fix-dc))
    
    (define/override (maybe-register-as-child parent on?)
      (register-as-child parent on?))
    
    (define/override (register-child child on?)
      (let ([now-on? (and (memq child children) #t)])
        (unless (eq? on? now-on?)
          (set! children 
                (if on?
                    (cons child children)
                    (remq child children)))
          (on-new-child child on?))))

    (define/override (show on?)
      (super show on?)
      (fix-dc))

    (define/override (refresh-all-children)
      (for ([child (in-list children)])
        (send child refresh)))
    
    (define/public (set-item-cursor x y) (void))))

(defclass panel% (panel-mixin window%)
  (inherit get-cocoa)
  (init parent
        x y w h
        style
        label)

  (define has-border? (memq 'border style))

  (super-new [parent parent]
             [cocoa
              (as-objc-allocation
               (tell (tell (if has-border? FrameView RacketPanelView) alloc)
                     initWithFrame: #:type _NSRect (make-NSRect (make-init-point x y)
                                                                (make-NSSize (max (if has-border? 3 1) w) 
                                                                             (max (if has-border? 3 1) h)))))]
             [no-show? (memq 'deleted style)])

  (define content-cocoa
    (and has-border?
         (let* ([c (get-cocoa)]
                [f (tell #:type _NSRect c frame)])
           (as-objc-allocation
            (tell (tell RacketPanelView alloc)
                  initWithFrame: #:type _NSRect (make-NSRect (make-init-point 1 1)
                                                             (let ([s (NSRect-size f)])
                                                               (make-NSSize (max 1 (- (NSSize-width s) 2))
                                                                            (max 1 (- (NSSize-height s) 2))))))))))
  (when has-border?
    (let ([cocoa (get-cocoa)])
      (tell #:type _void cocoa addSubview: content-cocoa)
      (set-ivar! content-cocoa wxb (->wxb this))))

  (define/override (get-cocoa-content)
    (if has-border?
        content-cocoa
        (super get-cocoa-content)))

  (define/override (set-size x y w h)
    (super set-size x y w h)
    (when has-border?
      (tellv content-cocoa setFrame: #:type _NSRect (make-NSRect (make-NSPoint 1 1)
                                                                (make-NSSize (max 1 (- w 2)) (max 1 (- h 2))))))))


