// Copyright 2015 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 pargzip contains a parallel gzip writer implementation.  By
// compressing each chunk of data in parallel, all the CPUs on the
// machine can be used, at a slight loss of compression efficiency.
// In addition, this implementation can use the system gzip binary as
// a child process, which is faster than Go's native implementation.
package pargzip

import (
	"bufio"
	"bytes"
	"compress/gzip"
	"io"
	"os/exec"
	"runtime"
	"strings"
	"sync"
)

// A Writer is an io.WriteCloser.
// Writes to a Writer are compressed and written to w.
//
// Any exported fields may only be mutated before the first call to
// Write.
type Writer struct {
	// UseSystemGzip controls whether the system gzip binary is
	// used. The default from NewWriter is true.
	UseSystemGzip bool

	// ChunkSize is the number of bytes to gzip at once.
	// The default from NewWriter is 1MB.
	ChunkSize int

	// Parallel is the number of chunks to compress in parallel.
	// The default from NewWriter is runtime.NumCPU().
	Parallel int

	w  io.Writer
	bw *bufio.Writer

	allWritten  chan struct{} // when writing goroutine ends
	wasWriteErr chan struct{} // closed after 'err' set

	sem    chan bool        // semaphore bounding compressions in flight
	chunkc chan *writeChunk // closed on Close

	mu     sync.Mutex // guards following
	closed bool
	err    error // sticky write error
}

type writeChunk struct {
	zw *Writer
	p  string // uncompressed

	donec chan struct{} // closed on completion

	// one of following is set:
	z   []byte // compressed
	err error  // exec error
}

// compress runs the gzip child process.
// It runs in its own goroutine.
func (c *writeChunk) compress() (err error) {
	defer func() {
		if err != nil {
			c.err = err
		}
		close(c.donec)
		<-c.zw.sem
	}()
	var zbuf bytes.Buffer
	if c.zw.UseSystemGzip {
		cmd := exec.Command("gzip")
		cmd.Stdin = strings.NewReader(c.p)
		cmd.Stdout = &zbuf
		if err := cmd.Run(); err != nil {
			return err
		}
	} else {
		zw := gzip.NewWriter(&zbuf)
		if _, err := io.Copy(zw, strings.NewReader(c.p)); err != nil {
			return err
		}
		if err := zw.Close(); err != nil {
			return err
		}
	}
	c.z = zbuf.Bytes()
	return nil
}

// NewWriter returns a new Writer.
// Writes to the returned writer are compressed and written to w.
//
// It is the caller's responsibility to call Close on the WriteCloser
// when done. Writes may be buffered and not flushed until Close.
//
// Any fields on Writer may only be modified before the first call to
// Write.
func NewWriter(w io.Writer) *Writer {
	return &Writer{
		w:           w,
		allWritten:  make(chan struct{}),
		wasWriteErr: make(chan struct{}),

		UseSystemGzip: true,
		ChunkSize:     1 << 20,
		Parallel:      runtime.NumCPU(),
	}
}

func (w *Writer) didInit() bool { return w.bw != nil }

func (w *Writer) init() {
	w.bw = bufio.NewWriterSize(newChunkWriter{w}, w.ChunkSize)
	w.chunkc = make(chan *writeChunk, w.Parallel+1)
	w.sem = make(chan bool, w.Parallel)
	go func() {
		defer close(w.allWritten)
		for c := range w.chunkc {
			if err := w.writeCompressedChunk(c); err != nil {
				close(w.wasWriteErr)
				return
			}
		}
	}()
}

func (w *Writer) startChunk(p []byte) {
	w.sem <- true // block until we can begin
	c := &writeChunk{
		zw:    w,
		p:     string(p), // string, since the bufio.Writer owns the slice
		donec: make(chan struct{}),
	}
	go c.compress() // receives from w.sem
	select {
	case w.chunkc <- c:
	case <-w.wasWriteErr:
		// Discard chunks that come after any chunk that failed
		// to write.
	}
}

func (w *Writer) writeCompressedChunk(c *writeChunk) (err error) {
	defer func() {
		if err != nil {
			w.mu.Lock()
			defer w.mu.Unlock()
			if w.err == nil {
				w.err = err
			}
		}
	}()
	<-c.donec
	if c.err != nil {
		return c.err
	}
	_, err = w.w.Write(c.z)
	return
}

func (w *Writer) Write(p []byte) (n int, err error) {
	if !w.didInit() {
		w.init()
	}
	return w.bw.Write(p)
}

func (w *Writer) Close() error {
	w.mu.Lock()
	err, wasClosed := w.err, w.closed
	w.closed = true
	w.mu.Unlock()
	if wasClosed {
		return nil
	}
	if !w.didInit() {
		return nil
	}
	if err != nil {
		return err
	}

	w.bw.Flush()
	close(w.chunkc)
	<-w.allWritten // wait for writing goroutine to end

	w.mu.Lock()
	err = w.err
	w.mu.Unlock()
	return err
}

// newChunkWriter gets large chunks to compress and write to zw.
type newChunkWriter struct {
	zw *Writer
}

func (cw newChunkWriter) Write(p []byte) (n int, err error) {
	n = len(p)
	max := cw.zw.ChunkSize
	for len(p) > 0 {
		chunk := p
		if len(chunk) > max {
			chunk = chunk[:max]
		}
		p = p[len(chunk):]
		cw.zw.startChunk(chunk)
	}
	return
}
