package paasio

import (
	"io"
	"sync"
)

const testVersion = 3

func NewReadCounter(r io.Reader) ReadCounter {
	return &readCounter{
		r:    r,
		lock: new(sync.Mutex),
	}
}

type readCounter struct {
	r         io.Reader
	bytesRead int64
	ops       int
	lock      *sync.Mutex
}

func (rc *readCounter) Read(p []byte) (int, error) {
	m, err := rc.r.Read(p)
	rc.lock.Lock()
	rc.bytesRead += int64(m)
	rc.ops++
	rc.lock.Unlock()
	return m, err
}

func (rc *readCounter) ReadCount() (n int64, ops int) {
	rc.lock.Lock()
	n, ops = rc.bytesRead, rc.ops
	rc.lock.Unlock()
	return n, ops
}

func NewWriteCounter(w io.Writer) WriteCounter {
	return &writeCounter{
		w:    w,
		lock: new(sync.Mutex),
	}
}

type writeCounter struct {
	w          io.Writer
	bytesWrote int64
	ops        int
	lock       *sync.Mutex
}

func (wc *writeCounter) Write(p []byte) (int, error) {
	m, err := wc.w.Write(p)
	wc.lock.Lock()
	wc.bytesWrote += int64(m)
	wc.ops++
	wc.lock.Unlock()
	return m, err
}

func (wc *writeCounter) WriteCount() (n int64, ops int) {
	wc.lock.Lock()
	n, ops = wc.bytesWrote, wc.ops
	wc.lock.Unlock()
	return n, ops
}

type ReadWriter interface {
	io.Reader
	io.Writer
}

func NewReadWriteCounter(rw ReadWriter) ReadWriteCounter {
	return &readWriteCounter{
		r: NewReadCounter(rw),
		w: NewWriteCounter(rw),
	}
}

type readWriteCounter struct {
	r ReadCounter
	w WriteCounter
}

func (rw *readWriteCounter) Read(p []byte) (int, error) {
	return rw.r.Read(p)
}

func (rw *readWriteCounter) Write(p []byte) (int, error) {
	return rw.w.Write(p)
}

func (rw *readWriteCounter) ReadCount() (n int64, ops int) {
	return rw.r.ReadCount()
}

func (rw *readWriteCounter) WriteCount() (n int64, ops int) {
	return rw.w.WriteCount()
}

func (nr *nopReader) ReadCount() (n int64, ops int) {
	return 0, 0
}

func (nw *nopWriter) WriteCount() (n int64, ops int) {
	return 0, 0
}
