class EventsController < SiteController
  require "uri"
  
  helper_method :events, :all_events, :continuing_events, :period, :calendars, :list_description
  helper_method :url_for_date, :url_for_month, :url_without_period, :calendar_parameters, :month_name, :short_month_name, :day_names
  before_filter :numerical_parameters
  
  radiant_layout { |controller| controller.layout_for :event_calendar }
  no_login_required

  # delivers designated lists of events in minimal formats

  def index
    @seen_events = {}
    respond_to do |format|
      format.html {
        if Radiant::Config['event_calendar:cached?']
          timeout = Radiant::Config['event_calendar:cache_duration'] || self.class.cache_timeout
          expires_in timeout.to_i, :public => true, :private => false
        else
          expires_now
        end
      }
      format.js {
        render :json => events.to_json
      }
      format.rss {
        render :layout => false
      }
      format.ics {
        headers["Content-disposition"] = %{attachment; filename="#{filename}.ics"}
        render :layout => false
      }
    end
  end
  
  def period
    return @period if @period
    this = Date.today
    if params[:mday]
      start = Date.civil(params[:year] || this.year, params[:month] || this.month, params[:mday])
      @period = CalendarPeriod.between(start, start.to_datetime.end_of_day)
    elsif params[:month]
      start = Date.civil(params[:year] || this.year, params[:month])
      @period = CalendarPeriod.between(start, start.to_datetime.end_of_month)
    elsif params[:year]
      start = Date.civil(params[:year])
      @period = CalendarPeriod.between(start, start.to_datetime.end_of_year)
    end
  end
  
  def calendars
    return @calendars if @calendars
    if params[:calendar_id]
      @calendars = [Calendar.find(params[:calendar_id])]
    elsif params[:slug]
      @calendars = Calendar.with_slugs(params[:slug])
    elsif params[:category]
      @calendars = Calendar.in_category(params[:category])
    end
  end
  
  def events
    @events ||= event_finder.paginate(pagination_parameters)
  end
  
  def all_events
    @all_events ||= event_finder.all
  end
  
  def event_finder
    ef = Event.scoped
    if period
      if period.bounded?
        ef = ef.between(period.start, period.finish) 
      elsif period.start
        ef = ef.after(period.start) 
      else
        ef = ef.before(period.finish) 
      end
    else
      ef = ef.future
    end
    ef = ef.approved if Radiant::Config['event_calendar.require_approval']
    ef = ef.in_calendars(calendars) if calendars
    ef
  end
  
  def continuing_events
    return @continuing_events if @continuing_events
    if period && period.start
      @continuing_events = Event.unfinished(period.start).by_end_date
    else
      @continuing_events = Event.unfinished(Time.now).by_end_date
    end
  end
  
  def list_description
    return @description if @description
    parts = []
    parts << (period ? period.description : "coming up")
    parts << "in #{calendars.to_sentence}" if calendars
    @description = parts.join(' ')
  end
      
  def url_for_date(date)
    url_for(url_parts({
      :mday => date.mday,
      :month => month_name(date.month).downcase,
      :year => date.year
    }))
  end
  
  def url_for_month(date)
    url_for(url_parts({
      :mday => nil,
      :month => month_name(date.month).downcase,
      :year => date.year
    }))
  end
  
  def url_without_period
    url_for(url_parts({
      :mday => nil,
      :month => nil,
      :year => nil
    }))
  end
  
  def query_string
    url_parts.map{|p| "#{p}=params[p]" }.join("&amp;")
  end
  
  def filename
    url_parts.map{|p| params[p] }.join("_")
  end
  
  # this is broken down to provide chain points for other extensions that add more ways to filter
  # eg, to start with, taggable_events

  def calendar_parameters
    url_parts
  end
  
  def url_parts(amendments={})
    parts = params.slice(*calendar_parameter_names)   # Hash#slice is defined in will_paginate/lib/core_ext
    parts.merge(amendments)
  end
  
  def calendar_parameter_names
    [:year, :month, :mday, :category, :slug, :calendar_id]
  end
  
  def month_name(month)
    month_names[month]
  end
  
  def short_month_name(month)
    short_month_names[month]
  end
  
  def day_names
    return @day_names if @day_names
    @day_names ||= Date::DAYNAMES.dup
    @day_names.push(@day_names.shift) # Class::Date and ActiveSupport::CoreExtensions::Time::Calculations have different ideas of when is the start of the week. We've gone for the rails standard.  
    @day_names
  end
  
protected
  
  def short_month_names
    @short_month_names ||= Date::ABBR_MONTHNAMES.dup
  end
  
  def month_names
    @month_names ||= Date::MONTHNAMES.dup
  end
  
  # months can be passed around either as names or numbers
  # any date part can be 'now' or 'next' for ease of linking
  # and everything is converted to_i to save clutter later
  
  def numerical_parameters
    if params[:month] && month_names.include?(params[:month].titlecase)
      params[:month] = month_names.index(params[:month].titlecase)
    end
    [:year, :month, :mday].select{|p| params[p] }.each do |p|
      params[p] = Date.today.send(p) if params[p] == 'now'
      params[p] = (Date.today + 1.send(p == :mday ? :day : p)).send(p) if params[p] == 'next'
      params[p] = params[p].to_i
    end
  end
  
  def pagination_parameters
    {
      :page => (params[:p] || 1).to_i, 
      :per_page => (params[:pp] || Radiant::Config['event_calendar.per_page'] || 10).to_i
    }
  end
  
end