# Author::    A.K.M. Ashrafuzzaman  (mailto:ashrafuzzaman.g2@gmail.com)
# License::   MIT-LICENSE

# The purpose of the helper module is to help controllers with the responders

require 'csv'
require 'query_report/report'
require 'query_report/report_pdf'

module QueryReport
  module Helper

    # Generates the reports
    # @param query The base query that the reporter with start with [filters will be applied on it]
    # @option options [Integer] :per_page If given then overrides the default kaminari per page option
    # @option options [Boolean] :custom_view by default false, if set to true then the reporter will look for the file to render
    # @option options [Boolean] :skip_rendering by default false, if set to true then the reporter will not render any thing, you will have to implement the rendering
    def reporter(query, options={}, &block)
      @report ||= QueryReport::Report.new(params, view_context, options)
      @report.query = query
      @report.instance_eval &block
      render_report(options) unless options[:skip_rendering]
      @report
    end

    def render_report(options)
      if (params[:send_as_email].to_i > 0)
        send_pdf_email(params[:email_to], params[:subject], params[:message], action_name, pdf_for_report(options))
      end

      @remote = false
      respond_to do |format|
        if options[:custom_view]
          format.js do
            @remote = true
          end
          format.html
        else
          format.js do
            @remote = true
            render 'query_report/list'
          end
          format.html { render('query_report/list') }
        end
        format.json { render json: @report.records_without_pagination }
        format.csv { send_data generate_csv_for_report(@report.records_without_pagination), :disposition => "attachment;" }
        format.pdf { send_data pdf_for_report(options), :type => 'application/pdf', :disposition => 'inline' }
      end
    end

    def pdf_for_report(options)
      query_report_pdf_template_class(options).new(@report).to_pdf.render
    end

    def query_report_pdf_template_class(options)
      options = QueryReport.config.pdf_options.merge(options)
      if options[:template_class]
        @template_class ||= options[:template_class].to_s.constantize
        return @template_class
      end
      QueryReport::ReportPdf
    end

    def generate_csv_for_report(records)
      if records.size > 0
        columns = records.first.keys
        CSV.generate do |csv|
          csv << columns
          records.each do |record|
            csv << record.values.collect { |val| val.kind_of?(String) ? view_context.strip_links(val) : val }
          end
        end
      else
        nil
      end
    end

    def send_pdf_email(email, subject, message, file_name, attachment)
      @user = current_user if defined? current_user
      to = email.split(',')
      ReportMailer.send_report(@user, to, subject, message, file_name, attachment).deliver
    end
  end
end


require 'action_view'
require 'active_record'
require 'active_support/time_with_zone'

module FoundationFormBuilder
  class Rails < ActionView::Helpers::FormBuilder

    # Renders a form field with label wrapped in an appropriate +<div>+, with another +<div>+ for errors if necessary.
    #
    # @param field_name [String, Symbol] Name of the field to render
    # @param label [String, Symbol] Override text for the +<label>+ element
    # @param type [Symbol] Override type of field to render.
    #   Known values are +:date+, +:email+, +:password+, +:select+, +:textarea+, and +:time_zone+. Anything else is rendered as a text field.
    # @param values [Array] Name-value pairs for +<option>+ elements. Only meaningful with +type:+ +:select+.
    # @param field [Hash] Options to pass through to the underlying Rails form helper. For +type:+ +:time_zone+, +:priority_zones+ is also understood.
    # @return [SafeBuffer] The rendered HTML
    def input_div(field_name, label: nil, type: nil, values: nil, field: {})
      raise ArgumentError, ':values is only meaningful with type: :select' if values && type != :select
      @template.content_tag :div, class: classes_for(field_name) do
        [
          label(field_name, label),
          input_for(field_name, type, field, values: values),
          errors_for(field_name)
        ].compact.join("\n").html_safe
      end
    end

    private

    def classes_for(field_name)
      [field_name, error_class(field_name)]
    end

    def error_class(field_name)
      errors[field_name].present? ? :error : nil
    end

    # Renders a +<span>+ with errors if there are any for the specified field, or returns +nil+ if not.
    #
    # @param field_name [String, Symbol] Name of the field to check for errors
    # @return [SafeBuffer, nil] The rendered HTML or nil
    def errors_for(field_name)
      error_messages = errors[field_name]
      if error_messages.present?
        @template.content_tag :span, class: :error do
          error_messages.join(@template.tag :br).html_safe
        end
      else
        nil
      end
    end

    def errors
      @errors ||= @object.errors
    end

    def input_for(field_name, type, field_options, values: nil)
      type ||= infer_type field_name

      case type
      when :select
        select field_name, values, field_options
      when :time_zone
        priority_zones = field_options.delete(:priority_zones)
        time_zone_select field_name, priority_zones, field_options
      else
        method_mappings = {
          date: :date_field,
          email: :email_field,
          numeric: :number_field,
          password: :password_field,
          textarea: :text_area,
        }

        field_method = method_mappings[type] || :text_field

        self.send field_method, field_name, field_options
      end
    end

    # Infers the type of field to render based on the field name.
    #
    # @param [String, Symbol] the name of the field
    # @return [Symbol] the inferred type
    def infer_type(field_name)
      case field_name
      when :email, :time_zone
        field_name
      when %r{(\b|_)password(\b|_)}
        :password
      else
        type_mappings = {text: :textarea}

        db_type = @object.column_for_attribute(field_name).type
        case db_type
        when :text
          :textarea
        when :decimal, :integer, :float
          :numeric
        else
          db_type
        end
      end
    end
  end
end


module ActiveRecordSurvey
	class Node < ::ActiveRecord::Base
		self.table_name = "active_record_survey_nodes"
		belongs_to :survey, :class_name => "ActiveRecordSurvey::Survey", :foreign_key => :active_record_survey_id
		has_many :node_maps, -> { includes(:node, parent: [:node]) }, :class_name => "ActiveRecordSurvey::NodeMap", :foreign_key => :active_record_survey_node_id, autosave: true, dependent: :destroy
		has_many :node_validations, :class_name => "ActiveRecordSurvey::NodeValidation", :foreign_key => :active_record_survey_node_id, autosave: true, dependent: :destroy
		has_many :instance_nodes, :class_name => "ActiveRecordSurvey::InstanceNode", :foreign_key => :active_record_survey_node_id

		before_destroy :before_destroy_rebuild_node_map, prepend: true # prepend is important! otherwise dependent: :destroy on node<->node_map relation is executed first and no records!

		# All the answer nodes that follow from this node
		def answers
			nm = self.survey.node_maps

			next_answer_nodes = lambda { |node, list|
				nm.select { |node_map|
					!node_map.parent.nil? && node_map.parent.node == node && node_map.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer) && !node_map.marked_for_destruction?
				}.select { |i|
					!list.include?(i.node)
				}.collect { |i|
					i.survey = self.survey
					i.node.survey = self.survey

					list << i.node

					next_answer_nodes.call(i.node, list)
				}.flatten.uniq

				list
			}
			next_answer_nodes.call(self, []).flatten.uniq
		end

		# The instance_node recorded for the passed instance for this node
		def instance_node_for_instance(instance)
			instance.instance_nodes.select { |instance_node|
				(instance_node.node === self)
			}.first
		end

		# Whether this node has an answer recorded the instance
		def has_instance_node_for_instance?(instance)
			!self.instance_node_for_instance(instance).nil?
		end

		# Whether considered answered for instance
		#
		# Is answered is a little different than has_answer
		# Is answered is answer type specific, as what constitutes "answered" changes depending on
		# the question type asked (e.g. boolean is answered if "1")
		#
		# Each specific answer type should override this method if they have special criteria for answered
		#
		# default - if instance node exists, answered
		def is_answered_for_instance?(instance)
			self.has_instance_node_for_instance?(instance)
		end

		# Default behaviour is to recurse up the chain (goal is to hit a question node)
		def validate_parent_instance_node(instance_node, child_node)
			!self.survey.node_maps.select { |i| i.node == self}.collect { |node_map|
				if node_map.parent
					node_map.parent.node.validate_parent_instance_node(instance_node, self)
				# Hit top node
				else
					true
				end
			}.include?(false)
		end

		# Run all validations applied to this node
		def validate_instance_node(instance_node)
			# Basically this cache is messed up? Why? TODO.
			# Reloading in the spec seems to fix this... but... this could be a booby trap for others
			#self.node_validations(true)

			# Check the validations on this node against the instance_node
			validations_passed = !self.node_validations.collect { |node_validation|
				node_validation.validate_instance_node(instance_node, self)
			}.include?(false)

			# More complex....
			# Recureses to the parent node to check
			# This is to validate Node::Question since they don't have instance_nodes directly to validate them
			parent_validations_passed = !self.survey.node_maps.select { |i| i.node == self}.collect { |node_map|
				if node_map.parent
					node_map.parent.node.validate_parent_instance_node(instance_node, self)
				# Hit top node
				else
					true
				end
			}.include?(false)

			validations_passed && parent_validations_passed
		end

		# Whether there is a valid answer path from this node to the root node for the instance
		def instance_node_path_to_root?(instance_node)
			instance_nodes = instance_node.instance.instance_nodes.select { |i| i.node == self }

			# if ::ActiveRecordSurvey::Node::Answer but no votes, not a valid path
			if self.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer) &&
				(instance_nodes.length === 0)
				return false
			end

			# if ::ActiveRecordSurvey::Node::Question but no answers, so needs at least one vote directly on itself
			if self.class.ancestors.include?(::ActiveRecordSurvey::Node::Question) &&
				(self.answers.length === 0) &&
				(instance_nodes.length === 0)
				return false
			end

			# Start at each node_map of this node
			# Find the parent node ma
			paths = self.survey.node_maps.select { |i| i.node == self }.collect { |node_map|
				# There is another level to traverse
				if node_map.parent
					node_map.parent.node.instance_node_path_to_root?(instance_node)
				# This is the root node - we made it!
				else
					true
				end
			}

			# If recursion reports back to have at least one valid path to root
			paths.include?(true)
		end

		# Build a link from this node to another node
		# Building a link actually needs to throw off a whole new clone of all children nodes
		def build_link(to_node)
			# build_link only accepts a to_node that inherits from Question
			if !to_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
				raise ArgumentError.new "to_node must inherit from ::ActiveRecordSurvey::Node::Question"
			end

			if self.survey.nil?
				raise ArgumentError.new "A survey is required before calling #build_link"
			end

			from_node_maps = self.survey.node_maps.select { |i| i.node == self && !i.marked_for_destruction? }

			# Answer has already got a question - throw error
			if from_node_maps.select { |i|
				i.children.length > 0
			}.length > 0
				raise RuntimeError.new "This node has already been linked"
			end

			# Because we need something to clone - filter this further below
			to_node_maps = self.survey.node_maps.select { |i| i.node == to_node && !i.marked_for_destruction? }

			if to_node_maps.first.nil?
				to_node_maps << self.survey.node_maps.build(:survey => self.survey, :node => to_node)
			end

			# Ensure we can through each possible path of getting to this answer
			to_node_map = to_node_maps.first
			to_node_map.survey = self.survey # required due to voodoo - we want to use the same survey with the same object_id

			# We only want node maps that aren't linked somewhere
			to_node_maps = to_node_maps.select { |i| i.parent.nil? }
			while to_node_maps.length < from_node_maps.length do
				to_node_maps.push(to_node_map.recursive_clone)
			end

			# Link unused node_maps to the new parents
			from_node_maps.each_with_index { |from_node_map, index|
				from_node_map.children << to_node_maps[index]
			}

			# Ensure no infinite loops were created
			from_node_maps.each { |node_map|
				# There is a path from Q -> A that is a loop
				if node_map.has_infinite_loop?
					raise RuntimeError.new "Infinite loop detected"
				end
			}
		end

		private
			# Before a node is destroyed, will re-build the node_map links from parent to child if they exist
			def before_destroy_rebuild_node_map
				# All the node_maps from this node
				self.survey.node_maps.select { |i|
					i.node == self
				}.each { |node_map|
					# Remap all of this nodes children to the parent
					node_map.children.each  { |child|
						node_map.parent.children << child
					}
				}

				true
			end
	end
