;;; -*- Mode:LISP; Package:TAPE; Readtable:CL; Base:10 -*-
;;;
;;; Remote tape device support
;;;
;;; -dg 2/18/86
;;;

(defmacro defmethod-forward ((flavor method))
  `(defmethod (,flavor ,method) (&rest arguments)
     (send self :forward-simple-operation ,method arguments)))

(defflavor remote-tape-device (unit
			       density
			       (device-type)
			       (host)
			       (stream)
			       (buffer))
	   (basic-tape-device)
  (:gettable-instance-variables device-type stream host buffer)
  (:required-instance-variables :device-type :host))

(defmethod (remote-tape-device :allocate-buffer) (size-in-pages)
  (unless (and buffer
	       (>= (si:dma-buffer-size-in-pages buffer) size-in-pages))
    (when buffer
      (deallocate-resource 'si:dma-buffer buffer))
    (allocate-resource 'si:dma-buffer size-in-pages)))

(defmethod (remote-tape-device :forward-simple-operation) (operation &rest args)
  (unless stream
    (ferror nil "REMOTE-TAPE: No stream to forward operation to..."))
  (format stream ":OPERATION ~S ~S "
	  operation args)
  (send stream :force-output)
  (let ((return-code (read stream)))
    (ecase return-code
      (:values (lexpr-funcall 'values (read stream)))
      (:error (signal-condition (read stream))))))

(defmethod-forward (remote-tape-device :unit))
(defmethod-forward (remote-tape-device :density))
(defmethod-forward (remote-tape-device :set-options))

(defmethod (remote-tape-device :initialize) (&rest init-options)
  (setq stream (chaos:open-stream host "LRTDP"))
  (lexpr-send self :set-options init-options))

(defmethod (remote-tape-device :deinitialize) ()
  (format stream ":finished ")
  (send stream :force-output)
  (close stream)
  (send self :unlock-device))

(defmethod (remote-tape-device :lock-device) ())

(defmethod (remote-tape-device :unlock-device) ())

(defmethod (remote-tape-device :device-locked-p) ()
  (and stream t))

(defmethod-forward (remote-tape-device :reset))
(defmethod-forward (remote-tape-device :status))
(defmethod-forward (remote-tape-device :speed-threshold))
(defmethod-forward (remote-tape-device :space))
(defmethod-forward (remote-tape-device :space-reverse))
(defmethod-forward (remote-tape-device :search-filemark))
(defmethod-forward (remote-tape-device :search-filemark-reverse))
(defmethod-forward (remote-tape-device :optimal-chunk-size))

(defmethod (remote-tape-device :read-block) (dma-buffer record-size)
  (format stream ":read-block ~D " record-size)
  (send stream :force-output)
  (let ((reply (read stream)))
    (ecase reply
      (:error (signal-condition (read stream)))
      (:data (let ((data-fill (read stream)))
	       (when (zerop data-fill)
		 (ferror nil "Block from remote tape device had 0 bytes!!!"))
	       (send stream :string-in t (si:dma-buffer-string dma-buffer) 0 data-fill)
	       data-fill)))))

(defmethod (remote-tape-device :write-block) (dma-buffer record-size)
  (format stream ":write-block ~D " record-size)
  (send stream :string-out (si:dma-buffer-string dma-buffer) 0 record-size)
  (let ((reply (read stream)))
    (ecase reply
      (:error (signal-condition (read stream)))
      (:values (lexpr-funcall 'values (read stream))))))

;(defmethod (remote-tape-device :read-array) (array number-of-records record-size)
;  (format stream ":read-array ~D ~D " number-of-records record-size)
;  (send stream :force-output)
;  (let ((reply (read stream)))
;    (ecase reply
;      (:error (signal-condition (read stream)))
;      (:data (let ((buffer (if (memq (array-type array) '(art-8b art-string))
;			       array
;			     (copy-array-contents
