;;; -*- Mode:LISP; Package:SYSTEM-INTERNALS; Base:8 -*-

(defvar nupi-tape-physical-unit #x18)

(defun nupi-tape-rewind ()
  (let ((rqb (get-disk-rqb)))
    (nupi-disk-command rqb #x20 nupi-tape-physical-unit 0 0 nil)
    (return-disk-rqb rqb)))

(defun nupi-tape-write-filemark ()
  (let ((rqb (get-disk-rqb)))
    (nupi-disk-command rqb #x25 nupi-tape-physical-unit 0 0 nil)))

(defun nupi-tape-read (rqb n-bytes)
  (if (> n-bytes (* 1024. (rqb-npages rqb))) (ferror nil "too big"))
  (nupi-tape-command rqb #x12 nupi-tape-physical-unit 0 n-bytes)
  (nupi-transfer-count rqb)
  )

(defun nupi-tape-write (rqb n-bytes)
  (if (> n-bytes (* 1024. (rqb-npages rqb))) (ferror nil "too big"))
  (nupi-tape-command rqb #x13 nupi-tape-physical-unit 0 n-bytes)
  (nupi-transfer-count rqb))

(defflavor nupi-simple-tape-input-stream
	   (rqb
	    (n-bytes-per-operation 10240.)
	    (eof-p nil)
	    buffer-8b
	    )
	   (si:buffered-input-stream)
  :settable-instance-variables
  )

(defmethod (nupi-simple-tape-input-stream :after :init) (ignore)
  (if (not (zerop (ldb (byte 10. 0) n-bytes-per-operation)))
      (ferror nil "n-bytes-per-operation must be multiple of 1024."))
  (setq rqb (get-disk-rqb (floor n-bytes-per-operation 1024.)))
  (setq buffer-8b (make-array n-bytes-per-operation
			      :type :art-8b
			      :displaced-to (rqb-8-bit-buffer rqb)
			      ))
  )

(defmethod (nupi-simple-tape-input-stream :next-input-buffer) (no-hang-p)
  no-hang-p
  (cond ((null eof-p)
	 (let* ((n-bytes (nupi-tape-read rqb n-bytes-per-operation))
		(status (ldb (byte 8 8) (nupi-disk-status rqb))))
	   (format t "~&nupi tape status ~d. xfer ~d. " status n-bytes)
	   (cond ((or (= status 114.) (= status 76.))
		  ;;got file mark before finishing transfer, or something like that
		  (setq eof-p t)
		  (values buffer-8b 0 n-bytes))
		 ((zerop status)
		  (values buffer-8b 0 n-bytes))
		 (t
		  (ferror nil "unknown status ~d." status)))))
	(t
	 (setq eof-p nil)
	 nil)))

(defmethod (nupi-simple-tape-input-stream :discard-input-buffer) (ignore)
  nil)

(defmethod (nupi-simple-tape-input-stream :after :close) (&rest ignore)
  (return-disk-rqb rqb))

(defflavor nupi-simple-tape-output-stream
	   (rqb
	    (n-bytes-per-operation 10240.)
	    (done-a-write-p nil)
	    )
	   (si:buffered-output-stream)
  )

(defmethod (nupi-simple-tape-output-stream :after :init) (ignore)
  (if (not (zerop (ldb (byte 10. 0) n-bytes-per-operation)))
      (ferror nil "n-bytes-per-operation must be multiple of 1024."))
  (setq rqb (get-disk-rqb (floor n-bytes-per-operation 1024.))))

(defmethod (nupi-simple-tape-output-stream :new-output-buffer) ()
  (values (si:rqb-8-bit-buffer rqb) 0 n-bytes-per-operation))

(defmethod (nupi-simple-tape-output-stream :send-output-buffer) (buffer ending-index)
  (if (not (zerop (ldb (byte 10. 0) ending-index)))
      (ferror nil "can't flush the buffer except on 1K boundaries"))
  (if (not (eq buffer (rqb-8-bit-buffer rqb)))
      (ferror nil "trying to write wrong buffer"))
  (setq done-a-write-p t)
  (nupi-tape-write rqb ending-index)
  )

(defmethod (nupi-simple-tape-output-stream :discard-output-buffer) (buffer)
  buffer
  )

(defmethod (nupi-simple-tape-output-stream :after :close) (&rest ignore)
  (if done-a-write-p
      (nupi-tape-write-filemark))
  (return-disk-rqb rqb))
