#===============================================================================
#
#===============================================================================
class AnimationEditor::AnimationSelector
  BORDER_THICKNESS       = 4

  QUIT_BUTTON_WIDTH      = 80
  QUIT_BUTTON_HEIGHT     = 30

  TYPE_BUTTONS_X         = 2
  TYPE_BUTTONS_Y         = 62
  TYPE_BUTTON_WIDTH      = 100
  TYPE_BUTTON_HEIGHT     = 48

  MOVES_LIST_X           = TYPE_BUTTONS_X + TYPE_BUTTON_WIDTH + 4
  MOVES_LIST_Y           = TYPE_BUTTONS_Y + 4
  MOVES_LIST_WIDTH       = 200
  MOVES_LIST_HEIGHT      = 26 * UIControls::List::ROW_HEIGHT

  ANIMATIONS_LIST_X      = MOVES_LIST_X + MOVES_LIST_WIDTH + 8
  ANIMATIONS_LIST_Y      = MOVES_LIST_Y
  ANIMATIONS_LIST_WIDTH  = 300
  ANIMATIONS_LIST_HEIGHT = MOVES_LIST_HEIGHT

  ACTION_BUTTON_WIDTH    = 200
  ACTION_BUTTON_HEIGHT   = 48
  ACTION_BUTTON_X        = ANIMATIONS_LIST_X + ANIMATIONS_LIST_WIDTH + 4
  ACTION_BUTTON_Y        = TYPE_BUTTONS_Y + ((ANIMATIONS_LIST_HEIGHT - (ACTION_BUTTON_HEIGHT * 3)) / 2) + 4

  # Pop-up window
  MESSAGE_BOX_WIDTH         = AnimationEditor::WINDOW_WIDTH * 3 / 4
  MESSAGE_BOX_HEIGHT        = 160
  MESSAGE_BOX_BUTTON_WIDTH  = 150
  MESSAGE_BOX_BUTTON_HEIGHT = 32
  MESSAGE_BOX_SPACING       = 16

  def initialize
    generate_lists
    @viewport = Viewport.new(0, 0, AnimationEditor::WINDOW_WIDTH, AnimationEditor::WINDOW_HEIGHT)
    @viewport.z = 99999
    @pop_up_viewport = Viewport.new(0, 0, AnimationEditor::WINDOW_WIDTH, AnimationEditor::WINDOW_HEIGHT)
    @pop_up_viewport.z = @viewport.z + 50
    @screen_bitmap = BitmapSprite.new(AnimationEditor::WINDOW_WIDTH, AnimationEditor::WINDOW_HEIGHT, @viewport)
    @pop_up_bg_bitmap = BitmapSprite.new(AnimationEditor::WINDOW_WIDTH, AnimationEditor::WINDOW_HEIGHT, @pop_up_viewport)
    @pop_up_bg_bitmap.z = -100
    @pop_up_bg_bitmap.visible = false
    draw_editor_background
    @animation_type = 0   # 0=move, 1=common
    @quit = false
    create_controls
    refresh
  end

  def dispose
    @screen_bitmap.dispose
    @pop_up_bg_bitmap.dispose
    @components.dispose
    @viewport.dispose
    @pop_up_viewport.dispose
  end

  LABEL_OFFSET_X = -4
  LABEL_OFFSET_Y = -32

  def create_controls
    @components = UIControls::ControlsContainer.new(0, 0, AnimationEditor::WINDOW_WIDTH, AnimationEditor::WINDOW_HEIGHT)
    # Quit button
    btn = UIControls::Button.new(QUIT_BUTTON_WIDTH, QUIT_BUTTON_HEIGHT, @viewport, _INTL("Quit"))
    btn.set_fixed_size
    @components.add_control_at(:quit, btn, 0, 0)
    # New button
    btn = UIControls::Button.new(QUIT_BUTTON_WIDTH, QUIT_BUTTON_HEIGHT, @viewport, _INTL("New"))
    btn.set_fixed_size
    @components.add_control_at(:new, btn, QUIT_BUTTON_WIDTH, 0)
    # Type label
    label = UIControls::Label.new(TYPE_BUTTON_WIDTH, TYPE_BUTTON_HEIGHT, @viewport, _INTL("Anim types"))
    label.header = true
    @components.add_control_at(:type_label, label, TYPE_BUTTONS_X + LABEL_OFFSET_X + 4, TYPE_BUTTONS_Y + LABEL_OFFSET_Y + 4)
    # Animation type toggle buttons
    [[:moves, _INTL("Moves")], [:commons, _INTL("Common")]].each_with_index do |val, i|
      btn = UIControls::Button.new(TYPE_BUTTON_WIDTH, TYPE_BUTTON_HEIGHT, @viewport, val[1])
      btn.set_fixed_size
      @components.add_control_at(val[0], btn, TYPE_BUTTONS_X, TYPE_BUTTONS_Y + (i * TYPE_BUTTON_HEIGHT))
    end
    # TODO: Add filter text box for :moves_list's contents. Applies the filter
    #       upon every change to the text box's value. Perhaps it should only do
    #       so after 0.5 seconds of non-typing. What exactly should the filter
    #       be applied to? Animation's name, move's name (if there is one), what
    #       else? Flags?
    # Moves list label
    label = UIControls::Label.new(MOVES_LIST_WIDTH, TYPE_BUTTON_HEIGHT, @viewport, _INTL("Moves"))
    label.header = true
    @components.add_control_at(:moves_label, label, MOVES_LIST_X + LABEL_OFFSET_X, MOVES_LIST_Y + LABEL_OFFSET_Y)
    # Moves list
    list = UIControls::List.new(MOVES_LIST_WIDTH, MOVES_LIST_HEIGHT, @viewport, [])
    @components.add_control_at(:moves_list, list, MOVES_LIST_X, MOVES_LIST_Y)
    # Animations list label
    label = UIControls::Label.new(ANIMATIONS_LIST_WIDTH, TYPE_BUTTON_HEIGHT, @viewport, _INTL("Animations"))
    label.header = true
    @components.add_control_at(:animations_label, label, ANIMATIONS_LIST_X + LABEL_OFFSET_X, ANIMATIONS_LIST_Y + LABEL_OFFSET_Y)
    # Animations list
    list = UIControls::List.new(ANIMATIONS_LIST_WIDTH, ANIMATIONS_LIST_HEIGHT, @viewport, [])
    @components.add_control_at(:animations_list, list, ANIMATIONS_LIST_X, ANIMATIONS_LIST_Y)
    # Edit, Copy and Delete buttons
    [[:edit, _INTL("Edit animation")], [:copy, _INTL("Copy animation")], [:delete, _INTL("Delete animation")]].each_with_index do |val, i|
      btn = UIControls::Button.new(ACTION_BUTTON_WIDTH, ACTION_BUTTON_HEIGHT, @viewport, val[1])
      btn.set_fixed_size
      @components.add_control_at(val[0], btn, ACTION_BUTTON_X, ACTION_BUTTON_Y + (i * ACTION_BUTTON_HEIGHT))
    end
  end

  def draw_editor_background
    # Fill the whole screen with white
    @screen_bitmap.bitmap.fill_rect(0, 0, AnimationEditor::WINDOW_WIDTH, AnimationEditor::WINDOW_HEIGHT, Color.white)
    # Outlines around lists
    areas = [
      [MOVES_LIST_X, MOVES_LIST_Y, MOVES_LIST_WIDTH, MOVES_LIST_HEIGHT],
      [ANIMATIONS_LIST_X, ANIMATIONS_LIST_Y, ANIMATIONS_LIST_WIDTH, ANIMATIONS_LIST_HEIGHT]
    ]
    areas.each do |area|
      @screen_bitmap.bitmap.outline_rect(area[0] - 2, area[1] - 2, area[2] + 4, area[3] + 4, Color.black)
    end
  end

  #-----------------------------------------------------------------------------

  def create_pop_up_window(width, height)
    ret = BitmapSprite.new(width + (BORDER_THICKNESS * 2),
                           height + (BORDER_THICKNESS * 2), @pop_up_viewport)
    ret.x = (AnimationEditor::WINDOW_WIDTH - ret.width) / 2
    ret.y = (AnimationEditor::WINDOW_HEIGHT - ret.height) / 2
    ret.z = -1
    ret.bitmap.font.color = Color.black
    ret.bitmap.font.size = 18
    # Draw pop-up box border
    ret.bitmap.border_rect(BORDER_THICKNESS, BORDER_THICKNESS, width, height,
                           BORDER_THICKNESS, Color.white, Color.black)
    # Fill pop-up box with white
    ret.bitmap.fill_rect(BORDER_THICKNESS, BORDER_THICKNESS, width, height, Color.white)
    return ret
  end

  #-----------------------------------------------------------------------------

  def message(text, *options)
    @pop_up_bg_bitmap.visible = true
    msg_bitmap = create_pop_up_window(MESSAGE_BOX_WIDTH, MESSAGE_BOX_HEIGHT)
    # Draw text
    text_size = msg_bitmap.bitmap.text_size(text)
    msg_bitmap.bitmap.draw_text(0, (msg_bitmap.height / 2) - MESSAGE_BOX_BUTTON_HEIGHT,
                                msg_bitmap.width, text_size.height, text, 1)
    # Create buttons
    buttons = []
    options.each_with_index do |option, i|
      btn = UIControls::Button.new(MESSAGE_BOX_BUTTON_WIDTH, MESSAGE_BOX_BUTTON_HEIGHT, @pop_up_viewport, option[1])
      btn.x = msg_bitmap.x + (msg_bitmap.width - (MESSAGE_BOX_BUTTON_WIDTH * options.length)) / 2
      btn.x += MESSAGE_BOX_BUTTON_WIDTH * i
      btn.y = msg_bitmap.y + msg_bitmap.height - MESSAGE_BOX_BUTTON_HEIGHT - MESSAGE_BOX_SPACING
      btn.set_fixed_size
      btn.set_interactive_rects
      buttons.push([option[0], btn])
    end
    # Interaction loop
    ret = nil
    captured = nil
    loop do
      Graphics.update
      Input.update
      if captured
        captured.update
        captured = nil if !captured.busy?
      else
        buttons.each do |btn|
          btn[1].update
          captured = btn[1] if btn[1].busy?
        end
      end
      buttons.each do |btn|
        next if !btn[1].changed?
        ret = btn[0]
        break
      end
      ret = :cancel if Input.trigger?(Input::BACK)
      break if ret
      buttons.each { |btn| btn[1].repaint }
    end
    # Dispose and return
    buttons.each { |btn| btn[1].dispose }
    buttons.clear
    msg_bitmap.dispose
    @pop_up_bg_bitmap.visible = false
    return ret
  end

  def confirm_message(text)
    return message(text, [:yes, _INTL("Yes")], [:no, _INTL("No")]) == :yes
  end

  #-----------------------------------------------------------------------------

  def generate_lists
    @move_list = []
    @common_list = []
    @move_animations = {}
    @common_animations = {}
    GameData::Animation.keys.each do |id|
      anim = GameData::Animation.get(id)
      name = ""
      name += _INTL("[Foe]") + " " if anim.opposing_animation?
      name += "[#{anim.version}]" + " " if anim.version > 0
      name += (anim.name || anim.move)
      if anim.move_animation?
        move_name = GameData::Move.try_get(anim.move)&.name || anim.move
        @move_list.push([anim.move, move_name]) if !@move_animations[anim.move]
        @move_animations[anim.move] ||= []
        @move_animations[anim.move].push([id, name])
      elsif anim.common_animation?
        @common_list.push([anim.move, anim.move]) if !@common_animations[anim.move]
        @common_animations[anim.move] ||= []
        @common_animations[anim.move].push([id, name])
      end
    end
    @move_list.sort!
    @common_list.sort!
    @move_animations.values.each do |val|
      val.sort! { |a, b| a[1] <=> b[1] }
    end
    @common_animations.values.each do |val|
      val.sort! { |a, b| a[1] <=> b[1] }
    end
  end

  def selected_move_animations
    val = @components.get_control(:moves_list).value
    return [] if !val
    return @move_animations[val] if @animation_type == 0
    return @common_animations[val] if @animation_type == 1
    return []
  end

  def selected_animation_id
    return @components.get_control(:animations_list).value
  end

  #-----------------------------------------------------------------------------

  def refresh
    # Put the correct list into the moves list
    case @animation_type
    when 0
      @components.get_control(:moves).disable
      @components.get_control(:commons).enable
      @components.get_control(:moves_list).values = @move_list
      @components.get_control(:moves_label).text = _INTL("Moves")
    when 1
      @components.get_control(:moves).enable
      @components.get_control(:commons).disable
      @components.get_control(:moves_list).values = @common_list
      @components.get_control(:moves_label).text = _INTL("Common animations")
    end
    # Put the correct list into the animations list
    @components.get_control(:animations_list).values = selected_move_animations
    # Enable/disable buttons depending on what is selected
    if @components.get_control(:animations_list).value
      @components.get_control(:edit).enable
      @components.get_control(:copy).enable
      @components.get_control(:delete).enable
    else
      @components.get_control(:edit).disable
      @components.get_control(:copy).disable
      @components.get_control(:delete).disable
    end
  end

  #-----------------------------------------------------------------------------

  def apply_button_press(button)
    case button
    when :quit
      @quit = true
      return   # Don't need to refresh the screen
    when :new
      new_anim = GameData::Animation.new_hash(@animation_type, @components.get_control(:moves_list).value)
      new_id = GameData::Animation.keys.max + 1
      screen = AnimationEditor.new(new_id, new_anim)
      screen.run
      generate_lists
    when :moves
      @animation_type = 0
      @components.get_control(:moves_list).selected = -1
      @components.get_control(:animations_list).selected = -1
    when :commons
      @animation_type = 1
      @components.get_control(:moves_list).selected = -1
      @components.get_control(:animations_list).selected = -1
    when :edit
      anim_id = selected_animation_id
      if anim_id
        screen = AnimationEditor.new(anim_id, GameData::Animation.get(anim_id).clone_as_hash)
        screen.run
        generate_lists
      end
    when :copy
      anim_id = selected_animation_id
      if anim_id
        new_anim = GameData::Animation.get(anim_id).clone_as_hash
        new_anim[:name] += " " + _INTL("(copy)") if !nil_or_empty?(new_anim[:name])
        new_id = GameData::Animation.keys.max + 1
        screen = AnimationEditor.new(new_id, new_anim)
        screen.run
        generate_lists
      end
    when :delete
      anim_id = selected_animation_id
      if anim_id && confirm_message(_INTL("Are you sure you want to delete this animation?"))
        pbs_path = GameData::Animation.get(anim_id).pbs_path
        GameData::Animation::DATA.delete(anim_id)
        if GameData::Animation::DATA.any? { |_key, anim| anim.pbs_path == pbs_path }
          Compiler.write_battle_animation_file(pbs_path)
        elsif FileTest.exist?("PBS/Animations/" + pbs_path + ".txt")
          File.delete("PBS/Animations/" + pbs_path + ".txt")
        end
        generate_lists
      end
    end
    refresh
  end

  def update
    @components.update
    if @components.changed?
      @components.values.each_pair do |property, value|
        apply_button_press(property)
      end
      @components.clear_changed
    end
  end

  def run
    Input.text_input = false
    loop do
      Graphics.update
      Input.update
      update
      break if !@components.busy? && @quit
    end
    dispose
  end
end

#===============================================================================
# Add to Debug menu.
#===============================================================================
MenuHandlers.add(:debug_menu, :use_pc, {
  "name"        => _INTL("New Animation Editor"),
  "parent"      => :main,
  "description" => _INTL("Open the new animation editor."),
  "effect"      => proc {
    Graphics.resize_screen(AnimationEditor::WINDOW_WIDTH, AnimationEditor::WINDOW_HEIGHT)
    pbSetResizeFactor(1)
    screen = AnimationEditor::AnimationSelector.new
    screen.run
    Graphics.resize_screen(Settings::SCREEN_WIDTH, Settings::SCREEN_HEIGHT)
    pbSetResizeFactor($PokemonSystem.screensize)
    $game_map&.autoplay
  }
})
