class Window_Settings
  MARGIN = 15
  TITLE_TOP_MARGIN = 16
  TITLE_MARGIN = 40
  ITEM_SPACING = 20
  VALUE_MARGIN = 270
  ACTIVE_MARGIN = MARGIN * 2 + 20

  def initialize
    @viewport = Viewport.new(0, 0, Graphics.width, Graphics.height)
    @viewport.z = 9998
    @bg = Sprite.new(@viewport)
    @bg.bitmap = Bitmap.new(1, 1)
    @bg.bitmap.fill_rect(0, 0, 1, 1, Color.new(0, 0, 0, 196))
    @bg.zoom_x = Graphics.width
    @bg.zoom_y = Graphics.height
    @title = Sprite.new(@viewport)
    @title.bitmap = Bitmap.new(320, 20)
    @title.bitmap.font.size = 20
    @title.y = TITLE_TOP_MARGIN
    @title.x = (Graphics.width - @title.bitmap.width) / 2
    @title.bitmap.draw_text(0, 0, @title.bitmap.width, @title.bitmap.height, tr("Settings"), 1)
    @title.opacity = 0
    Language.register_text_sprite(self.class.name + "_title", @title)

    @resized = false

    @update_connection = Graphics.viewport_resized do |w, h|
      if self.visible
        @viewport.rect.width = w
        @viewport.rect.height = h
        @bg.zoom_x = w
        @bg.zoom_y = h
        #@bg.bitmap.dispose
        #@bg.bitmap = Bitmap.new(w, h)
        #@bg.bitmap.fill_rect(0, 0, w, h, Color.new(0, 0, 0, 196))
        @title.x = (w - @title.bitmap.width) / 2
        init_content
      else
        @resized = true
      end
    end

    init_content

	  @left_hold_timer = 0
	  @right_hold_timer = 0

	  @up_hold_timer = 0
	  @down_hold_timer = 0

    @visible = self.visible = false
    RPG::Mod.exec_hooks("hooks/Window_Settings/init", binding)
  end

  def init_content
    old_screen = 0
    old_index = 0
    if (@content)
      old_screen = @content.screen
      old_index = @content.index
      @content.dispose
    end

    @content = SettingsContent.new(@viewport, TITLE_TOP_MARGIN + TITLE_MARGIN + 100, old_screen, old_index)

    DATA.each_with_index do |(screen_title, parameters_info), screen_index|
      @content.add_screen(screen_title)
      parameters_info.each_with_index do |parameter_info, parameter_index|
        parameter = nil
        if parameters_info == :sep
          parameter = @content.add_parameter(screen_title, Separator.new(@content, screen_index, parameter_index, ""))
        else
          case parameter_info[:type]
          when :bool
            parameter = 
            @content.add_parameter(screen_title, BoolParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:default]))
          when :switch
            parameter = 
            @content.add_parameter(screen_title, SwitchPatameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:default],
              parameter_info[:switch], parameter_info[:invert]))
          when :int
            parameter = 
            @content.add_parameter(screen_title, IntParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:default],
              parameter_info[:min], parameter_info[:max]))
          when :slider
            parameter = 
            @content.add_parameter(screen_title, SliderParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:default],
              parameter_info[:min], parameter_info[:max]))
          when :float
            parameter = 
            @content.add_parameter(screen_title, FloatParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:default],
              parameter_info[:step], parameter_info[:min], parameter_info[:max]))
          when :enum
            parameter = 
            @content.add_parameter(screen_title, EnumParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:default],
              parameter_info[:values]))
          when :sep
            parameter = 
            @content.add_parameter(screen_title, Separator.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon]))
          when :key
            parameter = 
            @content.add_parameter(screen_title, KeyParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:key_binds],
              parameter_info[:bind]))
          when :action
            parameter = 
            @content.add_parameter(screen_title, ActionParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:default], parameter_info[:action],
              parameter_info[:arg1], parameter_info[:arg2], parameter_info[:arg3], parameter_info[:arg4]))
          when :custom
            parameter = 
            @content.add_parameter(screen_title, CustomParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:default],
              parameter_info[:callbacks]))
          else
            parameter = 
            @content.add_parameter(screen_title, BaseParameter.new(@content, screen_index, parameter_index,
              parameter_info[:name], parameter_info[:icon], parameter_info[:parameter], parameter_info[:default]))
          end
        end
        parameter.disabled = true if parameter_info[:disabled] && parameter 
      end
    end
    @content.redraw_all
  end

  def dispose
    @bg.dispose
    @title.dispose
    @content.dispose
    @update_connection.disconnect
  end

  def disable_setting(screen, position)
    @content.disable_setting(screen, position)
  end
  def enable_setting(screen, position)
    @content.enable_setting(screen, position)
  end

  def open
    self.visible = true
    self.opacity = 0
    @fade_in = true
  end

  def redraw_all
    @title.bitmap.clear
    @title.bitmap.draw_text(0, 0, @title.bitmap.width, @title.bitmap.height, tr("Settings"), 1)
    @content.redraw_all
  end

  def redraw_setting(screen, index)
    if @visible == false
      return
    end
    
    @content.get_parameter_by_sceen_id(screen, index)&.redraw
  end

  def self.load_settings
    Settings.load!
  end

  def update
    if @resized
      @viewport.rect.width = Graphics.width
      @viewport.rect.height = Graphics.height
      @bg.bitmap.dispose
      @bg.bitmap = Bitmap.new(Graphics.width, Graphics.height)
      @bg.bitmap.fill_rect(0, 0, Graphics.width, Graphics.height, Color.new(0, 0, 0, 196))
      @title.x = (Graphics.width - @title.bitmap.width) / 2
      init_content
      @resized = false
    end

    if Input.key_press?(Input.key_from_name("F1"))
      if Oneshot.msgbox(Oneshot::Msg::YESNO, tr("Are you sure you want to reset the control settings?"))
        Settings.reset_controls!
        @content.redraw_all
      end
    end

    if self.visible
      @content.update
    end

    if @fade_in
      self.opacity += 20
      @title.opacity += 20
      if self.opacity == 255
        @fade_in = false
      end
      return
    end

    if @fade_out
      self.opacity -= 20
      @title.opacity -= 20
      if self.opacity == 0
        @fade_out = false
        self.visible = false
      end
      return
    end

    return if !self.visible
    return if @content.waiting_for_key

    # navigation
    if Input.wheel_y != 0
      if (Input::key_press?(Input::key_from_name("Left Shift")))
        for _ in 0...Input.wheel_y.round.abs
          Input.wheel_y.round > 0 ? @content.parameter_right : @content.parameter_left
        end
      else
        @content.parameter_select_offset(-Input.wheel_y.round)
        $game_system.se_play($data_system.cursor_se)
      end
    end

    if (Input.trigger?(Input::L))
      @content.screen_left
      $game_system.se_play($data_system.cursor_se)
    end
    if (Input.trigger?(Input::R))
      @content.screen_right
      $game_system.se_play($data_system.cursor_se)
    end

    # hold timers
  	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

  	if Input.press?(Input::UP)
  	  @up_hold_timer += 1
  	else
  	  @up_hold_timer = 0
  	end

  	if Input.press?(Input::DOWN)
  	  @down_hold_timer += 1
  	else
  	  @down_hold_timer = 0
  	end

    #parameters navigation
    if Input.trigger?(Input::UP) || (Input.press?(Input::UP) && (@up_hold_timer >= 15))
      @up_hold_timer -= 2
      @content.parameter_up
      $game_system.se_play($data_system.cursor_se)
    elsif Input.trigger?(Input::DOWN) || (Input.press?(Input::DOWN) && (@down_hold_timer >= 15))
      @down_hold_timer -= 2
      @content.parameter_down
      $game_system.se_play($data_system.cursor_se)
    end

    # parameter setting
    current_parameter = @content.get_current_parameter
    if Input.trigger?(Input::LEFT) || (Input.press?(Input::LEFT) && (@left_hold_timer >= 15))
      @left_hold_timer -= 2
      @content.parameter_left
    elsif Input.trigger?(Input::RIGHT) || (Input.press?(Input::RIGHT) && (@right_hold_timer >= 15))
      @right_hold_timer -= 2
      @content.parameter_right
    end
    if (Input.trigger?(Input::ACTION))
      current_parameter&.action
    end
    
    # menu closing
    if Input.trigger?(Input::CANCEL)
      $game_system.se_play($data_system.cancel_se)
      @fade_out = true

      Settings.save!
    end
  end

  # Attributes
  def visible
    return @visible
  end
  def visible=(val)
    @viewport.visible = val
    @visible = val
  end
  def opacity=(val)
    @bg.opacity = val
    @content.opacity = val
  end
  def opacity
    @bg.opacity
  end
end
