package net.vermaas;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.Authenticator;
import java.net.MalformedURLException;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.net.URLConnection;
import net.sourceforge.pebble.api.event.blog.BlogEvent;
import net.sourceforge.pebble.api.event.blogentry.BlogEntryEvent;
import net.sourceforge.pebble.api.event.blogentry.BlogEntryListener;
import net.sourceforge.pebble.api.event.comment.CommentEvent;
import net.sourceforge.pebble.api.event.comment.CommentListener;
import net.sourceforge.pebble.domain.Blog;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 *
 * @author gero
 */
public class TwitterTweeter implements BlogEntryListener, CommentListener{

  private String userName;
  private String password;
  private String twitterUrl;
  private String tweetBlogWhen;
  private String tweetCommentWhen;
  
  public final static String TWITTER_URL = "TwitterTweeter.twitterUrl";
  public final static String USERNAME = "TwitterTweeter.userName";
  public final static String PASSWORD = "TwitterTweeter.password";
  /**
   * Property name to identify setting for when tweets for blog entries should 
   * be done.
   * Value is a string that with 1 character per kind of tweet:
   * A: Tweet when blog entry created (is still in draft).
   * R: Tweet when blog entry removed.
   * C: Tweet when blog entry changed (and already published).
   * P: Tweet when blog entry published.
   * U: Tweet when blog entry unpublished (but not deleted).
   * 
   * As an example: PC would publish tweets when an blog post is pubished and
   * when it's changed.
   */ 
  public final static String BLOG_ENTRY_TWEETS = "TwitterTweeter.blog.entry.tweets";
  /**
   * Property name to identify setting for when tweets for comments should 
   * be done.
   * Value is a string that with 1 character per kind of tweet:
   * C: Tweet when comment added.
   * D: Tweet when comment removed.
   * A: Tweet when comment approved.
   * R: Tweet when comment is rejected
   * 
   * As an example: PC would publish tweets when an blog post is pubished and
   * when it's changed.
   */ 
  public final static String COMMENT_TWEETS = "TwitterTweeter.comment.tweets";  
  
  private final static Log log = LogFactory.getLog(TwitterTweeter.class);

  public void blogEntryAdded(BlogEntryEvent bee) {
    tweet(bee);
  }

  public void blogEntryRemoved(BlogEntryEvent bee) {
    tweet(bee);
  }

  public void blogEntryChanged(BlogEntryEvent bee) {
    tweet(bee);
  }

  public void blogEntryPublished(BlogEntryEvent bee) {
    tweet(bee);
  }

  public void blogEntryUnpublished(BlogEntryEvent bee) {
    tweet(bee);
  }

  public void commentAdded(CommentEvent ce) {
    tweet(ce);
  }

  public void commentRemoved(CommentEvent ce) {
    tweet(ce);
  }

  public void commentApproved(CommentEvent ce) {
    tweet(ce);
  }

  public void commentRejected(CommentEvent ce) {
    tweet(ce);
  }

  protected void tweet(BlogEntryEvent bee) {
    initProperties(bee.getBlogEntry().getBlog());
    
    if (BlogEntryEvent.BLOG_ENTRY_ADDED == bee.getType()
        && tweetBlogWhen.contains("A")
        ||
        BlogEntryEvent.BLOG_ENTRY_CHANGED == bee.getType()
        && tweetBlogWhen.contains("C") 
        && bee.getBlogEntry().isPublished()
        ||
        BlogEntryEvent.BLOG_ENTRY_REMOVED == bee.getType()
        && tweetBlogWhen.contains("R")
        ||
        BlogEntryEvent.BLOG_ENTRY_PUBLISHED == bee.getType()
        && tweetBlogWhen.contains("P")
        ||
        BlogEntryEvent.BLOG_ENTRY_UNPUBLISHED == bee.getType()
        && tweetBlogWhen.contains("U") ) {

      tweet(format(bee));
      
    }
  }

