znmud-0.0.1/benchmark/
znmud-0.0.1/cmd/
znmud-0.0.1/cmd/emotes/
znmud-0.0.1/cmd/objects/
znmud-0.0.1/cmd/tiny/
znmud-0.0.1/doc/
znmud-0.0.1/farts/
znmud-0.0.1/lib/
znmud-0.0.1/lib/combat/
znmud-0.0.1/lib/core/bodytypes/
znmud-0.0.1/lib/engine/
znmud-0.0.1/lib/farts/
znmud-0.0.1/logs/
# File: olcmenu.rb
# Author: Craig Smith
#
# This source code copyright (C) 2009 Craig Smith
# All rights reserved.
#
# Released under the terms of the GNU Public License
# See COPYING file for additional information.
#


require 'utility/log'

# Main menu interface object
class OlcMenu
  logger "DEBUG"
  attr_accessor :title, :options, :state, :selected_opt, :editor, :default_array, :set_array, :default_hash, :calling, :init, :active_hash
  def initialize(title,calling,init)
	self.title = title
	self.calling = calling
	self.init = init
	self.options = []
	self.state = nil
	self.selected_opt = nil
	self.editor = nil
	self.default_hash = {}
	self.active_hash = {}
	self.default_array = []
	self.set_array = []
	@menu_picks = ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","R","S","T","U","V","W","X","Y","Z","Q"]
  end

  # Adds another hash item to the default hash
  # [+hash+] Hash to add
  def add_default_hash(hash)
	self.default_hash.merge!(hash)
  end

  # Adds a default item to default_array
  # [+item+] Item to add
  def add_default_item(item)
	self.default_array << item
  end

  # Numbered has arrays use both a default_hash and active_hash
  # to sink up the numbered selection it best to use the same method for keys
  # [+return+] Default and Active keys in the same array given
  def get_hash_keys
	keys = []
	active_hash = {} if not active_hash
	keys = active_hash.keys
	keys.concat(default_hash.keys)
	keys.uniq!
	keys
  end

  # Sets the caller that initialized this menu
  def set_caller(parent,init)
	self.calling = parent
	self.init = init
  end

  # Resets the menus state and removes of menu items
  def reset
	self.options.clear
	self.default_hash.clear
	self.default_array.clear
	self.set_array.clear
	calling.send(init,"reset") if init and calling
  end

  # Finds the next unused menu_pick from menu_picks
  # [+return+] letter to use
  def get_next_pick
	@menu_picks.each do |p|
		found = false
		options.each do |opt|
			found = true if opt.pick=~/#{p}/i
		end
		return p if not found
	end
  end

  # Adds a standard menu option. uses :get_string
  # [+pick+] Item to pick, EG: A, B, etc.
  # [+name+] Items menu name EG: "Hair Color: "
  # [+target+] Object values to edit
  # [+obj+] Calling object
  # [+func+] Function that handles this option from calling object
  # [+return+] Undefined
  def add_std_option(pick, name, target, obj, func)
	opt = OlcMenuOption.new
	if pick
		opt.pick = pick
	else
		opt.pick = get_next_pick
	end
	opt.name = name
	opt.target = target
	opt.obj = obj
	opt.func = func
	opt.get_string = true
	self.options << opt
  end

  # Adds a editor menu option. uses :editor
  # [+pick+] Item to pick, EG: A, B, etc.
  # [+name+] Items menu name EG: "Hair Color: "
  # [+target+] Object values to edit
  # [+obj+] Calling object
  # [+func+] Function that handles this option from calling object
  # [+return+] Undefined
  def add_editor_option(pick, name, target, obj, func)
	opt = OlcMenuOption.new
	if pick
		opt.pick = pick
	else
		opt.pick = get_next_pick
	end
	opt.name = name
	opt.target = target
	opt.obj = obj
	opt.func = func
	opt.multi_line = true
	self.options << opt
  end

  # Makes a list of numbered options for array lists
  # [+arr+] Array to number
  # [+obj+] Calling object
  # [+func+] Function to handle call
  def add_numbered_option(arr,obj,func)
	opt = OlcMenuOption.new
	opt.target = arr
	opt.obj = obj
	opt.func = func
	opt.numbered_array = true
	self.options << opt
  end

  # Makes a list of numbered options for array lists of Oids that resolve object names
  # [+arr+] Array to number
  # [+obj+] Calling object
  # [+func+] Function to handle call
  def add_named_numbered_option(arr,obj,func)
	opt = OlcMenuOption.new
	opt.target = arr
	opt.obj = obj
	opt.func = func
	opt.named = true
	opt.numbered_array = true
	self.options << opt
  end

  # Very similar to add_numbered_option but uses two
  # builtin arrays and marks them.  The OlcMenu object keeps
  # Track of both the standard array and what is set and passes
  # them at display time
  # [+obj+] Calling obj
  # [+func+] Function to handle call
  def add_toggled_numbered_options(obj,func)
	opt = OlcMenuOption.new
	opt.obj = obj
	opt.func = func
	opt.numbered_array = true
	opt.toggle = true
	self.options << opt
  end

  # Same as numbered_options but with default_hash key listings
  # [+hash+] Current hash of the object
  # [+obj+] Calling obj
  # [+func+] Function to handle call
  def add_hash_numbered_options(hash,obj,func)
	opt = OlcMenuOption.new
	opt.obj = obj
	opt.func = func
	hash = {} if not hash
	if hash.is_a? Hash
		opt.target = hash.dup
		self.active_hash = hash.dup
		opt.numbered_hash = true
		self.options << opt
	else
		log.error "OLC: add_hash_numbered_options: hash != Hash"
	end
  end

  # Adds a menu option that is typically text for an action or submenu
  # [+pick+] Item character to pick
  # [+name+] Name of option
  # [+obj+] Calling object
  # [+func+] Function that handles this option from calling object
  # [+target+] Optional target data to show
  # [+return+] Undefined
  def add_text_option(pick, name, obj, func, target=nil)
	opt = OlcMenuOption.new
	if pick
		opt.pick = pick
	else
		opt.pick = get_next_pick
	end
	opt.name = name
	opt.obj = obj
	opt.func = func
	opt.target = target
	self.options << opt
  end

  # Removes a menu option by name
  # [+name+] Name of option to remove
  def del_option_by_name(name)
	options.each do |opt|
		options.delete opt if opt.name == name
	end
  end

  # Updates target info.  Call this after an update
  # [+pick+] Menu option pick
  # [+target+] New updated target info
  def update_target(pick, target)
	options.each do |opt|
		opt.target = target if opt.pick == pick
	end
  end

  # Print the menu
  def to_s
	msg = "-------------[ [color Green]#{title}[/color] ]------------\n"
	@options.each do |opt|
		if opt.numbered_array
			if opt.toggle
				msg << opt.to_s(default_array,set_array)
			else
				msg << opt.to_s
			end
		elsif opt.numbered_hash
			opt.target = get_hash_keys
			opt.active_hash = active_hash
			msg << opt.to_s
		end
	end
	@menu_picks.each do |p|
		options.each do |opt|
			msg << opt.to_s if opt.pick=~/#{p}/i
		end
	end
	msg << "Enter Choice> "
	msg
  end

  # Parses message from user to determine a match
  # [+m+] message
  # [+return+] Msg to print
  def parse(m)
	msg = ""
	case state
	when :get_string
		t=selected_opt.obj.send(selected_opt.func, m)
		if not t == nil
			update_target(selected_opt.pick, t)
		end
		self.state = nil
		self.selected_opt = nil
		return
	when :editor
		msg = editor.parse(m)
		if editor.done
			t=selected_opt.obj.send(selected_opt.func, editor.editstr)
			if t
				update_target(selected_opt.pick, t)
			end
			self.state = nil
			self.selected_opt = nil
		end
		return msg
	end
	options.each do |opt|
		if opt.is_match? m
			if opt.get_string
				msg = "#{opt.name}:"
				self.state = :get_string
				self.selected_opt = opt
			elsif opt.multi_line
				self.editor = OlcEditor.new(opt.target)
				self.state = :editor
				self.selected_opt = opt
				msg = editor.edit_display(opt.target)
			else
				opt.obj.send(opt.func, m) if opt.func
			end
			return msg
		end
	end
	msg
  end
end