#===============================================================================
# Also known as a Combo Box.
# NOTE: This control lets you type in whatever text you want. The dropdown list
#       only offers autocomplete-like suggestions, but you don't need to match
#       any of them.
#===============================================================================
class UIControls::TextBoxDropdownList < UIControls::TextBox
  attr_accessor :max_rows

  TEXT_BOX_WIDTH = 200 - TEXT_BOX_HEIGHT
  BUTTON_X       = TEXT_BOX_X + TEXT_BOX_WIDTH
  BUTTON_WIDTH   = TEXT_BOX_HEIGHT
  BUTTON_HEIGHT  = TEXT_BOX_HEIGHT
  MAX_LIST_ROWS  = 8

  def initialize(width, height, viewport, options, value = "")
    super(width, height, viewport, value)
    @box_width              = TEXT_BOX_WIDTH
    @options                = options
    @toggling_dropdown_list = false
    @max_rows               = MAX_LIST_ROWS
  end

  def dispose
    remove_dropdown_menu
    super
  end

  def values=(new_vals)
    @options = new_vals
    @dropdown_menu.values = @options if @dropdown_menu
  end

  def set_interactive_rects
    @text_box_rect = Rect.new(TEXT_BOX_X, (height - TEXT_BOX_HEIGHT) / 2,
                              [@box_width, width - (TEXT_BOX_X * 2) - BUTTON_WIDTH].min, TEXT_BOX_HEIGHT)
    @button_rect = Rect.new(BUTTON_X, @text_box_rect.y, BUTTON_WIDTH, BUTTON_HEIGHT)
    @interactions = {
      :text_box => @text_box_rect,
      :button => @button_rect
    }
  end

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

  def busy?
    return true if @dropdown_menu || @toggling_dropdown_list
    return super
  end

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

  def make_dropdown_menu
    menu_height = UIControls::List::ROW_HEIGHT * [@options.length, @max_rows].min
    # Draw menu's background
    @dropdown_menu_bg = BitmapSprite.new(@text_box_rect.width + @button_rect.width, menu_height + 4, self.viewport)
    @dropdown_menu_bg.x = self.x + @text_box_rect.x
    @dropdown_menu_bg.y = self.y + @text_box_rect.y + @text_box_rect.height
    @dropdown_menu_bg.z = self.z + 1
    @dropdown_menu_bg.bitmap.outline_rect(0, 0, @dropdown_menu_bg.width, @dropdown_menu_bg.height, Color.black)
    @dropdown_menu_bg.bitmap.fill_rect(1, 1, @dropdown_menu_bg.width - 2, @dropdown_menu_bg.height - 2, Color.white)
    # Create menu
    @dropdown_menu = UIControls::List.new(@text_box_rect.width + @button_rect.width - 4, menu_height, self.viewport, @options)
    @dropdown_menu.x = @dropdown_menu_bg.x + 2
    @dropdown_menu.y = @dropdown_menu_bg.y + 2
    @dropdown_menu.z = self.z + 2
    @dropdown_menu.set_interactive_rects
    @dropdown_menu.repaint
  end

  def remove_dropdown_menu
    @dropdown_menu_bg&.dispose
    @dropdown_menu_bg = nil
    @dropdown_menu&.dispose
    @dropdown_menu = nil
    @captured_area = nil
    @applied_filter = false
  end

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

  def draw_area_highlight
    highlight_color = nil
    if @captured_area == :text_box && !@hover_area && Input.press?(Input::MOUSELEFT)
      highlight_color = CAPTURE_COLOR
    elsif !@captured_area && [:text_box, :button].include?(@hover_area)
      # Draw mouse hover over area highlight
      highlight_color = HOVER_COLOR
    end
    return if !highlight_color
    [:text_box, :button].each do |area|
      rect = @interactions[area]
      self.bitmap.fill_rect(rect.x, rect.y, rect.width, rect.height, highlight_color) if rect
    end
  end

  def refresh
    @dropdown_menu&.refresh
    super
    # Draw disabled colour in button
    if disabled?
      self.bitmap.fill_rect(@button_rect.x, @button_rect.y,
                            @button_rect.width, @button_rect.height,
                            DISABLED_COLOR)
    end
    # Draw button outline
    self.bitmap.outline_rect(@button_rect.x, @button_rect.y,
                             @button_rect.width, @button_rect.height,
                             self.bitmap.font.color)
    # Draw down arrow
    arrow_area_x = @button_rect.x + @button_rect.width - @button_rect.height + 1
    arrow_area_width = @button_rect.height - 2
    # self.bitmap.fill_rect(arrow_area_x, @button_rect.y + 1, arrow_area_width, arrow_area_width,
    #                       (@hover_area && @captured_area != :button) ? HOVER_COLOR : Color.white)
    6.times do |i|
      self.bitmap.fill_rect(arrow_area_x + (arrow_area_width / 2) - 5 + i,
                            @button_rect.y + (arrow_area_width / 2) - 1 + i,
                            11 - (2 * i), 1, (disabled?) ? DISABLED_COLOR_DARK : self.bitmap.font.color)
    end
  end

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

  def on_mouse_press
    mouse_x, mouse_y = mouse_pos
    return if !mouse_x || !mouse_y
    if @dropdown_menu
      if @text_box_rect.contains?(mouse_x, mouse_y)
        # Clicked into the text box; put the text cursor in there
        @captured_area = :text_box
        @cursor_pos = get_cursor_index_from_mouse_position
        @cursor_timer = System.uptime
        invalidate
      elsif !@dropdown_menu.mouse_in_control?
        @value.strip! if @value.respond_to?("strip!")
        @value = @initial_value.dup if disabled?
        set_changed if @initial_value && @value != @initial_value
        reset_interaction
        remove_dropdown_menu
        @toggling_dropdown_list = true
      end
    else
      @captured_area = nil
      super
      if @captured_area
        make_dropdown_menu
        @toggling_dropdown_list = true
      end
    end
  end

  def on_mouse_release
    return if !@captured_area && !@dropdown_menu && !@toggling_dropdown_list
    if @toggling_dropdown_list
      @toggling_dropdown_list = false
      mouse_x, mouse_y = mouse_pos
      if mouse_x && mouse_y && @interactions[:text_box].contains?(mouse_x, mouse_y)
        @initial_value = @value.dup
        Input.text_input = true
        invalidate
      end
      return
    end
    if @dropdown_menu
      if @dropdown_menu.changed?
        new_val = @dropdown_menu.value
        new_val = @options[new_val] if new_val.is_a?(Integer)
        if new_val && new_val != @value
          self.value = new_val
          set_changed
        end
        @value.strip! if @value.respond_to?("strip!")
        reset_interaction
        remove_dropdown_menu
        @captured_area = nil
      elsif @captured_area
        mouse_x, mouse_y = mouse_pos
        if mouse_x && mouse_y && @interactions[:text_box].contains?(mouse_x, mouse_y)
          @captured_area = :text_box
          @initial_value = @value.dup
          Input.text_input = true
        end
      elsif !mouse_in_control? && !@dropdown_menu.mouse_in_control?
        @value.strip! if @value.respond_to?("strip!")
        self.value = @initial_value if disabled?
        set_changed if @initial_value && @value != @initial_value
        reset_interaction
        remove_dropdown_menu
        @captured_area = nil
      end
    else
      super
    end
    invalidate
  end

  def update
    @dropdown_menu&.update
    @dropdown_menu&.repaint
    super
    # Filter the dropdown menu options based on @value if it changes
    if @dropdown_menu && @initial_value && (@applied_filter || @value != @initial_value)
      filtered_options = @options.select do |key, val|
        key.downcase.include?(@value.downcase) || val.downcase.include?(@value.downcase)
      end
      @dropdown_menu.values = filtered_options
      @applied_filter = true
    end
  end
end
