package main

import (
	"encoding/binary"
	"flag"
	"io"
	"io/ioutil"
	"log"
	"os"

	"github.com/syndtr/goleveldb/leveldb/storage"
	"github.com/syndtr/goleveldb/leveldb/table"
)

func main() {
	filename := flag.String("name", "", "Name of ldb file to inspect")
	outname := flag.String("output", "", "Name of output file")
	flag.Parse()

	os.Stdin.Read(nil)

	f, err := os.Open(*filename)
	if err != nil {
		log.Fatalf("Open err=%q", err)
	}
	defer f.Close()

	info, err := f.Stat()
	if err != nil {
		log.Fatalf("Stat err=%q", err)
	}

	rd, err := table.NewReader(f, info.Size(),
		storage.FileDesc{Type: storage.TypeTable, Num: 4080},
		nil, nil, nil)
	if err != nil {
		log.Fatalf("NewReader err=%q", err)
	}
	defer rd.Release()

	var out io.Writer = ioutil.Discard
	if *outname != "" {
		outfile, err := os.OpenFile(*outname, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
		if err != nil {
			log.Fatalf("OpenFile err=%q", err)
		}
		defer func() {
			err := outfile.Close()
			if err != nil {
				log.Fatalf("Close err=%q", err)
			}
		}()

		out = outfile
	}

	w := table.NewWriter(out, nil)
	defer func() {
		err := w.Close()
		if err != nil {
			log.Fatalf("Close err=%q", err)
		}
	}()

	it := rd.NewIterator(nil, nil)

	var k, v []byte
	var i, n int
	for ; it.Next(); i++ {
		k, v = it.Key(), it.Value()
		if i == 0 {
			logStuff(i, k, v)
		}
		if i > n {
			logStuff(i, k, v)
			n += n + 1
		}

		if i < 100 {
			err := w.Append(k, v)
			if err != nil {
				log.Fatalf("Append err=%q", err)
			}
		}
	}
	logStuff(-1, k, v)
}

func logStuff(i int, k, v []byte) {
	head := k
	var tail []byte
	var tailv uint64
	if l := 8; len(k) > l {
		head, tail = k[:len(k)-l], k[len(k)-l:len(k)]
		tailv = uint64(binary.LittleEndian.Uint64(tail))
	}
	log.Printf("i=%d lk=%d head=%q lv=%d tail=%02x tailv=%d", i, len(k), head, len(v), tail, tailv)
}
