// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package io

type eofReader struct{}

func (eofReader) ([]byte) (int, error) {
	return 0, EOF
}

type multiReader struct {
	readers []Reader
}

func ( *multiReader) ( []byte) ( int,  error) {
	for len(.readers) > 0 {
		// Optimization to flatten nested multiReaders (Issue 13558).
		if len(.readers) == 1 {
			if ,  := .readers[0].(*multiReader);  {
				.readers = .readers
				continue
			}
		}
		,  = .readers[0].Read()
		if  == EOF {
			// Use eofReader instead of nil to avoid nil panic
			// after performing flatten (Issue 18232).
			.readers[0] = eofReader{} // permit earlier GC
			.readers = .readers[1:]
		}
		if  > 0 ||  != EOF {
			if  == EOF && len(.readers) > 0 {
				// Don't return EOF yet. More readers remain.
				 = nil
			}
			return
		}
	}
	return 0, EOF
}

func ( *multiReader) ( Writer) ( int64,  error) {
	return .writeToWithBuffer(, make([]byte, 1024*32))
}

func ( *multiReader) ( Writer,  []byte) ( int64,  error) {
	for ,  := range .readers {
		var  int64
		if ,  := .(*multiReader);  { // reuse buffer with nested multiReaders
			,  = .(, )
		} else {
			,  = copyBuffer(, , )
		}
		 += 
		if  != nil {
			.readers = .readers[:] // permit resume / retry after error
			return , 
		}
		.readers[] = nil // permit early GC
	}
	.readers = nil
	return , nil
}

var _ WriterTo = (*multiReader)(nil)

// MultiReader returns a Reader that's the logical concatenation of
// the provided input readers. They're read sequentially. Once all
// inputs have returned EOF, Read will return EOF.  If any of the readers
// return a non-nil, non-EOF error, Read will return that error.
func ( ...Reader) Reader {
	 := make([]Reader, len())
	copy(, )
	return &multiReader{}
}

type multiWriter struct {
	writers []Writer
}

func ( *multiWriter) ( []byte) ( int,  error) {
	for ,  := range .writers {
		,  = .Write()
		if  != nil {
			return
		}
		if  != len() {
			 = ErrShortWrite
			return
		}
	}
	return len(), nil
}

var _ StringWriter = (*multiWriter)(nil)

func ( *multiWriter) ( string) ( int,  error) {
	var  []byte // lazily initialized if/when needed
	for ,  := range .writers {
		if ,  := .(StringWriter);  {
			,  = .WriteString()
		} else {
			if  == nil {
				 = []byte()
			}
			,  = .Write()
		}
		if  != nil {
			return
		}
		if  != len() {
			 = ErrShortWrite
			return
		}
	}
	return len(), nil
}

// MultiWriter creates a writer that duplicates its writes to all the
// provided writers, similar to the Unix tee(1) command.
//
// Each write is written to each listed writer, one at a time.
// If a listed writer returns an error, that overall write operation
// stops and returns the error; it does not continue down the list.
func ( ...Writer) Writer {
	 := make([]Writer, 0, len())
	for ,  := range  {
		if ,  := .(*multiWriter);  {
			 = append(, .writers...)
		} else {
			 = append(, )
		}
	}
	return &multiWriter{}
}