package dithering

import (
	"image"
	"image/color"
)

const side = 16

// tile
type grid struct {
	color.Gray
	Factor float64
}

func (_ grid) ColorModel() color.Model {
	return color.RGBAModel
}

func (_ grid) Bounds() image.Rectangle {
	return image.Rect(0, 0, side, side)
}

func (g grid) At(x, y int) color.Color {
	n := uint8(float64(g.Gray.Y) * g.Factor)

	if n == 0 {
		return color.Black
	}
	step := int((side*side - 1) / n)
	if (y*side+x)%step == 0 {
		return color.White
	}
	return color.Black
}

type uniformGrid struct {
	image.Image
}

func (g uniformGrid) ColorModel() color.Model {
	return g.Image.ColorModel()
}

func (g uniformGrid) Bounds() image.Rectangle {
	// just need to return something
	return g.Image.Bounds()
}

func (g uniformGrid) At(x, y int) color.Color {
	dx, dy := g.Image.Bounds().Dx(), g.Image.Bounds().Dy()
	return g.Image.At(x%dx, y%dy)
}

type Dithering struct {
	image.Image
	Factor float64
}

func (d Dithering) ColorModel() color.Model { return color.GrayModel }
func (d Dithering) Bounds() image.Rectangle { return d.Image.Bounds() }
func (d Dithering) At(x, y int) color.Color {
	c := color.GrayModel.Convert(d.Image.At(x, y))
	return uniformGrid{grid{c.(color.Gray), d.Factor}}.
		At(x, y)
}
