#lang scheme
(require scheme/class)

(provide interfaz%)
(define agente% 
  (class object%
;;;;propiedades
    (init-field
     (parte-de-sistema 'object)
     )
;;;;métodos de acceso y cambio
    (define get-sistema
      (lambda ()
        parte-de-sistema))
    (define set-sistema
      (lambda (obj)
        (set! parte-de-sistema obj) ))
;;;;métodos de procesamiento
    (define entrada
      (lambda (mensa)
        "cada tipo de agente ha de establecer este método"))
    (define tarea
      (lambda (datos)
        "cada tipo de agente ha de establecer este método"))
    (define accion 
      (lambda () 
        "cada tipo de agente ha de establecer este método" ))
    (public get-sistema set-sistema entrada tarea accion)
    (super-new) ))
;;;;
(define interfaz%
  (class agente%
    (init-field 
     (palabras-clave 'lista-palabras))
    (inherit-field parte-de-sistema)
    (field
     (historia-frases '()))
    ;;:
    (define/public get-historia-frases
      (lambda ()
        historia-frases))
    ;;;
    (define string->lista-palabras
      (lambda (str)
        (letrec
            ((aux
              (lambda (str i)
                (if (= (string-length str) i)
                    (list str)
                    (if (char=? (string-ref str i) #\space)
                        (cons
                         (substring str 0 i)
                         (aux (substring str (add1 i) (string-length str)) 0))
                        (aux str (add1 i)))
                    )))
             )
          (aux str 0))))
    (define orden
      (lambda (entrada claves)
        (let ((orden #f))
          (for-each
           (lambda (clave)
             (for-each
              (lambda (palabra)
                (when (string=? palabra clave)
                  (set! orden clave)))
              entrada))
           claves)
          (string->symbol orden))))
    (define datos-para-orden;obliga a convertir el string en simbolo
      (lambda (orden)
        (case orden
          ((abrir) (list 'nombre 'dni 'cantidad))
          ((ingresar) (list 'num-cc 'dni 'cantidad))
          ((sacar) (list 'nun-cc 'dni 'cantidad))
          ((saldo) (list 'num-cc 'dni)) )))
    
    (define solicitar-dato
      (lambda (identificador)
        (printf "~nEscribe, por favor, tu ~a: " identificador)
        (case identificador
          ((nombre) (read-line))
          (else (string->number (read-line))))))
    
    (define pedir-datos
      (lambda (lista-datos)
        (if (null? lista-datos)
            '()
            (cons
             (solicitar-dato (car lista-datos))
             (pedir-datos (cdr lista-datos))))))
    
    (define establecer-datos
      (lambda (orden)
        (let* ((segun-lista (datos-para-orden orden))
               (datos (pedir-datos segun-lista)) )
          datos)))
    ;;;proceso
    (override accion)
    (define accion
      (lambda (mensa)
        (case mensa
          ((input) (accion-input))
          ((output) (accion-output)))))
    (define accion-input
      (lambda ()
        (printf "Son posibles operaciones: abrir, ingresar, sacar y saldo~n")
        (printf "Escribe una orden ")
        (let* ((frase (read-line))
               (lst-palabras (string->lista-palabras frase))
               (operacion (orden lst-palabras palabras-clave))
               (datos (establecer-datos operacion)) 
               (mensaje (list operacion datos))
               )
          (set! historia-frases (cons frase historia-frases));para estadística
          mensaje)))
    (define accion-output
      (lambda ()
        (let* ((datos (send parte-de-sistema lo-ultimo)))
          (printf "~a~n" datos) )))
          
          
    ;;;
    ;(public accion)
    (super-new)))

(define banco (make-object object%))
(define q (make-object interfaz% (list "abrir" "ingresar" "ingreso" "sacar" "retirar" "saldo" "estado") banco ))