end


module ActiveRecordSurvey
	# Can hold a value on a scale (e.g. from 0-10)
	class Node::Answer::Scale < Node::Answer
		include Answer::Chained::InstanceMethods
		extend Answer::Chained::ClassMethods

		# Accept integer, float, or empty values
		def validate_instance_node(instance_node)
			# super - all validations on this node pass
			super &&
			(instance_node.value.to_s.empty? || !instance_node.value.to_s.match(/^(\d+(\.\d+)?)$/).nil?)
		end

		# Scale answers are considered answered if they have a value of greater than "0"
		def is_answered_for_instance?(instance)
			if instance_node = self.instance_node_for_instance(instance)
				# Answered if not empty and > 0
				!instance_node.value.to_s.empty? && instance_node.value.to_i >= 0
			else
				false
			end
		end
	end
end


module ActiveRecordSurvey
	# Text answers are... text answers
	class Node::Answer::Text < Node::Answer
		include Answer::Chained::InstanceMethods
		extend Answer::Chained::ClassMethods

		# Text answers are considered answered if they have text entered
		def is_answered_for_instance?(instance)
			if instance_node = self.instance_node_for_instance(instance)
				# Answered if has text
				instance_node.value.to_s.strip.length > 0
			else
				false
			end
		end
	end
end


module ActiveRecordSurvey
	class NodeMap < ::ActiveRecord::Base
		self.table_name = "active_record_survey_node_maps"
		belongs_to :node, :foreign_key => :active_record_survey_node_id
		belongs_to :survey, :class_name => "ActiveRecordSurvey::Survey", :foreign_key => :active_record_survey_id
		acts_as_nested_set :scope => [:active_record_survey_id]

		validates_presence_of :survey

		# Recursively creates a copy of this entire node_map
		def recursive_clone
			node_map = self.survey.node_maps.build(:survey => self.survey, :node => self.node)
			self.survey.node_maps.select { |i| i.parent == self && !i.marked_for_destruction? }.each { |child_node|
				child_node.survey = self.survey # required due to voodoo - we want to use the same survey with the same object_id
				node_map.children << child_node.recursive_clone
			}
			node_map
		end

		def as_map(options)
			node_maps = options[:node_maps]

			c = (node_maps.nil?)? self.children : node_maps.select { |i|
				i.parent == self && !i.marked_for_destruction?
			}.sort { |a,b| a.left<=>b.left }

			result = {}
			result.merge!({ :id => self.id, :node_id => ((self.node.respond_to?(:id))? self.node.id : "") }) if !options[:no_ids] && !self.node.nil?
			result.merge!({
				:type => ((!self.node.nil?)? self.node.class.to_s : ""),
				:children => c.collect { |i|
					i.as_map(options)
				}
			})

			result
		end

		# Whether decendant of a particular node_map
		def is_decendant_of?(node_map)
			# Hit ourselves
			if node_map == self
				return true
			end

			# Recurse
			if self.parent
				return self.parent.is_decendant_of?(node_map)
			end

			false
		end

		# Gets all the ancestor nodes until one is not an ancestor of klass
		def ancestors_until_node_not_ancestor_of(klass)
			if !self.parent || !self.node.class.ancestors.include?(klass)
				return []
			end

			[self] + self.parent.ancestors_until_node_not_ancestor_of(klass)
		end

		# Gets all the child nodes until one is not an ancestor of klass
		def children_until_node_not_ancestor_of(klass)
			if !self.node.class.ancestors.include?(klass)
				return []
			end

			[self] + self.children.collect { |i|
				i.children_until_node_not_ancestor_of(klass)
			}
		end

		# Check to see whether there is an infinite loop from this node_map
		def has_infinite_loop?(path = [])
			self.survey.node_maps.select { |i| i.parent == self && !i.marked_for_destruction? }.each { |i|
				# Detect infinite loop
				if path.include?(self.node) || i.has_infinite_loop?(path.clone.push(self.node))
					return true
				end
			}
			path.include?(self.node)
		end

		def mark_self_and_children_for_destruction
			removed = [self]
			self.mark_for_destruction
			self.children.each { |i|
				removed.concat(i.mark_self_and_children_for_destruction)
			}
			removed
		end
	end
end


module ActiveRecordSurvey
	# Ensure the instance_node has a value greater than the minimum
	class NodeValidation::MinimumValue < NodeValidation
		# Validate the instance_node value is greater than the minimum
		def validate_instance_node(instance_node, answer_node = nil)
			is_valid = (!instance_node.value.to_s.empty? && instance_node.value.to_f >= self.value.to_f)

			instance_node.errors[:base] << { :nodes => { answer_node.id => ["MINIMUM_VALUE"] } } if !is_valid

			is_valid
		end
	end
end


module ActiveRecordSurvey
	# Ensure the a minimum number of answers are made
	class NodeValidation::MinimumAnswer < NodeValidation
		# Validate the instance_node to ensure a minimum number of answers are made
		def validate_instance_node(instance_node, question_node = nil)
			# Only makes sense for questions to have minimum answers
			if !question_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
				return false
			end

			instance = instance_node.instance

			# Go through the node_map of this node
			total_answered = question_node.node_maps.collect { |question_node_map|
				# Get all children until a childs node isn't an answer
				question_node_map.children.collect { |i|
					i.children_until_node_not_ancestor_of(::ActiveRecordSurvey::Node::Answer)
				}.flatten.collect { |i|
					i.node.is_answered_for_instance?(instance)
				}
			}.flatten.select { |i| i }.count

			is_valid = (total_answered >= self.value.to_i)

			instance_node.errors[:base] << { :nodes => { question_node.id => ["MINIMUM_ANSWER"] } } if !is_valid

			is_valid
		end
	end
end


module ActiveRecordSurvey
	class Node::Answer < Node
		# Answer nodes are valid if their questions are valid!
		# Validate this node against an instance
		def validate_node(instance)
			# Ensure each parent node to this node (the goal here is to hit a question node) is valid
			!self.survey.node_maps.select { |i|
				i.node == self
			}.collect { |node_map|
				node_map.parent.node.validate_node(instance)
			}.include?(false)
		end

		# Returns the question that preceeds this answer
		def question
			self.survey.node_maps.select { |i|
				i.node == self
			}.collect { |node_map|
				if node_map.parent && node_map.parent.node
					# Question is not the next parent - recurse!
					if node_map.parent.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
						node_map.parent.node.question
					else
						node_map.parent.node
					end
				# Root already
				else
					nil
				end
			}.first
		end

		# Returns the question that follows this answer
		def next_question
			self.survey.node_maps.select { |i|
				i.node == self && !i.marked_for_destruction?
			}.each { |answer_node_map|
				answer_node_map.children.each { |child|
					if !child.node.nil? && !child.marked_for_destruction?
						if child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
							return child.node
						elsif child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
							return child.node.next_question
						end
					else
						return nil
					end
				}
			}
			return nil
		end

		# Removes the node_map from this answer to its next question
		def remove_link
			# not linked to a question - nothing to remove!
			return true if (question = self.next_question).nil?

			count = 0
			to_remove = []
			self.survey.node_maps.each { |node_map|
				if node_map.node == question
					if count > 0
						to_remove.concat(node_map.self_and_descendants)
					else
						node_map.parent = nil
						node_map.move_to_root unless node_map.new_record?
					end
					count = count + 1
				end

				if node_map.node == self
					node_map.children = []
				end
			}

			self.survey.node_maps.each { |node_map|
				if to_remove.include?(node_map)
					node_map.parent = nil
					node_map.mark_for_destruction
				end
			}
		end

		def build_link(to_node)
			if self.question.nil?
				raise ArgumentError.new "A question is required before calling #build_link"
			end

			super(to_node)
		end

		# Gets index in sibling relationship
		def sibling_index
			node_maps = self.survey.node_maps

			if node_map = node_maps.select { |i| i.node == self }.first
				parent = node_map.parent

				children = node_maps.select { |i| i.parent && i.parent.node === parent.node }

				children.each_with_index { |nm, i|
					if nm == node_map
						return i
					end
				}
			end
		end

		def sibling_index=index
			current_index = self.sibling_index

			offset = index - current_index

			(1..offset.abs).each { |i|
				self.send(((offset > 0)? "move_down" : "move_up"))
			}
		end

		# Moves answer up relative to other answers
		def move_up
			self.survey.node_maps.select { |i|
				i.node == self
			}.collect { |node_map|
				begin
					node_map.move_left
				rescue
				end
			}
		end

		# Moves answer down relative to other answers
		def move_down
			self.survey.node_maps.select { |i|
				i.node == self
			}.collect { |node_map|
				begin
					node_map.move_right
				rescue
				end
			}
		end

		private
			# By default - answers build off the original question node
			#
			# This allows us to easily override the answer removal behaviour for different answer types
			def remove_answer(question_node)
				#self.survey = question_node.survey

				# The node from answer from the parent question
				self.survey.node_maps.select { |i|
					!i.marked_for_destruction? &&
					i.node == self && i.parent && i.parent.node === question_node
				}.each { |answer_node_map|
					answer_node_map.send((answer_node_map.new_record?)? :destroy : :mark_for_destruction )
				}
			end

			# By default - answers build off the original question node
			#
			# This allows us to easily override the answer building behaviour for different answer types
			def build_answer(question_node)
				self.survey = question_node.survey

				answer_node_maps = self.survey.node_maps.select { |i|
					i.node == self && i.parent.nil?
				}.collect { |i|
					i.survey = self.survey

					i
				}

				question_node_maps = self.survey.node_maps.select { |i| i.node == question_node && !i.marked_for_destruction? }

				# No node_maps exist yet from this question
				if question_node_maps.length === 0
					# Build our first node-map
					question_node_maps << self.survey.node_maps.build(:node => question_node, :survey => self.survey)
				end

				# Each instance of this question needs the answer hung from it
				question_node_maps.each_with_index { |question_node_map, index|
					if answer_node_maps[index]
						new_node_map = answer_node_maps[index]
					else
						new_node_map = self.survey.node_maps.build(:node => self, :survey => self.survey)
					end

					question_node_map.children << new_node_map
				}

				true
			end
	end
