#lang scheme

(require scheme/class)

(provide sistema%)

;;; REGISTROS Y TABLAS 

(define registro-per (vector 'id-per 'nombre 'dni 'id-cc));relación uno a uno

(define registro-cc (vector 'id-cc 'saldo 'id-per))


;;; LA CLASE SISTEMA. Un banco es un ejemplar
(define sistema%
  (class object%
    (field
     (tabla-cc (list registro-cc))
     (tabla-per (list registro-per))
     (lista-agentes '())
     (interfaz 'agente)
     (historico '());una pila de respuestas
     )
;;Métodos sobre tablas
    (define-syntax tabla-set!
      (syntax-rules ()
        ((tabla-set! lista pos new-reg)
         (for-each
          (lambda (reg)
            (when (= (vector-ref reg 0) pos)
              (vector-copy! reg 0 new-reg)))
          lista)) ))

    (define tabla-new
      (lambda (nombre-tabla)
        (let ((tabla #f) )
          (cond
            ((equal? nombre-tabla 'cuentas) (set! tabla tabla-cc))
            ((equal? nombre-tabla 'personas) (set! tabla tabla-per)) )
          (length tabla) )))
    
    (define tabla-add!
      (lambda (nombre-tabla reg)
          (cond
            ((equal? nombre-tabla 'cuentas) 
             (set! tabla-cc (append tabla-cc (list reg))))
            ((equal? nombre-tabla 'personas) 
             (set! tabla-per (append tabla-per (list reg)))) )
           ))
    
    (define tabla-mod!
      (lambda (nombre-tabla id reg)
        (let ((tabla #f) 
              (pos (vector-ref reg 0))
              )
          (cond
            ((equal? nombre-tabla 'cuentas) (set! tabla tabla-cc))
            ((equal? nombre-tabla 'personas) (set! tabla tabla-per)))
          (tabla-set! (cdr tabla) pos reg) ) ))
    
    (define tabla-match ; devuelve una lista de registros
      (lambda (nombre-tabla key valor);no orden de key
        (let ((tabla #f) 
              (lista-registros '()) )
          (cond
            ((equal? nombre-tabla 'cuentas) (set! tabla tabla-cc))
            ((equal? nombre-tabla 'personas) (set! tabla tabla-per)) 
            )
          (for-each ;ormap
           (lambda (reg)
             (if (equal? (vector-ref reg key) valor)
                 (set! lista-registros (cons reg lista-registros))
                 #f))
           tabla)
          (if (null? lista-registros)
              #f
              lista-registros)
          ) ))
;;
    (define set-pila 
      (lambda (respuesta)
        (set! historico (cons respuesta historico))
        ))
    (define get-pila
      (lambda ()
        historico))
    (define get-tablas
      (lambda ()
        (list tabla-cc tabla-per) ))
;;Métodos para tratar solicitudes y respuestas    
    (define/public salida-respuesta
      (lambda ()
        (car historico)))
;;El Control del Dinamismo
    (define operar
      (lambda ()
        (let ((mensaje #f)
              (respuesta #f))
          (set! mensaje (send interfaz dinamismo 'input))
          (ormap
           (lambda (agente)
             (send agente dinamismo mensaje))
           lista-agentes)
          (send interfaz dinamismo 'output)
;        (salida-respuesta) 
        ) ))
;;Métodos para establecer elementos estructurales
    (define set-agentes
      (lambda (lst)
        (set! lista-agentes lst) ))
    (define set-interfaz
      (lambda (obj)
        (set! interfaz obj)))
    (define get-agentes
      (lambda ()
        lista-agentes))
;;Hacer públicos los métodos
    (public tabla-new tabla-add! tabla-mod! tabla-match set-agentes set-interfaz get-agentes set-pila operar get-tablas get-pila)
    (super-new) ))

;;;; EL EJEMPLAR

;(define banco (make-object sistema%))

