# Copyright (c) 2023 M.J.N. Corino, The Netherlands
#
# This software is released under the MIT license.
# 
# Some parts are
# Copyright 2004-2007, wxRuby development team
# released under the MIT-like wxRuby2 license

# A single labelled list within a drop-down menu, or a popup menu

class Wx::Menu

  alias :wx_initialize :initialize

  def initialize(*args, &block)
    wx_initialize(*args)
    if block
      if block.arity == -1 or block.arity == 0
        self.instance_eval(&block)
      elsif block.arity == 1
        block.call(self)
      else
        Kernel.raise ArgumentError,
                     "Block to initialize should accept a single argument or none"
      end
    end
  end

  # Overload to provide Enumerator without block
  wx_each_item = instance_method :each_item
  wx_redefine_method :each_item do |&block|
    if block
      wx_each_item.bind(self).call(&block)
    else
      ::Enumerator.new { |y| wx_each_item.bind(self).call { |mi| y << mi } }
    end
  end

  # In the standard WxWidgets API, the methods append, prepend, insert
  # (and their variants) require a constant integer id as the identifier
  # of the menu item. This is then used in event handling. 
  #
  # In WxRuby the use of explicit ids can be avoided in most cases,
  # being a most unruby-ish practice. So, by analogy with the general
  # use of Wx::Window classes and event handlers, where the id is
  # implicit in the constructor, and the window can be passed direct to
  # the event handler setup method, the below sets up a similar facility
  # for adding items to Wx::Menu.
  #
  # For all these methods, the only required argument is the string name
  # of the menu item; a system-default id will be supplied if no
  # explicit one is given. The return value of these methods in all
  # cases is a Wx::MenuItem object, which can be passed directly as the
  # first argument to an evt_menu handler.
  def self.methods_with_optional_ids(*meth_names)
    class_eval do 
      meth_names.each do | meth |
        old_meth = instance_method(meth)
        wx_redefine_method(meth) do | *args |
          case args.first
            when Integer, Wx::Enum then old_meth.bind(self).call(*args)
            when String then old_meth.bind(self).call(Wx::ID_ANY, *args)
            when Wx::MenuItem then old_meth.bind(self).call(args.first)
          end
        end
      end
    end
  end

  # Create the optional-id methods
  methods_with_optional_ids :append, :prepend,
                            :append_check_item, :prepend_check_item, 
                            :append_radio_item, :prepend_radio_item

  # This is much the same as above, except for insert and variants,
  # which take an additional first argument, the position at which to
  # insert the new item.
  def self.methods_with_optional_ids_and_pos(*meth_names)
    class_eval do 
      meth_names.each do | meth |
        old_meth = instance_method(meth)
        wx_redefine_method(meth) do | pos, *args |
          case args.first
            when Integer, Wx::Enum then old_meth.bind(self).call(pos, *args)
            when String then old_meth.bind(self).call(pos, Wx::ID_ANY, *args)
            when Wx::MenuItem then old_meth.bind(self).call(pos, args.first)
          end
        end
      end
    end
  end

  # Create the optional-id methods
  methods_with_optional_ids_and_pos :insert,
                                    :insert_check_item,
                                    :insert_radio_item

  # wxRuby2 backward compatibility version; no alias as #append has been altered above
  def append_item(*args)
    append(*args)
  end
end
