package filesync

import (
	"io"

	"github.com/docker/docker/pkg/archive"
	"github.com/docker/docker/pkg/chrootarchive"
	"github.com/pkg/errors"
	"github.com/sirupsen/logrus"
	"google.golang.org/grpc"
)

func sendTarStream(stream grpc.Stream, dir string, includes, excludes []string, progress progressCb) error {
	a, err := archive.TarWithOptions(dir, &archive.TarOptions{
		ExcludePatterns: excludes,
	})
	if err != nil {
		return err
	}

	size := 0
	buf := make([]byte, 1<<15)
	t := new(BytesMessage)
	for {
		n, err := a.Read(buf)
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
		t.Data = buf[:n]

		if err := stream.SendMsg(t); err != nil {
			return err
		}
		size += n
		if progress != nil {
			progress(size, false)
		}
	}
	if progress != nil {
		progress(size, true)
	}
	return nil
}

func recvTarStream(ds grpc.Stream, dest string, cs CacheUpdater) error {

	pr, pw := io.Pipe()

	go func() {
		var (
			err error
			t   = new(BytesMessage)
		)
		for {
			if err = ds.RecvMsg(t); err != nil {
				if err == io.EOF {
					err = nil
				}
				break
			}
			_, err = pw.Write(t.Data)
			if err != nil {
				break
			}
		}
		if err = pw.CloseWithError(err); err != nil {
			logrus.Errorf("failed to close tar transfer pipe")
		}
	}()

	decompressedStream, err := archive.DecompressStream(pr)
	if err != nil {
		return errors.Wrap(err, "failed to decompress stream")
	}

	if err := chrootarchive.Untar(decompressedStream, dest, nil); err != nil {
		return errors.Wrap(err, "failed to untar context")
	}
	return nil
}