end


module ActiveRecordSurvey
	# Rank in relation to parent/children of ActiveRecordSurvey::Node::Answer::Rank
	class Node::Answer::Rank < Node::Answer
		include Answer::Chained::InstanceMethods
		extend Answer::Chained::ClassMethods

		# Accept integer or empty values
		# Must be within range of the number of ranking nodes
		def validate_instance_node(instance_node)
			# super - all validations on this node pass
			super &&
			(instance_node.value.to_s.empty? || !instance_node.value.to_s.match(/^\d+$/).nil?) &&
			(instance_node.value.to_s.empty? || instance_node.value.to_i >= 1) &&
			instance_node.value.to_i <= self.max_rank
		end

		# Rank answers are considered answered if they have a value of greater than "0"
		def is_answered_for_instance?(instance)
			if instance_node = self.instance_node_for_instance(instance)
				# Answered if > 0
				instance_node.value.to_i > 0
			end
		end

		protected

		# Calculate the number of Rank nodes above this one
		def num_above
			count = 0
			self.node_maps.each { |i|
				# Parent is one of us as well - include it and check its parents
				if i.parent.node.class.ancestors.include?(self.class)
					count = count + 1 + i.parent.node.num_above
				end
			}
			count
		end

		# Calculate the number of Rank nodes below this one
		def num_below
			count = 0
			self.node_maps.each { |node_map|
				node_map.children.each { |child|
					# Child is one of us as well - include it and check its children
					if child.node.class.ancestors.include?(self.class)
						count = count + 1 + child.node.num_below
					end
				}
			}
			count
		end

		# Calculate the maximum rank value that is accepted
		def max_rank
			self.num_above + self.num_below + 1
		end
	end
end


module ActiveRecordSurvey
	# Ensure the instance_node has a length less than the maximum
	class NodeValidation::MaximumLength < NodeValidation
		# Validate the instance_node value
		def validate_instance_node(instance_node, answer_node = nil)
			is_valid = (self.value.to_i >= instance_node.value.to_s.length.to_i)

			instance_node.errors[:base] << { :nodes => { answer_node.id => ["MAXIMUM_LENGTH"] } } if !is_valid

			is_valid
		end
	end
end


module ActiveRecordSurvey
	class Survey < ::ActiveRecord::Base
		self.table_name = "active_record_surveys"
		has_many :node_maps, -> { includes(:node, parent: [:node]) }, :class_name => "ActiveRecordSurvey::NodeMap", :foreign_key => :active_record_survey_id, autosave: true
		has_many :nodes, :class_name => "ActiveRecordSurvey::Node", :foreign_key => :active_record_survey_id
		has_many :questions, :class_name => "ActiveRecordSurvey::Node::Question", :foreign_key => :active_record_survey_id

		def root_node
			self.node_maps.includes(:node).select { |i| i.depth === 0 }.first
		end

		# Builds first question
		def build_first_question(question_node)
			if !question_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
				raise ArgumentError.new "must inherit from ::ActiveRecordSurvey::Node::Question"
			end

			question_node_maps = self.node_maps.select { |i| i.node == question_node && !i.marked_for_destruction? }

			# No node_maps exist yet from this question
			if question_node_maps.length === 0
				# Build our first node-map
				question_node_maps << self.node_maps.build(:node => question_node, :survey => self)
			end
		end

		# All the connective edges
		def edges
			self.node_maps.select { |i| !i.marked_for_destruction? }.select { |i|
				i.node && i.parent
			}.collect { |i|
				{
					:source => i.parent.node.id,
					:target => i.node.id,
				}
			}.uniq
		end

		def as_map(*args)
			options = args.extract_options!
			options[:node_maps] ||= self.node_maps

			self.node_maps.select { |i| !i.parent && !i.marked_for_destruction? }.collect { |i|
				i.as_map(options)
			}
		end
	end
end


module ActiveRecordSurvey
	class Node::Question < Node
		# Stop validating at the Question node
		def validate_parent_instance_node(instance_node, child_node)
			!self.node_validations.collect { |node_validation|
				node_validation.validate_instance_node(instance_node, self)
			}.include?(false)
		end

		# Updates the answers of this question to a different type
		def update_question_type(klass)
			if self.next_questions.length > 0
				raise RuntimeError.new "No questions can follow when changing the question type"
			end

			nm = self.survey.node_maps

			answers = self.answers.collect { |answer|
				nm.select { |i|
					i.node == answer
				}
			}.flatten.uniq.collect { |answer_node_map|
				node = answer_node_map.node
				answer_node_map.send((answer_node_map.new_record?)? :destroy : :mark_for_destruction)
				node
			}.collect { |answer|
				answer.type = klass.to_s
				answer = answer.becomes(klass)
				answer.save if !answer.new_record?

				answer
			}.uniq

			answers.each { |answer|
				answer.survey = self.survey

				self.build_answer(answer)
			}
		end

		# Removes an answer
		def remove_answer(answer_node)
			# A survey must either be passed or already present in self.node_maps
			if self.survey.nil?
				raise ArgumentError.new "A survey must be passed if ActiveRecordSurvey::Node::Question is not yet added to a survey"
			end

			if !answer_node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
				raise ArgumentError.new "::ActiveRecordSurvey::Node::Answer not passed"
			end

			# Cannot mix answer types
			# Check if not match existing - throw error
			if !self.answers.include?(answer_node)
				raise ArgumentError.new "Answer not linked to question"
			end

			answer_node.send(:remove_answer, self)
		end

		# Build an answer off this node
		def build_answer(answer_node)
			# A survey must either be passed or already present in self.node_maps
			if self.survey.nil?
				raise ArgumentError.new "A survey must be passed if ActiveRecordSurvey::Node::Question is not yet added to a survey"
			end

			# Cannot mix answer types
			# Check if not match existing - throw error
			if !self.answers.select { |answer|
				answer.class != answer_node.class
			}.empty?
				raise ArgumentError.new "Cannot mix answer types on question"
			end

			# Answers actually define how they're built off the parent node
			if answer_node.send(:build_answer, self)

				# If any questions existed directly following this question, insert after this answer
				self.survey.node_maps.select { |i|
					i.node == answer_node && !i.marked_for_destruction?
				}.each { |answer_node_map|
					self.survey.node_maps.select { |j|
						# Same parent
						# Is a question
						!j.marked_for_destruction? &&
						j.parent == answer_node_map.parent && j.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
					}.each { |j|
						answer_node_map.survey = self.survey
						j.survey = self.survey

						answer_node_map.children << j
					}
				}

				true
			end
		end

		# Removes the node_map link from this question all of its next questions
		def remove_link
			return true if (questions = self.next_questions).length === 0

			# Remove the link to any direct questions
			self.survey.node_maps.select { |i|
				i.node == self
			}.each { |node_map|
				self.survey.node_maps.select { |j|
					node_map.children.include?(j)
				}.each { |child|
					if child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
						child.parent = nil
						child.send((child.new_record?)? :destroy : :mark_for_destruction )
					end
				}
			}

			# remove link any answeres that have questions
			self.answers.collect { |i|
				i.remove_link
			}
		end

		# Returns the questions that follows this question (either directly or via its answers)
		def next_questions
			list = []

			if question_node_map = self.survey.node_maps.select { |i|
				i.node == self && !i.marked_for_destruction?
			}.first
				question_node_map.children.each { |child|
					if !child.node.nil? && !child.marked_for_destruction?
						if child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Question)
							list << child.node
						elsif child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
							list << child.node.next_question
						end
					end
				}
			end

			list.compact.uniq
		end

		private
			# Before a node is destroyed, will re-build the node_map links from parent to child if they exist
			# If a question is being destroyed and it has answers - don't link its answers - only parent questions that follow it
			def before_destroy_rebuild_node_map

				self.survey.node_maps.select { |i|
					i.node == self
				}.each { |node_map|
					# Remap all of this nodes children to the parent
					node_map.children.each  { |child|
						if !child.node.class.ancestors.include?(::ActiveRecordSurvey::Node::Answer)
							node_map.parent.children << child
						end
					}
				}

				true
			end
	end
end


