class BlogController < ApplicationController
  layout :determine_layout

  # all matching posts
  def posts
    paginate_with_path :conditions => 'parent_id IS NULL'
  end

  # all matching comments
  def comments
    paginate :conditions => 'parent_id IS NOT NULL'
    params[:flav] = 'post' if params['flav'] == 'html'
  end

  # date range
  def by_date
    paginate_with_path :conditions => parse_date
  end

  # archives
  def archive
    unless request.get?
      return render(:file => "#{RAILS_ROOT}/public/405.html",
        :status => '405 Method not allowed')
    end

    params[:year] ||= Time.now.year
    params[:month] ||= Time.now.month
    @entries = Entry.find_all parse_date

    @this_month = Time.mktime(params[:year],params[:month]).to_date
    @prev_month = @this_month-1
    @next_month = @this_month+31
    render :layout=>'archive', :template=>'blog/archive'
  end

  # obsolete id.flav format
  def by_id
    id = [params[:path]].flatten[-1].to_s.split('.')[0]
    paginate_with_path :conditions=>"atomid='tag:intertwingly.net,2004:#{id}'"
  end

private

  # convert date from URI into a time range
  def parse_date
    if params[:day]
      start = Time.mktime(params[:year], params[:month], params[:day])
      fin = start+1.day
    elsif params[:month]
      fin = start = Time.mktime(params[:year], params[:month], 1)
      fin = fin+1.day until fin.month != start.month
    else
      start = Time.mktime(params[:year])
      fin = Time.mktime(1+params[:year].to_i)
    end

    return ['updated >= ? AND updated < ? AND parent_id IS NULL', start, fin]
  end

  # subparse the path component of the URI
  def paginate_with_path options
    params[:path] = [params[:path]].flatten
    params[:path] = ['index'] if params[:path].length == 0
  
    if params[:path][-1] =~ /(.*)\.(\w+)/
      params[:path][-1], params[:flav] = $1, $2
    end

    params[:path] = params[:path].join('/')

    options[:conditions] = [options[:conditions]].flatten

    if params[:path] and params[:path] != 'index' and params[:path] !~ /^\d+$/
      options[:conditions][0] += ' AND slug = ?'
      options[:conditions] << params[:path]
    end

    if request.post?
      entries = Entry.find :all, options
      if entries.length == 1
        post entries[0]
      elsif entries.length == 0
        render(:file => "#{RAILS_ROOT}/public/404.html",
          :status => '404 Not Found')
      else
        render(:file => "#{RAILS_ROOT}/public/405.html",
          :status => '405 Method not allowed')
      end
    else
      paginate options
    end
  end

  # issue query and paginate results.  If the query results in a single
  # result, redirect to the page with that result and show comments.
  def paginate options
    unless request.get?
      render(:file => "#{RAILS_ROOT}/public/405.html",
        :status => '405 Method not allowed')
      return
    end

    if params[:q]
      options[:conditions][0] += ' AND MATCH(title,summary,content) AGAINST(?)'
      options[:conditions] << params[:q]
    end

    options[:order_by] ||= 'updated DESC'

    @entry_pages, @entries = super :entries, options

    if @entries.length == 0 and not @parent
      render(:file => "#{RAILS_ROOT}/public/404.html",
        :status => "404 Not Found")
    end

    if @entry_pages.item_count == 1 and @entries[0].id and not @parent
      @parent = @entries[0]

      if @parent.slug and (params[:path] == 'index' or params[:day] == nil)
        redirect_to @parent.by_date
      end

      paginate :order_by => 'updated', :per_page => 50,
        :conditions => ['parent_id = ?', @parent.id]
      params[:flav] = 'post' if params[:flav] == 'html'
    end

    params[:flav] ||= 'html'
  end

  # post a comment
  def post entry
    if not params[:preview]
      @comment = entry.children.create
      @comment.title = entry.title
      @comment.content = params['comment']

      params.reject!{|k,v| v.to_s.empty?}
      params['name'] ||= 'anonymous'
      params['uri'] ||= params['url']

      if `host #{request.remote_ip}` =~ / domain name pointer (\S+)\.\s*$/
        params['ipaddr'] = $1
      else
        params['ipaddr'] = request.remote_ip
      end

      @comment.author = Author.find_or_create params
      @comment.updated = Time.now
      if @comment.save
        redirect_to({:action=>'posts', :path=>['index.html']})
        return
      end
    end

    @parent, @entries = entry, []
    params[:flav] = 'preview'
  end

  # determine which layout to use (if any)
  def determine_layout
    case params[:flav]
      when 'archive': 'archive'
      when 'html', 'post', 'preview': 'blog'
      else nil
    end
  end

  # determine which template to use based on the flavour selected
  def default_template_name default=action_name
    "#{self.class.controller_path}/#{params[:flav]}"
  end
end
