module ReaderTags
  include Radiant::Taggable
  include ReaderHelper
  
  class TagError < StandardError; end

  # I can see this causing problems: will change soon

  desc %{
    The root 'site' tag is not meant to be called directly. 
    All it does is to prepare the way for eg.
    <pre><code><r:site:url /></code></pre>
  }
  tag 'site' do |tag|
    raise TagError, "r:site currently only works in email" unless @mailer_vars
    raise TagError, "no site" unless tag.locals.site = @mailer_vars[:@site]
    tag.expand
  end
  tag 'site:name' do |tag|
    if defined?(Site) && tag.locals.site.is_a?(Site)
      tag.locals.site.name
    else
      tag.locals.site[:name]
    end
  end
  tag 'site:url' do |tag|
    if defined?(Site) && tag.locals.site.is_a?(Site)
      tag.locals.site.base_domain
    else
      tag.locals.site[:url]
    end
  end
  tag 'site:login_url' do |tag|
    reader_login_url(:host => @mailer_vars[:@host])
  end

  desc %{
    The root 'recipient' tag is not meant to be called directly. 
    All it does is summon a reader object so that its fields can be displayed with eg.
    <pre><code><r:recipient:name /></code></pre>
  }
  tag 'recipient' do |tag|
    raise TagError, "r:recipient only works in email" unless @mailer_vars
    raise TagError, "no recipient" unless tag.locals.recipient = @mailer_vars[:@reader]
    tag.expand
  end
  
  [:name, :forename, :email, :description, :login].each do |field|
    desc %{
      Only for use in email messages. Displays the #{field} field of the reader currently being emailed.
      <pre><code><r:recipient:#{field} /></code></pre>
    }
    tag "recipient:#{field}" do |tag|
      tag.locals.recipient.send(field)
    end
  end
  
  desc %{
    Only for use in email messages. Displays the password of the reader currently being emailed, if we still have it.

    (After the first successful login we forget the cleartext version of their password, so you only want to use this 
    tag in welcome and activation messages.)
    
    <pre><code><r:recipient:url /></code></pre>
  }
  tag "recipient:password" do |tag|
    tag.locals.recipient.clear_password || "<encrypted>"
  end
  
  desc %{
    Only for use in email messages. Displays the me-page url of the reader currently being emailed.
    <pre><code><r:recipient:url /></code></pre>
  }
  tag "recipient:url" do |tag|
    reader_url(tag.locals.recipient, :host => @mailer_vars[:@host])
  end

  desc %{
    Only for use in email messages. Displays the preferences url of the reader currently being emailed.
    <pre><code><r:recipient:url /></code></pre>
  }
  tag "recipient:edit_url" do |tag|
    edit_reader_url(tag.locals.recipient, :host => @mailer_vars[:@host])
  end

  desc %{
    Only for use in email messages. Displays the address that will activate the current reader account.
    <pre><code><r:recipient:activation_url /></code></pre>
  }
  tag "recipient:activation_url" do |tag|
    activate_me_url(tag.locals.recipient, :activation_code => tag.locals.recipient.perishable_token, :host => @mailer_vars[:@host])
  end

  desc %{
    Only for use in email messages. Displays the address that will bring up a new-password form for the current reader account.
    <pre><code><r:recipient:repassword_url /></code></pre>
  }
  tag "recipient:repassword_url" do |tag|
    repassword_me_url(tag.locals.recipient, :confirmation_code => tag.locals.recipient.perishable_token, :host => @mailer_vars[:@host])
  end

  desc %{
    The root 'sender' tag is not meant to be called directly. 
    All it does is summon a sender object so that its fields can be displayed with eg.
    <pre><code><r:sender:name /></code></pre>
  }
  tag 'sender' do |tag|
    raise TagError, "r:sender only works in email" unless @mailer_vars
    tag.expand
  end

  desc %{
    Only for use in email messages. Displays the name of the email-sender (which is probably configured in `email.name`)
    <pre><code><r:sender:name /></code></pre>
  }
  tag "sender:name" do |tag|
    @mailer_vars['sender']
  end

  desc %{
    Only for use in email messages. Displays the address of the email-sender (which is probably configured in `email.address`)
    <pre><code><r:sender:address /></code></pre>
  }
  tag "sender:address" do |tag|
    @mailer_vars['reply_to']
  end

  # and for referring to messages on pages
  # at the moment this only works inside r:reader:messages:each or r:group:messages:each, 
  # both of which are defined in reader_group
  # but soon there will be a conditional r:messages:each tag here too

  desc %{
    The root 'message' tag is not meant to be called directly. 
    All it does is summon a message object so that its fields can be displayed with eg.
    <pre><code><r:message:subject /></code></pre>
  }
  tag 'message' do |tag|
    raise TagError, "no message!" unless tag.locals.message
    tag.expand
  end

  desc %{
    Displays the message subject.
    
    <pre><code><r:message:subject /></code></pre>
  }
  tag "message:subject" do |tag|
    tag.locals.message.subject
  end

  desc %{
    Displays the formatted message body.
    
    <pre><code><r:message:body /></code></pre>
  }
  tag "message:body" do |tag|
    tag.locals.message.filtered_body
  end

  desc %{
    Returns the url of the show-message page.
    
    <pre><code><r:message:url /></code></pre>
  }
  tag "message:url" do |tag|
    preview_message_path(tag.locals.message)
  end

  desc %{
    Displays a link to the show-message page.
    
    <pre><code><r:message:link /></code></pre>
  }
  tag "message:link" do |tag|
    options = tag.attr.dup
    attributes = options.inject('') { |s, (k, v)| s << %{#{k.downcase}="#{v}" } }.strip
    attributes = " #{attributes}" unless attributes.empty?
    text = tag.double? ? tag.expand : tag.render('message:subject')
    %{<a href="#{tag.render('message:url')}"#{attributes}>#{text}</a>}
  end

  desc %{
    The root 'reader' tag is not meant to be called directly.
    All it does is summon a reader object so that its fields can be displayed with eg.
    <pre><code><r:reader:name /></code></pre>
    
    This will only work on an access-protected page and should never be used on a cached page, because everyone will see it.
  }
  tag 'reader' do |tag|
    tag.expand if !tag.locals.page.cache? && tag.locals.reader = Reader.current
  end

  [:name, :forename, :email, :description, :login].each do |field|
    desc %{
      Displays the #{field} field of the current reader.
      <pre><code><r:reader:#{field} /></code></pre>
    }
    tag "reader:#{field}" do |tag|
      tag.locals.reader.send(field)
    end
  end

  desc %{
    Expands if the current reader has been sent any messages.
    
    <pre><code><r:reader:if_messages>...</r:reader:if_messages /></code></pre>
  }
  tag "reader:if_messages" do |tag|
    tag.expand if tag.locals.reader.messages.any?
  end

  desc %{
    Expands if the current reader has not been sent any messages.
    
    <pre><code><r:reader:unless_messages>...</r:reader:unless_messages /></code></pre>
  }
  tag "reader:unless_messages" do |tag|
    tag.expand unless tag.locals.reader.messages.any?
  end

  desc %{
    Loops through the messages that belong to this reader (whether they have been sent or not, so at the moment this may include drafts).
    
    <pre><code><r:reader:messages:each>...</r:reader:messages:each /></code></pre>
  }
  tag "reader:messages" do |tag|
    tag.locals.messages = tag.locals.reader.messages
    tag.expand if tag.locals.messages.any?
  end
  tag "reader:messages:each" do |tag|
    result = []
    tag.locals.messages.each do |message|
      tag.locals.message = message
      result << tag.expand
    end
    result
  end
  
  desc %{
    Displays the standard reader_welcome block, but only if a reader is present. For a block that shows an invitation to non-logged-in
    people, use @r:reader_welcome@
    
    <pre><code><r:reader:controls /></code></pre>
  }
  tag "reader:controls" do |tag|
    tag.render('reader_welcome')
  end
  
  desc %{
    Displays the standard block of reader controls: greeting, links to preferences, etc.
    If there is no reader, this will show a 'login or register' invitation, provided the reader.allow_registration? config entry is true. 
    If you don't want that, use @r:reader:controls@ instead: the reader: prefix means it will only show when a reader is present.
    
    If this tag appears on a cached page, we return an empty @<div class="remote_controls">@ into which you can drop whatever you like.
    
    <pre><code><r:reader_welcome /></code></pre>
  }
  tag "reader_welcome" do |tag|
    if tag.locals.page.cache?
      %{<div class="remote_controls"></div>}
    else
      if tag.locals.reader = Reader.current
        welcome = %{<span class="greeting">Hello #{tag.render('reader:name')}.</span> }
        links = []
        if tag.locals.reader.activated?
          links << %{<a href="#{edit_reader_path(tag.locals.reader)}">Preferences</a>}
          links << %{<a href="#{reader_path(tag.locals.reader)}">Your page</a>}
          links << %{<a href="/admin">Admin</a>} if tag.locals.reader.is_user?
          links << %{<a href="#{reader_logout_path}">Log out</a>}
        else
          welcome << "Please check your email and activate your account."
        end
        %{<div class="controls"><p>} + welcome + links.join(%{<span class="separator"> | </span>}) + %{</p></div>}
      elsif Radiant::Config['reader.allow_registration?']
        %{<div class="controls"><p><span class="greeting">Welcome!</span> To take part, please <a href="#{reader_login_path}">log in</a> or <a href="#{reader_register_path}">register</a>.</p></div>}
      end
    end
  end
    
  desc %{
    Expands only if there is a reader and we are on an uncached page.
    
    <pre><code><r:if_reader><div id="controls"><r:reader:controls /></r:if_reader></code></pre>
  }
  tag "if_reader" do |tag|
    tag.expand if !tag.locals.page.cache? && tag.locals.reader = Reader.current
  end
  
  desc %{
    Expands only if there is no reader or we are not on an uncached page.
    
    <pre><code><r:unless_reader>Please log in</r:unless_reader></code></pre>
  }
  tag "unless_reader" do |tag|
    tag.expand unless Reader.current && !tag.locals.page.cache?
  end
  
  # work in progress
  tag "truncated" do |tag|
    limit = tag.attr['limit'] || 64
    omission = tag.attr['omission'] || '&hellip;'
    content = tag.expand
    
    Rails.logger.warn "!! truncating #{content} to #{limit}#{omission}"
    
    truncate_words(content, limit, omission)
  end

end