module Tabletastic
  module Helper
    # returns and outputs a table for the given active record collection
    def table_for(collection, *args, &block)
      block = Tabletastic.default_table_block unless block_given?
      klass = default_class_for(collection)
      options = args.extract_options!
      initialize_html_options(options, klass)
      result = capture { block.call(TableBuilder.new(collection, klass, self)) }
      content_tag(:table, result, options[:html])
    end

    private
    # Finds the class representing the objects within the collection
    def default_class_for(collection)
      if collection.respond_to?(:klass) # ActiveRecord::Relation
        collection.klass
      elsif !collection.empty?
        collection.first.class
      end
    end

    def initialize_html_options(options, klass)
      options[:html] ||= {}
      options[:html][:id] ||= get_id_for(klass)
      options[:html].reverse_merge!(Tabletastic.default_table_html)
    end

    def get_id_for(klass)
      klass ? klass.model_name.collection : ""
    end
  end
end

ActiveSupport.on_load(:action_view) do
  include Tabletastic::Helper
end


require_relative 'event_factory'

module Metro

  module EventDictionary
    extend self

    #
    # All defined events within this dictionary.
    #
    def events
      @events ||= HashWithIndifferentAccess.new
    end

    #
    # @example Adding a new SceneEvent to the Dictionary
    #
    #     SceneEventDictionary.add target: scene_name, type: event_type, args: args, block: block
    #
    def add(params = {})
      target = params[:target]
      event = EventFactory.new params[:type], params[:args], &params[:block]
      events[target] = events_for_target(target).push event
    end

    #
    # Return all the events for all the specified targets.
    #
    def events_for_targets(*list)
      found_events = Array(list).flatten.compact.map {|s| events_for_target(s) }.flatten.compact
      found_events
    end

    #
    # Return the events for the specified target
    #
    def events_for_target(scene_name)
      events[scene_name] ||= []
    end

    #
    # When the game is reset the event dictionary needs to flush out all of the events that it
    # has loaded as the game files will be reloaded. All metro related components will not
    # be removed as those files are not reloaded when the game is reloaded.
    #
    def reset!
      events.delete_if { |name,events| ! name.start_with? "metro/" }
    end

  end

end


require_relative 'parsers'
require_relative 'writers'

module Metro

  #
  # A view represents the representation of the content found within
  # the view file. A view has the ability to save/load the content
  # as well.
  #
  class View

    #
    # The name of the view, which is used to influence the file path.
    #
    attr_accessor :name

    #
    # The content contained within the view.
    #
    def content
      @content ||= begin
        parsed_content = parse
        parsed_content.default = {}
        parsed_content
      end
    end

    #
    # Set the content of the view.
    #
    # @param [Hash] value the hash content that will represent this view
    #
    def content=(value)
      value.default = {}
      @content = value
    end

    #
    # A Scene view path is based on the view name.
    #
    # @example Standard View Path
    #
    #     class OpeningScene < Metro::Scene
    #     end
    #
    #     OpeniningScene.view_path # => views/opening
    #
    # @example Custom View Path
    #
    #     class ClosingScene < Metro::Scene
    #       view_name 'alternative'
    #     end
    #
    #     ClosingScene.view_path # => views/alternative
    #
    def view_path
      File.join "views", name
    end

    #
    # Parse the content found at the view path for the view.
    #
    # @return the hash of content stored within the view file.
    #
    def parse
      parser.parse(view_path)
    end

    #
    # The parser for this view is one of the supported parsers. A parser
    # is selected if the parser is capable of finding the content to
    # load.
    #
    def parser
      @parser ||= supported_parsers.find { |parser| parser.exists? view_path }
    end

    #
    # Supported view formats
    #
    def supported_parsers
      Views::Parsers.parsers_with_no_view_fallback
    end

    #
    # Ask the parser to save the current content of the view at the view path
    #
    def save
      writer.write(view_path,content)
    end

    #
    # Return the format of the view. By default the format of the view is dictated
    # by the format of the content that is parsed.
    #
    def format
      @format || parser.format
    end

    #
    # Setting the format allows the view to be changed from the current format as
    # dictated what is parsed by the parser.
    #
    # This is mostly to benefit the edit transition scene which inherits all the view
    # related data from the scene that is being edited but does not inherit the
    # the view (which would have the parser).
    #
    # @see EditTransitionScene
    #
    attr_writer :format

    #
    # The writer for this view. If the view has already been parsed then use
    #
    def writer
      @writer ||= begin
        writer_matching_existing_parser = supported_writers.find { |writer| writer.format == format }
        writer_matching_existing_parser || default_writer
      end
    end

    def supported_writers
      Views::Writers.writers
    end

    def default_writer
      Views::Writers.default_writer
    end

  end

end


module Tmx

  class Object

    # TODO: the mass and moment of interia should configurable through properties
    def body
      @body ||= CP::Body.new default_mass, default_moment_of_inertia
    end

    def shape
      @poly_shape ||= begin
        new_shape = CP::Shape::Poly.new(body,poly_vec2s,default_shape_attach_point)
        new_shape.collision_type = type.to_sym
        new_shape.e = default_elasticity
        new_shape.sensor = default_sensor
        new_shape
      end
    end

    private

    #
    # A TMX object currently has an array of points in a format
    # list of strings. This will convert the points into
    # list of CP::Vec2 objects which can be used to create the
    # proper CP::Shape::Poly for the Object.
    #
    # @note this assumes that we want to convert the points into
    #   a format of vec2s specifically for a CP::Shape::Poly
    #   shape.
    #
    def poly_vec2s
      points.map do |point|
        x,y = point.split(",").map {|p| p.to_i }
        CP::Vec2.new(x,y)
      end.reverse
    end

    def default_sensor
      false
    end

    def default_mass
      Float::INFINITY
    end

    def default_moment_of_inertia
      Float::INFINITY
    end

    def default_elasticity
      0.0
    end

    def default_shape_attach_point
      CP::Vec2::ZERO
    end

  end

end


require_relative 'animation_factory'

module Metro
  module HasAnimations

    def self.included(base)
      base.extend ClassMethods
    end

    #
    # Define an animation from within another animation block, an event block
    # or a method.
    #
    # @example Defining an animation that fades out the hero when they have
    #   died.
    #
    #     class HellScene
    #       draws :hero
    #
    #       def update
    #         if hero.dead?
    #           animate :hero, to: { alpha: 0 }, interval: 60.ticks do
    #             transition_to :game_over
    #           end
    #         end
    #       end
    #
    #     end
    #
    def animate(actor_or_actor_name,options,&block)
      options[:actor] = actor(actor_or_actor_name)
      options[:context] = self
      animation_group = SceneAnimation.build options, &block
      enqueue animation_group
    end

    # An alternative to stating `animate` syntax.
    alias_method :change, :animate

    module ClassMethods

      #
      # Define an animation to execute when the scene starts.
      #
      # @example Defining an animation that fades in and moves a logo when it is
      #   done, transition to the title scene.
      #
      #     animate :logo, to: { y: 80, alpha: 50 }, interval: 120.ticks do
      #       transition_to :title
      #     end
      #
      def animate(actor_name,options,&block)
        scene_animation = AnimationFactory.new actor_name, options, &block
        animations.push scene_animation
      end

      # Provide an alternative to the `animate` syntax.
      alias_method :change, :animate

      #
      # All the animations that are defined for the scene to be run the scene starts.
      #
      def animations
        @animations ||= []
      end

    end

  end
end


require_relative 'event_data'

