package moxio

import (
	"encoding/base64"
	"io"
)

// implement io.Closer
type closerFunc func() error

func (f closerFunc) Close() error {
	return f()
}

// Base64Writer turns a writer for data into one that writes base64 content on
// \r\n separated lines of max 78+2 characters length.
func Base64Writer(w io.Writer) io.WriteCloser {
	lw := &lineWrapper{w: w}
	bw := base64.NewEncoder(base64.StdEncoding, lw)
	return struct {
		io.Writer
		io.Closer
	}{
		Writer: bw,
		Closer: closerFunc(func() error {
			if err := bw.Close(); err != nil {
				return err
			}
			return lw.Close()
		}),
	}
}

type lineWrapper struct {
	w io.Writer
	n int // Written on current line.
}

func (lw *lineWrapper) Write(buf []byte) (int, error) {
	wrote := 0
	for len(buf) > 0 {
		n := 78 - lw.n
		if n > len(buf) {
			n = len(buf)
		}
		nn, err := lw.w.Write(buf[:n])
		if nn > 0 {
			wrote += nn
			buf = buf[nn:]
		}
		if err != nil {
			return wrote, err
		}
		lw.n += nn
		if lw.n == 78 {
			_, err := lw.w.Write([]byte("\r\n"))
			if err != nil {
				return wrote, err
			}
			lw.n = 0
		}
	}
	return wrote, nil
}

func (lw *lineWrapper) Close() error {
	if lw.n > 0 {
		lw.n = 0
		_, err := lw.w.Write([]byte("\r\n"))
		return err
	}
	return nil
}