module Spontaneous::Output
  class Format
    module ClassMethods
      # class_attribute :template_engine

      def inherited(subclass)
        subclass.helper_formats.concat helper_formats
      end

      def provides_format(*formats)
        helper_formats.concat formats
        Spontaneous::Output.register_format(self, *formats)
      end

      def helper_formats
        @helper_formats ||= []
      end

      def configure(output_name, options)
        format    = options[:format]
        extension = options[:extension]
        language  = options[:language]
        mimetype  = options[:mimetype] || options[:mime_type] || calculate_mimetype(format)
        options.update({
          :format => format.to_sym,
          :mimetype => mimetype,
          :extension => extension,
          :language => language
        })
        @name    = output_name.to_sym
        @options = default_options.merge(options)
      end

      def calculate_mimetype(format)
        ::Rack::Mime.mime_type(".#{format}", nil) || inherited_mimetype
      end

      def default_options
        { :private => false,
          :dynamic => false }
      end

      def inherited_mimetype
        ::Rack::Mime.mime_type(".#{helper_formats.first}")
      end

      def mimetype
        return inherited_mimetype if @options.nil?
        @options[:mimetype]
      end

      alias_method :mime_type, :mimetype
      def format
        @options[:format]
      end

      def name
        @name
      end

      alias_method :extension, :name

      def to_sym
        @name
      end

      def extension(is_dynamic = false, dynamic_extension = Spontaneous::Output::Template.extension)
        if (override = @options[:extension])
          return normalise_extension(override.to_s)
        end
        ext =  normalise_extension(name.to_s)
        ext << ".#{self.dynamic_extension(dynamic_extension)}" if (is_dynamic or self.dynamic?)
        ext
      end

      def normalise_extension(ext)
        ext =  "." << ext unless ext.start_with?(".")
        ext
      end

      def dynamic_extension(default_extension)
        @options[:language] || default_extension
      end

      def private?
        @options[:private]
      end

      def public?
        !self.private?
      end

      def dynamic?
        @options[:dynamic]
      end

      def postprocess
        @options[:postprocess]
      end

      def context
        Spontaneous::Site.context (helper_formats + [name]).uniq.compact
      end
    end

    extend ClassMethods
    extend Forwardable

    attr_reader :page
    attr_accessor :content

    def_delegators "self.class", :format, :dynamic?, :extension, :to_sym, :mimetype, :mime_type, :public?, :private?, :context, :name, :extension

    def initialize(page, content = nil)
      @page, @content = page, content
      @content ||= page
    end

    def render(params = {}, *args)
      render_using(default_renderer, params, *args)
    end

    def render_using(renderer, params, *args)
      before_render
      output = render_page(renderer, params, *args)
      output = postprocess(output)
      after_render(output)
      output
    end

    def default_renderer
      Spontaneous::Output.renderer
    end

    def before_render
    end

    def after_render(output)
    end

    def postprocess(output)
      if (process = self.class.postprocess) && (process.is_a?(Proc))
        output = process.call(@page, output)
      end
      output
    end

    def render_page(renderer, params = {}, *args)
      renderer.render(self, params, *args)
    end

    def publish_page(renderer, revision)
      rendered = render_using(renderer, {:revision => revision})
      path = output_path(revision, rendered)
      File.open(path, 'w') do |file|
        case rendered
        when IO
          IO.copy_stream(rendered, file)
        else
          file.write(rendered.to_s)
        end
      end
    end

    def output_path(revision, render)
      ext = nil
      template_dynamic = Spontaneous::Output::Template.is_dynamic?(render)
      path = Spontaneous::Output.output_path(revision, self, template_dynamic)

      dir = File.dirname(path)
      FileUtils.mkdir_p(dir) unless File.exist?(dir)
      path
    end
  end
end

Dir[File.join(File.dirname(__FILE__), 'format', '*.rb')].each do |format|
  require format
end