#lang scheme
;(require scheme/class)

(define base-cuentas%
  (class object%
    (init-field
     (sucursal 0))
    (field
     (bd-cuentas '())
     (n-siguiente 1))
    ;;;;;;;;;;;;;;;;;;;;
    (define/private extrae-cuenta
      (lambda (bd id)
        (if (null? bd)
            "no existe"
            (if (= (send (car bd) get-id) id)
                (car bd)
                (extrae-cuenta (cdr bd) id)) )))
    ;;;;;;
    (define crear
      (lambda ()
        (let*
            ((numero (+ sucursal n-siguiente))
             (cuenta 0) )
          (display "Tipo de cuenta: A(horro) / C(orriente)")
          (case (read)
            ((a A) (set! cuenta (make-object cuenta-ahorro% numero)))
            ((c C) (set! cuenta (make-object cuenta-corriente% numero))) )
          (set! bd-cuentas (cons cuenta bd-cuentas))
          (display "Titular? ")
          (send cuenta set-titular (read))
          (display "Saldo inicial? ")
          (send cuenta set-saldo (read))
          (set! n-siguiente (add1 n-siguiente))
          (display "Cuenta creada con número: ")
          (display (send cuenta get-id))
          (display " Titular: ")
          (display (send cuenta get-titular))
          (display " Saldo: ")
          (display (send cuenta get-saldo)) )))
    (define ingresar
      (lambda ()
        (display "Número de cuenta? ")
        (let*
            ((numero (read))
             (cuenta (extrae-cuenta bd-cuentas numero)))
          (display "Confirme titular = ")
          (display (send cuenta get-titular))
          (if (equal? (read) 's)
              (begin
                (display "Cantidad? ")
                (send cuenta ingresar (read)) 
                )
              "Titular no confirmado")
          ) ))    
    (define sacar
      (lambda ()
        (display "Número de cuenta? ")
        (let*
            ((numero (read))
             (cuenta (extrae-cuenta bd-cuentas numero)))
          (display "Confirme titular = ")
          (display (send cuenta get-titular))
          (if (equal? (read) 's)
              (begin
                (display "Cantidad? ")
                (send cuenta sacar (read)) )
              "Titular no confirmado")
          ) ))
    (define saldo
      (lambda ()
        (display "Número de cuenta? ")
        (let*
            ((numero (read))
             (cuenta (extrae-cuenta bd-cuentas numero)))
          (display "Confirme titular = ")
          (display (send cuenta get-titular))
          (if (equal? (read) 's)
              (begin
                (display "Saldo disponible ")
                (display (send cuenta get-saldo)))
              "Titular no confirmado")
              ) ))
    (define cerrar
      (lambda ()
        (display "Número de cuenta? ")
        (let*
            ((numero (read))
             (cuenta (extrae-cuenta bd-cuentas numero)))
          (display "Confirme titular = ")
          (display (send cuenta get-titular))
          (if (equal? (read) 's)
              (begin
                (display "Cuenta ")
                (display (send cuenta get-id))
                (display " Titular ")
                (display (send cuenta get-titular))
                (send cuenta set-acceso #f)
                (display " cerrada")
                )
              "Titular no confirmado")
              ) ))
    ;;;;;;
    (public crear ingresar sacar saldo cerrar)
    ;;;;;;
    (super-new) ))

;(define bd (make-object base-cuentas% 1000))


            



;;;;;;;;;;;
(define cuenta%
  (class object%
    (init-field
     identificador)
    (field
     (poseedor 'ssss)
     (acceso #t)
     (saldo 0) )
    ;;;;;;;;;;;;;;;;;;;;
    (define get-id
      (lambda ()
        identificador))
    ;;;;;;
    (define get-titular
      (lambda ()
        poseedor))
    (define set-titular
      (lambda (x)
        (set! poseedor x)))
    ;;;;;;
    (define get-saldo
      (lambda ()
        saldo))
    (define set-saldo
      (lambda (x)
        (set! saldo x)))
    ;;;;::
    (define get-acceso
      (lambda ()
        acceso))
    (define set-acceso
      (lambda (x)
        (set! acceso x)))
    ;;;;;;Override en subclases
    (define ingresar
      (lambda (x)
        (set! saldo (+ saldo x)) ))
    (define sacar
      (lambda (x)
        (set! saldo (- saldo x)) ))    
    ;;;;;;
    (public get-id get-acceso get-titular get-saldo
            set-saldo set-acceso set-titular
            ingresar sacar)
    ;;;;;;
    (super-new) ))

(define cuenta-ahorro%
  (class cuenta%
    (inherit-field identificador poseedor acceso saldo)
    (field
     (comision 0.001)); 1 por 1000
    ;;;;;;;;;;;;;;;;;;;;
    (define get-comision
      (lambda ()
        comision))
    (define set-comision
      (lambda (x)
        (set! comision x) ))
    ;;;;;;
    (override ingresar sacar)
    (define ingresar
      (lambda (x)
        (let* ((cantidad x)
               (cargo (* cantidad comision))
               (asiento (- cantidad cargo)) )
          (set! saldo (+ saldo asiento))
          (display "Saldo resultante ")
          (display saldo)
          ) ))    
    (define sacar
      (lambda (x)
        (let* ((cantidad x)
               (cargo (* cantidad comision))
               (asiento (+ cantidad cargo)) )
          (cond
            ((> cantidad saldo)
             "Crédito insuficiente" )
            (else
             (set! saldo (- saldo asiento))
;             saldo) )
             (display "Saldo resultante ")
             (display saldo)) )
          ) ))    
    ;;;;;;
    (public get-comision set-comision)
    ;;;;;;
    (super-new) ))

(define cuenta-corriente%
  (class cuenta%
    (inherit-field identificador poseedor acceso saldo)
    (field
     (comision 0.0015); 1,5 por 1000
     (credito 500) )
    ;;;;;;;;;;;;;;;;;;;;
    (define get-comision
      (lambda ()
        comision))
    (define set-comision
      (lambda (x)
        (set! comision x) ))
    (define get-credito
      (lambda ()
        credito))
    (define set-credito
      (lambda (x)
        (set! credito x)))
    ;;;;;;
    (override ingresar sacar)
    (define ingresar
      (lambda (x)
        (let* ((cantidad x)
               (cargo (* cantidad comision))
               (asiento (- cantidad cargo)) )
          (set! saldo (+ saldo asiento))
          (display "Saldo resultante ")
          (display saldo)
          ) ))    
    ;;;;;;
    (define sacar
      (lambda (x)
        (let ((cantidad x)
              (cargo 0)
              (asiento 0) 
              )
          (cond
            ((> cantidad (+ credito saldo))
             "Crédito insuficiente" )
            ((>= saldo cantidad)
             (set! cargo (* cantidad comision))
             (set! asiento (+ cantidad cargo))
             (set! saldo (- saldo asiento))
             (display "Saldo resultante ")
             (display saldo) )
            (else
             (set! 
              cargo 
              (+ 
               (* (- cantidad saldo) 0.001);lo sacado a crédito 
               (* saldo comision)));comisión sobre el disponible
             (set! asiento (+ cantidad cargo))
             (set! saldo (- saldo asiento))
             (display "Saldo resultante ")
             (display saldo) )
            ) )) )
    ;;;;;;
    (public get-comision set-comision get-credito set-credito)
    ;;;;;;
    (super-new) ))

;(define q (make-object cuenta-ahorro% 1001))

;(define w (make-object cuenta-corriente% 1002))