package main

import (
	"image"
	"image/color"
	"image/png"
	"log"
	"os"
)

func main() {
	err := run()
	if err != nil {
		log.Fatal(err)
	}
}

func loadPNG(path string) (image.Image, error) {
	f, err := os.Open(path)
	if err != nil {
		return nil, err
	}
	defer f.Close()
	return png.Decode(f)
}

func storePNG(path string, im image.Image) error {
	f, err := os.Create(path)
	if err != nil {
		return err
	}
	defer f.Close()
	return png.Encode(f, im)
}

type warpFn func(image.Image) image.Image

func warp(path string, warp warpFn) error {
	im, err := loadPNG(path)
	if err != nil {
		return err
	}
	warped := warp(im)
	return storePNG(path, warped)
}

type warpTile struct {
	im image.Image

	right    int
	farRight int
	top      int
	farTop   int

	src tile
	dst tile

	yOffset int
}

type tile struct {
	width  int
	height int
}

func (w warpTile) ColorModel() color.Model { return w.im.ColorModel() }

func (w warpTile) Bounds() image.Rectangle {
	bounds := w.im.Bounds()
	bounds.Max.Y = bounds.Dy() * w.dst.height / w.src.height
	return bounds
}

func (w warpTile) At(x, y int) color.Color {
	offset := image.Point{}
	for x >= w.dst.width {
		x -= w.dst.width
		offset.X += w.src.width
	}
	for y >= w.dst.height {
		y -= w.dst.height
		offset.Y += w.src.height
	}
	y += w.yOffset

	if y >= w.top && x < w.right {
		return w.im.At(x+offset.X, y-6*30+offset.Y)
	}

	isTopSide := func() bool {
		if y >= w.top {
			return false
		}
		if x < w.right {
			return true
		}
		sideX := w.farRight - (w.farRight-w.right)*(y-w.farTop)/(w.top-w.farTop)
		return x < sideX
	}
	if isTopSide() {
		srcY := w.farTop + (6*40)*(y-w.farTop)/(w.top-w.farTop)
		return w.im.At(x+offset.X, srcY+offset.Y)
	}
	srcY := y - (6*30)*(w.farRight-x)/(w.farRight-w.right)
	srcBottom := 6 * 160
	if srcY > srcBottom {
		srcY = srcBottom
	}
	return w.im.At(x+offset.X, srcY+offset.Y)
}

func run() error {
	warp("../krampus19/res/tile_lava_brick.png", func(im image.Image) image.Image {
		return &warpTile{
			im:       im,
			dst:      tile{width: 6 * 170, height: 6 * 190},
			src:      tile{width: 6 * 170, height: 6 * 160},
			right:    6 * 110,
			farRight: 6 * 160,
			top:      6 * 80,
			farTop:   6 * 10,
		}
	})
	warp("../krampus19/res/tile_magma.png", func(im image.Image) image.Image {
		return &warpTile{
			im:       im,
			dst:      tile{width: 6 * 170, height: 6 * 190},
			src:      tile{width: 6 * 170, height: 6 * 160},
			right:    6 * 110,
			farRight: 6 * 160,
			top:      6 * 100,
			farTop:   6 * 30,
		}
	})
	warp("../krampus19/res/entity_brick.png", func(im image.Image) image.Image {
		return &warpTile{
			im:       im,
			dst:      tile{width: 6 * 170, height: 6 * 190},
			src:      tile{width: 6 * 170, height: 6 * 160},
			yOffset:  18,
			right:    6 * 100,
			farRight: 6 * 150,
			top:      6 * 100,
			farTop:   6 * 30,
		}
	})
	return nil
}
