package hashing

import (
	"hash"
	"io"
)

// ReadSumer hashes all data read from the underlying reader.
type ReadSumer interface {
	io.Reader
	// Sum returns the hash of the data read so far.
	Sum(d []byte) []byte
}

type reader struct {
	io.Reader
	h hash.Hash
}

type readWriterTo struct {
	reader
	writerTo io.WriterTo
}

// NewReader returns a new ReadSummer that uses the hash h. If the underlying
// reader supports WriteTo then the returned reader will do so too.
func NewReader(r io.Reader, h hash.Hash) ReadSumer {
	rs := reader{
		Reader: io.TeeReader(r, h),
		h:      h,
	}

	if _, ok := r.(io.WriterTo); ok {
		return &readWriterTo{
			reader:   rs,
			writerTo: r.(io.WriterTo),
		}
	}

	return &rs
}

// Sum returns the hash of the data read so far.
func (h *reader) Sum(d []byte) []byte {
	return h.h.Sum(d)
}

// WriteTo reads all data into the passed writer
func (h *readWriterTo) WriteTo(w io.Writer) (int64, error) {
	return h.writerTo.WriteTo(NewWriter(w, h.h))
}