class PokemonGlobalMetadata
  attr_accessor :pokeradarBattery
end

class PokemonTemp
  attr_accessor :pokeradar # [species, level, chain count, grasses (x,y,ring,rarity)]
  attr_accessor :pokeradar_ui # [species, level, chain count, grasses (x,y,ring,rarity)]

end

################################################################################
# Using the Poke Radar
################################################################################
def pbCanUsePokeRadar?
  # Can't use Radar if not in tall grass
  terrain = $game_map.terrain_tag($game_player.x, $game_player.y)
  # if !terrain.land_wild_encounters || !terrain.shows_grass_rustle
  #   pbMessage(_INTL("Can't use that here."))
  #   return false
  # end
  if $PokemonEncounters.encounter_type == nil
    pbMessage(_INTL("Can't use that here."))
    return false
  end
  # Can't use Radar if map has no grass-based encounters (ignoring Bug Contest)
  # if !$PokemonEncounters.has_normal_land_encounters?
  #   pbMessage(_INTL("Can't use that here."))
  #   return false
  # end
  # Can't use Radar while cycling
  # if $PokemonGlobal.bicycle
  #   pbMessage(_INTL("Can't use that while on a bicycle."))
  #   return false
  # end
  # Debug
  return true if $DEBUG && Input.press?(Input::CTRL)
  # Can't use Radar if it isn't fully charged
  if $PokemonGlobal.pokeradarBattery && $PokemonGlobal.pokeradarBattery > 0
    pbMessage(_INTL("The battery has run dry!\nFor it to recharge, you need to walk another {1} steps.",
                    $PokemonGlobal.pokeradarBattery))
    return false
  end
  return true
end

def pbUsePokeRadar
  return false if !pbCanUsePokeRadar?
  $PokemonTemp.pokeradar = [0, 0, 0, []] if !$PokemonTemp.pokeradar
  $PokemonGlobal.pokeradarBattery = Settings::POKERADAR_BATTERY_STEPS
  unseenPokemon = listPokemonInCurrentRoute($PokemonEncounters.encounter_type, false, true)
  seenPokemon = listPokemonInCurrentRoute($PokemonEncounters.encounter_type, true, false)

  rareAllowed = canEncounterRarePokemon(unseenPokemon)
  displayPokeradarBanner(seenPokemon, unseenPokemon, rareAllowed)
  playPokeradarLightAnimation(rareAllowed)
  pbWait(20)
  pbPokeRadarHighlightGrass
  if $PokemonGlobal.repel <= 0
    $PokemonGlobal.repel=10
    $PokemonGlobal.tempRepel=true
  end
  return true
end

def listPokeradarRareEncounters()
  map = $game_map.map_id
  array = []
  Settings::POKE_RADAR_ENCOUNTERS.each do |enc|
    if enc[0] == map
      species = enc[2]
      array.push(species)
    end
  end
  return array
end

# #can only encounter rare if have seen every encounterable land pokemon on the route
# def canEncounterRarePokemon()
#   processed = []
#   for encounter in $PokemonEncounters.listPossibleEncounters($PokemonEncounters.pbEncounterType)
#     species = encounter[0]
#     if !processed.include?(species)
#       if $Trainer.seen[species]
#         processed << species
#       else
#         return false
#       end
#     end
#   end
#   return true
# end

def playPokeradarLightAnimation(rareAllowed = false)
  if rareAllowed
    $scene.spriteset.addUserAnimation(Settings::POKERADAR_LIGHT_ANIMATION_GREEN_ID, $game_player.x, $game_player.y, true)
  else
    $scene.spriteset.addUserAnimation(Settings::POKERADAR_LIGHT_ANIMATION_RED_ID, $game_player.x, $game_player.y, true)
  end
end

def displayPokeradarBanner(seenPokemon = [], unseenPokemon = [], includeRare = false)
  return if $PokemonTemp.pokeradar_ui != nil
  rarePokemon = includeRare ? listPokeradarRareEncounters() : []
  $PokemonTemp.pokeradar_ui = PokeRadar_UI.new(seenPokemon, unseenPokemon, rarePokemon)
end

def pbPokeRadarCancel
  if $PokemonGlobal.tempRepel
    $PokemonGlobal.repel=0
  end
  $PokemonGlobal.tempRepel=false

  if $PokemonTemp.pokeradar_ui != nil
    $PokemonTemp.pokeradar_ui.dispose
    $PokemonTemp.pokeradar_ui = nil
  end
  $PokemonTemp.pokeradar = nil
