class AR::Events::Event
  attr_accessor :id
  attr_accessor :engine
  attr_accessor :dont_narrate
  @@auto_incr = 0
  @@engine = nil
  @@event_participant_keys =  {}

  def self.set_engine eng
    @@engine = eng
  end
  def self.engine
    @@engine
  end

  def self.event_participant_keys 
    if self == AR::Events::Event
      @@event_participant_keys
    else
      @@event_participant_keys[self] ||= []
    end
  end

  def debug
    "#{roles_and_participants.map{|role, o| "#{role} -> #{o.class.to_s.split("::").last}@#{o.id}" }}"
  end


  def participants
    ret = []
    self.class.event_participant_keys.each do |k|
      ret.push(self.send(k))
    end
    ret
  end

  def story
    ret = ""
    roles_and_participants.each do |role,participant|    
      if participant.respond_to? "story"
        part_story = (participant.story _for: self, as: role)
        part_story += " " unless part_story.nil? or part_story.empty?
        ret += part_story
      end
    end
    ret
  end

  #a way to always print something... should only be used when no other story is there.
  def default_story
    ""
  end

  def roles
    self.class.event_participant_keys
  end

  def roles_and_participants
    ret = {}
    self.class.event_participant_keys.each do |k|
      participant = self.send(k)
      ret[k] = participant unless participant.nil?
    end
    ret
  end

  def self.attr_participant *args
    @@event_participant_keys[self] ||= []
    args.each do |arg|
      @@event_participant_keys[self].push arg unless @@event_participant_keys[self].include? arg
      self.class_eval("def #{arg}=(val);@#{arg} = val; end")
      self.class_eval("def #{arg};@#{arg}; end")
    end
  end

  def self.preprocess e, story_text
    template_regx = /\{%(.*?)\%}/
    begin
      new_text  = story_text
      return "" if story_text.nil?
      matches = story_text.scan(template_regx)
      until matches.empty?
        matches.each do |m|
        m = m[0]
        chain_calls = m.split(".")
        value = e.send chain_calls.shift
        while chain_calls.size > 0
          tmp = chain_calls.shift
          value = value.send tmp 
        end
        new_text = new_text.sub(template_regx, value.to_s)
        end
        matches = new_text.scan(template_regx)
      end
      return new_text
    rescue StandardError => e
      AR.log "Failed to process: \n\n#{story_text}\n\n!!!\nError: #{e.to_s}: #{e.backtrace}"
      return story_text
    end
  end
  

  def self.gen_id 
    @@auto_incr += 1
  end
  

  def initialize params
    self.dont_narrate = params[:dont_narrate]
    self.id = AR::Events::Event.gen_id
    self.engine = params[:engine] || AR::Events::Event.engine
    self.roles.each do |role|
      #AR.put_s "Warning: #{role} was not defined on initializing a #{self.class}".colorize(:yellow) if params[role].nil?
      self.send "#{role}=", params[role] 
    end
  end
  
  
  

  def resolve!
    results = []
    roles_and_participants.each do |role, participant|
      begin
        next if participant.nil?
        results.push (participant.resolve! _for: self, as: role)
      rescue Exception => e
        AR.log "Error resolving #{self.class} #{role}!"
        raise e
      end
    end
    results.flatten.compact
  end

  def sensed_by? ar_object
    return true if self.class == AR::Events::NarrationEvent
    o_props = ar_object_attributes 
    #if the object known objects has any intersections with objects involved in event 
    known_intersects  = !(ar_object.known_objects & o_props).empty? rescue false
    known_intersects || o_props.include?(ar_object)
  end  

  def ar_object_attributes
    instance_variables.map{|iv| instance_variable_get iv}.select{|o| o.is_a? AR::Game::ARObject}
  end

end

require_relative "event/ar_object_entered_inhabitable_event"
require_relative "event/perception_account_changed_event"
require_relative "event/discovery_made_event"
require_relative "event/discovery_lost_event"

require_relative "event/clock_tick_event"

require_relative "event/game_over_event"

require_relative "event/actor_turn_event"

require_relative "event/action_began_event"

require_relative "event/ar_object_created_event"
require_relative "event/action_performed_event"
require_relative "event/present_menu_event"
require_relative "event/present_menu_event"
require_relative "event/narration_event"
require_relative "event/discoverable_remembered_event"
require_relative "event/name_learned_event"
require_relative "event/discoverable_inspected_event"

require_relative "event/ar_object_travelled_event"
require_relative "event/ar_object_travelled_event"

require_relative "event/ar_object_entry_blocked_event"
require_relative "event/game_save_event"

require_relative "event/item_added_to_inventory"
require_relative "event/item_removed_from_inventory"
require_relative "event/item_picked_up"
require_relative "event/item_given_event"

require_relative "event/dialog_began_event"

require_relative "event/dialog_node_activated_event"

require_relative "event/dialog_menu_presented"
require_relative "event/character_talked"

require_relative "event/game_started_event"

require_relative "event/blocker_removed"

require_relative "event/damage_received"
require_relative "event/ar_object_died"

require_relative "event/gauge_changed"

require_relative "event/gauges_initialized"
require_relative "event/hit_attempt"
require_relative "event/hit_failure"
require_relative "event/hit_success"

require_relative "event/defense_choice"

require_relative "event/object_removed_from_game"

require_relative "event/buff_applied"
require_relative "event/buff_removed"

require_relative "event/item_consumed"
require_relative "event/item_equipped"
require_relative "event/item_unequipped"

require_relative "event/status_review"
require_relative "event/character_slept"
require_relative "event/loot"

require_relative "event/character_entered_battle"
require_relative "event/character_exited_battle"
require_relative "event/battle_exit_attempt"
require_relative "event/ran_proc"

require_relative "event/exp_level_gained"
