require 'darkhall/action'

module DarkHall
	class AIContext
		Candidate = Struct.new(:rate, :action, :on_choice)
		
		def self.decide(actor, &block)
			context = self.new(actor)
			context.instance_eval(&block)
			
			return context.pick
		end
		
		def initialize(actor)
			@actor = actor
			@candidates = []
			@rate_total = 0
		end
		
		def pick
			value = rand(@rate_total)
			
			start = 0
			# 一つ一つの候補を順にチェック
			@candidates.each do |cand|
				if value < start + cand.rate then
					cand.on_choice.call if cand.on_choice
					return cand.action 
				end
				
				start += cand.rate
			end
			
			# どのアクションも選択されなければnil
			return nil
		end
		
		private
		
		def round
			$battle.round
		end
		
		def attack(rate, targets = short_targeting, &on_choice)
			add_candidate(rate, AttackAction.new(@actor, targets), &on_choice)
		end
		
		def ranpage(rate, targets = short_targeting, &on_choice)
			add_candidate(rate, RanpageAction.new(@actor, targets), &on_choice)
		end
		
		def smash(rate, targets = short_targeting, &on_choice)
			add_candidate(rate, SmashAction.new(@actor, targets), &on_choice)
		end
		
		def guard(rate, &on_choice)
			add_candidate(rate, GuardAction.new(@actor), &on_choice)
		end


		# obsolete
		def short_attack(rate, &on_choice)
			attack(rate, &on_choice)
		end

		
		def long_attack(rate, &on_choice)
			attack(rate, long_targeting, &on_choice)
		end
		
		def spell_cast(rate, targets, trick_id, &on_choice)
			trick = DB.find_trick(trick_id)
			if @actor.mp[trick.spell_id] and @actor.mp[trick.spell_id] >= trick.mp_cost then
				add_candidate(rate, SpellCastAction.new(@actor, targets, trick_id), &on_choice)
			else
				nil
			end
		end
		
		def special(rate, targets, effect_id, &on_choice)
			add_candidate(rate, SpecialAction.new(@actor, targets, effect_id.to_s), &on_choice)
		end
		
		def wait(rate, &on_choice)
			add_candidate(rate, nil, &on_choice)
		end





		def add_candidate(rate, action, &on_choice)
			@candidates << Candidate.new(rate, action, on_choice)
			@rate_total += rate
		end
		

		
		def short_targeting
			if @actor.forward? then
				targets = GS.party.forward_members.find_all{|x| x.alive?}
				blockers = targets.find_all{|x| x.blocking?}
				targets = blockers unless blockers.empty?
				return [Util.random_pick(targets)]
			else
				return []
			end
		end
		
		def long_targeting
			targets = GS.party.standing_members
			blockers = targets.find_all{|x| x.blocking?}
			targets = blockers unless blockers.empty?
			return [Util.random_pick(targets)]
		end
		
		def group_targeting
			GS.party.standing_members
		end
		


	end

end