/*

Command precipitate consumes a stream of trace events, emitting set of events
grouped by transaction id.

*/
package main

import (
	"flag"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"sort"
	"strings"
	"time"

	"code.justin.tv/common/chitin"
	_ "code.justin.tv/common/golibs/bininfo"
	"code.justin.tv/release/trace/scanproto"
)

func main() {
	var dataDir string
	flag.StringVar(&dataDir, "data", "", "Path to data directory")
	flag.Parse()

	err := chitin.ExperimentalTraceProcessOptIn()
	if err != nil {
		log.Fatalf("trace enable err=%q", err)
	}

	filenames := make(chan [2]string)

	go func() {
		t := time.NewTicker(1 * time.Second)
		defer t.Stop()
		defer close(filenames)

		for range t.C {
			names, err := findData(dataDir)
			if err != nil {
				log.Printf("findData err=%q", err)
				continue
			}

			filenames <- names
		}
	}()

	names := <-filenames

	current := names[0]
	if current == "" {
		log.Fatalf("current=%q", current)
	}

	cmd := exec.Command("tail", "-F", "-c", "1000000000000", "--", current)
	rc, err := cmd.StdoutPipe()
	if err != nil {
		log.Fatalf("pipe err=%q", err)
	}

	err = cmd.Start()
	if err != nil {
		log.Fatalf("tail start err=%q", err)
	}

	go func() {
		for names := range filenames {
			if current != names[0] {
				err := cmd.Process.Kill()
				if err != nil {
					log.Printf("kill err=%q", err)
					continue
				}
			}
		}
	}()

	sc := scanproto.NewEventSetScanner(rc)
	var i int64
	for sc.Scan() {
		i++
	}

	log.Printf("events=%d", i)

	err = sc.Err()
	if err != nil {
		log.Fatalf("scan err=%q", err)
	}

	for names := range filenames {
		log.Printf("cat=%q tail=%q", names[1], names[0])
	}
}

func findData(dataDir string) ([2]string, error) {
	var out [2]string

	infos, err := ioutil.ReadDir(dataDir)
	if err != nil {
		return out, err
	}

	timely := make([]os.FileInfo, 0, len(infos))
	for _, info := range infos {
		if strings.HasSuffix(info.Name(), ".timely.pb") {
			timely = append(timely, info)
		}
	}

	sort.Sort(sort.Reverse(fileInfoByTime(timely)))

	for i, info := range timely {
		if i == cap(out) {
			break
		}
		fullname := filepath.Join(dataDir, info.Name())
		out[i] = fullname
	}

	return out, nil
}

type fileInfoByTime []os.FileInfo

func (l fileInfoByTime) Len() int           { return len(l) }
func (l fileInfoByTime) Less(i, j int) bool { return l[i].ModTime().Before(l[j].ModTime()) }
func (l fileInfoByTime) Swap(i, j int)      { l[i], l[j] = l[j], l[i] }
