; Bankkonto im Objekt-Orientierten "Message-Passing" Stil

; MAKE-ACCOUNT zum Erzeugen eines Bankkontos
(define (make-account balance)
  (debug Top-Level "Enter MAKE-ACCOUNT with " balance)

  ; WITHDRAW zum Abheben vom Bankkonto
  (define (withdraw amount)
    (debug Level-1 "Enter WITHDRAW with " amount)
    (invariant (<= 0 amount)) ; Keine negativen Betrge

    (if (>= balance amount)
        (sequence (set! balance (- balance amount))
                  balance)
        "Insufficient funds"))

  ; DEPOSIT zum Einzahlen aufs Konto
  (define (deposit amount)
    (debug Level-1 "Enter DEPOSIT with " amount)
    (invariant (<= 0 amount)) ; Keine negativen Betrge

    (set! balance (+ balance amount))
    balance)

  ; Dispatch verkrpert den "Message-Selector" und wird als Funktionswert
  ; von MAKE-ACCOUNT zurckgeliefert.
  (define (dispatch m)
    (debug Level-1 "Enter DISPATCH with " m)

    (cond ((eq? m 'withdraw) withdraw) ; Ergebnis ist Prozedur WITHDRAW
          ((eq? m 'deposit)  deposit)  ; Ergebnis ist Prozedur DEPOSIT
          ((eq? m 'balance)  balance)  ; Ergebnis ist der Wert BALANCE
          ; Unbekannte Botschaft
          (else  (error "Unknown request -- MAKE-ACCOUNT" m))))

  ; Rumpf von 'MAKE-ACCOUNT'
  dispatch) ; Ergebnis ist Prozedur DISPATCH mit Lokalem Environment in dem
            ; die Prozeduren WITHDRAW und DEPOSIT, sowie der aktuelle Wert
            ; von BALANCE gebunden sind. Bei jedem Aufruf von MAKE-WITHDRAW
            ; wird ein neues Environment erzeugt und als Bindungsenviron-
            ; ment von DISPATCH mit DISPATCH zurckgegeben.

; Debuging stuff

(define Top-Level 0)
(define Level-1 1)
(set-debuglevel! Top-Level) ; Nur "Top-Level" debugen.
(debug-off)                 ; Debuging ausschalten.
(invariant-on)              ; Invariant-Test einschalten.

;---------------------------------------------------------------------------
;
; Beipiele:
; ---------
;
;  Erzeugung eine Kontos:
;
;       (define peter (make-account 200)) ; 200 ist Anfangsbetrag
;       (define paul  (make-account 300))
;       (define mary  paul)
;
;  Erfragen des Kontostandes:
;
;       (peter 'balance)        -->200
;       (paul  'balance)        -->300
;       (mary  'balance)        -->300
;
;  Einzahlen auf ein Konto:
;
;       ((peter 'deposit) 150)  -->350
;       ((paul  'deposit) 50)   -->250
;       ((mary  'deposit) 100)  -->350 ; Die 350 ist KEIN Druckfehler, son-
;                                      ; dern macht deutlich, da Paul und
;                                      ; Mary das SELBE Bankkonto haben.
;  Abheben von einem Konto:
;       ((peter 'withdraw) 400) -->"Insufficient funds"
;       ((peter 'withdraw) 300) -->50
;       ((paul  'withdraw) 200) -->150
;       ((mary  'withdraw) 200) -->"Insufficient funds"
;       ((mary  'withdraw) 100) -->50
;       (paul   'balance)       -->50
;
;---------------------------------------------------------------------------