end



def listPokemonInCurrentRoute(encounterType, onlySeen = false, onlyUnseen = false)
  return [] if encounterType == nil
  processed = []
  seen = []
  unseen = []
  for encounter in $PokemonEncounters.listPossibleEncounters(encounterType)
    species = $game_switches[SWITCH_RANDOM_WILD] && !$game_switches[SWITCH_RANDOM_WILD_AREA] ? getRandomizedTo(encounter[1]) : encounter[1]

    if !processed.include?(species)
      if $Trainer.seen?(species)
        seen << species
        processed << species
      else
        unseen << species
        processed << species
      end
    end
  end
  if onlySeen
    return seen
  elsif onlyUnseen
    return unseen
  else
    return processed
  end
end

#can only encounter rare if have seen every encounterable land pokemon on the route
def canEncounterRarePokemon(unseenPokemon)
  terrain = $game_map.terrain_tag($game_player.x, $game_player.y)
  return unseenPokemon.length == 0 &&
    $PokemonEncounters.has_normal_land_encounters? &&
    terrain.land_wild_encounters &&
    terrain.shows_grass_rustle
end

def pbPokeRadarHighlightGrass(showmessage = true)
  grasses = [] # x, y, ring (0-3 inner to outer), rarity§
  # Choose 1 random tile from each ring around the player
  for i in 0...4
    r = rand((i + 1) * 8)
    # Get coordinates of randomly chosen tile
    x = $game_player.x
    y = $game_player.y
    if r <= (i + 1) * 2
      x = $game_player.x - i - 1 + r
      y = $game_player.y - i - 1
    elsif r <= (i + 1) * 6 - 2
      x = [$game_player.x + i + 1, $game_player.x - i - 1][r % 2]
      y = $game_player.y - i + ((r - 1 - (i + 1) * 2) / 2).floor
    else
      x = $game_player.x - i + r - (i + 1) * 6
      y = $game_player.y + i + 1
    end
    # Add tile to grasses array if it's a valid grass tile
    if x >= 0 && x < $game_map.width &&
      y >= 0 && y < $game_map.height
      terrain = $game_map.terrain_tag(x, y)
      if terrain.land_wild_encounters && terrain.shows_grass_rustle
        # Choose a rarity for the grass (0=normal, 1=rare, 2=shiny)
        s = (rand(100) < 25) ? 1 : 0
        if $PokemonTemp.pokeradar && $PokemonTemp.pokeradar[2] > 0
          v = [(65536 / Settings::SHINY_POKEMON_CHANCE) - $PokemonTemp.pokeradar[2] * 200, 200].max
          v = 0xFFFF / v
          v = rand(65536) / v
          s = 2 if v == 0
        end
        grasses.push([x, y, i, s])
      end
    end
  end
  if grasses.length == 0
    # No shaking grass found, break the chain
    pbMessage(_INTL("Nothing happened...")) if showmessage
    pbPokeRadarCancel
  else
    # Show grass rustling animations
    for grass in grasses
      case grass[3]
      when 0 # Normal rustle
        $scene.spriteset.addUserAnimation(Settings::RUSTLE_NORMAL_ANIMATION_ID, grass[0], grass[1], true, 1)
      when 1 # Vigorous rustle
        $scene.spriteset.addUserAnimation(Settings::RUSTLE_VIGOROUS_ANIMATION_ID, grass[0], grass[1], true, 1)
      when 2 # Shiny rustle
        $scene.spriteset.addUserAnimation(Settings::RUSTLE_SHINY_ANIMATION_ID, grass[0], grass[1], true, 1)
      end
    end
    $PokemonTemp.pokeradar[3] = grasses if $PokemonTemp.pokeradar
    pbWait(Graphics.frame_rate / 2)
  end
end

def pbPokeRadarGetShakingGrass
  return -1 if !$PokemonTemp.pokeradar
  grasses = $PokemonTemp.pokeradar[3]
  return -1 if grasses.length == 0
  for i in grasses
    return i[2] if $game_player.x == i[0] && $game_player.y == i[1]
  end
  return -1
end

def pbPokeRadarOnShakingGrass
  return pbPokeRadarGetShakingGrass >= 0
end

