package main

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

type Ship struct {
	Pos        h.Coordinate
	Dir        int
	Waypoint   h.Coordinate
	ByWaypoint bool
}

func (s *Ship) Navigate(inp []string) {
	for i := range inp {
		cmd, dist := inp[i][0], h.Atoi(inp[i][1:])
		switch cmd {
		case 'N':
			if s.ByWaypoint {
				s.MoveWaypoint(N, dist)
			} else {
				s.MoveDirection(N, dist)
			}
		case 'S':
			if s.ByWaypoint {
				s.MoveWaypoint(S, dist)
			} else {
				s.MoveDirection(S, dist)
			}
		case 'E':
			if s.ByWaypoint {
				s.MoveWaypoint(E, dist)
			} else {
				s.MoveDirection(E, dist)
			}
		case 'W':
			if s.ByWaypoint {
				s.MoveWaypoint(W, dist)
			} else {
				s.MoveDirection(W, dist)
			}
		case 'L':
			if s.ByWaypoint {
				s.RotateWaypointLeft(dist)
			} else {
				s.TurnLeft(dist)
			}
		case 'R':
			if s.ByWaypoint {
				s.RotateWaypointRight(dist)
			} else {
				s.TurnRight(dist)
			}
		case 'F':
			if s.ByWaypoint {
				s.MoveToWaypoint(dist)
			} else {
				s.MoveDirection(s.Dir, dist)
			}
		}
	}
}

func (s *Ship) MoveDirection(dir int, dist int) {
	switch dir {
	case N:
		s.Pos.Y = s.Pos.Y - dist
	case E:
		s.Pos.X = s.Pos.X + dist
	case S:
		s.Pos.Y = s.Pos.Y + dist
	case W:
		s.Pos.X = s.Pos.X - dist
	}
}

func (s *Ship) TurnRight(deg int) {
	deg = deg % 360
	for deg > 0 {
		s.Dir = s.Dir + 1
		deg = deg - 90
	}
	s.Dir = s.Dir % (W + 1)
}

func (s *Ship) TurnLeft(deg int) {
	deg = deg % 360
	for deg > 0 {
		s.Dir = s.Dir - 1
		deg = deg - 90
		if s.Dir == -1 {
			s.Dir = W
		}
	}
}

func (s *Ship) MoveToWaypoint(times int) {
	for i := times; i > 0; i-- {
		s.Pos.X += s.Waypoint.X
		s.Pos.Y += s.Waypoint.Y
	}
}

func (s *Ship) MoveWaypoint(dir int, dist int) {
	switch dir {
	case N:
		s.Waypoint.Y = s.Waypoint.Y - dist
	case E:
		s.Waypoint.X = s.Waypoint.X + dist
	case S:
		s.Waypoint.Y = s.Waypoint.Y + dist
	case W:
		s.Waypoint.X = s.Waypoint.X - dist
	}
}

func (s *Ship) RotateWaypointLeft(deg int) {
	deg = deg % 360
	for deg > 0 {
		s.Waypoint.X, s.Waypoint.Y = s.Waypoint.Y, s.Waypoint.X*-1
		deg = deg - 90
	}
}

func (s *Ship) RotateWaypointRight(deg int) {
	deg = deg % 360
	for deg > 0 {
		s.Waypoint.X, s.Waypoint.Y = s.Waypoint.Y*-1, s.Waypoint.X
		deg = deg - 90
	}
}
