class Middleman::TemplateRenderer

def self.cache

def self.cache
  @_cache ||= Cache.new
end

def self.locate_layout(app, name, preferred_engine=nil)

def self.locate_layout(app, name, preferred_engine=nil)
  resolve_opts = {}
  resolve_opts[:preferred_engine] = preferred_engine unless preferred_engine.nil?
  # Check layouts folder
  layout_file = resolve_template(app, File.join(app.config[:layouts_dir], name.to_s), resolve_opts)
  # If we didn't find it, check root
  layout_file = resolve_template(app, name, resolve_opts) unless layout_file
  # Return the path
  layout_file
end

def self.resolve_template(app, request_path, options={})

def self.resolve_template(app, request_path, options={})
  # Find the path by searching
  relative_path = Util.strip_leading_slash(request_path.to_s)
  # By default, any engine will do
  preferred_engines = []
  # If we're specifically looking for a preferred engine
  if options.key?(:preferred_engine)
    extension_class = ::Tilt[options[:preferred_engine]]
    # Get a list of extensions for a preferred engine
    preferred_engines += ::Tilt.mappings.select do |_, engines|
      engines.include? extension_class
    end.keys
  end
  preferred_engines << '*'
  preferred_engines << nil if options[:try_static]
  found_template = nil
  preferred_engines.each do |preferred_engine|
    path_with_ext = relative_path.dup
    path_with_ext << ('.' + preferred_engine) unless preferred_engine.nil?
    globbing = preferred_engine == '*'
    # Cache lookups in build mode only
    file = if app.build?
      cache.fetch(path_with_ext, preferred_engine) do
        app.files.find(:source, path_with_ext, globbing)
      end
    else
      app.files.find(:source, path_with_ext, globbing)
    end
    found_template = file if file && (preferred_engine.nil? || ::Tilt[file[:full_path]])
    break if found_template
  end
  # If we found one, return it
  found_template
end

def _render_with_all_renderers(path, locs, context, opts, &block)

def _render_with_all_renderers(path, locs, context, opts, &block)
  # Keep rendering template until we've used up all extensions. This
  # handles cases like `style.css.sass.erb`
  content = nil
  while ::Tilt[path]
    begin
      opts[:template_body] = content if content
      content_renderer = ::Middleman::FileRenderer.new(@app, path)
      content = content_renderer.render(locs, opts, context, &block)
      path = File.basename(path, File.extname(path))
    rescue LocalJumpError
      raise "Tried to render a layout (calls yield) at #{path} like it was a template. Non-default layouts need to be in #{@app.config[:source]}/#{@app.config[:layouts_dir]}."
    end
  end
  content
end

def fetch_layout(engine, opts)

def fetch_layout(engine, opts)
  # The layout name comes from either the system default or the options
  local_layout = opts.key?(:layout) ? opts[:layout] : @app.config[:layout]
  return unless local_layout
  # Look for engine-specific options
  engine_options = @app.config.respond_to?(engine) ? @app.config.send(engine) : {}
  # The engine for the layout can be set in options, engine_options or passed
  # into this method
  layout_engine = if opts.key?(:layout_engine)
    opts[:layout_engine]
  elsif engine_options.key?(:layout_engine)
    engine_options[:layout_engine]
  else
    engine
  end
  # Automatic mode
  if local_layout == :_auto_layout
    # Look for :layout of any extension
    # If found, use it. If not, continue
    locate_layout(:layout, layout_engine)
  else
    # Look for specific layout
    # If found, use it. If not, error.
    if layout_file = locate_layout(local_layout, layout_engine)
      layout_file
    else
      raise ::Middleman::TemplateRenderer::TemplateNotFound, "Could not locate layout: #{local_layout}"
    end
  end
end

def initialize(app, path)

def initialize(app, path)
  @app = app
  @path = path
end

def locate_layout(name, preferred_engine=nil)

def locate_layout(name, preferred_engine=nil)
  self.class.locate_layout(@app, name, preferred_engine)
end

def render(locs={}, opts={}, &block)

def render(locs={}, opts={}, &block)
  path = @path.dup
  locals = locs.dup.freeze
  options = opts.dup
  extension = File.extname(path)
  engine = extension[1..-1].to_sym
  if defined?(::I18n)
    old_locale = ::I18n.locale
    ::I18n.locale = options[:lang] if options[:lang]
  end
  # Sandboxed class for template eval
  context = @app.template_context_class.new(@app, locals, options)
  # TODO: Only for HAML files
  context.init_haml_helpers if context.respond_to?(:init_haml_helpers)
  content = _render_with_all_renderers(path, locs, context, opts, &block)
  # If we need a layout and have a layout, use it
  if layout_file = fetch_layout(engine, options)
    layout_renderer = ::Middleman::FileRenderer.new(@app, layout_file[:relative_path].to_s)
    content = layout_renderer.render(locals, options, context) { content }
  end
  # Return result
  content
ensure
  # Pop all the saved variables from earlier as we may be returning to a
  # previous render (layouts, partials, nested layouts).
  ::I18n.locale = old_locale if defined?(::I18n)
end

def resolve_template(request_path, options={})

def resolve_template(request_path, options={})
  self.class.resolve_template(@app, request_path, options)
end