package geometry

import "math"

// RaycastResult holds the results of the Raycast operation
type RaycastResult struct {
	In bool // point on the left
	On bool // point is directly on top of
}

// Raycast performs the raycast operation
func (seg Segment) Raycast(point Point) RaycastResult {

	p, a, b := point, seg.A, seg.B
	// make sure that the point is inside the segment bounds
	if a.Y < b.Y && (p.Y < a.Y || p.Y > b.Y) {
		return RaycastResult{false, false}
	} else if a.Y > b.Y && (p.Y < b.Y || p.Y > a.Y) {
		return RaycastResult{false, false}
	}

	// test if point is in on the segment
	if a.Y == b.Y {
		if a.X == b.X {
			if p == a {
				return RaycastResult{false, true}
			}
			return RaycastResult{false, false}
		}
		if p.Y == b.Y {
			// horizontal segment
			// check if the point in on the line
			if a.X < b.X {
				if p.X >= a.X && p.X <= b.X {
					return RaycastResult{false, true}
				}
			} else {
				if p.X >= b.X && p.X <= a.X {
					return RaycastResult{false, true}
				}
			}
		}
	}
	if a.X == b.X && p.X == b.X {
		// vertical segment
		// check if the point in on the line
		if a.Y < b.Y {
			if p.Y >= a.Y && p.Y <= b.Y {
				return RaycastResult{false, true}
			}
		} else {
			if p.Y >= b.Y && p.Y <= a.Y {
				return RaycastResult{false, true}
			}
		}
	}
	if (p.X-a.X)/(b.X-a.X) == (p.Y-a.Y)/(b.Y-a.Y) {
		return RaycastResult{false, true}
	}

	// do the actual raycast here.
	for p.Y == a.Y || p.Y == b.Y {
		p.Y = math.Nextafter(p.Y, math.Inf(1))
	}
	if a.Y < b.Y {
		if p.Y < a.Y || p.Y > b.Y {
			return RaycastResult{false, false}
		}
	} else {
		if p.Y < b.Y || p.Y > a.Y {
			return RaycastResult{false, false}
		}
	}
	if a.X > b.X {
		if p.X >= a.X {
			return RaycastResult{false, false}
		}
		if p.X <= b.X {
			return RaycastResult{true, false}
		}
	} else {
		if p.X >= b.X {
			return RaycastResult{false, false}
		}
		if p.X <= a.X {
			return RaycastResult{true, false}
		}
	}
	if a.Y < b.Y {
		if (p.Y-a.Y)/(p.X-a.X) >= (b.Y-a.Y)/(b.X-a.X) {
			return RaycastResult{true, false}
		}
	} else {
		if (p.Y-b.Y)/(p.X-b.X) >= (a.Y-b.Y)/(a.X-b.X) {
			return RaycastResult{true, false}
		}
	}
	return RaycastResult{false, false}
}