module Metro

  #
  # An EventRelay represents a target's willingness to respond to events
  # generate from the window. An event relay is generate for every scene
  # but additional relays can be generated to also listen for events.
  #
  # An event relay can register a target to listen for the following window
  # events: 'button_down'; 'button_up'; and 'button_held'.
  #
  # @note registering for 'button_held' events require that the window be
  #   speicfied. As that is the only way to ask if the button is currently
  #   pressed.
  #
  # @see #on_up
  # @see #on_down
  # @see #on_hold
  #
  class EventRelay

    #
    # Defines the provided controls for every EventRelay that is created.
    #
    # @see #define_control
    #
    # @param [Array<ControlDefinition>] controls the definitions of controls
    #   that should be added to all EventRelays.
    #
    def self.define_controls(controls)
      controls.each { |control| define_control control }
    end

    #
    # Defines a control from a ControlDefinition for all EventRelays. A
    # control is a way of defining a shortcut for a common event. This
    # could be the use of a common set of keys for confirmation or canceling.
    #
    def self.define_control(control)
      check_for_already_defined_control!(control)

      define_method control.name do |&block|
        send(control.event,*control.args,&block)
      end
    end

    def self.check_for_already_defined_control!(control)
      if instance_methods.include? control.name
        error! "error.reserved_control_name", name: control.name
      end
    end

    #
    # An event relay is created a with a target and optionally a window.
    #
    # @param [Object] target the object that will execute the code when
    #   the button events have fired have been triggered.
    # @param [Window] window the window of the game. This parameter is
    #   optional and only required if the events are interested in buttons
    #   being held.
    #
    def initialize(target,window = nil)
      @target = target
      @window = window
      @up_actions ||= {}
      @down_actions ||= {}
      @held_actions ||= {}
      @mouse_movement_actions ||= []
      @custom_notifications ||= HashWithIndifferentAccess.new([])
    end

    attr_reader :target, :window

    #
    # Register for a button_down event. These events are fired when
    # the button is pressed down. This event only fires once when the
    # button moves from the not pressed to the down state.
    #
    # @example Registering for a button down event to call a method named 'previous_option'
    #
    #     class ExampleScene
    #       event :on_down, GpLeft, GpUp, do: :previous_option
    #
    #       def previous_option
    #         @selected_index = @selected_index - 1
    #         @selected_index = options.length - 1 if @selected_index <= -1
    #       end
    #     end
    #
    # Here in this scene if the GpLeft or GpUp buttons are pressed down the method
    # `previous_options` will be executed.
    #
    #
    # @example Registering for a button down event with a block of code to execute
    #
    #     class ExampleScene
    #        event :on_down, GpLeft, GpUp do
    #         @selected_index = @selected_index - 1
    #         @selected_index = options.length - 1 if @selected_index <= -1
    #       end
    #     end
    #
    # This example uses a block instead of a method name but it is absolultey the same
    # as the last example.
    #
    def on_down(*args,&block)
      _on(@down_actions,args,block)
    end

    alias_method :button_down, :on_down

    #
    # Register for a button_up event. These events are fired when
    # the button is released (from being pressed down). This event only fires
    # once when the button moves from the pressed state to the up state.
    #
    # @example Registering for a button down event to call a method named 'next_option'
    #
    #     class ExampleScene
    #        event :on_up, KbEscape, do: :leave_scene
    #
    #       def leave_scene
    #         transition_to :title
    #       end
    #     end
    #
    # Here in this scene if the Escape Key is pressed and released the example scene
    # will transition to the title scene.
    #
    # @example Registering for a button up event with a block of code to execute
    #
    #     class ExampleScene
    #       event :on_up, KbEscape do
    #        transition_to :title
    #       end
    #     end
    #
    # This example uses a block instead of a method name but it is absolultey the same
    # as the last example.
    #
    def on_up(*args,&block)
      _on(@up_actions,args,block)
    end

    alias_method :button_up, :on_up

    #
    # Register for a button_held event. These events are fired when
    # the button is currently in the downstate. This event continues to fire at the
    # beginning of every update of a scene until the button is released.
    #
    # @note button_held events require that the window be specified during initialization.
    #
    # @example Registering for button held events
    #
    #     class ExampleScene
    #       event :on_hold KbLeft, GpLeft do
    #         player.turn_left
    #       end
    #
    #       event :on_hold, KbRight, GpRight do
    #         player.turn_right
    #       end
    #
    #       event :on_hold, KbUp, Gosu::GpButton0, do: :calculate_accleration
    #
    #       def calculate_acceleration
    #         long_complicated_calculated_result = 0
    #         # ... multi-line calculations to determine the player acceleration ...
    #         player.accelerate = long_complicated_calculated_result
    #       end
    #     end
    #
    def on_hold(*args,&block)
      log.warn "Registering for a on_hold event requires that a window be provided." unless window
      _on(@held_actions,args,block)
    end

    alias_method :button_hold, :on_hold
    alias_method :button_held, :on_hold

    #
    # Register for mouse movements events. These events are fired each update
    # providing an event which contains the current position of the mouse.
    #
    # @note mouse movement events fire with each update so it is up to the
    #    receiving object of the event to determine if the new mouse movement
    #    is a delta.
    #
    # @note mouse movement events require that the window be specified during initialization.
    #
    # @example Registering for button held events
    #
    #     class ExampleScene
    #
    #       draws :player
    #
    #       event :on_mouse_movement do |event|
    #         player.position = event.mouse_point
    #       end
    #     end
    #
    def on_mouse_movement(*args,&block)
      options = (args.last.is_a?(Hash) ? args.pop : {})
      @mouse_movement_actions << ( block || lambda { |instance| send(options[:do]) } )
    end

    #
    # Register for a custom notification event. These events are fired when
    # another object within the game posts a notification with matching criteria.
    # If there has indeed been a match, then the stored action block will be fired.
    #
    # When the action block is specified is defined with no parameters it is assumed that
    # that the code should be executed within the context of the object that defined
    # the action, the 'target'.
    #
    # @example Registering for a save complete event that would re-enable a menu.
    #
    #     class ExampleScene
    #       event :notification, :save_complete do
    #         menu.enabled!
    #       end
    #     end
    #
    # The action block can also be specified with two parameters. In this case the code is
    # no longer executed within the context of the object and is instead provided the
    # the action target and the action source.
    #
    # @example Registering for a win game event that explicitly states the target and source.
    #
    #     class ExampleScene
    #
    #       event :notification, :win_game do |target,winner|
    #         target.declare_winner winner
    #       end
    #
    #       def declare_winner(winning_player)
    #         # ...
    #       end
    #     end
    #
    def notification(param,&block)
      custom_notifications[param.to_sym] = custom_notifications[param.to_sym] + [ block ]
    end

    attr_reader :up_actions, :down_actions, :held_actions

    attr_reader :mouse_movement_actions

    attr_reader :custom_notifications

    def _on(hash,args,block)
      options = (args.last.is_a?(Hash) ? args.pop : {})

      args.each do |keystroke|
        hash[keystroke] = block || lambda { |instance| send(options[:do]) }
      end
    end

    #
    # This is called by external or parent source of events, usually a Scene, when a button up event
    # has been triggered.
    #
    def fire_button_up(id)
      execute_block_for_target( &up_action(id) )
    end

    #
    # This is called by external or parent source of events, usually a Scene, when a button down
    # event has been triggered.
    #
    def fire_button_down(id)
      execute_block_for_target( &down_action(id) )
    end

    #
    # Fire the events mapped to the held buttons within the context
    # of the specified target. This method is differently formatted because held buttons are not
    # events but polling to see if the button is still being held.
    #
    def fire_events_for_held_buttons
      held_actions.each do |key,action|
        execute_block_for_target(&action) if window and window.button_down?(key)
      end
    end

    #
    # Fire events for all the registered actions that are suppose to receive
    # the mouse movement events.
    #
    def fire_events_for_mouse_movement
      mouse_movement_actions.each do |action|
        execute_block_for_target(&action)
      end
    end

    def execute_block_for_target(&block)
      event_data = EventData.new(window)
      target.instance_exec(event_data,&block)
    end

    # @return a block of code that is mapped for the 'button_up' id
    def up_action(id)
      up_actions[id] || lambda {|no_op| }
    end

    # @return a block of code that is mapped for the 'button_down' id
    def down_action(id)
      down_actions[id] || lambda {|no_op| }
    end

    #
    # Fire all events mapped to the matching notification.
    #
    def fire_events_for_notification(event,sender)
      notification_actions = custom_notifications[event]
      notification_actions.each do |action|
        _fire_event_for_notification(event,sender,action)
      end
    end

    #
    # Fire a single event based on the matched notification.
    #
    # An action without any parameters is assumed to be executed within the contexxt
    # of the target. If there are two parameters we will simply execute the action and
    # pass it both the target and the sender.
    #
    def _fire_event_for_notification(event,sender,action)
      if action.arity == 2
        target.instance_exec(sender,event,&action)
      elsif action.arity == 1
        target.instance_exec(sender,&action)
      else
        target.instance_eval(&action)
      end
    end

  end
end


module Metro

  module Models
    extend self

    #
    # Add a model, and all it's subclasses, to the list of available models.
    #
    # A model has several names added so that it accessible in many ways:
    #
    # * Model Class Name
    # * Model Name
    # * Model Name with slashes replaced with `::` separator
    #
    def add(model)
      all_models_for(model).each do |model|
        models_hash[model.to_s] = model.to_s
        name_with_slashes = model.model_name
        models_hash[name_with_slashes] = model.to_s
        name_with_colons  = name_with_slashes.gsub('/','::')
        models_hash[name_with_colons] = model.to_s
      end
    end

    #
    # @param [String] name the name of the model that you want to return.
    #
    # @return [String] the name of the model class
    #
    def find(name)
      models_hash[name].constantize
    end

    #
    # @return [Array<String>] all the names supported by the models hash.
    #
    def list
      models_hash.keys
    end

    #
    # @return [Hash] a hash of the available models. The keys are the various
    #   supported names, with the values being the names of the model classes.
    def models_hash
      @models_hash ||= HashWithIndifferentAccess.new("Metro::UI::Generic")
    end

    #
    # @param [Class,Array<Class>] models a model or array of models.
    # @return [Array] an array that contains the model itself and all of the
    #   models that are sub-classes of this model on down.
    #
    def all_models_for(models)
      Array(models).map do |model_class_name|
        model = model_class_name.constantize
        [ model ] + all_models_for(models.models)
      end.flatten.compact
    end

  end
end


require_relative 'easing/easing'

module Metro

  #
  # An Implicit Animation is an animation without all the work.
  # This little animation will take care of figuring out moving an
  # actor from one position to another, the rotation, the alpha,
  # etc.
  #
  # @example Creating an explicit animation that moves a player
  #
  #     animation = ImplicitAnimation.new actor: player,
  #       to: { x: final_x, y: final_y },
  #       interval: 80,
  #       easing: :ease_in,
  #       context: scene
  #
  #     animation.on_complete do
  #       transition_to :main
  #     end
  #
  # Here an animation is created that will move the player to the
  # position (final_x,final_y), specified in the :to hash that is
  # provided, over the interval of 80 steps. Additionally the movement
  # is done with an easing in.
  #
  # @note The actor object must respond to setter methods that match
  #   the specified attributes (e.g. x, y).
  #
  # The context provided is the context that the 'on_complete' block
  # is executed. In this case, upon completition, transition the scene
  # from the current one to the main scene.
  #
  class ImplicitAnimation < OnUpdateOperation

    def animations
      @animations ||= []
    end

    #
    # @return the type of easing that the implicit animation should employ.
    #   By default it uses linear but can be overridden when the easing is
    #   configured.
    #
    attr_reader :easing

    #
    # Additional initializion is required to calculate the attributes
    # that are going to be animated and to determine each of their deltas.
    #
    def after_initialize
      to.each do |attribute,final|
        start = actor.send(attribute)
        animations.push build_animation_step(attribute,start,final)
      end
    end

    def build_animation_step(attribute,start,final)
      step = AnimationStep.new
      step.actor = actor
      step.attribute = attribute
      step.deltas = easing_for(easing).calculate(start.to_f,final.to_f,interval.to_f)
      step
    end

    class AnimationStep
      attr_accessor :actor, :attribute, :deltas

      def execute_step(step)
        actor.set(attribute,deltas.at(step))
      end
    end

    #
    # @return the correct easing based on the specified name. When the name
    #   provided does not match anything then default to linear easing.
    #
    def easing_for(name)
      Metro::Easing.easing_for(name)
    end

    #
    # The ImplicitAnimation overrides the {Animation#execute_step} and
    # updates the attributes of the actor based upon the value of the
    # current animation step.
    #
    def execute_step
      animations.each {|step| step.execute_step(current_step) }
    end

    #
    # @return the delta for the attribute for the given step
    #
    def delta_for_step(attribute)
      deltas[attribute].at(current_step)
    end

  end
end


require_relative 'event_relay'

