# Copyright (c) 2023 M.J.N. Corino, The Netherlands
#
# This software is released under the MIT license.
#
# Adapted for wxRuby from wxWidgets widgets sample
# Copyright (c) 2001 Vadim Zeitlin

module Widgets

  module Button

    class ButtonPage < Widgets::Page

      module ID
        include Wx::IDHelper

        Reset = self.next_id(Widgets::Frame::ID::Last)
        ChangeLabel = self.next_id
        ChangeNote = self.next_id
        ChangeImageMargins = self.next_id
        Button = self.next_id

        ImagePos_Left = 0
        ImagePos_Right = 1
        ImagePos_Top = 2
        ImagePos_Bottom = 3

        HAlign_Left = 0
        HAlign_Centre = 1
        HAlign_Right = 2

        VAlign_Top = 0
        VAlign_Centre = 1
        VAlign_Bottom = 2
      end

      def initialize(book, images)
        super(book, images, :button)

        # init everything
        @chkBitmapOnly =
        @chkTextAndBitmap =
        @chkFit =
        @chkAuthNeeded = nil
        if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
        @chkCommandLink = nil
        end # wxUSE_COMMANDLINKBUTTON
        if Wx.has_feature?(:USE_MARKUP)
        @chkUseMarkup = nil
        end # wxUSE_MARKUP
        @chkDefault =
        @chkUseBitmapClass =
        @chkDisable =
        @chkUsePressed =
        @chkUseFocused =
        @chkUseCurrent =
        @chkUseDisabled = nil

        @radioImagePos =
        @radioHAlign =
        @radioVAlign = nil

        @textLabel = nil

        @textImageMarginH = nil
        @textImageMarginV = nil

        @button = nil
        @sizerButton = nil

        @imageMarginH = 0
        @imageMarginV = 0
      end

      Info = Widgets::PageInfo.new(self, 'Button', Widgets::NATIVE_CTRLS)

      def get_widget
        @button
      end
      def recreate_widget
        create_button
      end

      # lazy creation of the content
      def create_content
        sizerTop = Wx::HBoxSizer.new

        # left pane
        sizerLeft = Wx::StaticBoxSizer.new(Wx::VERTICAL, self, '&Set style')
        sizerLeftBox = sizerLeft.get_static_box

        @chkBitmapOnly = create_check_box_and_add_to_sizer(sizerLeft, "&Bitmap only", Wx::ID_ANY, sizerLeftBox)
        @chkTextAndBitmap = create_check_box_and_add_to_sizer(sizerLeft, "Text &and bitmap", Wx::ID_ANY, sizerLeftBox)
        @chkFit = create_check_box_and_add_to_sizer(sizerLeft, "&Fit exactly", Wx::ID_ANY, sizerLeftBox)
        @chkAuthNeeded = create_check_box_and_add_to_sizer(sizerLeft, "Require a&uth", Wx::ID_ANY, sizerLeftBox)
        if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
          @chkCommandLink = create_check_box_and_add_to_sizer(sizerLeft, "Use command &link button", Wx::ID_ANY, sizerLeftBox)
        end
        if Wx.has_feature?(:USE_MARKUP)
          @chkUseMarkup = create_check_box_and_add_to_sizer(sizerLeft, "Interpret &markup", Wx::ID_ANY, sizerLeftBox)
        end # wxUSE_MARKUP
        @chkDefault = create_check_box_and_add_to_sizer(sizerLeft, "&Default", Wx::ID_ANY, sizerLeftBox)

        @chkUseBitmapClass = create_check_box_and_add_to_sizer(sizerLeft,
            "Use wxBitmapButton", Wx::ID_ANY, sizerLeftBox)
        @chkUseBitmapClass.set_value(true)

        @chkDisable = create_check_box_and_add_to_sizer(sizerLeft, "Disable", Wx::ID_ANY, sizerLeftBox)

        sizerLeft.add_spacer(5)

        sizerUseLabels =
          Wx::StaticBoxSizer.new(Wx::VERTICAL, sizerLeftBox,
                    '&Use the following bitmaps in addition to the normal one?')
        sizerUseLabelsBox = sizerUseLabels.get_static_box

        @chkUsePressed = create_check_box_and_add_to_sizer(sizerUseLabels,
            "&Pressed (small help icon)", Wx::ID_ANY, sizerUseLabelsBox)
        @chkUseFocused = create_check_box_and_add_to_sizer(sizerUseLabels,
            "&Focused (small error icon)", Wx::ID_ANY, sizerUseLabelsBox)
        @chkUseCurrent = create_check_box_and_add_to_sizer(sizerUseLabels,
            "&Current (small warning icon)", Wx::ID_ANY, sizerUseLabelsBox)
        @chkUseDisabled = create_check_box_and_add_to_sizer(sizerUseLabels,
            "&Disabled (broken image icon)", Wx::ID_ANY, sizerUseLabelsBox)
        sizerLeft.add(sizerUseLabels, Wx::SizerFlags.new.expand.border)

        sizerLeft.add_spacer(10)

        dirs = %w[left right top bottom]
        @radioImagePos = Wx::RadioBox.new(sizerLeftBox, Wx::ID_ANY, 'Image &position', choices: dirs)
        sizerLeft.add(@radioImagePos, Wx::SizerFlags.new.expand.border)

        sizerImageMargins = Wx::StaticBoxSizer.new(Wx::VERTICAL, sizerLeftBox, 'Image margins')
        sizerImageMarginsBox = sizerImageMargins.get_static_box
        sizerImageMarginsRow, @textImageMarginH = create_sizer_with_text_and_button(ID::ChangeImageMargins,
                                                                                    'Horizontal and vertical',
                                                                                    Wx::ID_ANY, sizerImageMarginsBox)
        @textImageMarginH.set_validator(Wx::IntegerValidator.new(0, 100))

        @textImageMarginV = Wx::TextCtrl.new(sizerImageMarginsBox, validator: Wx::IntegerValidator.new(0,100))
        sizerImageMarginsRow.add(@textImageMarginV, Wx::SizerFlags.new(1).centre_vertical.border(Wx::LEFT))

        @textImageMarginH.set_value(@imageMarginH.to_s)
        @textImageMarginV.set_value(@imageMarginV.to_s)

        sizerImageMargins.add(sizerImageMarginsRow, Wx::SizerFlags.new.border.centre)
        sizerLeft.add(sizerImageMargins, Wx::SizerFlags.new.expand.border)

        sizerLeft.add_spacer(15)

        # should be in sync with enums Button[HV]Align!
        halign = %w[left centre right]

        valign = %w[top centre bottom]

        @radioHAlign = Wx::RadioBox.new(sizerLeftBox, label: '&Horz alignment', choices: halign)
        @radioVAlign = Wx::RadioBox.new(sizerLeftBox, label: '&Vert alignment', choices: valign)

        sizerLeft.add(@radioHAlign, Wx::SizerFlags.new.expand.border)
        sizerLeft.add(@radioVAlign, Wx::SizerFlags.new.expand.border)

        sizerLeft.add_spacer(5)

        btn = Wx::Button.new(sizerLeftBox, ID::Reset, '&Reset')
        sizerLeft.add(btn, Wx::SizerFlags.new.centre_horizontal.triple_border(Wx::ALL))

        # middle pane
        sizerMiddle = Wx::StaticBoxSizer.new(Wx::VERTICAL, self, '&Operations')
        sizerMiddleBox = sizerMiddle.get_static_box

        sizerRow, @textLabel = create_sizer_with_text_and_button(ID::ChangeLabel,
                                                                 'Change label',
                                                                 Wx::ID_ANY,
                                                                 sizerMiddleBox)
        @textLabel.set_value('&Press me!')
        sizerMiddle.add(sizerRow, Wx::SizerFlags.new.expand.border)

        if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
          @sizerNote, @textNote = create_sizer_with_text_and_button(ID::ChangeNote,
                                                                    'Change note',
                                                                    Wx::ID_ANY,
                                                                    sizerMiddleBox)
          @textNote.set_value('Writes down button clicks in the log.')

          sizerMiddle.add(@sizerNote, Wx::SizerFlags.new.expand.border)
        end

        # right pane
        @sizerButton = Wx::HBoxSizer.new
        @sizerButton.set_min_size(from_dip(150), 0)

        # the 3 panes panes compose the window
        sizerTop.add(sizerLeft,
                     Wx::SizerFlags.new(0).expand.double_border(Wx::ALL & ~Wx::LEFT))
        sizerTop.add(sizerMiddle,
                     Wx::SizerFlags.new(1).expand.double_border(Wx::ALL))
        sizerTop.add(@sizerButton,
                     Wx::SizerFlags.new(1).expand.double_border(Wx::ALL & ~Wx::RIGHT))

        # do create the main control
        reset
        create_button

        set_sizer(sizerTop)

        # connect event handlers
        evt_button(ID::Button, :on_button)

        evt_button(ID::Reset, :on_button_reset)
        evt_button(ID::ChangeLabel, :on_button_change_label)
        evt_button(ID::ChangeNote, :on_button_change_note)
        evt_button(ID::ChangeImageMargins, :on_button_change_image_margins)

        evt_checkbox(Wx::ID_ANY, :on_check_or_radio_box)
        evt_radiobox(Wx::ID_ANY, :on_check_or_radio_box)
      end

      protected

      # event handlers
      def on_check_or_radio_box(_event)
        create_button
        layout # make sure the text field for changing note displays correctly.
      end

      def on_button(_event)
        Wx.log_message('Test button clicked.')
      end

      def on_button_reset(_event)
        reset
        create_button
      end

      def on_button_change_label(_event)
        labelText = @textLabel.value

        if Wx.has_feature?(:USE_COMMANDLINKBUTTON) && @cmdLnkButton
          @cmdLnkButton.set_main_label(labelText)
        elsif Wx.has_feature?(:USE_MARKUP) && @chkUseMarkup.value
          @button.set_label_markup(labelText)
        else
          @button.set_label(labelText)
        end

        create_button if @chkBitmapOnly.checked?

        @sizerButton.layout
      end

      def on_button_change_note(_event)
        if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
          @cmdLnkButton.set_note(@textNote.value)

          @sizerButton.layout
        end # wxUSE_COMMANDLINKBUTTON
      end

      def on_button_change_image_margins(_event)
        margH = @textImageMarginH.value.to_i
        margV = @textImageMarginV.value.to_i
        if margH < 0 || margV < 0
          Wx.log_warning('Invalid margin values for bitmap.')
          return
        end

        @imageMarginH = margH
        @imageMarginV = margV

        @button.set_bitmap_margins(@imageMarginH, @imageMarginV)
        @button.refresh
        @sizerButton.layout
      end

      # reset the wxButton parameters
      def reset
        @chkBitmapOnly.value = false
        @chkFit.value = false
        @chkAuthNeeded.value = false
        @chkTextAndBitmap.value = false
        @chkDefault.value = false
        if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
          @chkCommandLink.value = false
        end
        if Wx.has_feature?(:USE_MARKUP)
          @chkUseMarkup.value = false
        end # wxUSE_MARKUP
        @chkUseBitmapClass.value = true
        @chkDisable.value = false

        @chkUsePressed.value = true
        @chkUseFocused.value = true
        @chkUseCurrent.value = true
        @chkUseDisabled.value = true

        @radioImagePos.set_selection(ID::ImagePos_Left)
        @radioHAlign.set_selection(ID::HAlign_Centre)
        @radioVAlign.set_selection(ID::VAlign_Centre)

        @imageMarginH = 0
        @imageMarginV = 0
        @textImageMarginH.value = @imageMarginH.to_s
        @textImageMarginV.value = @imageMarginV.to_s
      end

      # (re)create the wxButton
      def create_button
        label = ''
        if @button
          if Wx.has_feature?(:USE_COMMANDLINKBUTTON) && @cmdLnkButton
            label = @cmdLnkButton.get_main_label
          else
            label = @button.get_label
          end

          @sizerButton.item_count.times { @sizerButton.remove(0) }

          @button.destroy
        end

        if label.empty?
          # creating for the first time or recreating a button after bitmap
          # button
          label = @textLabel.get_value
        end

        flags = get_attrs.default_flags
        case @radioHAlign.selection
        when ID::HAlign_Left
          flags |= Wx::BU_LEFT
        when ID::HAlign_Centre
          # noop
        when ID::HAlign_Right
          flags |= Wx::BU_RIGHT
        else
          ::Kernel.raise RuntimeError, "unexpected radiobox selection"
        end

        case  @radioVAlign.selection
        when ID::VAlign_Top
          flags |= Wx::BU_TOP
        when ID::VAlign_Centre
          # centre vertical alignment is the default (no style)
        when ID::VAlign_Bottom
          flags |= Wx::BU_BOTTOM
        else
          ::Kernel.raise RuntimeError, "unexpected radiobox selection"
        end


        flags |= Wx::BU_EXACTFIT if @chkFit.value

        showsBitmap = false
        if @chkBitmapOnly.value
          if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
            @chkCommandLink.value = false # Wx::CommandLinkButton cannot be "Bitmap only"
          end

          showsBitmap = true

          if @chkUseBitmapClass.value
            bbtn = Wx::BitmapButton.new(self, ID::Button,
                                      create_bitmap('normal', Wx::ART_INFORMATION),
                                      style: flags)
          else
            bbtn = Wx::Button.new(self, ID::Button)
            bbtn.set_bitmap_label(create_bitmap('normal', Wx::ART_INFORMATION))
          end
          bbtn.set_bitmap_margins(@imageMarginH, @imageMarginV)

          bbtn.set_bitmap_pressed(create_bitmap('pushed', Wx::ART_HELP)) if @chkUsePressed.value
          bbtn.set_bitmap_focus(create_bitmap('focused', Wx::ART_ERROR)) if @chkUseFocused.value
          bbtn.set_bitmap_current(create_bitmap('hover', Wx::ART_WARNING)) if @chkUseCurrent.value
          bbtn.set_bitmap_disabled(create_bitmap('disabled', Wx::ART_MISSING_IMAGE)) if @chkUseDisabled.value

          @button = bbtn
          if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
            @cmdLnkButton = nil
          end
        else # normal button
          if Wx.has_feature?(:USE_COMMANDLINKBUTTON) && @chkCommandLink.value
              @cmdLnkButton = Wx::CommandLinkButton.new(self, ID::Button,
                                                        label,
                                                        @textNote.value,
                                                        style: flags)
              @button = @cmdLnkButton
          else
              @button = Wx::Button.new(self, ID::Button, label, style: flags)
              @cmdLnkButton = nil
          end
        end

        if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
          @sizerNote.show_items(@chkCommandLink.value)
        end

        if !showsBitmap && @chkTextAndBitmap.value
          showsBitmap = true

          positions = [Wx::LEFT, Wx::RIGHT, Wx::TOP, Wx::BOTTOM]

          @button.set_bitmap(Wx::ArtProvider.get_icon(Wx::ART_INFORMATION, Wx::ART_BUTTON),
                             positions[@radioImagePos.selection])

          @button.set_bitmap_margins(@imageMarginH, @imageMarginV)

          @button.set_bitmap_pressed(Wx::ArtProvider.get_icon(Wx::ART_HELP, Wx::ART_BUTTON)) if @chkUsePressed.value
          @button.set_bitmap_focus(Wx::ArtProvider.get_icon(Wx::ART_ERROR, Wx::ART_BUTTON)) if @chkUseFocused.value
          @button.set_bitmap_current(Wx::ArtProvider.get_icon(Wx::ART_WARNING, Wx::ART_BUTTON)) if @chkUseCurrent.value
          @button.set_bitmap_disabled(Wx::ArtProvider.get_icon(Wx::ART_MISSING_IMAGE, Wx::ART_BUTTON)) if @chkUseDisabled.value
        end

        @chkTextAndBitmap.enable(!@chkBitmapOnly.checked?)
        @chkBitmapOnly.enable(!@chkTextAndBitmap.checked?)
        if Wx.has_feature?(:USE_COMMANDLINKBUTTON)
          @chkCommandLink.enable(!@chkBitmapOnly.checked?)
        end
        @chkUseBitmapClass.enable(showsBitmap)

        @chkUsePressed.enable(showsBitmap)
        @chkUseFocused.enable(showsBitmap)
        @chkUseCurrent.enable(showsBitmap)
        @chkUseDisabled.enable(showsBitmap)
        @radioImagePos.enable(@chkTextAndBitmap.checked?)
        @textImageMarginH.enable(showsBitmap)
        @textImageMarginV.enable(showsBitmap)
        Wx::Window.find_window_by_id(ID::ChangeImageMargins).enable(showsBitmap)

        @button.set_auth_needed if @chkAuthNeeded.value

        @button.set_default if @chkDefault.value

        @button.enable(!@chkDisable.checked?)

        @sizerButton.add_stretch_spacer
        @sizerButton.add(@button, Wx::SizerFlags.new.centre.border)
        @sizerButton.add_stretch_spacer

        @sizerButton.layout
      end

      # helper function: create a bitmap bundle for wxBitmapButton
      def create_bitmap(label, type)
        bmp = Wx::Bitmap.new(from_dip(Wx::Size.new(180, 70))) # shouldn't hardcode but it's simpler like this
        Wx::MemoryDC.draw_on(bmp) do |dc|
          dc.set_font(self.font)
          dc.set_background(Wx::CYAN_BRUSH)
          dc.clear
          dc.set_text_foreground(Wx::BLACK)
          dc.draw_label(Wx.strip_menu_codes(@textLabel.value) + "\n" +
                          "(" + label + " state)",
                        Wx::ArtProvider.get_bitmap(type),
                        Wx::Rect.new(10, 10, bmp.width - 20, bmp.height - 20),
                        Wx::ALIGN_CENTRE)
        end
        bmp
      end
    end

  end

end
