// Package progressreader provides a Reader with a progress bar that can be
// printed out using the streamformatter package.
package progressreader

import (
	"io"

	"github.com/docker/docker/pkg/jsonmessage"
	"github.com/docker/docker/pkg/streamformatter"
)

// Config contains the configuration for a Reader with progress bar.
type Config struct {
	In         io.ReadCloser // Stream to read from
	Out        io.Writer     // Where to send progress bar to
	Formatter  *streamformatter.StreamFormatter
	Size       int64
	Current    int64
	LastUpdate int64
	NewLines   bool
	ID         string
	Action     string
}

// New creates a new Config.
func New(newReader Config) *Config {
	return &newReader
}

func (config *Config) Read(p []byte) (n int, err error) {
	read, err := config.In.Read(p)
	config.Current += int64(read)
	updateEvery := int64(1024 * 512) //512kB
	if config.Size > 0 {
		// Update progress for every 1% read if 1% < 512kB
		if increment := int64(0.01 * float64(config.Size)); increment < updateEvery {
			updateEvery = increment
		}
	}
	if config.Current-config.LastUpdate > updateEvery || err != nil {
		updateProgress(config)
		config.LastUpdate = config.Current
	}

	if err != nil && read == 0 {
		updateProgress(config)
		if config.NewLines {
			config.Out.Write(config.Formatter.FormatStatus("", ""))
		}
	}
	return read, err
}

// Close closes the reader (Config).
func (config *Config) Close() error {
	if config.Current < config.Size {
		//print a full progress bar when closing prematurely
		config.Current = config.Size
		updateProgress(config)
	}
	return config.In.Close()
}

func updateProgress(config *Config) {
	progress := jsonmessage.JSONProgress{Current: config.Current, Total: config.Size}
	fmtMessage := config.Formatter.FormatProgress(config.ID, config.Action, &progress)
	config.Out.Write(fmtMessage)
}