def pbPokeRadarGetEncounter(rarity = 0)
  # Poké Radar-exclusive encounters can only be found in vigorously-shaking grass
  if rarity > 0
    # Get all Poké Radar-exclusive encounters for this map
    map = $game_map.map_id
    array = []
    Settings::POKE_RADAR_ENCOUNTERS.each do |enc|
      array.push(enc) if enc[0] == map && GameData::Species.exists?(enc[2])
    end
    # If there are any exclusives, first have a chance of encountering those
    if array.length > 0 && listPokemonInCurrentRoute($PokemonEncounters.encounter_type, false, true).length==0
      rnd = rand(100)
      array.each do |enc|
        rnd -= enc[1]
        next if rnd >= 0
        level = (enc[4] && enc[4] > enc[3]) ? rand(enc[3]..enc[4]) : enc[3]
        return [enc[2], level]
      end
    end
  end
  # Didn't choose a Poké Radar-exclusive species, choose a regular encounter instead
  return $PokemonEncounters.choose_wild_pokemon($PokemonEncounters.encounter_type, rarity + 1)
end

################################################################################
# Event handlers
################################################################################
EncounterModifier.register(proc { |encounter|
  if GameData::EncounterType.get($PokemonTemp.encounterType).type != :land ||
    $PokemonGlobal.partner # $PokemonGlobal.bicycle || $PokemonGlobal.partner
    pbPokeRadarCancel
    next encounter
  end
  ring = pbPokeRadarGetShakingGrass
  if ring >= 0 # Encounter triggered by stepping into rustling grass
    # Get rarity of shaking grass
    rarity = 0 # 0 = rustle, 1 = vigorous rustle, 2 = shiny rustle
    $PokemonTemp.pokeradar[3].each { |g| rarity = g[3] if g[2] == ring }
    if $PokemonTemp.pokeradar[2] > 0 # Chain count, i.e. is chaining
      if rarity == 2 || rand(100) < 86 + ring * 4 + ($PokemonTemp.pokeradar[2] / 4).floor
        # Continue the chain
        encounter = [$PokemonTemp.pokeradar[0], $PokemonTemp.pokeradar[1]]
        $PokemonTemp.forceSingleBattle = true
      else
        # Break the chain, force an encounter with a different species
        100.times do
          break if encounter && encounter[0] != $PokemonTemp.pokeradar[0]
          encounter = $PokemonEncounters.choose_wild_pokemon($PokemonEncounters.encounter_type)
        end
        pbPokeRadarCancel
      end
    else
      # Not chaining; will start one
      # Force random wild encounter, vigorous shaking means rarer species
      encounter = pbPokeRadarGetEncounter(rarity)
      $PokemonTemp.forceSingleBattle = true
    end
  else
    # Encounter triggered by stepping in non-rustling grass
    pbPokeRadarCancel if encounter  && $PokemonGlobal.repel <= 0
  end
  next encounter
})

Events.onWildPokemonCreate += proc { |_sender, e|
  pokemon = e[0]
  next if !$PokemonTemp.pokeradar
  grasses = $PokemonTemp.pokeradar[3]
  next if !grasses
  for grass in grasses
    next if $game_player.x != grass[0] || $game_player.y != grass[1]
    pokemon.shiny = true if grass[3] == 2
    break
  end
}

Events.onWildBattleEnd += proc { |_sender, e|
  species = e[0]
  level = e[1]
  decision = e[2]
  if $PokemonTemp.pokeradar && (decision == 1 || decision == 4) # Defeated/caught
    $PokemonTemp.pokeradar[0] = species
    $PokemonTemp.pokeradar[1] = level
    $PokemonTemp.pokeradar[2] += 1
    $PokemonTemp.pokeradar[2] = 40 if $PokemonTemp.pokeradar[2] > 40
    pbPokeRadarHighlightGrass(false)
  else
    pbPokeRadarCancel
  end
}

Events.onStepTaken += proc { |_sender, _e|
  if $PokemonGlobal.pokeradarBattery && $PokemonGlobal.pokeradarBattery > 0 &&
    !$PokemonTemp.pokeradar
    $PokemonGlobal.pokeradarBattery -= 1
  end
  terrain = $game_map.terrain_tag($game_player.x, $game_player.y)
  if !terrain.land_wild_encounters || !terrain.shows_grass_rustle
    pbPokeRadarCancel
  end
}

Events.onMapChange += proc { |_sender, _e|
  pbPokeRadarCancel
}

################################################################################
# Item handlers
################################################################################
ItemHandlers::UseInField.add(:POKERADAR, proc { |item|
  next (pbCanUsePokeRadar?) ? pbUsePokeRadar : 0
})

ItemHandlers::UseFromBag.add(:POKERADAR, proc { |item|
  next (pbCanUsePokeRadar?) ? 2 : 0
})


