package main

import (
	"fmt"

	h "git.bullercodeworks.com/brian/adventofcode/helpers"
)

func main() {
	inp := h.StdinToCoordMap()
	part1(inp)
	part2(inp)
}

func part1(m h.CoordByteMap) {
	var total int
	for y := m.TLY; y <= m.BRY; y++ {
		for x := m.TLX; x <= m.BRX; x++ {
			total += checkPos(m, h.Coordinate{X: x, Y: y})
		}
	}
	fmt.Println("# Part 1")
	fmt.Println("Instances of XMAS:", total)
}

func part2(m h.CoordByteMap) {
	var total int
	for y := m.TLY; y <= m.BRY; y++ {
		for x := m.TLX; x <= m.BRX; x++ {
			if checkXPos(m, h.Coordinate{X: x, Y: y}) {
				total++
			}
		}
	}
	fmt.Println("# Part 2")
	fmt.Println("Instances of X-MAS:", total)
}

// checkPos takes an x,y and returns how many instances of
// 'XMAS' occur starting there.
func checkPos(m h.CoordByteMap, c h.Coordinate) int {
	if m.Get(c) != 'X' {
		return 0
	}

	var total int
	for _, dir := range []h.Coordinate{
		{X: -1, Y: 0},  // North
		{X: -1, Y: 1},  // Northeast
		{X: 0, Y: 1},   // East
		{X: 1, Y: 1},   // Southeast
		{X: 1, Y: 0},   // South
		{X: 1, Y: -1},  // Southwest
		{X: 0, Y: -1},  // West
		{X: -1, Y: -1}, // Northwest
	} {
		if checkDir(m, c, dir, []byte{'X', 'M', 'A', 'S'}) {
			total++
		}
	}
	return total
}

// checkDir follows a direction to look for the word returning true if found.
func checkDir(m h.CoordByteMap, c h.Coordinate, dir h.Coordinate, word []byte) bool {
	if len(word) == 0 {
		return true
	}
	if m.Get(c) != word[0] {
		return false
	}
	return checkDir(m, c.Relative(dir), dir, word[1:])
}

func checkXPos(m h.CoordByteMap, c h.Coordinate) bool {
	if m.Get(c) != 'A' {
		return false
	}
	// A X-Mas can be:
	// M S  S M  M M  S S
	//  A    A    A    A
	// M S  S M  S S  M M
	wrk := string([]byte{m.Get(c.NE()), m.Get(c.SW()), m.Get(c.NW()), m.Get(c.SE())})
	return wrk == "MSMS" || wrk == "SMSM" || wrk == "MSSM" || wrk == "SMMS"
}