// Requires jQuery 1.4.
// Requires jquery-regex-selector plugin.

/* Installation on WOL site

  0. Have a developer migrate site to threadedcomments.
  1. Be running on worldonline_default templates.
  2. Add this script to the site (should be there if you are using
     worldonline_default/abstract_base.html).
  3. Same as 2 for jquery-regex-selector script.
  4. To the site’s site.js, add `$('.comment_list').threaded_comments();`.
  5. If you want inter-comment ads, add an `inter_comment_ad_invo_code` variable
     to the site.js. It should contain the ad invocation code.
  6. To handle the `no_advertisements` framing on stories, be sure the site’s
     story_detail.html’s body_class block contains something like
     `{% if story.default_framing %}framed-{{ story.default_framing.slug }}{% endif %}`

*/

jQuery.fn.threaded_comments = function(options) {

  // Settings
  var settings = jQuery.extend({
    collapsed_class: 'collapsed',
    thread_selector: '.replies',
    comment_selector: '.comment',
    comment_wrapper_selector: '.comment_content_wrapper',
    reply_link_selector: '.replylink',
    depth_limit: 2,
    ad_frequency: 8
  }, options);

  // If the browser is IE6 kill the script. Kill it dead!
  if (jQuery.browser.msie && jQuery.browser.version == '6.0') { return false; }

  var add_collapse_link = function(comment) {
    $(comment).find('.collapse_link').remove();
    var collapse_link = $('<a href="#" class="collapse_link button" title="Collapse this thread.">collapse</a>');
    collapse_link.bind('click', collapse_click);
    collapse_link.clone(true).prependTo($(comment));
  };

  // This collapses at the OL level.
  var collapse_threads = function(threads) {
    threads.find(settings.comment_selector).each(function() {
      collapse($(this));
    });
  };

  // This is its own function rather than a part of collapse_click() because
  // When the page initially loads we call this to do the initial collapsing.
  var collapse = function(comment) {
    comment.each(function() {
      // Mark as collapsed, yo!
      $(this).find(settings.comment_wrapper_selector).first().addClass(settings.collapsed_class);
      $(this).addClass('collapsed_thread');

      // Remove collapse thread link (if one, which there will not
      // be initially).
      $(this).find('.collapse_link').remove();

      // Add click handler to the collapsed comment.
      $(this).find(settings.comment_wrapper_selector).bind('click', expand_click);
    });
  };

  var collapse_click = function(e) {

    // Don’t do anything unexpected.
    e.preventDefault();

    // Collapse this thread and its children threads.
    var parent = $(this).parent(settings.comment_selector);
    collapse(parent.find(settings.comment_selector).andSelf());
    cancel_click(e);
  };

  // This is its own function rather than a part of expand_click() because
  // When the page initially loads we may call this to expand a linked-to comment.
  var expand = function(comment) {
    var comment = $(comment);
    if (comment.hasClass('collapsed_thread')) {
      comment.removeClass('collapsed_thread');
      comment.find(settings.comment_wrapper_selector).first().removeClass(settings.collapsed_class);

      // Remove the click handler from the comment. Remember that we added
      // a handler to almost the entire comment. We want the user to be
      // able to interact with the comment now, so we must unbind.
      comment.find(settings.comment_wrapper_selector).first().unbind('click', expand_click);

      // Add collapse thread link.
      add_collapse_link(comment);
    }
  };

  var expand_click = function(e) {

    // If they happend to click on a link, don’t follow it; just
    // expand the comment.
    e.preventDefault();

    var parent = $(this).parent(settings.comment_selector);
    return parent.find(settings.comment_selector).andSelf().each(function() {
      expand(this);
    });
  };

  var reply_click = function(e) {

    // Wait! Don’t go anywhere …
    e.preventDefault();

    // … we’ll bring the form to you!
    var link = $(this);
    var comment = link.closest(settings.comment_selector);

    // But first remove any other reply forms.
    cancel_click(e);

    if (comment.data('form')) {
      // This block currently unused because the code that populates
      // comment.data('form') is currently commented out.
      prep_reply(comment.data('form'));
    }
    else {

      // Give the user some feedback if there is any latency.
      link.text('form loading …');
      comment.addClass('reply_form_loading');

      // AJAX!
      $.get(link.attr('href'), function(data) {
        var form = $(data);

        // Add a cancel button to the form.
        var cancel_link = $('<a href="#" class="cancel_link">cancel</a>');
        cancel_link.bind('click', cancel_click);
        form.find('.preview').append(' or ');
        form.find('.preview').append(cancel_link);

        prep_reply(form);

        // Remove our feedback bits.
        link.fadeOut('slow', function() {
          comment.removeClass('reply_form_loading');
          comment.addClass('has_reply_form');
          link.text('cancel reply');
        });
      });
    }

    var prep_reply = function(form) {
      var textarea = form.find('textarea');
      textarea.css('opacity', 0);

      // Hide the form so we can animate it in.
      form.hide();

      // Append the form just after the comment being replied to.
      link.closest(settings.comment_wrapper_selector).after(form);

      // Animate in the form.
      form.animate({opacity: 'show', height: 'show'}, 'slow', function() {
        // Switch the link to a cancel button.
        link.text('cancel reply');
        link.unbind('click', reply_click);
        link.bind('click', cancel_click);

        // Adjust width of the textarea.
        var width = textarea.parent().width() - (textarea.outerWidth() - textarea.width());
        textarea.width(width);
        textarea.focus();
        textarea.animate({ opacity: 1 }, 300);
      });
    };
  };

  var cancel_click = function(e) {

    e.preventDefault();

    $(settings.comment_selector + ' .comment_form_wrapper').each(function() {
      var form = $(this);
      var comment = form.closest(settings.comment_selector);
      var link = comment.find(settings.reply_link_selector).first();

      form.animate({opacity: 'hide', height: 'hide'}, 'slow', function() {
        // Switch the from a cancel button back to a reply link.
        link.text('reply');
        link.unbind('click', cancel_click);
        link.bind('click', reply_click);
        link.fadeIn('slow', function() {
          comment.removeClass('has_reply_form');
        });

        // TODO: (pony) The idea here is to save the form that has been
        // loaded for the given comment. That saves us ajaxing again if
        // the user decides to reply, cancels, and then decides to reply
        // again. However, it is somehow causing problems. Let’s fix it.
        // comment.data('form', form);
        form.detach();
      });

    });
  };

  var highlight = function(comment) {
    $(settings.comment_selector).removeClass('highlighted_comment');
    $(comment).addClass('highlighted_comment');
  };

  // For each comment list selected, thread it.
  return this.each(function() {

    var comment_list = $(this);

    // Collapse threads that need initial collapsing.
    // Create a selector like `.replies:regex(class,[2-9]+)'`.
    // (We should be doing something like `.replies:regex([any_num_larger_than_depth_limit])`
    // but I don’t konw now to do that.)
    var threads_to_collapse = comment_list.find(settings.thread_selector + ':regex(class,[' + settings.depth_limit + '-9]+)');
    collapse_threads(threads_to_collapse);

    // Add collapse links to expanded threads.
    var expanded_threads = comment_list.find(settings.thread_selector).not(threads_to_collapse);
    expanded_threads.find('>' + settings.comment_selector).each(function() {
      add_collapse_link(this);
    });

    // Ajaxify the reply form.
    comment_list.find(settings.reply_link_selector).bind('click', reply_click);

    $(settings.collapsed_class).hover(
      function(){ $(this).addClass('collapsed_hover'); },
      function(){ $(this).removeClass('collapsed_hover'); }
      );

    // If this is a permalink to a comment make sure that comment is expanded and give it
    // a class to highlight it
    if (document.location.hash) {
        expand($(document.location.hash));
        highlight($(document.location.hash));
    }

    // highlight any comment when you click the permalink
    $(settings.comment_selector + ' .permalink').click(function(){
      highlight($(this).closest(settings.comment_selector));
    });

    // Insert our inter-comment ads.
    // Check for invo code and that we are not on a no-ad page.
    if (typeof(inter_comment_ad_invo_code) != "undefined" && !$('body').hasClass('framed-no_advertisements')) {
      // The ad markup
      var inter_comment_ad = $('<li class="ad comment_list_ad"></li>');
      inter_comment_ad.append('<h6>Advertisement</h6>');
      inter_comment_ad.append('<div class="spot"></div>');
      inter_comment_ad.find('div').append(inter_comment_ad_invo_code);

      // Create an array of comments.
      var comments = $(this).find('.comment');
      for (var i=0; i <= comments.length; i++) {
        // Modulus (%) lets us check for comment indexes divisible by the
        // frequency we wish (settings.ad_frequency).
        if (i != 0 && i % settings.ad_frequency == 0) {
          inter_comment_ad.clone().insertBefore(comments[i]);
        }
      }
    }

  });

};

