package aoc

import (
	"fmt"
	"math"
	"strings"
)

type Coordinate struct {
	X, Y int
}

func NewCoordinate(x, y int) *Coordinate {
	return &Coordinate{x, y}
}

func (c Coordinate) Relative(t Coordinate) Coordinate {
	return Coordinate{X: c.X + t.X, Y: c.Y + t.Y}
}

func (c Coordinate) North() Coordinate {
	return Coordinate{X: c.X, Y: c.Y - 1}
}
func (c Coordinate) East() Coordinate {
	return Coordinate{X: c.X + 1, Y: c.Y}
}
func (c Coordinate) South() Coordinate {
	return Coordinate{X: c.X, Y: c.Y + 1}
}
func (c Coordinate) West() Coordinate {
	return Coordinate{X: c.X - 1, Y: c.Y}
}
func (c *Coordinate) NW() Coordinate {
	return Coordinate{X: c.X - 1, Y: c.Y - 1}
}
func (c *Coordinate) NE() Coordinate {
	return Coordinate{X: c.X + 1, Y: c.Y - 1}
}
func (c *Coordinate) SW() Coordinate {
	return Coordinate{X: c.X - 1, Y: c.Y + 1}
}
func (c *Coordinate) SE() Coordinate {
	return Coordinate{X: c.X + 1, Y: c.Y + 1}
}

func (c *Coordinate) GetNorthCoord() *Coordinate {
	return &Coordinate{
		X: c.X,
		Y: c.Y - 1,
	}
}
func (c *Coordinate) GetEastCoord() *Coordinate {
	return &Coordinate{
		X: c.X + 1,
		Y: c.Y,
	}
}
func (c *Coordinate) GetSouthCoord() *Coordinate {
	return &Coordinate{
		X: c.X,
		Y: c.Y + 1,
	}
}
func (c *Coordinate) GetWestCoord() *Coordinate {
	return &Coordinate{
		X: c.X - 1,
		Y: c.Y,
	}
}

func CoordinateFromString(str string) *Coordinate {
	c := Coordinate{}
	r := strings.NewReader(str)
	_, err := fmt.Fscanf(r, "[%d, %d]", &c.X, &c.Y)
	if err != nil {
		panic(err)
	}
	return &c
}

func (c Coordinate) Angle(t Coordinate) float64 {
	ret := math.Atan2(float64(t.X-c.X), float64(c.Y-t.Y)) * 180 / math.Pi
	if ret < 0 {
		ret = ret + 360
	}
	return ret
}

func (c Coordinate) String() string {
	return fmt.Sprintf("[%d, %d]", c.X, c.Y)
}

func (c Coordinate) Distance(t Coordinate) int {
	return AbsInt(c.X-t.X) + AbsInt(c.Y-t.Y)
}

func (c Coordinate) Equals(c2 Coordinate) bool {
	return c.X == c2.X && c.Y == c2.Y
}
