# Asserts a given file exists. You need to supply an absolute path or a path relative
# to the configured destination:
#
#   generator.should have_generated_file "app/controller/products_controller.rb" 
#            

module RSpec::FileMatchers
  class HaveFile    
    attr_accessor :relative_path

    def initialize(relative_path, type = nil)
      @relative_path = relative_rails_file(relative_path, type)
    end

    def matches?(generator, &block)
      file = File.expand_path(relative_path, Rails.root)
      file_exists = File.exists?(file)
      if block && file_exists
        read = File.read(file)
        ruby_content = read.extend(RSpec::RubyContent::Helpers)
        yield ruby_content
      else
        file_exists
      end        
    end          
  
    def failure_message
      "Expected file #{relative_path} to have been generated, but it was not"
    end

    def negative_failure_message
      "Did not expected file #{relative_path} to have been generated, but it was"
    end
    
    protected
    
    def relative_rails_file path, type = nil                       
      path = path.to_s
      f_name = file_name(path, type)      
      return File.join(::Rails.root, base_dir(type), folder(type), f_name) if type        
      File.join(::Rails.root, path)
    end
    
    def file_name path, type
      return "#{path}#{postfix(type)}.rb" if !path.include? '.'
      path
    end
      

    def postfix type
      "_#{type}" if ![:model].include?(type)
    end

    def folder type
      case type
      when :observer
        'models'
      else
        type.to_s.pluralize
      end
    end      
    
    def base_dir type
      case type
      when :model, :controller, :view, :helper, :observer, :mailer
        'app'
      when :migration
        'db'
      when :javascript, :stylesheet
        'public'
      when :initializer, :locale
        'config'
      else
        ''          
      end
    end
  end

  def have_file(relative, type = nil)
    HaveFile.new(relative, type)
  end
  alias_method :contain_file, :have_file

  def have_model(relative)
    HaveFile.new(relative, :model)
  end
  alias_method :contain_model, :have_model

  def have_controller(relative) 
    HaveFile.new(relative, :controller)
  end
  alias_method :contain_controller, :have_controller

  def have_helper(relative)
    HaveFile.new(relative, :helper)
  end
  alias_method :contain_helper, :have_helper

  def have_view(relative, action='show', ext='html.erb')
    HaveFile.new("#{relative}/#{action}.#{ext}", :view)
  end
  alias_method :contain_view, :have_view
  
  def have_observer(relative)
    HaveFile.new(relative, :observer)
  end  
  alias_method :contain_observer, :have_observer  

  def have_mailer(relative)
    HaveFile.new(relative, :mailer)
  end  
  alias_method :contain_mailer, :have_mailer

end