package downscale

import (
	"errors"
	"image"
	"image/color"
)

var errOutOfBounds error = errors.New("downscale: out of bounds")

type Downscaled struct {
	image.Image
	Factor int
}

func isOutOfBounds(pt image.Point, img image.Image) bool {
	x, y := img.Bounds().Dx(), img.Bounds().Dy()
	if pt.X > x || pt.Y > y {
		return true
	}
	return false
}

func meanColor(palette color.Palette) color.Color {
	var r, g, b int
	for _, v := range palette {
		c := color.RGBAModel.Convert(v).(color.RGBA)
		r += int(c.R)
		g += int(c.G)
		b += int(c.B)
	}
	r, g, b = r/len(palette), g/len(palette), b/len(palette)
	return color.RGBA{uint8(r), uint8(g), uint8(b), 0xff}
}

func (d Downscaled) ColorModel() color.Model { return d.Image.ColorModel() }
func (d Downscaled) Bounds() image.Rectangle {
	return image.Rect(0, 0, d.Image.Bounds().Dx()/d.Factor, d.Image.Bounds().Dy()/d.Factor)
}
func (d Downscaled) At(x, y int) color.Color {
	palette := color.Palette{}
	pt := image.Point{x * d.Factor, y * d.Factor}
	if isOutOfBounds(pt, d.Image) {
		panic(errOutOfBounds)
	}
	for i := 0; i < d.Factor; i++ {
		for j := 0; j < d.Factor; j++ {
			currentPt := image.Point{pt.X + i, pt.Y + j}
			if i > 0 || j > 0 {
				if isOutOfBounds(currentPt, d.Image) {
					continue
				}
			}
			palette = append(palette, d.Image.At(currentPt.X, currentPt.Y))
		}
	}
	return palette.Convert(meanColor(palette))
}