module Metro

  class EventStateManager
    def initialize
      @current_state = []
    end

    attr_accessor :window

    attr_reader :current_state

    #
    # Clear all the event relays of the current game state
    #
    def clear
      current_state.clear
    end

    #
    # Fire events for held buttons within the current game state
    #
    def fire_events_for_held_buttons
      current_state.each {|cs| cs.fire_events_for_held_buttons }
    end

    #
    # Fire events for mouse events within the current game state
    #
    def fire_events_for_mouse_movement
      current_state.each {|cs| cs.fire_events_for_mouse_movement }
    end

    #
    # Fire events for button up for the current game state
    #
    def fire_button_up(id)
      current_state.each {|cs| cs.fire_button_up(id) }
    end

    #
    # Fire events for button down within the current game state
    #
    def fire_button_down(id)
      current_state.each {|cs| cs.fire_button_down(id) }
    end

    #
    # Fire notification events within the current game state
    #
    def fire_events_for_notification(event,sender)
      current_state.each {|cs| cs.fire_events_for_notification(event,sender) }
    end

    #
    # An an event relay to the current game state
    #
    def add_events_for_target(target,events)
      relay = EventRelay.new(target,window)

      events.each do |target_event|
        relay.send target_event.event, *target_event.buttons, &target_event.block
      end

      current_state.push relay
    end
  end

end


require_relative 'control_definition'

module Metro
  #
  # Assists in creating and the storing of ControlDefinitions.
  #
  # @see DSL
  #
  class Controls

    #
    # Creation through controls is usually done with an instance_eval
    # of a block and this allows for a flexible interface.
    #
    # @param [String,Symbol] name the name or the alias of the control
    #   as it will be used within the course of the game.
    #
    def method_missing(name,*params,&block)
      options = params.find {|param| param.is_a? Hash }
      define_control(name,options)
    end

    def define_control(name,options)
      event = _event_type(options)
      args = _event_args(options)

      defined_controls.push ControlDefinition.new name, event, args
    end

    def _event_type(options)
      options[:is]
    end

    def _event_args(options)
      options[:with]
    end

    def defined_controls
      @defined_controls ||= []
    end
  end
end


require 'metro/game/dsl'

module Metro
  module Game
    extend self

    def setup(game_configuration)
      @config = game_configuration
    end

    #
    # Creates a window and starts the game with the game parameters.
    #
    def start!
      @window = Window.new width, height, fullscreen?
      window.caption = name
      window.scene = Scenes.generate(first_scene)
      window.show
    end

    # The original parameters specified during execution. These are the args
    # found on the command-line that are passed in when the game started.
    def execution_parameters
      @execution_parameters ||= []
    end

    attr_writer :execution_parameters

    #
    # @return the current game window.
    #
    attr_reader :window

    #
    # @return [Scene,NilClass] the current scene that is being displayed. If
    #   this is called before the window is being displayed when this will return
    #   a nil value.
    #
    def current_scene
      window ? window.scene : nil
    end

    def first_scene
      fetch(:first_scene)
    end

    def width
      fetch(:width,640)
    end

    def height
      fetch(:height,480)
    end

    def bounds
      Units::RectangleBounds.new left: 0, right: width, top: 0, bottom: height
    end

    def dimensions
      Units::Dimensions.of width, height
    end

    def center
      Units::Point.at width / 2 , height / 2
    end

    def fullscreen?
      !!fetch(:fullscreen)
    end

    def debug?
      !!fetch(:debug)
    end

    def name
      fetch(:name)
    end

    def authors
      fetch(:authors)
    end

    def website
      fetch(:website,Metro::WEBSITE)
    end

    def contact
      fetch(:contact)
    end

    def controls
      config.controls.defined_controls
    end

    def fetch(name,fallback = nil)
      config.send(name) rescue fallback
    end

    attr_reader :config

  end
end


module Metro
  class FadeTransitionScene < TransitionScene

    draw :rectangle, model: "metro::ui::rectangle"

    #
    # When the scene is shown set up the starting color for the rectangle
    # and queue the animation to transition the color to the final color.
    #
    def show
      rectangle.color = starting_color

      color = final_color

      animate :rectangle, to: { red: color.red,
                                green: color.green,
                                blue: color.blue,
                                alpha: color.alpha },
                          interval: interval do

        transition_to next_scene
      end
    end

    def interval
      options[:interval] || default_interval
    end

    def default_interval
      60
    end

    def starting_color
      options_starting_color || default_starting_color
    end

    def options_starting_color
      color_from_options(:from)
    end

    def default_starting_color
      Gosu::Color.new "rgb(255,255,255)"
    end

    def final_color
      options_final_color || default_final_color
    end

    def options_final_color
      color_from_options(:to)
    end

    def default_final_color
      Gosu::Color.new "rgb(0,0,0)"
    end

    def color_from_options(position)
      if options[position]
        if options[position][:color]
          Gosu::Color.new options[position][:color]
        end
      end
    end

  end
end


require File.join(File.dirname(__FILE__), 'table_field')

module Tabletastic
  class TableBuilder
    @@default_hidden_columns = %w[created_at updated_at created_on updated_on lock_version version]
    @@destroy_confirm_message = "Are you sure?"

    attr_reader   :collection, :klass, :table_fields

    def initialize(collection, klass, template)
      @collection, @klass, @template = collection, klass, template
      @table_fields = []
    end

    # builds up the fields that the table will include,
    # returns table head and body with all data
    #
    # Can be used one of three ways:
    #
    # * Alone, which will try to detect all content columns on the resource
    # * With an array of methods to call on each element in the collection
    # * With a block, which assumes you will use +cell+ method to build up
    #   the table
    #
    def data(*args, &block) # :yields: tablebody
      options = args.extract_options!
      if block_given?
        yield self
      else
        @table_fields = args.empty? ? orm_fields : args.collect {|f| TableField.new(f.to_sym)}
      end
      action_cells(options[:actions], options[:action_prefix])
      ["\n", head, "\n", body, "\n"].join("").html_safe
    end

    # individually specify a column, which will build up the header,
    # and method or block to call on each resource in the array
    #
    # Should always be called within the block of +data+
    #
    # For example:
    #
    #   t.cell :blah
    #
    # will simply call +blah+ on each resource
    #
    # You can also provide a block, which allows for other helpers
    # or custom formatting. Since by default erb will just call +to_s+
    # on an any element output, you can more greatly control the output:
    #
    #   t.cell(:price) {|resource| number_to_currency(resource)}
    #
    # would output something like:
    #
    #   <td>$1.50</td>
    #
    def cell(*args, &proc)
      options = args.extract_options!
      options.merge!(:klass => klass)
      args << options
      @table_fields << TableField.new(*args, &proc)
      # Since this will likely be called with <%= %> (aka 'concat'), explicitly return an
      # empty string; this suppresses unwanted output
      return ""
    end

    def head
      content_tag(:thead) do
        content_tag(:tr) do
          @table_fields.inject("") do |result,field|
            result + content_tag(:th, field.heading, field.heading_html)
          end.html_safe
        end
      end
    end

    def body
      content_tag(:tbody) do
        @collection.inject("\n") do |rows, record|
          rowclass = @template.cycle("odd","even")
          rows += @template.content_tag_for(:tr, record, :class => rowclass) do
            cells_for_row(record)
          end + "\n"
        end.html_safe
      end
    end

    def cells_for_row(record)
      @table_fields.inject("") do |cells, field|
        cells + content_tag(:td, field.cell_data(record), field.cell_html)
      end.html_safe
    end

    # Used internally to build up cells for common CRUD actions
    def action_cells(actions, prefix = nil)
      return if actions.blank?
      actions = [actions] if !actions.respond_to?(:each)
      actions = [:show, :edit, :destroy] if actions == [:all]
      actions.each do |action|
        action_link(action.to_sym, prefix)
      end
    end

    # Dynamically builds links for the action
    def action_link(action, prefix)
      html_class = "actions #{action.to_s}_link"
      block = lambda do |resource|
        compound_resource = [prefix, resource].compact
        compound_resource.flatten! if prefix.kind_of?(Array)
        case action
        when :show
          @template.link_to(link_title(action), compound_resource)
        when :destroy
          @template.link_to(link_title(action), compound_resource,
                            :method => :delete, :data => { :confirm => confirmation_message })
        else # edit, other resource GET actions
          @template.link_to(link_title(action),
                            @template.polymorphic_path(compound_resource, :action => action))
        end
      end
      self.cell(action, :heading => "", :cell_html => {:class => html_class}, &block)
    end

    protected

    def orm_fields
      return [] if klass.blank?
      fields = if klass.respond_to?(:content_columns)
        active_record_fields
      elsif klass.respond_to?(:fields)
        mongoid_fields
      else
        []
      end
      fields -= @@default_hidden_columns
      fields.collect {|f| TableField.new(f.to_sym)}
    end

    private

    def mongoid_fields
      klass.fields.keys
    end

    def active_record_fields
      klass.content_columns.map(&:name) + active_record_association_reflections
    end

    def active_record_association_reflections
      return [] unless klass.respond_to?(:reflect_on_all_associations)
      associations = []
      associations += klass.reflect_on_all_associations(:belongs_to).map(&:name)
      associations += klass.reflect_on_all_associations(:has_one).map(&:name)
      associations
    end

    def confirmation_message
      I18n.t("tabletastic.actions.confirmation", :default => @@destroy_confirm_message)
    end

    def content_tag(name, content = nil, options = nil, escape = true, &block)
      @template.content_tag(name, content, options, escape, &block)
    end

    def link_title(action)
      I18n.translate(action, :scope => "tabletastic.actions", :default => action.to_s.titleize)
    end
  end
end