  protected void tweet(CommentEvent ce) {
    initProperties(ce.getComment().getBlogEntry().getBlog());

    if (CommentEvent.COMMENT_ADDED == ce.getType()
        && tweetBlogWhen.contains("C")
        ||
        CommentEvent.COMMENT_APPROVED == ce.getType()
        && tweetBlogWhen.contains("A")
        ||
        CommentEvent.COMMENT_REJECTED == ce.getType()
        && tweetBlogWhen.contains("R")
        ||
        CommentEvent.COMMENT_REMOVED == ce.getType()
        && tweetBlogWhen.contains("D") ) {

      tweet(format(ce));
      
    }
  }

  void tweet(String msg) {
    DataOutputStream out = null;
    BufferedReader in = null;
    log.info("Update status on Twitter with: " + msg);

    try {
      Authenticator.setDefault(new Authenticator() {

        protected PasswordAuthentication getPasswordAuthentication() {
          return new PasswordAuthentication(userName, password.toCharArray());
        }
      });

      URL url = new URL(twitterUrl);
      URLConnection conn = url.openConnection();

      conn.setDoInput(true);
      conn.setDoOutput(true);
      conn.setUseCaches(false);
      conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

      out = new DataOutputStream(conn.getOutputStream());
      out.writeBytes("status=");
      out.writeBytes(msg);
      out.flush();

      in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
      String temp;
      while ((temp = in.readLine()) != null) {
        log.info("Response by Twitter: " + temp);
      }

    } catch (MalformedURLException mue) {
      mue.printStackTrace();
    } catch (IOException mue) {
      mue.printStackTrace();
    } finally {
      if (out != null) {
        try {
          out.close();
        } catch (IOException ex) {
        // Nothing to do...
        }
      }
      if (in != null) {
        try {
          in.close();
        } catch (IOException ex) {
        // Nothing to do...
        }
      }
    }
  }

  protected String format(BlogEntryEvent bee) {
    StringBuilder sb = new StringBuilder();
    switch (bee.getType()) {
      case BlogEntryEvent.BLOG_ENTRY_PUBLISHED:
        sb.append("Published");
        break;
      case BlogEntryEvent.BLOG_ENTRY_CHANGED:
        sb.append("Updated");
        break;
      case BlogEntryEvent.BLOG_ENTRY_ADDED:
        sb.append("Added");
        break;
      case BlogEntryEvent.BLOG_ENTRY_REMOVED:
        sb.append("Removed");
        break;
      case BlogEntryEvent.BLOG_ENTRY_UNPUBLISHED:
        sb.append("Unublished");
        break;
      default:
        sb.append("??");
    }
    sb.append(" blog entry \"");
    sb.append(bee.getBlogEntry().getTitle());
    sb.append("\" at: ");
    sb.append(bee.getBlogEntry().getPermalink());
    return sb.toString();
  }

  protected String format(CommentEvent ce) {
    StringBuilder sb = new StringBuilder();

    sb.append("A comment was ");
    switch (ce.getType()) {
      case CommentEvent.COMMENT_ADDED:
        sb.append("added");
        break;
      case CommentEvent.COMMENT_APPROVED:
        sb.append("approved");
        break;
      case CommentEvent.COMMENT_REJECTED:
        sb.append("rejected");
        break;
      case CommentEvent.COMMENT_REMOVED:
        sb.append("removed");
        break;
      default:
        sb.append("??");
    }
    sb.append(" for blog entry: \"");
    sb.append(ce.getComment().getBlogEntry().getTitle());
    sb.append("\" by ");
    sb.append(ce.getComment().getAuthor());
    sb.append(" at ");
    sb.append(ce.getComment().getBlogEntry().getCommentsLink());

    return sb.toString();
  }

  public void initProperties(Blog blog) {
    userName = blog.getPluginProperties().getProperty(USERNAME);
    password = blog.getPluginProperties().getProperty(PASSWORD);
    twitterUrl = blog.getPluginProperties().getProperty(TWITTER_URL);
    tweetBlogWhen = blog.getPluginProperties().getProperty(BLOG_ENTRY_TWEETS);
    if (tweetBlogWhen == null) {
      tweetBlogWhen = "";
    }
    tweetCommentWhen = blog.getPluginProperties().getProperty(COMMENT_TWEETS);
    if (tweetCommentWhen == null) {
      tweetCommentWhen = "";
    }
    log.info("TwitterTweeter uses: " + twitterUrl);
  }

  public void blogStopped(BlogEvent be) {
  // NOP
  }
}
