// Copyright 2015, Joe Tsai. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE.md file.

// +build ignore

//go:generate go run repeats.go

// Generates repeats.bin. This test file heavily favors LZ77 based compression
// since a large bulk of its data is a copy from some distance ago. Also, since
// the source data is mostly random, prefix encoding does not benefit as much.
package main

import (
	"io/ioutil"
	"math/rand"
)

const (
	name = "repeats.bin"
	size = 1 << 18
)

func main() {
	var b []byte
	r := rand.New(rand.NewSource(0))

	randLen := func() (l int) {
		p := r.Float32()
		switch {
		case p <= 0.15: // 4..7
			l = 4 + r.Intn(4)
		case p <= 0.30: // 8..15
			l = 8 + r.Intn(8)
		case p <= 0.45: // 16..31
			l = 16 + r.Intn(16)
		case p <= 0.60: // 32..63
			l = 32 + r.Intn(32)
		case p <= 0.75: // 64..127
			l = 64 + r.Intn(64)
		case p <= 0.90: // 128..255
			l = 128 + r.Intn(128)
		case p <= 1.0: // 256..511
			l = 256 + r.Intn(256)
		}
		return l
	}

	randDist := func() (d int) {
		for d == 0 || d > len(b) {
			p := r.Float32()
			switch {
			case p <= 0.1: // 1..1
				d = 1 + r.Intn(1)
			case p <= 0.2: // 2..3
				d = 2 + r.Intn(2)
			case p <= 0.3: // 4..7
				d = 4 + r.Intn(4)
			case p <= 0.4: // 8..15
				d = 8 + r.Intn(8)
			case p <= 0.5: // 16..31
				d = 16 + r.Intn(16)
			case p <= 0.55: // 32..63
				d = 32 + r.Intn(32)
			case p <= 0.60: // 64..127
				d = 64 + r.Intn(64)
			case p <= 0.65: // 128..255
				d = 128 + r.Intn(128)
			case p <= 0.70: // 256..511
				d = 256 + r.Intn(256)
			case p <= 0.75: // 512..1023
				d = 512 + r.Intn(512)
			case p <= 0.80: // 1024..2047
				d = 1024 + r.Intn(1024)
			case p <= 0.85: // 2048..4095
				d = 2048 + r.Intn(2048)
			case p <= 0.90: // 4096..8191
				d = 4096 + r.Intn(4096)
			case p <= 0.95: // 8192..16383
				d = 8192 + r.Intn(8192)
			case p <= 1.00: // 16384..32767
				d = 16384 + r.Intn(16384)
			}
		}
		return d
	}

	writeRand := func(l int) {
		for i := 0; i < l; i++ {
			b = append(b, byte(r.Int()))
		}
	}

	writeCopy := func(d, l int) {
		for i := 0; i < l; i++ {
			b = append(b, b[len(b)-d])
		}
	}

	writeRand(randLen())
	for len(b) < size {
		p := r.Float32()
		switch {
		case p <= 0.1:
			// Generate random new data.
			writeRand(randLen())
		case p <= 0.9:
			// Write a long distance copy.
			d, l := randDist(), randLen()
			for d <= l {
				d, l = randDist(), randLen()
			}
			writeCopy(d, l)
		case p <= 1.0:
			// Write a possibly short distance copy.
			writeCopy(randDist(), randLen())
		}
	}

	if err := ioutil.WriteFile(name, b[:size], 0664); err != nil {
		panic(err)
	}
}