module Metro

  #
  # @example Finding a scene based on the scene name
  #
  #     class IntroScene < Metro::Scene
  #       # ... scene content ...
  #     end
  #
  #     Scenes.find("intro")    # => IntroScene
  #     Scenes.find(:intro)     # => IntroScene
  #
  # @example Creating a scene instance based on the scene name
  #
  #     class IntroScene < Metro::Scene
  #       # ... scene content ...
  #     end
  #
  #     Scenes.generate("intro")    # => [SCENE: title]
  #     Scenes.generate(:intro)     # => [SCENE: title]
  #
  # @example Finding a scene that does not exist
  #
  #     scene = Scenes.find(:unknown)
  #     scene.missing_scene            # => :unknown
  #
  module Scenes
    extend self

    #
    # Add a scene to the hash of scenes with the scene name of the scene as the key
    # to retrieving this scene.
    #
    # @param [Scene] scene the scene to be added to the hash of Scenes.
    #
    def add(scene)
      all_scenes_for(scene).each { |scene| scenes_hash[scene.scene_name] = scene.to_s }
    end

    #
    # Finds the scene based on the specified scene name.
    #
    # @param [String,Symbol] scene_name the name of the scene to locate.
    # @return the Scene class that is found matching the specified scene name.
    #
    def find(scene_name)
      scenes_hash[scene_name].constantize
    end

    #
    # @return [Array<String>] all the names supported by the scenes hash.
    #
    def list
      scenes_hash.keys
    end

    #
    # Finds the scene with the specified name and then creates an instance of that
    # scene.
    #
    # @param [String,Symbol,Object] scene_name the name of the scene to locate.
    # @return an instance of Scene that is found matching the specified scene name
    #
    def generate(scene_or_scene_name,options = {})
      new_scene = generate_scene_from(scene_or_scene_name)
      apply_post_filters(new_scene,options)
    end

    #
    # If we have been given a scene, then we simply want to use it otherwise
    # we need to find and generate our scene from the scene name.
    #
    # @param [String,Sybmol,Class] scene_or_scene_name the name of the scene or an instance
    #   of Scene.
    #
    def generate_scene_from(scene_or_scene_name)
      if scene_or_scene_name.is_a? Scene
        scene_or_scene_name
      else
        find(scene_or_scene_name).new
      end
    end

    #
    # Post filters are applied to the scene after it has been found. These are
    # all objects that can respond to the #filter method.
    #
    def post_filters
      @post_filters ||= []
    end

    #
    # Register a filter that will be executed after a scene is found and generated. This
    # allows for the scene to be modified or changed based on the provided options.
    #
    # A filter is any object that responds to #filter and accepts two parameters: the
    # scene and a hash of options.
    #
    # @param [#filter] post_filter a filter is an object that can act as a filter.
    #
    def register_post_filter(post_filter)
      post_filters.push(post_filter)
    end

    private

    #
    # Apply all the post filtering to the specified scene with the given options
    #
    # @return a Scene object that has been filtered.
    #
    def apply_post_filters(new_scene,options)
      post_filters.inject(new_scene) {|scene,post| post.filter(scene,options) }
    end

    #
    # @return a Hash that allows for accessing  symbol names of the scenes
    #   as well as the class name constants to allow for the scenes to be found.
    #
    def scenes_hash
      @scenes_hash ||= hash_with_missing_scene_default
    end

    #
    # Create a hash that will return a setup missing scene by default.
    #
    def hash_with_missing_scene_default
      hash = HashWithIndifferentAccess.new do |hash,key|
        missing_scene = hash[:missing_scene].constantize
        missing_scene.missing_scene = key.to_sym
        missing_scene
      end
      hash[:missing_scene] = "Metro::MissingScene"
      hash
    end

    #
    # Returns all subclassed scenes of the scene or scenes provided. This method is
    # meant to be called recursively to generate the entire list of all the scenes.
    #
    # @param [Scene,Array<Scene>] scenes a scene or scene subclass or an array of
    #   scene subclasses.
    #
    def all_scenes_for(scenes)
      Array(scenes).map do |scene_class_name|
        scene = scene_class_name.constantize
        [ scene ] + all_scenes_for(scene.scenes)
      end.flatten.compact
    end

  end
end

require_relative 'transitions/scene_transitions'


require_relative 'views/scene_view'
require_relative 'events/events'
require_relative 'models/draws'

require_relative 'animation/has_animations'
require_relative 'animation/scene_animation'
require_relative 'animation/after_interval_factory'

module Metro

  #
  # A scene is a basic unit of a game. Within a scene you define a number of methods
  # that handle the initial setup, event configuration, logic updating, and drawing.
  #
  # @see #show
  # @see #update
  # @see #draw
  #
  # A fair number of private methods within Scene are prefaced with an underscore.
  # These methods often call non-underscored methods within those methods. This allows
  # for scene to configure or perform some functionality, while providing an interface
  # so that every subclass does not have to constantly call `super`.
  #
  class Scene
    include Units

    #
    # As Scene does a lot of work for you with regarding to setting up content, it is
    # best not to override #initialize and instead define an #after_initialize method
    # within the subclasses of Scene.
    #
    # @note This method should be implemented in the Scene subclass.
    #
    def after_initialize ; end

    #
    # This method is called right after the scene has been adopted by the window
    #
    # @note This method should be implemented in the Scene subclass.
    #
    def show ; end

    #
    # This is called every update interval while the window is being shown.
    #
    # @note This method should be implemented in the Scene subclass.
    #
    def update ; end

    #
    # This is called after every {#update} and when the OS wants the window to
    # repaint itself.
    #
    # @note This method should be implemented in the Scene subclass.
    #
    def draw ; end

    #
    # Before a scene is transitioned away from to a new scene, this method is called
    # to allow for the scene to complete any tasks, stop any actions, or pass any
    # information from the existing scene to the scene that is about to replace it.
    #
    # @note This method should be implemented in the Scene subclass.
    #
    # @param [Scene] new_scene this is the instance of the scene that is about to replace
    #   the current scene.
    #
    def prepare_transition_to(new_scene) ; end

    #
    # Before a scene is transitioned to it is called with the previous scene. This
    # allows for the new scene to retrieve any data from the previous scene to assist
    # with the layout of the current scene.
    #
    # @note This method should be implemented in the Scene subclass.
    #
    # @param [Scene] old_scene this is the instance of the scene that is being moved
    #   away from.
    #
    def prepare_transition_from(old_scene) ; end

    include Draws

    #
    # When an actor is defined, through the class method `draw` a getter and setter method
    # is defined. However, it is a better interface internally not to rely heavily on send
    # and have this small amount of obfuscation in the event that this needs to change.
    #
    # @return the actor with the given name.
    #
    def actor(actor_or_actor_name)
      if actor_or_actor_name.is_a? String or actor_or_actor_name.is_a? Symbol
        send(actor_or_actor_name)
      else
        actor_or_actor_name
      end
    end

    #
    # Post a custom notification event. This will trigger an event for all the
    # objects that are registered for notification with the current state.
    #
    def notification(event,sender=nil)
      sender = sender || UnknownSender
      state.fire_events_for_notification(event,sender)
    end

    #
    # A scene has events which it will register when the window is established.
    #
    include HasEvents

    #
    # A scene defines animations which it will execute when the scene starts
    #
    include HasAnimations

    #
    # Allow the definition of a updater that will be executed when the scene starts.
    #
    # @example Setting up an event to 2 seconds after the scene has started.
    #
    #     class ExampleScene
    #
    #       draws :title
    #
    #       after 2.seconds do
    #         transition_to :next_scene
    #       end
    #     end
    #
    def self.after(ticks,&block)
      after_intervals.push AfterIntervalFactory.new ticks, &block
    end

    #
    # Perform an operation after the specified interval.
    #
    #     class ExampleScene
    #
    #       draws :player
    #
    #       def update
    #         if player.is_dead?
    #           after 2.seconds do
    #             transition_to :game_over
    #           end
    #         end
    #       end
    #
    #     end
    #
    def after(ticks,&block)
      tick = OnUpdateOperation.new interval: ticks, context: self
      tick.on_complete(&block)
      enqueue tick
    end

    #
    # Setups up the Actors for the Scene based on the ModelFactories that have been
    # defined.
    #
    # @note this method should not be overriden, otherwise the actors will perish!
    # @see #after_initialize
    #
    def initialize
      add_actors_to_scene
      after_initialize
    end

    def add_actors_to_scene
      self.class.actors.each do |scene_actor|
        actor_instance = scene_actor.create
        actor_instance.scene = self
        send "#{scene_actor.name}=", actor_instance
      end
    end

    #
    # The window is the main instance of the game. Using window can access a lot of
    # underlying Metro::Window, a subclass of Gosu::Window, that the Scene class is
    # obfuscating.
    #
    # @see Metro::Window
    # @see Gosu::Window
    #
    attr_reader :window

    #
    # Setting the window places the scene within in the specified window. Which
    # will cause a number of variables and settings to be set up. The {#show}
    # method is called after the window has been set.
    #
    def window=(window)
      @window = window

      state.window = window
      state.clear

      register_events!
      register_actors!
      register_animations!
      register_after_intervals!

      show
    end

    #
    # Register all the events that were defined for this scene.
    #
    def register_events!
      register_events_for_target(self,self.class.events)
    end

    #
    # Register all the actors that were defined for this scene.
    #
    def register_actors!
      self.class.actors.each { |actor| register_actor(actor) }
    end

    #
    # Register all the animations that were defined for this scene.
    #
    def register_animations!
      self.class.animations.each do |animation|
        animate animation.actor, animation.options, &animation.on_complete_block
      end
    end

    def register_after_intervals!
      self.class.after_intervals.each do |after_interval|
        after after_interval.ticks, &after_interval.block
      end
    end

    #
    # Registering an actor involves setting up the actor within
    # the window, adding them to the list of things that need to be
    # drawn and then registering any eventst that they might have.
    #
    def register_actor(actor_factory)
      registering_actor = actor(actor_factory.name)
      registering_actor.window = window
      registering_actor.show

      drawers.push(registering_actor)
      updaters.push(registering_actor)

      register_events_for_target(registering_actor,registering_actor.class.events)
    end

    #
    # Allows you to set or retrieve the scene name for the Scene.
    #
    # @example Retrieving the default scene name
    #
    #     class ExampleScene < GameScene
    #     end
    #
    #     ExampleScene.scene_name # => "example"
    #
    # @example Setting a custom name for the Scene
    #
    #     class RollingCreditsScene < GameScene
    #       scene_name "credits"
    #     end
    #
    #     RollingCreditsScene.scene_name # => "credits"
    #
    # @param [String] scene_name when specified it will set the scene name for the class
    #   to the value specified.
    #
    # @return the String name of the scene which it can be used as a reference for transitioning
    #   or for generating the appropriate view information.
    #
    def self.scene_name(scene_name=nil)
      @scene_name ||= begin
        if to_s == "Metro::Scene"
          to_s.underscore
        else
          to_s.gsub(/_?Scene$/i,'').underscore
        end
      end

      scene_name ? @scene_name = scene_name.to_s : @scene_name
    end

    #
    # @return a common name that can be used through the system as a common identifier.
    #
    def self.metro_name
      scene_name
    end

    #
    # @return an array of all the scene names of all the ancestor scenes
    #
    def self.hierarchy
      ancestors.find_all {|a| a.respond_to? :metro_name }.map(&:metro_name)
    end

    #
    # Allows you to set or retrieve the scene name for the Scene.
    #
    # @example Retrieving the default scene name
    #
    #     class ExampleScene
    #       def show
    #         puts "Showing Scene: #{self.scene_name}" # => Showing Scene: example
    #       end
    #     end
    #
    # @return the string name of the Scene.
    #
    def scene_name
      self.class.scene_name
    end

    #
    # @return the string representation of a scene, this is used for debugging.
    #
    def to_s
      "[SCENE: #{self.class.scene_name}(#{self.class})]"
    end

    #
    # Captures all classes that subclass Scene.
    #
    def self.inherited(base)
      scenes << base.to_s
      Scenes.add(base)
    end

    #
    # All subclasses of Scene, this should be all the defined scenes within the game.
    #
    # @return an Array of Scene subclasses
    #
    def self.scenes
      @scenes ||= []
    end

    #
    # Enqueue will add an updater to the list of updaters that are run initially when
    # update is called. An updater is any object that can respond to #update. This
    # is used for animations.
    #
    def enqueue(updater)
      updaters.push(updater)
    end

    #
    # The class defined updaters which will be converted to instance updaters when the scene
    # has started.
    #
    def self.after_intervals
      @after_intervals ||= []
    end

    #
    # The objects that need to be executed on every update. These objects are traditionally
    # animations or window events for held pressed buttons. But can be any objects that responds
    # to the method #update.
    #
    def updaters
      @updaters ||= []
    end

    #
    # The `base_update` method is called by the Game Window. This is to allow for any
    # special update needs to be handled before calling the traditional `update` method
    # defined in the subclassed Scene.
    #
    def base_update
      updaters.each { |updater| updater.update }
      update
      updaters.reject! { |updater| updater.update_completed? }
    end

    #
    # The objects that need to be drawn with every draw cycle. These objects are traditionally
    # the model objects, like the actors defined within the scene.
    #
    def drawers
      @drawers ||= []
    end

    #
    # The `base_draw` method is called by the Game Window. This is to allow for any
    # special drawing needs to be handled before calling the traditional `draw` method
    # defined in the subclassed Scene.
    #
    def base_draw
      drawers.each { |drawer| drawer.draw }
      draw
      drawers.reject! { |drawer| drawer.draw_completed? }
    end

    # This provides the functionality for view handling.
    include SceneView

    #
    # `transition_to` performs the work of transitioning this scene
    # to another scene.
    #
    # @param [String,Symbol,Object] scene_or_scene_name the name of the Scene which can
    #   be either the class or a string/symbol representation of the shortened scene name.
    #   This could also be an instance of scene.
    #
    def transition_to(scene_or_scene_name,options = {})
      new_scene = Scenes.generate(scene_or_scene_name,options)
      _prepare_transition(new_scene)
      window.scene = new_scene
    end

    #
    # Before a scene is transitioned away from to a new scene, this private method is
    # here to allow for any housekeeping or other work that needs to be done before
    # calling the subclasses implementation of `prepare_transition`.
    #
    # @param [Scene] new_scene this is the instance of the scene that is about to replace
    #   the current scene.
    #
    def _prepare_transition(new_scene)
      log.debug "Preparing to transition from scene #{self} to #{new_scene}"

      new_scene.class.actors.find_all {|actor_factory| actor_factory.load_from_previous_scene? }.each do |actor_factory|
        new_actor = new_scene.actor(actor_factory.name)
        current_actor = actor(actor_factory.name)
        new_actor._load current_actor._save
      end

      prepare_transition_to(new_scene)
      new_scene.prepare_transition_from(self)
    end

    #
    # Helper method that is used internally to setup the events for the specified target.
    #
    # @param [Object] target the intended target for the specified events. This object
    #   will have the appropriate methods and functionality to respond appropriately
    #   to the action blocks defined in the methods.
    #
    # @param [Array<EventFactory>] events an array of EventFactory objects that need to now
    #   be mapped to the specified target.
    #
    def register_events_for_target(target,events)
      state.add_events_for_target(target,events)
    end

    #
    # The event state manager is configured through the {#events} method, which
    # stores all the gamepad and keyboard events defined. By default a scene is
    # placed in the default state and events that are added to this basic state.
    #
    # @see Events
    #
    def state
      @event_state_manager ||= EventStateManager.new
    end

    #
    # A Scene represented as a hash currently only contains the drawers
    #
    # @return a hash of all the drawers
    #
    def to_hash
      drawn = drawers.find_all{|draw| draw.saveable_to_view }.inject({}) do |hash,drawer|
        drawer_hash = drawer.to_hash
        hash.merge drawer_hash
      end

      drawn
    end

  end
