module AR::Game::Behavior
  attr_accessor :resolutions
  attr_accessor :subscriptions
  attr_accessor :behaviors
  attr_accessor :narration_stories
  attr_accessor :world

  @@world = nil 

  def self.set_world world
    @@world = world
  end

  def subscribe!
    self.world.add_subscriptions_from self
    self
  end

  def self.extended ar_object
    ar_object.resolutions = []
    ar_object.subscriptions = []
    ar_object.behaviors = []

    #this won't work for subscriptions, need like a game began event to hook into to do this automagically.
    unless ar_object == @@world or @@world.nil?
      AR.log("BEHAVIOR: hooking in #{ar_object.tag}")
      @@world.hook_in_object ar_object
    end
    
    #should be keyed by event_class
    #each key should point to this structure:
    #  {"perceiever": "talk about what happens"}
    ar_object.narration_stories = {}    
  end 

  def load_all_behavior beh
    beh.each do |behavior_class, properties|
      behavior_class = Object.const_get(behavior_class.to_s) if(behavior_class.class == String or behavior_class.class == Symbol)
      behavior_class.load_data self, properties
    end
  end

  def unload_all_behavior
    ret = {id: self.id, type: self.class, behaviors: {}}
    behaviors.each do |behavior_class|
      begin
        ret[:behaviors][behavior_class] = behavior_class.unload_data self
      rescue StandardError => e 
        puts "warning: #{behavior_class} was unable to serialize because of this error: #{e.to_s}"   
      end
    end
    
    ret
  end

  def has_behavior? behavior_class
    behaviors.include? behavior_class
  end

  def add_behavior behavior_class
    unless has_behavior? behavior_class
      extend behavior_class 
      behaviors << behavior_class
    end
  end 

  def on_resolved e, as_who
    relevant = resolutions.select{|r| r.is_for?(e.class, as_who)}
    results  = relevant.map{|r| r.call e }
    results.flatten.compact
  end

  def resolve! params
    e = params[:_for] || params[:event]
    as_who = params[:as] || params[:as_who]
    relevant = resolutions.select{|r| r.is_for?(e.class, as_who)}
    results  = relevant.map{|r| r.call e }
    results.flatten.compact
  end
  def trigger event_class, params
    begin #anything but a world
    self.world.events_engine.trigger event_class, params
    rescue #happens when it's a world
    self.events_engine.trigger event_class, params
    end
  end

  def create event_class, params
    begin #anything but a world
      self.world.events_engine.create event_class, params
    rescue Exception => e#happens when it's a world
      AR.log("World creating an Event.  Got this: #{e}")
      self.events_engine.create event_class, params
    end
  end

end

#generator depends on this being at the end
require_relative "behavior/perception"
require_relative "behavior/discoverable"
require_relative "behavior/inhabitable"
require_relative "behavior/narrator"
require_relative "behavior/discoverable"
require_relative "behavior/custom_narrations"
require_relative "behavior/inhabitant"
require_relative "behavior/world_behavior"
require_relative "behavior/agility"
require_relative "behavior/player_control"

require_relative "behavior/memory_of_objects"

require_relative "behavior/gateway"

require_relative "behavior/gateway_blocker"

require_relative "behavior/actor_behavior"
require_relative "behavior/ai_control"
require_relative "behavior/emote_behavior"
require_relative "behavior/inventory_behavior"
require_relative "behavior/item_behavior"

require_relative "behavior/story_behavior"

require_relative "behavior/npc_dialog_behavior"

require_relative "behavior/printer_behavior"
require_relative "behavior/hostilities"
require_relative "behavior/health"

require_relative "behavior/attack_behavior"
require_relative "behavior/defense_behavior"
require_relative "behavior/dexterity"
require_relative "behavior/gauge_behavior"

require_relative "behavior/gauge_management"
require_relative "behavior/strength"

require_relative "behavior/buff_behavior"
require_relative "behavior/hunger_behavior"
require_relative "behavior/consumable"
require_relative "behavior/equippable"

require_relative "behavior/paper_doll"
require_relative "behavior/rest_station"
require_relative "behavior/lootable_container"
require_relative "behavior/drops_loot"
