# author: Ethosa
import math
{.used.}


type
  Vector2Obj* = object
    x*, y*: float
  Vector2Ref* = ref Vector2Obj


proc Vector2*(x, y: float): Vector2Obj {.inline.} =
  Vector2Obj(x: x, y: y)

proc Vector2*(b: Vector2Obj): Vector2Obj {.inline.} =
  Vector2Obj(x: b.x, y: b.y)

proc Vector2*(num: float): Vector2Obj {.inline.} =
  Vector2Obj(x: num, y: num)

proc Vector2*(): Vector2Obj {.inline.} =
  Vector2Obj(x: 0, y: 0)


proc newVector2*(x, y: float): Vector2Ref {.inline.} =
  Vector2Ref(x: x, y: y)

proc newVector2*(o: Vector2Obj): Vector2Ref {.inline.} =
  Vector2Ref(x: o.x, y: o.y)

proc newVector2*(o: float): Vector2Ref {.inline.} =
  Vector2Ref(x: o, y: o)

proc newVector2*(): Vector2Ref {.inline.} =
  Vector2Ref(x: 0f, y: 0f)



proc abs*(a: Vector2Obj): Vector2Obj =
  Vector2(abs(a.x), abs(a.y))

proc angle*(a: Vector2Obj): float {.inline.} =
  arctan2(a.y, a.x)

proc clear*(a: var Vector2Obj) =
  a.x = 0
  a.y = 0

proc cross*(a, b: Vector2Obj): float {.inline.} =
  a.x*b.x - a.y*b.y

proc cross*(a: Vector2Obj, x, y: float): float {.inline.} =
  a.x*x - a.y*y

proc dot*(a, b: Vector2Obj): float {.inline.} =
  a.x*b.x + a.y*b.y

proc dot*(a: Vector2Obj, x, y: float): float {.inline.} =
  a.x*x + a.y*y

proc angleTo*(a, b: Vector2Obj): float {.inline.} =
  arctan2(a.cross(b), a.dot(b))

proc angleTo*(a: Vector2Obj, x, y: float): float {.inline.} =
  arctan2(a.cross(x, y), a.dot(x, y))

proc angleToPoint*(a, b: Vector2Obj): float {.inline.} =
  arctan2(a.y - b.y, a.x - b.x)

proc angleToPoint*(a: Vector2Obj, x, y: float): float {.inline.} =
  arctan2(a.y - y, a.x - x)

proc length*(a: Vector2Obj): float {.inline.} =
  sqrt(a.x*a.x + a.y*a.y)

proc normalize*(a: var Vector2Obj) =
  var l: float = a.x*a.x + a.y*a.y
  if l != 0:
    l = sqrt(l)
    a.x /= l
    a.y /= l

proc normalized*(a: Vector2Obj): Vector2Obj =
  result = Vector2(a)
  result.normalize()

proc distance*(a, b: Vector2Obj): float {.inline.} =
  sqrt((b.x - a.x)*(b.x - a.x) + (b.y - a.y)*(b.y - a.y))

proc distance*(a: Vector2Obj, x, y: float): float {.inline.} =
  sqrt((x - a.x)*(x - a.x) + (y - a.y)*(y - a.y))

proc directionTo*(a, b: Vector2Obj): Vector2Obj =
  result = Vector2(b.x - a.x, b.y - a.y)
  result.normalize()

proc directionTo*(a: Vector2Obj, x, y: float): Vector2Obj =
  result = Vector2(x - a.x, y - a.y)
  result.normalize()

proc intersects*(a, b, c, d: Vector2Obj): bool =
  let
    uA = ((d.x-c.x)*(a.y-c.y) - (d.y-c.y)*(a.x-c.x)) / ((d.y-c.y)*(b.x-a.x) - (d.x-c.x)*(b.y-a.y))
    uB = ((b.x-a.x)*(a.y-c.y) - (b.y-a.y)*(a.x-c.x)) / ((d.y-c.y)*(b.x-a.x) - (d.x-c.x)*(b.y-a.y))
  return uA >= 0 and uA <= 1 and uB >= 0 and uB <= 1

proc isEmpty*(a: Vector2Obj): bool =
  a.x == 0f and a.y == 0f


# --- Operators --- #
proc `$`*(a: Vector2Obj): string {.inline.} =
  "Vector2(" & $a.x & ", " & $a.y & ")"

proc `+`*(a, b: Vector2Obj): Vector2Obj =
  Vector2(a.x + b.x, a.y + b.y)
proc `-`*(a, b: Vector2Obj): Vector2Obj =
  Vector2(a.x - b.x, a.y - b.y)
proc `/`*(a, b: Vector2Obj): Vector2Obj =
  Vector2(a.x / b.x, a.y / b.y)
proc `*`*(a, b: Vector2Obj): Vector2Obj =
  Vector2(a.x * b.x, a.y * b.y)

proc `*`*(x: Vector2Obj, y: float): Vector2Obj =
  Vector2(x.x * y, x.y * y)
proc `+`*(x: Vector2Obj, y: float): Vector2Obj =
  Vector2(x.x + y, x.y + y)
proc `-`*(x: Vector2Obj, y: float): Vector2Obj =
  Vector2(x.x - y, x.y - y)
proc `/`*(x: Vector2Obj, y: float): Vector2Obj =
  Vector2(x.x / y, x.y / y)

proc `*=`*(x: var Vector2Obj, y: Vector2Obj) =
  x = x * y
proc `+=`*(x: var Vector2Obj, y: Vector2Obj) =
  x = x + y
proc `-=`*(x: var Vector2Obj, y: Vector2Obj) =
  x = x - y
proc `/=`*(x: var Vector2Obj, y: Vector2Obj) =
  x = x / y

proc `>`*(x, y: Vector2Obj): bool =
  x.x > y.x and x.y > y.y
proc `<`*(x, y: Vector2Obj): bool =
  x.x < y.x and x.y < y.y
proc `>=`*(x, y: Vector2Obj): bool =
  x.x >= y.x and x.y >= y.y
proc `<=`*(x, y: Vector2Obj): bool =
  x.x <= y.x and x.y <= y.y
proc `==`*(x, y: Vector2Obj): bool =
  x.x == y.x and x.y == y.y
proc `!=`*(x, y: Vector2Obj): bool =
  x.x != y.x and x.y != y.y