end


require_relative 'key_value_coding'
require_relative 'properties/property'
require_relative 'models'

module Metro

  #
  # The Model is a basic, generic representation of a game object
  # that has a visual representation within the scene's window.
  #
  # Model is designed to be an abstract class, to be subclassed by
  # other models.
  #
  # @see Models::Generic
  #
  class Model
    include PropertyOwner
    include Units

    #
    # This is an entry point for customization. As the model's {#initialize}
    # method performs may perform some initialization that may be necessary.
    #
    # At this point the model has been created. However, the window and scene
    # of the model will not have been defined and defined properties rely on
    # the window or scene will return nil values. Other properties also will
    # likely not be set.
    #
    # @note This method should be implemented in the Model subclass.
    #
    def after_initialize ; end

    #
    # This is an entry point for customization. After the model's properties
    # have been set and the model has been assigned to the window and scene
    # this method is called. Here is where customization of properties or
    # final positioning can be performed.
    #
    # @note This method may be implemented in the Model subclass.
    #
    def show ; end

    #
    # This is called every update interval while the actor is in the scene
    #
    # @note This method should be implemented in the Model subclass
    #
    def update ; end

    #
    # This is called after an update. A model normally is not removed after
    # an update, however if the model responds true to #update_completed? then it
    # will be removed.
    #
    # @note This method should be implemented in the Model sublclass if you
    #   are interested in having the model be removed from the scene.
    #
    def update_completed? ; false ; end

    #
    # This is called after every {#update} and when the OS wants the window to
    # repaint itself.
    #
    # @note This method should be implemented in the Model subclass.
    #
    def draw ; end

    #
    # This is called after a draw. A model normally is not removed after
    # a draw, however if the model responds true to #draw_completed? then it
    # will be removed.
    #
    # @note This method should be implemented in the Model sublclass if you
    #   are interested in having the model be removed from the scene.
    #
    def draw_completed? ; false ; end

    def self.model_name(model_name=nil)
      @model_name ||= to_s.underscore
      model_name ? @model_name = model_name.to_s : @model_name
    end

    #
    # @return [String] the name of the model class.
    #
    property :model, type: :text

    #
    # @return [String] the name of model as it is used within the view or the scene.
    #   This is the common name, the key within the view file, or the name symbol
    #   name specified in the scene.
    #
    property :name, type: :text

    #
    # @return [TrueClass,FalseClass] true if the model should be saved to the
    #   view file, false when the model should not be savedable to the view file.
    #
    property :saveable_to_view, type: :boolean, default: true

    #
    # The window that this model that this window is currently being
    # displayed.
    #
    # The current value of window is managed by the scene
    # as this is set when the Scene is added to the window. All the
    # models gain access to the window.
    #
    # @see Window
    #
    attr_accessor :window

    #
    # The scene that this model is currently being displayed.
    #
    # The current value of scene is managed by the scene as this
    # is set when the scene is created.
    #
    # @see Scene
    attr_accessor :scene

    include KeyValueCoding

    #
    # Generate a custom notification event with the given name.
    #
    # @param [Symbol] event the name of the notification to generate.
    #
    def notification(event)
      scene.notification(event.to_sym,self)
    end

    #
    # Allows for the definition of events within the scene.
    #
    include HasEvents

    #
    # A helper method that allows the current model to generate another model. This
    # is useful as it allows for the current model to pass window and scene state
    # to the created model.
    #
    # @param [String] model_name the name of the model to be created.
    # @return [Metro::Model] the metro model instance
    #
    def create(model_name,options={})
      # @TODO: this is another path that parallels the ModelFactory
      model_class = Metro::Models.find(model_name)
      mc = model_class.new options
      mc.scene = scene
      mc.window = window
      mc
    end

    #
    # By default a model has no bounds. Each subclass of model will have to
    # define how their bounds are defined.
    #
    def bounds
      Bounds.none
    end

    #
    # Create an instance of a model.
    #
    # @note Overridding initialize method should be avoided, using the {#aftter_initialize)
    # method or done with care to ensure that functionality is preserved.
    #
    def initialize(options = {})
      _load(options)
      after_initialize
    end

    #
    # Loads a hash of content into the model. This process will convert the hash
    # of content into setter and getter methods with appropriate ruby style names.
    #
    # This is used internally when the model is created for the Scene. It is loaded
    # with the contents of the view.
    #
    def _load(options = {})
      # Clean up and symbolize all the keys then merge that with the existing properties
      options.keys.each do |key|
        property_name = key.to_s.underscore.to_sym
        if respond_to? "#{property_name}="
          send("#{property_name}=",options.delete(key))
        else
          options[property_name] = options.delete(key)
        end
      end

      properties.merge! options
    end

    #
    # Generate a hash export of all the fields that were previously stored within
    # the model.
    #
    # This is used internally within the scene to transfer the data from one model
    # to another model.
    #
    def _save
      properties
    end

    #
    # Generate a hash representation of the model.
    #
    def to_hash
      { name => properties.except(:name) }
    end

    #
    # @return a common name that can be used through the system as a common identifier.
    #
    def self.metro_name
      name.underscore
    end

    #
    # @return an array of all ancestor models by name
    #
    def self.hierarchy
      ancestors.find_all {|a| a.respond_to? :metro_name }.map(&:metro_name)
    end

    #
    # Captures all classes that subclass Model.
    #
    def self.inherited(base)
      models << base.to_s
      Models.add(base)
    end

    #
    # All subclasses of Model, this should be all the defined
    #
    def self.models
      @models ||= []
    end

  end
end

require_relative 'ui/ui'
require_relative 'audio/song'