#---
# Excerpted from "The ThoughtWorks Anthology",
# published by The Pragmatic Bookshelf.
# Copyrights apply to this code. It may not be used to create training material, 
# courses, books, articles, and the like. Contact us if you are in doubt.
# We make no guarantees that this code is fit for any purpose. 
# Visit http://www.pragmaticprogrammer.com/titles/twa for more book information.
#---
require 'model'

# initial builder. Mix of method chaining and parameters.

class RulesBuilder1
  def initialize
    @configuration = Configuration.new
  end

  def item srcSymbol
    @current_item = Item.new srcSymbol
    @configuration.add_item @current_item
    self
  end

  def load lines
    instance_eval lines.join("\n")
    return @configuration
  end

  def uses arg
    @current_item.add_usage @current_resource
    self
  end    

  def acid
    @current_resource = Acid.new
    self
  end

  def type acidType
    @current_resource.type = acidType
    self
  end
  def grade aNumber
    @current_resource.grade = aNumber
    self
  end

  def electricity powerNumber
    @current_resource = Electricity.new(powerNumber)
    self
  end
  
  def provides arg
    @current_item.add_provision(@current_resource)
    self
  end

  def depends_on arg
    @current_item.add_dependency(@configuration[arg])
  end

  def method_missing symbol, *args
    raise ParseException.new("unknown method <#{symbol}>")
    super symbol, *args
  end
end

class ParseException < RuntimeError
  def initialize parse_message
    super
    @parse_message = parse_message.dup
  end
  attr_accessor :parse_message
  def line_number
    backtrace.detect{|line| line =~ /^\(eval\):(\d*):/}
    return $1.to_i
  end
end

class Diagnostic
  require 'forwardable'
  extend Forwardable
  def_delegators :@error, :message
  def initialize error, aString
    @error = error
    @lines = aString.split("\n")
  end
  def to_s
    result = []
    result << "Exception: #{@error.class} in #{line_number} of DSL"
    result << ("<%s>" % @lines[line_number - 1])
    result << parse_message
    return result.join("\n")
  end
  def line_number
    @error.backtrace.detect{|line| line =~ /^\(eval\):(\d*):/}
    return $1.to_i
  end    
  def parse_message
    if  @error.respond_to?(:parse_message)
      return @error.parse_message
    else 
      return  @error.message
    end
  end
end

