package day03

import (
	"strconv"
	"strings"
)

type Claim struct {
	ID       int
	Overlaps bool
	x1       int
	y1       int
	x2       int
	y2       int
}

// PopulateGrid takes a series of claims and 'draws' them on a 2d
// array, writing the claim ID to each cell. If an overlap happens,
// the value -1 is written instead.
// It also flags the claim object as 'overwritten' when this happens.
func PopulateGrid(data map[int]*Claim, maxX, maxY int) [][]int {
	grid := make([][]int, maxY)
	for i := 0; i < maxY; i++ {
		grid[i] = make([]int, maxX)
	}

	for _, claim := range data {
		for y := claim.y1; y < claim.y2; y++ {
			for x := claim.x1; x < claim.x2; x++ {
				if grid[y][x] != 0 {
					if grid[y][x] != -1 {
						data[grid[y][x]].Overlaps = true
					}

					grid[y][x] = -1
					data[claim.ID].Overlaps = true
				} else {
					grid[y][x] = claim.ID
				}
			}
		}
	}
	return grid
}

// ParseClaims takes our input data and creates some usable, structured data from it.
// Unfortunately the input data is ugly, and so this function reflects that.
// Returns a list of Claim objects, the highest seen X value, and the highest seen Y value.
func ParseClaims(rawData []string) (map[int]*Claim, int, int) {
	claims := make(map[int]*Claim)
	maxX := 0
	maxY := 0

	for _, line := range rawData {
		// Split the data on spaces, since that's the top-order delimiter.
		data := strings.Split(line, " ")
		id, _ := strconv.Atoi(data[0][1:])

		// The coordinate chunk (data[2]) needs the last character chopped off, since it is an unused ':'
		// That's what [:len(data[2])-1] is doing.
		coords := strings.Split(data[2][:len(data[2])-1], ",")
		x1, _ := strconv.Atoi(coords[0])
		y1, _ := strconv.Atoi(coords[1])

		size := strings.Split(data[3], "x")
		width, _ := strconv.Atoi(size[0])
		height, _ := strconv.Atoi(size[1])

		claim := &Claim{
			ID:       id,
			x1:       x1,
			x2:       x1 + width,
			y1:       y1,
			y2:       y1 + height,
			Overlaps: false,
		}
		claims[id] = claim

		if claim.y2 > maxY {
			maxY = claim.y2
		}
		if claim.x2 > maxX {
			maxX = claim.x2
		}
	}

	return claims, maxX, maxY
}