class Game
  attr_gtk

  def defaults
    state.show_debug_layer = true if state.tick_count == 0

    state.player ||= {
      tile_size: 64,
      speed: 3,
      slash_frames: 15,
      x: 50,
      y: 400,
      dir_x: 1,
      dir_y: -1,
      is_moving: false
    }

    state.enemies ||= []
  end

  def add_enemy
    state.enemies << {
      x: 1200 * rand,
      y: 600 * rand,
      w: 64,
      h: 64,
      anchor_x: 0.5,
      anchor_y: 0.5,
      path: 'sprites/enemy.png'
    }
  end

  def sprite_horizontal_run
    tile_index = 0.frame_index(6, 3, true)
    tile_index = 0 if !player.is_moving

    {
      x: player.x,
      y: player.y,
      w: player.tile_size,
      h: player.tile_size,
      anchor_x: 0.5,
      anchor_y: 0.5,
      path: 'sprites/horizontal-run.png',
      tile_x: 0 + (tile_index * player.tile_size),
      tile_y: 0,
      tile_w: player.tile_size,
      tile_h: player.tile_size,
      flip_horizontally: player.dir_x > 0,
    }
  end

  def sprite_horizontal_stand
    {
      x: player.x,
      y: player.y,
      w: player.tile_size,
      h: player.tile_size,
      anchor_x: 0.5,
      anchor_y: 0.5,
      path: 'sprites/horizontal-stand.png',
      flip_horizontally: player.dir_x > 0,
    }
  end

  def sprite_horizontal_slash
    tile_index   = player.slash_at.frame_index(5, player.slash_frames.idiv(5), false) || 0

    {
      x: player.x + player.dir_x.sign * 9.25,
      y: player.y + 9.25,
      w: 165,
      h: 165,
      anchor_x: 0.5,
      anchor_y: 0.5,
      path: 'sprites/horizontal-slash.png',
      tile_x: 0 + (tile_index * 128),
      tile_y: 0,
      tile_w: 128,
      tile_h: 128,
      flip_horizontally: player.dir_x > 0
    }
  end

  def render_player
    if player.slash_at
      outputs.sprites << sprite_horizontal_slash
    elsif player.is_moving
      outputs.sprites << sprite_horizontal_run
    else
      outputs.sprites << sprite_horizontal_stand
    end
  end

  def render_enemies
    outputs.borders << state.enemies
  end

  def render_debug_layer
    return if !state.show_debug_layer
    outputs.borders << player.slash_collision_rect
  end

  def slash_initiate?
    inputs.controller_one.key_down.a || inputs.keyboard.key_down.j
  end

  def input
    # player movement
    if slash_complete? && (vector = inputs.directional_vector)
      player.x += vector.x * player.speed
      player.y += vector.y * player.speed
    end
    player.slash_at = slash_initiate? if slash_initiate?
  end

  def calc_movement
    # movement
    if vector = inputs.directional_vector
      state.debug_label = vector
      player.dir_x = vector.x if vector.x != 0
      player.dir_y = vector.y if vector.y != 0
      player.is_moving = true
    else
      state.debug_label = vector
      player.is_moving = false
    end
  end

  def calc_slash
    player.slash_collision_rect = {
      x: player.x + player.dir_x.sign * 52,
      y: player.y,
      w: 40,
      h: 20,
      anchor_x: 0.5,
      anchor_y: 0.5,
      path: "sprites/debug-slash.png"
    }

    # recalc sword's slash state
    player.slash_at = nil if slash_complete?

    # determine collision if the sword is at it's point of damaging
    return unless slash_can_damage?

    state.enemies.reject! { |e| e.intersect_rect? player.slash_collision_rect }
  end

  def slash_complete?
    !player.slash_at || player.slash_at.elapsed?(player.slash_frames)
  end

  def slash_can_damage?
    # damage occurs half way into the slash animation
    return false if slash_complete?
    return false if (player.slash_at + player.slash_frames.idiv(2)) != state.tick_count
    return true
  end

  def calc
    # generate an enemy if there aren't any on the screen
    add_enemy if state.enemies.length == 0
    calc_movement
    calc_slash
  end

  # source is at http://github.com/amirrajan/dragonruby-link-to-the-past
  def tick
    defaults
    render_enemies
    render_player
    outputs.labels << [30, 30, "Gamepad: D-Pad to move. B button to attack."]
    outputs.labels << [30, 52, "Keyboard: WASD/Arrow keys to move. J to attack."]
    render_debug_layer
    input
    calc
  end

  def player
    state.player
  end
end

$game = Game.new

def tick args
  $game.args = args
  $game.tick
end

$gtk.reset