package main

import (
	"bytes"
	"errors"
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	resp, err := http.Get("https://github.com/aditya43/golang/tree/master/43-IO-Reusable-Streams/some-file.unknown")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	defer resp.Body.Close()

	// creates a file (or truncates if the file exists)
	file, err := os.Create("rosie.png")
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	defer file.Close()

	n, err := transfer(resp.Body, file)
	if err != nil {
		fmt.Fprintln(os.Stderr, err)
		return
	}
	fmt.Printf("%d bytes transferred.\n", n)

	// main() runs the deferred funcs in reverse order:
	// file.Close()
	// resp.Body.Close()
}

// transfer streams data from a reader to a writer.
// if the reader doesn't contain a PNG signature, transfer returns errNotPNG.
// otherwise, it transfers the data to the writer.
func transfer(r io.Reader, w io.Writer) (n int64, err error) {
	const pngSign = "\x89PNG\r\n\x1a\n"
	const pngSignLen = 8

	var memory bytes.Buffer

	// limit what copy() reads.
	// lr := io.LimitReader(r, pngSignLen)
	// if n, err = io.Copy(&memory, lr); err != nil {
	// return n, err
	// }

	// same as above. behind the scenes CopyN() calls LimitReader.
	if n, err = io.CopyN(&memory, r, pngSignLen); err != nil {
		return n, err
	}

	// check the png signature.
	if !bytes.HasPrefix(memory.Bytes(), []byte(pngSign)) {
		return n, errors.New("not png")
	}

	// stitch the PNG signature (memory) and the response body reader together.
	// then copy them successively to the writer (*os.File).
	return io.Copy(w, io.MultiReader(&memory, r))
}
