extends Node2D 
class_name RayCaster

const UP = Vector2(0, -1)
const DOWN = Vector2(0, 1)
const LEFT = Vector2(-1, 0)
const RIGHT = Vector2(1, 0)
const SKIN_WIDTH = 0

export (int) var buffer_size = 10 setget _set_buffer_size
var buffer = []

# Casts Rays into a given direction.
#   direction: 2D up, down, left or right vector
#   rect: Shape of the node the raycaster is attached to
#   mask: Collision layers
#   exceptions: Excepted collision layers
#   ray_length: Length of the rays
#   ray_buffer: Array to which the rays get saved
func _raycast(direction, rect, mask, exceptions = [], ray_length = 16, ray_buffer = self.buffer):
  if !(direction == UP || direction == DOWN || direction == LEFT || direction == RIGHT):
    return 0

  # TODO Manage debug options globally
  self.get_child(0).clear_lines()
  
  var space_state = get_world_2d().direct_space_state
  var extents = rect.extents - Vector2(SKIN_WIDTH, SKIN_WIDTH)
  var count = 0
  var ray_count = ray_buffer.size()
  var cast_to = (ray_length + SKIN_WIDTH) * direction
  var origin
  var spacing

  if direction == UP || direction == DOWN:
    spacing = extents.x * 2 / (ray_count - 1)
  else:
    spacing = extents.y * 2 / (ray_count - 1)
    
  for i in range(ray_count):
    if direction == UP || direction == DOWN:
      origin = Vector2(-extents.x + spacing * i, extents.y)
      if direction == UP:
        origin.y = -origin.y
      else:
        # TODO Manage debug options globally
        self.get_child(0).add_line(origin, Vector2(origin.x, origin.y + ray_length), Color( 1, 0, 0, 1 ))
    else:
      origin = Vector2(extents.x, -extents.y + spacing * i)
      if direction == LEFT:
        origin.x = -origin.x
      else:
        draw_line(origin, Vector2(origin.x + ray_length, origin.y), Color( 1, 0, 0, 1 ))

    var result = space_state.intersect_ray(global_position + origin, global_position + origin + cast_to,
                        exceptions, mask)
    if result:
      ray_buffer[count] = result
      count += 1
    
  self.get_child(0).update()
    
  return {ray_buffer = ray_buffer, count = count}


func _set_buffer_size(value):
  buffer_size = max(value, 2)
  self.buffer.resize(buffer_size)


# Called when the node enters the scene tree for the first time.
func _ready():
  _set_buffer_size(buffer_size)
