#==============================================================================
# ** Window_Settings
#==============================================================================----
#  This window class handles settings
#==============================================================================
class Window_Settings
  MARGIN = 30
  TITLE_TOP_MARGIN = 32
  TITLE_MARGIN = 100
  ITEM_SPACING = 28
  VALUE_MARGIN = 270
  ACTIVE_MARGIN = MARGIN * 2 + 20

  CATEGORIES = {
    Audio: [
      SettingsElement.new("BGM Volume", Slider.new(Settings::VAR_PROXIES[:bgm_volume], 0, 100, 5)),
      SettingsElement.new("SE Volume", Slider.new(Settings::VAR_PROXIES[:sfx_volume], 0, 100, 5)),
      SettingsElement.new("Audio Filters", Boolean.new(Settings::VAR_PROXIES[:audio_filters])),
    ],
    Graphics: [
      SettingsElement.new("Fullscreen", Boolean.new(Settings::VAR_PROXIES[:fullscreen])),
      SettingsElement.new("Smooth Scaling", Boolean.new(Settings::VAR_PROXIES[:smoothing])),
      SettingsElement.new("Frameskip", Boolean.new(Settings::VAR_PROXIES[:frameskip])),
      SettingsElement.new("Colorblind Mode", Boolean.new(Settings::VAR_PROXIES[:colorblind_mode])),
      SettingsElement.new("Phosphor Glow", Boolean.new(Settings::VAR_PROXIES[:modglow])),
    ],
    Gameplay: [
      SettingsElement.new("DEFAULT RUN", Boolean.new(Settings::VAR_PROXIES[:default_run], "RUN", "WALK")),
      SettingsElement.new("Auto-mash", Boolean.new(Settings::VAR_PROXIES[:automash])),
    ],
    Misc: [
      SettingsElement.new("Equinox Debug", Boolean.new(Settings::VAR_PROXIES[:edebug])),
      SettingsElement.new("(Press F1 for controls)", Text.new, Color.new(255, 70, 70)),
    ],
    Close: [],
  }

  def initialize
    @viewport = Viewport.new(0, 0, 640, 480)
    @viewport.z = 9998

    @hints = {
      # Categorires
      "Audio" => "Audio related settings",
      "Graphics" => "Graphical settings (i.e frameskip)",
      "Gameplay" => "Gameplay settings (Movement speed, etc)",
      "Misc" => "Miscellaneous settings",
      "Close" => "Closes the settings menu",
      # Audio
      "BGM Volume" => "Background Music Volume",
      "SE Volume" => "Sound Effects Volume",
      "Audio Filters" => "Enable/Disable audio filters",
      # Graphics
      "Fullscreen" => "Toggle Fullscreen",
      "Smooth Scaling" => "Toggle Smooth Scaling",
      "Frameskip" => "Toggle Frameskips",
      "Colorblind Mode" => "Toggle Colorblind Mode",
      "Phosphor Glow" => "Toggle Sprite Glows",
      # Gameplay
      "DEFAULT RUN" => "Default Movement Type",
      "Auto-mash" => "Toggle Automash Usage",
      # Misc
      "Equinox Debug" => "Equinox Mod Debug Mode",
      "(Press F1 for controls)" => "Press F1 to edit controls",
    }

    @state = "categories"
    @category_index = CATEGORIES.keys[0]
    @index = 0

    @bg = Sprite.new(@viewport)
    @bg.bitmap = Bitmap.new(640, 480)
    @bg.bitmap.fill_rect(0, 0, 640, 480, Color.new(0, 0, 0, 128))

    @title = Sprite.new(@viewport)
    @title.bitmap = Bitmap.new(320, TITLE_MARGIN)
    @title.bitmap.font.size = 40
    @title.y = TITLE_TOP_MARGIN
    @title.x = MARGIN

    @hint = Sprite.new(@viewport)
    @hint.bitmap = Bitmap.new(640, 20)
    @hint.bitmap.font.color = Color.new(255, 255, 0)
    @hint.x = 10
    @hint.y = 450
    @hint.opacity = 128

    @version = Sprite.new(@viewport)
    @version.bitmap = Bitmap.new(640, 20)
    @version.x = 10
    @version.y = 420
    @version.opacity = 128

    Language.register_text_sprite(self.class.name + "_title", @title)
    Language.register_text_sprite(self.class.name + "_hint", @hint)
    Language.register_text_sprite(self.class.name + "_ver", @version)

    self.visible = false
    @fade_in = false
    @fade_out = false
    @transition_in = false
    @transition_out = false

    @sprites = []
    @hint_text = ""

    @left_hold_timer = 0
    @right_hold_timer = 0
  end

  def update
    update_render()
    return if !self.visible || @fade_out || @fade_in || @transition_in || @transition_out

    if @state == "categories"
      if Input.trigger?(Input::UP)
        @index = (@index - 1) % CATEGORIES.size
        $game_system.se_play($data_system.cursor_se)
      end
      if Input.trigger?(Input::DOWN)
        @index = (@index + 1) % CATEGORIES.size
        $game_system.se_play($data_system.cursor_se)
      end
      if Input.trigger?(Input::ACTION)
        if CATEGORIES.keys[@index].to_s == "Close"
          if Input.trigger?(Input::ACTION)
            Settings.save()
            @fade_out = true
          end
        else
          $game_system.se_play($data_system.decision_se)
          @state = "values"
          @category_index = CATEGORIES.keys[@index]
          @transition_out = true
        end
      end

      if Input.trigger?(Input::CANCEL)
        $game_system.se_play($data_system.cancel_se)
        @fade_out = true
        Settings.save()
      end
    elsif @state == "values"
      if Input.trigger?(Input::UP)
        @index = (@index - 1) % CATEGORIES[@category_index].size
        $game_system.se_play($data_system.cursor_se)
      end
      if Input.trigger?(Input::DOWN)
        @index = (@index + 1) % CATEGORIES[@category_index].size
        $game_system.se_play($data_system.cursor_se)
      end
      if Input.trigger?(Input::CANCEL)
        $game_system.se_play($data_system.cancel_se)
        @state = "categories"
        @index = CATEGORIES.find_index { |key, _| key == @category_index }
        @transition_out = true
      end
      if Input.press?(Input::LEFT)
        @left_hold_timer += 1
      else
        @left_hold_timer = 0
      end

      if Input.press?(Input::RIGHT)
        @right_hold_timer += 1
      else
        @right_hold_timer = 0
      end
      selected_setting = CATEGORIES[@category_index][@index]
      return if selected_setting.nil?
      if selected_setting.type == "window_settings::slider" # Slider processing
        if Input.trigger?(Input::LEFT) || (Input.press?(Input::LEFT) && (@left_hold_timer >= 15))
          @left_hold_timer -= 2
          unless selected_setting.value <= selected_setting.type_class.min
            selected_setting.decrement
            Audio.se_play("Audio/SE/text_robot.wav", 70, (selected_setting.value / 2) + 75)
          end
          redraw_setting_index(@index)
        elsif Input.trigger?(Input::RIGHT) || (Input.press?(Input::RIGHT) && (@right_hold_timer >= 15))
          @right_hold_timer -= 2
          unless selected_setting.value >= selected_setting.type_class.max
            selected_setting.increment
            Audio.se_play("Audio/SE/text_robot.wav", 70, (selected_setting.value / 2) + 75)
          end
          redraw_setting_index(@index)
        end
      elsif selected_setting.type == "window_settings::text"
      else
        if Input.trigger?(Input::LEFT) || Input.trigger?(Input::ACTION)
          selected_setting.decrement
          redraw_all_settings
          $game_system.se_play(selected_setting.custom_sound || $data_system.decision_se)
        elsif Input.trigger?(Input::RIGHT)
          selected_setting.increment
          redraw_all_settings
          $game_system.se_play(selected_setting.custom_sound || $data_system.decision_se)
        end
      end
    end
  end

  def update_render
    if @fade_in
      self.opacity += 20
      active_spr = nil

      @sprites.each do |spr|
        active_spr = spr if !active_spr && spr.x < MARGIN * 2
      end

      if active_spr
        active_spr.x += 6
        active_spr.x = MARGIN * 2 if active_spr.x > MARGIN * 2
      elsif self.opacity == 255
        @fade_in = false
      end

      @hint.opacity = 128
      @version.opacity = 128

      return
    end

    if @fade_out
      self.opacity -= 20

      if self.opacity == 0
        @fade_out = false
        self.visible = false

        @sprites.each do |spr|
          spr.dispose
        end
        @sprites = []
      end

      return
    end

    if @transition_in
      active_spr = nil
      @sprites.each_with_index do |spr|
        spr.opacity += 10
        spr.opacity = 128 if spr.opacity > 128
        active_spr = spr if !active_spr && spr.x < MARGIN * 2
        if spr.opacity == 128
          @transition_in = false
          @index = 0
          @sprites.each do |spr|
            if spr.x < MARGIN * 2
              spr.x = MARGIN * 2
            end
          end
          return
        end
        if active_spr
          active_spr.x += 6
          active_spr.x = MARGIN * 2 if active_spr.x > MARGIN * 2
        end
      end
      return
    end

    if @transition_out
      @sprites.each do |spr|
        spr.opacity -= 10
        if spr.opacity == 0
          @sprites.each do |spr|
            spr.dispose
          end
          @transition_out = false
          @transition_in = true
          setup_sprites
          return
        end
      end
      return
    end

    return if !self.visible

    @sprites.each_with_index do |spr, i|
      if i == @index
        if spr.x < ACTIVE_MARGIN
          spr.x += 6
          spr.x = ACTIVE_MARGIN if spr.x > ACTIVE_MARGIN
        end
        spr.opacity += 10 if spr.opacity < 255
      else
        if spr.x > MARGIN * 2
          spr.x -= 6
          spr.x = MARGIN * 2 if spr.x < MARGIN * 2
        end
        spr.opacity -= 10 if spr.opacity > 128
        spr.opacity = 128 if spr.opacity < 128
      end
    end

    if @state == "categories"
      if @hint_text != CATEGORIES.keys[@index].to_s
        @hint_text = CATEGORIES.keys[@index].to_s
        @hint.bitmap.clear
        @hint.bitmap.draw_text(0, 0, @hint.bitmap.width, @hint.bitmap.height, tr(@hints[@hint_text].to_s))
      end
    elsif @state == "values"
      selected_setting = CATEGORIES[@category_index][@index]
      @hint_text = selected_setting.name
      @hint.bitmap.clear
      @hint.bitmap.draw_text(0, 0, @hint.bitmap.width, @hint.bitmap.height, tr(@hints[@hint_text].to_s))
    end
  end

  def open
    self.visible = true
    self.opacity = 0

    @title.bitmap.clear
    @title.bitmap.draw_text(0, 0, @title.bitmap.width, @title.bitmap.height, tr("Settings"))

    @hint.bitmap.clear
    @hint.bitmap.draw_text(0, 0, @hint.bitmap.width, @hint.bitmap.height, tr(@hints[@hint_text].to_s))

    @version.bitmap.clear
    @version.bitmap.draw_text(0, 0, @version.bitmap.width, @version.bitmap.height, tr($version))

    setup_sprites()
    @fade_in = true
  end

  def setup_sprites
    @sprites = []
    if @state == "values"
      CATEGORIES[@category_index].each_with_index do |setting, index| # value index
        spr = Sprite.new(@viewport)
        spr.bitmap = Bitmap.new(640, ITEM_SPACING)
        spr.x = MARGIN
        spr.y = TITLE_MARGIN + TITLE_TOP_MARGIN + ITEM_SPACING * index
        spr.opacity = 0
        Language.register_text_sprite(self.class.name + "_option_#{index}", spr)
        draw_setting(spr, setting.name, setting.value.to_s, setting.color)

        @sprites << spr
      end
    elsif @state == "categories"
      CATEGORIES.each_with_index do |(category_name, category), index| # Key, value
        spr = Sprite.new(@viewport)
        spr.bitmap = Bitmap.new(640, ITEM_SPACING)
        spr.x = MARGIN
        spr.y = TITLE_MARGIN + TITLE_TOP_MARGIN + ITEM_SPACING * index
        spr.opacity = 0
        Language.register_text_sprite(self.class.name + "_option_#{index}", spr)
        draw_setting(spr, category_name.to_s, "")

        @sprites << spr
      end
    end
  end

  def draw_setting(spr, name, value, color = Color.new(255, 255, 255))
    return unless @visible
    spr.bitmap.clear
    if name == "Close"
      spr.bitmap.font.color = Color.new(255, 70, 70)
    else
      spr.bitmap.font.color = color
    end
    spr.bitmap.draw_text(0, 0, spr.bitmap.width, spr.bitmap.height, name)
    spr.bitmap.draw_text(VALUE_MARGIN, 0, spr.bitmap.width, spr.bitmap.height, value)
  end

  def redraw_setting_index(index)
    draw_setting(
      @sprites[index],
      CATEGORIES[@category_index][index].name,
      CATEGORIES[@category_index][index].value.to_s,
      CATEGORIES[@category_index][index].color
    )
  end

  def redraw_all_settings
    CATEGORIES[@category_index].each_with_index do |setting, index| # Key, value
      draw_setting(@sprites[index], setting.name, setting.value.to_s, setting.color)
    end
  end

  def in_transition
    @transition_in || @transition_out
  end

  def visible
    @visible
  end

  def dispose
    @sprites.each do |spr|
      spr.dispose
    end
    @sprites = []

    @bg.dispose
    @title.dispose
    @hint.dispose
    @version.dispose
    @viewport.dispose
  end

  def opacity=(val)
    @sprites.each do |spr|
      spr.opacity = val / 2
    end

    @bg.opacity = val
    @title.opacity = val
    @hint.opacity = val
    @version.opacity = val
  end

  def opacity
    @bg.opacity
  end

  def visible=(val)
    @viewport.visible = val
    @visible = val
  end

  # Legacy
  def self.load_settings
    Settings.load()
  end
end
