<?php

/**
 * @file
 * AJAX comments module file.
 */

/**
 * Implements hook_menu().
 */
function ajax_comments_menu() {
  $items['admin/config/content/ajax_comments'] = array(
    'title' => 'AJAX comments',
    'description' => 'AJAXifies comments on site.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('ajax_comments_settings'),
    'access arguments' => array('administer site configuration'),
    'file' => 'ajax_comments.admin.inc',
  );

  $items['ajax_comment/%comment/edit'] = array(
    'page callback' => 'ajax_comments_edit',
    'page arguments' => array(1),
    'access callback' => 'comment_access',
    'access arguments' => array('edit', 1),
    'delivery callback' => 'ajax_deliver',
    'type' => MENU_CALLBACK,
  );

  // Special-casing for EditLimit Module.
  if (module_exists('edit_limit')) {
    $items['ajax_comment/%comment/edit']['access callback'] = 'edit_limit_comment_access';
  }

  $items['ajax_comment/%/delete'] = array(
    'page callback' => 'ajax_comments_delete',
    'page arguments' => array(1),
    'access arguments' => array('administer comments'),
    'delivery callback' => 'ajax_deliver',
    'type' => MENU_CALLBACK,
  );

  // Special-casing for comment_goodness Module
  if (module_exists('comment_goodness')) {
    $items['ajax_comment/%/delete']['access arguments'] = array(1);
    $items['ajax_comment/%/delete']['access callback'] = 'comment_goodness_delete_comment_access';
  }

  // Special-casing for CommentAccess Module
  if (module_exists('commentaccess')) {
    $items['ajax_comment/%/delete']['access callback'] = 'commentaccess_access_check';
    $items['ajax_comment/%/delete']['access arguments'] = array(1, 'delete');
  }

  $items['ajax_comment/reply/%node'] = array(
    'page callback' => 'ajax_comments_reply',
    'page arguments' => array(2),
    'access callback' => 'node_access',
    'access arguments' => array('view', 2),
    'delivery callback' => 'ajax_deliver',
    'type' => MENU_CALLBACK,
  );

  return $items;
}

/**
 * Implements hook_views_api().
 */
function ajax_comments_views_api() {
  return array(
    'api' => 3,
    'path' => drupal_get_path('module', 'ajax_comments'),
  );
}

/**
 * Implements hook_views_data().
 */
function ajax_comments_views_data() {

  $data['node']['list_comments'] = array(
    'title' => t('List of comments'),
    'help' => t("Display the node's list of comments."),
    'field' => array(
      'handler' => 'ajax_comments_handler_field_list_comments',
    ),
  );

  $data['node']['ajax_comment'] = array(
    'title' => t('AJAX Add Comment'),
    'help' => t('Adds an inline AJAX comment form.'),
    'field' => array(
      'handler' => 'ajax_comments_handler_field_ajax_add_comment',
    ),
  );
  return $data;
}

/**
 * Implements hook_preprocess_node().
 *
 * AJAXify "Add new comment" link when there is no default form.
 */
function ajax_comments_preprocess_node(&$variables) {
  $node = $variables['node'];
  $view_mode = $variables['view_mode'];

  if (!ajax_comments_node_type_active($node->type)) {
    return;
  }

  if (variable_get('comment_form_location_' . $node->type, COMMENT_FORM_BELOW) == COMMENT_FORM_BELOW) {
    return;
  }

  if (empty($node->comment) || $node->comment == COMMENT_NODE_CLOSED) {
    return;
  }

  drupal_add_library('system', 'drupal.ajax');
  drupal_add_library('system', 'drupal.form');

  drupal_add_js(drupal_get_path('module', 'ajax_comments') .'/ajax_comments.js', 'file');

  $variables['content']['links']['comment']['#links']['comment-add']['attributes']['class'][] = 'use-ajax-comments';
  $variables['content']['links']['comment']['#links']['comment-add']['attributes']['class'][] = 'ajax-comments-reply-' . $node->nid . '-0';;
  $variables['content']['links']['comment']['#links']['comment-add']['fragment'] = NULL;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function ajax_comments_form_comment_form_alter(&$form, &$form_state, $form_id) {
  // Check to see if this node type uses ajax comments.
  if (!ajax_comments_node_type_active($form['#node']->type)) {
    return;
  }
  // Disable output original node/comment in preview
  if (isset($form['comment_preview'])) {
    $form['notify_text'] = array(
      '#markup' => variable_get('ajax_comments_notify', '') ? theme('ajax_comments_notify_text', array('type' => 'preview', 'comment' => $form_state['comment'])) : '',
      '#weight' => "-100",
    );
    if (isset($form['comment_output_below'])) {
      unset($form['comment_output_below']);
    }
  }

  if (empty($form_state['storage']['ajax_comments_form_id'])) {
    $cid = $pid = empty($form_state['comment']->cid) ? 0 : $form_state['comment']->cid;
    $pid = empty($form_state['comment']->pid) ? 0 : $form_state['comment']->pid;
    $id = 'ajax-comments-reply-form-' . $form_state['comment']->nid . '-' . $pid . '-' . $cid;
    $form_state['storage']['ajax_comments_form_id'] = $id;
    // Get comment form state class
    if (!empty($cid)) {
      // Comment Edit Form
      $form_state_class = 'ajax-comments-form-edit';
    }
    else {
      if (!empty($pid)) {
        // Comment Reply Form
        $form_state_class = 'ajax-comments-form-reply';
      }
      else {
        // Add New Comment Form
        $form_state_class = 'ajax-comments-form-add';
      }
    }
    $form_state['storage']['form_state_class'] = $form_state_class;
  }
  else {
    $id = $form_state['storage']['ajax_comments_form_id'];
    $form_state_class = $form_state['storage']['form_state_class'];
  }

  $form['#attributes']['id'] = drupal_html_id($id);
  $form['#attributes']['class'][] = $id;
  $form['#attributes']['class'][] = $form_state_class;

  $form['actions']['submit']['#ajax'] = array(
    'callback' => 'ajax_comments_submit_js',
    'wrapper' => $form['#attributes']['id'],
    'method' => 'replace',
    'effect' => 'fade',
  );

  // Set unique id (need for Views with enabled AJAX)
  if (empty($form['actions']['submit']['#id'])) {
    $form['actions']['submit']['#id'] = drupal_html_id('edit-' . $id);
  }

  $form['actions']['preview']['#ajax'] = array(
    'callback' => 'ajax_comments_preview_js',
    'wrapper' => $form['#attributes']['id'],
    'method' => 'replace',
    'effect' => 'fade',
  );
  // Set unique id (need for Views with enabled AJAX)
  if (empty($form['actions']['preview']['#id'])) {
    $form['actions']['preview']['#id'] = drupal_html_id('preview-' . $id);
  }

  // If this a reply to comment offer a 'cancel' button
  if (isset($form_state['comment']->pid)) {
    $form['actions']['cancel'] = array (
      '#type' => 'button',
      '#value' => t('Cancel'),
      '#access' => true,
      '#weight' => 21,
      '#limit_validation_errors' => array(),
    );
    $form['actions']['cancel']['#ajax'] = array(
      'wrapper' => $form['#attributes']['id'],
      'method' => 'replace',
      'effect' => 'fade',
    );


    if (empty($form_state['comment']->cid)) {

      $form['actions']['cancel']['#ajax']['callback'] = 'ajax_comments_cancel_js';
    }
    else {

      if ($form_state['comment']->original_parent_id) {

        $form['actions']['cancel']['#ajax']['callback'] = 'ajax_comments_custom_cancel_js';
      } else {

        $form['actions']['cancel']['#ajax']['callback'] = 'ajax_comments_edit_cancel_js';
      }
    }

    // Set unique id (need for Views with enabled AJAX)
    if (empty($form['actions']['cancel']['#id'])) {
      $form['actions']['cancel']['#id'] = drupal_html_id('cancel-' . $id);
    }
  }

  $form['#attached'] = array(
    'js' => array(drupal_get_path('module', 'ajax_comments') . '/ajax_comments.js'),
  );

  $form['actions'] = ajax_pre_render_element($form['actions']);

  // HACK, stop ctools from modifying us in node_comment_form.inc
  $form_state['ctools comment alter'] = FALSE;
}

/**
 * Implements hook_form_FORM_ID_alter().
 */
function ajax_comments_form_comment_confirm_delete_alter(&$form, &$form_state, $form_id) {
  if (ajax_comments_node_type_active(substr($form['#comment']->node_type, strlen('comment_node_')))) {
    $form['actions']['submit']['#ajax'] = array(
      'callback' => 'ajax_comments_delete_js',
      'wrapper' => $form['#id'],
      'method' => 'replace',
    );

    $form['actions']['cancel']['#attributes']['onclick'][] = 'jQuery(\'#' . $form['#id'] . '\').siblings().show().end().remove(); return false;';
  }
}

/**
 * Previews the comment.
 */
function ajax_comments_preview_js($form, &$form_state) {
  // Return the actual form if it contains errors.
  if (form_get_errors()) {
    // Remove comment preview
    if (isset($form['comment_preview'])) {
      unset($form['notify_text']);
      unset($form['comment_preview']);
    }
    return $form;
  }

  $pid = empty($form_state['comment']->pid) ? 0 : $form_state['comment']->pid;
  $cid = empty($form_state['comment']->cid) ? 0 : $form_state['comment']->cid;

  $commands[] = ajax_command_replace('.ajax-comments-reply-form-' . $form_state['comment']->nid . '-' . $pid . '-' . $cid, drupal_render($form));
  // Disabling scrolling to element.
//  if (!variable_get('ajax_comments_disable_scroll', 0)) {
//    $commands[] = array('command' => 'ajaxCommentsScrollToElement', 'selector' => '.ajax-comments-reply-form-' . $form_state['comment']->nid . '-' . $pid . '-' . $cid);
//  }

  return array('#type' => 'ajax', '#commands' => $commands);
}

/**
 * Custom Cancel.
 */
function ajax_comments_custom_cancel_js($form, &$form_state) {

  $comment = comment_load($form_state['comment']->cid);
  $comment_p = comment_load($form_state['comment']->original_parent_id);

  $commands[] = ajax_command_remove('.ajax-comments-reply-form-' . $comment->nid . '-' . $comment_p->cid . '-0');

  return array('#type' => 'ajax', '#commands' => $commands);
}

/**
 * Cancel edit  the comment.
 */
function ajax_comments_cancel_js($form, &$form_state) {
  $cid = empty($form_state['comment']->cid) ? 0 : $form_state['comment']->cid;
  $pid = empty($form_state['comment']->pid) ? 0 : $form_state['comment']->pid;
  $commands[] = ajax_command_remove('.ajax-comments-reply-form-' . $form['#node']->nid . '-' . $pid . '-' . $cid);
  // Disabling scrolling to element.
//  if (variable_get('comment_form_location_' . $form['#node']->type, COMMENT_FORM_SEPARATE_PAGE) == COMMENT_FORM_BELOW) {
//    if (!variable_get('ajax_comments_disable_scroll', 0)) {
//      $commands[] = array('command' => 'ajaxCommentsScrollToElement', 'selector' => '.comment-wrapper-' . $pid);
//    }
//  }

  // Show reply to comment link
  $commands[] = ajax_command_invoke('.ajax-comments-reply-' . $form['#node']->nid . '-' . $pid, 'show');

  return array('#type' => 'ajax', '#commands' => $commands);
}

/**
 * Re-grabs comment after editing is cancelled.
 */
function ajax_comments_edit_cancel_js($form, &$form_state) {

  $comment = comment_load($form_state['comment']->cid);
  $comment_build = comment_view($comment, $form['#node']);
  $comment_output = drupal_render($comment_build);

  $commands[] = ajax_command_replace('.ajax-comments-reply-form-' . $comment->nid . '-' . $comment->pid . '-' . $comment->cid, $comment_output);

  return array('#type' => 'ajax', '#commands' => $commands);
}

/**
 * Builds the comment.
 */
function ajax_comments_submit_js($form, &$form_state) {

  ajax_comments_remove_status();

  $cid = empty($form['cid']['#value']) ? 0 : $form['cid']['#value'];
  $pid = empty($form_state['comment']->pid) ? 0 : $form_state['comment']->pid;

  $key = _ajax_comments_cache_key($form_state['comment']->nid, $pid);
  if (cache_get($key)) {
    // This form cached. Remove it from cache.
    cache_clear_all($key, 'cache');
  }

  $comment = comment_load($form_state['comment']->cid);
  $node = $form['#node'];

  $comment_build = comment_view($comment, $node);

  // remove messages
  if (variable_get('ajax_comments_notify')) {
    $commands[] = ajax_command_remove('.messages.warning');
    $commands[] = ajax_command_remove('.messages.status');
  }

  // Don't display as a preview as this is being submitted.
  unset($comment_build['comment_body']['#object']->in_preview);
  unset($form_state['comment_preview']);

  $comment_output = drupal_render($comment_build);

  // Are we editing a comment.
  if (isset($form['cid']['#value'])) {

    // Fix bug when not working 1level comment reply.
    if ($form_state['comment']->original_parent_id) {
      $commands[] = ajax_command_invoke('.ajax-comments-form-reply', 'remove');
      // Set place where comment prepend.
      $commands[] = array('command' => 'ajaxCommentsAppend', 'selector' => '.comment-wrapper-' . $comment->pid . '> .content > .col__comment-content', 'html' => $comment_output);
    } else {

      //$commands[] = ajax_command_replace('.ajax-comments-reply-form-' . $comment->nid . '-' . $pid . '-' . $cid, $comment_output);
      $commands[] = array('command' => 'ajaxCommentsReplace', 'selector' => '.ajax-comments-reply-form-' . $comment->nid . '-' . $pid . '-' . $cid, 'html' => $comment_output);
    }

  }
  // Or are we replying to another comment.

  // Custom comment ajax appending.
  if ($comment->pid != 0) {
    // Removing reply form.
    $commands[] = ajax_command_invoke('.ajax-comments-form-reply', 'remove');

    //Check if comment is new/edited
    if ($comment->created == $comment->changed) {
      // Set place where comment prepend.
      $commands[] = array('command' => 'ajaxCommentsAppend', 'selector' => '.comment-wrapper-' . $comment->pid . '> .content > .col__comment-content', 'html' => $comment_output);
    }

    // Scrolling to 1st level just added comment.
    $commands[] = array('command' => 'ajaxCommentsScrollToElement', 'selector' => '.comment-wrapper-' . $comment->cid);
  }

  // Or is this a brand new comment?
  else {

    $commands[] = array('command' => 'ajaxCommentsAfter', 'selector' => '.comment-wrapper-nid-' . $comment->nid . '> .comment-form:first', 'html' => $comment_output);
  }

  $commands[] = ajax_command_invoke('.ajax-comments-reply-' . $comment->nid . '-' . $pid, 'show');

  if ($comment->pid == 0) {
    // Clear form after submit.
    $new_form_state['build_info']['args'][] = (object) array('nid' => $node->nid);
    $new_form_state['input'] = array();
    $new_form_build = drupal_build_form($form['#form_id'], $new_form_state);

    $commands[] = ajax_command_replace('.ajax-comments-reply-form-' . $form_state['comment']->nid . '-' . $pid . '-' . $cid, drupal_render($new_form_build));
  }

  $output = array('#type' => 'ajax', '#commands' => $commands);

  return $output;
}

/**
 * Removes the comment.
 */
function ajax_comments_delete_js($form, &$form_state) {
  $comment = $form['#comment'];

  ajax_comments_remove_status();

  $notify_text = variable_get('ajax_comments_notify', '') ? theme('ajax_comments_notify_text', array('type' => 'delete', 'comment' => $comment)) : '';

  if ($notify_text) {
    $commands[] = ajax_command_remove('.messages.status');
    $commands[] = ajax_command_remove('.messages.warning');
    $commands[] = ajax_command_replace('.comment-wrapper-' . $comment->cid, $notify_text);
    $commands[] = ajax_command_remove('a#comment-' . $comment->cid);
  }
  else {
    $commands[] = ajax_command_remove('.comment-wrapper-' . $comment->cid);
    $commands[] = ajax_command_remove('a#comment-' . $comment->cid);
  }

  // Remove all replies to deleted comment from page
  if (!empty($form_state['storage']['cids'])) {
    foreach ($form_state['storage']['cids'] as $cid) {
      $commands[] = ajax_command_remove('.comment-wrapper-' . $cid);
      $commands[] = ajax_command_remove('a#comment-' . $cid);
    }
  }

  return array('#type' => 'ajax', '#commands' => $commands);
}

/**
 * Implements hook_comment_view_alter().
 */
function ajax_comments_comment_view_alter(&$build) {
  global $user;
  // Check
  if (ajax_comments_node_type_active($build['#node']->type)) {
    // A little HACK for do not mark as NEW own comments
    if (isset($build['#comment']->new) && $build['#comment']->uid == $user->uid && ($build['#comment']->new == MARK_NEW || $build['#comment']->new == MARK_UPDATED)) {
      $build['#comment']->new = MARK_READ;
    }
    // Reply.
    if (isset($build['links']['comment']['#links']['comment-reply'])) {
      $classes = array('use-ajax-comments', 'ajax-comments-reply', 'ajax-comments-reply-' . $build['#comment']->nid . '-' . $build['#comment']->cid);
      if (empty($build['links']['comment']['#links']['comment-reply']['attributes']['class'])) {
        $build['links']['comment']['#links']['comment-reply']['attributes']['class'] = $classes;
      }
      else {
        $build['links']['comment']['#links']['comment-reply']['attributes']['class'] = array_unique(array_merge($build['links']['comment']['#links']['comment-reply']['attributes']['class'],$classes));
      }
    }
    // Edit.
    if (isset($build['links']['comment']['#links']['comment-edit'])) {
      $classes = array('use-ajax-comments', 'ajax-comments-edit', 'ajax-comments-edit-' . $build['#comment']->cid);
      if (empty($build['links']['comment']['#links']['comment-edit']['attributes']['class'])) {
        $build['links']['comment']['#links']['comment-edit']['attributes']['class'] = $classes;
      }
      else {
        $build['links']['comment']['#links']['comment-edit']['attributes']['class'] = array_unique(array_merge($build['links']['comment']['#links']['comment-edit']['attributes']['class'],$classes));
      }
    }
    // Delete.
    if (isset($build['links']['comment']['#links']['comment-delete'])) {
      $classes = array('use-ajax-comments', 'ajax-comments-delete', 'ajax-comments-delete-' . $build['#comment']->cid);
      if (empty($build['links']['comment']['#links']['comment-delete']['attributes']['class'])) {
        $build['links']['comment']['#links']['comment-delete']['attributes']['class'] = $classes;
      }
      else {
        $build['links']['comment']['#links']['comment-delete']['attributes']['class'] = array_unique(array_merge($build['links']['comment']['#links']['comment-delete']['attributes']['class'],$classes));
      }
    }
  }
}

/**
 * Implements template_preprocess_comment()
 * Wrap comments and their replies in a #comment-wrapper-(cid) div
 */
function ajax_comments_preprocess_comment(&$variables) {
  $element = $variables['elements'];
  $comment = $element['#comment'];
  if (ajax_comments_node_type_active(substr($comment->node_type, strlen('comment_node_')))) {
    $variables['classes_array'][] = 'ajax-comment-wrapper';
    $variables['classes_array'][] = 'comment-wrapper-' . $comment->cid;
  }
}

/*
 * Implements template_preprocess_comment_wrapper()
 */
function ajax_comments_preprocess_comment_wrapper(&$variables) {
  $variables['classes_array'][] = 'comment-wrapper-nid-' . $variables['node']->nid;

  if (empty($variables['content']['comments']) && $variables['node']->comment == COMMENT_NODE_OPEN && ajax_comments_node_type_active($variables['node']->type)) {
    /**
     * A little HACK for adding dummy comment which give us right point to place first comment on the page.
     */
    $variables['content']['comments']['dummyComment'] = array(
      '#prefix' => '<div class="ajax-comment-wrapper ajax-comment-dummy-comment" style="display:none">',
      '#type' => 'item',
      '#markup' => '',
      '#suffix' => '</div>',
    );
  }
}

/**
 * Helper function to get comment replies count.
 */
function _axax_comments_comment_num_replies($cid) {

  $count = db_query('SELECT COUNT(*) FROM {comment} WHERE pid = :cid', array(':cid' => $cid))->fetchField();
  return $count;
}

/**
 * Callback for clicking "reply".
 * Note: $pid is an optional parameter. This functionality is utilized by the
 * "Add new comment" link on pages where there is no default comment form
 * (comment_form_location is COMMENT_FORM_SEPARATE_PAGE)
 */
function ajax_comments_reply($node, $pid = 0, $flag = 0) {
  if (!user_access('post comments')) {
    return MENU_ACCESS_DENIED;
  }

  // If there is a pid this is a reply to a comment.
  if (!empty($pid)) {
    if (!user_access('access comments')) {
      return MENU_ACCESS_DENIED;
    }

    // Make sure the comment is valid and published.
    if (!($comments = comment_load_multiple(array($pid), array('status' => COMMENT_PUBLISHED)))) {
      return MENU_NOT_FOUND;
    }
    $comment = $comments[$pid];

    // Make sure the comment belongs to this node.
    if ($comment->nid != $node->nid) {
      return MENU_NOT_FOUND;
    }
  }

  if ((!user_is_anonymous() || (user_is_anonymous() && variable_get('cache', 0) != 0))) {
    // Authenticated user or anonymous and page cache is enabled
    $key = _ajax_comments_cache_key($node->nid, $pid);
    if ($cache = cache_get($key)) {
      // Get form from cache
      //$form_build = $cache->data;
      $form_build = drupal_get_form("comment_node_{$node->type}_form", (object) array('nid' => $node->nid, 'pid' => $pid), array('flag' => $flag));
    }
    else {
      // Build form and Save to cache*/
      $form_build = drupal_get_form("comment_node_{$node->type}_form", (object) array('nid' => $node->nid, 'pid' => $pid), array('flag' => $flag));
      //cache_set($key, $form_build, 'cache', time() + 360);
    }
  }
  else {
    // Anonymous and page cache is disabled
    $form_build = drupal_get_form("comment_node_{$node->type}_form", (object) array('nid' => $node->nid, 'pid' => $pid), array('flag' => $flag));
  }

  $form = trim(drupal_render($form_build));

  if (variable_get('ajax_comments_reply_autoclose') && !empty($pid)) {
    $commands[] = ajax_command_remove('.ajax-comments-form-reply');
    $commands[] = ajax_command_invoke('.ajax-comments-reply', 'show');
  }

  // Add the new form.
  if (!empty($pid)) {
    $mode = variable_get('comment_default_mode_' . $node->type, COMMENT_MODE_THREADED);
    if (empty($mode)) {

      if ($comment->pid != 0) {

        $commands[] = ajax_command_after('.comment-wrapper-' . $pid, $form);
      } else {

        if (_axax_comments_comment_num_replies($comment->cid) == 0) {

          $commands[] = ajax_command_after('.comment-wrapper-' . $pid, $form);
        } else {

          $commands[] = ajax_command_before('.comment-wrapper-' . $pid . ' .comment:first', $form);
        }
      }
    }
    else {
      // Add div with class "indented" if they are not exist
      $commands[] = array('command' => 'ajaxCommentsAddDummyDivAfter', 'selector' => '.comment-wrapper-' . $pid, 'class' => 'indented');
      // Check sort by comment_goodness.
      if (_ajax_comments_get_comment_sort_order($node) == 1) {
        // Newer first.
        $commands[] = ajax_command_append('.comment-wrapper-' . $pid . ' + .indented', $form);
      }
      else {
        // Older first.
        $commands[] = ajax_command_prepend('.comment-wrapper-' . $pid . ' + .indented', $form);
      }
    }
  }
  else {
    // Check Views Add form
    if (!empty($flag)) {
      $commands[] = ajax_command_after('.views-comment-wrapper-nid-' . $node->nid . ' > .ajax-comment-wrapper:last', $form);
    }
    else {
      // Check sort by comment_goodness.
      if (_ajax_comments_get_comment_sort_order($node) == 1) {
        // Older first. Append comment to last wrapper.
        $commands[] = ajax_command_after('.comment-wrapper-nid-' . $node->nid . ' > .ajax-comment-wrapper:last', $form);
      }
      else {
        // Newer first. Append comment to top.
        $commands[] = ajax_command_before('.comment-wrapper-nid-' . $node->nid . '> .ajax-comment-wrapper:first', $form);
      }
    }
  }

  // Hide reply to comment link
//  $commands[] = ajax_command_invoke('.ajax-comments-reply-' . $node->nid . '-' . $pid, 'hide');

  if (!variable_get('ajax_comments_disable_scroll', 0)) {
    // Disabling scrolling to element.
    //$commands[] = array('command' => 'ajaxCommentsScrollToElement', 'selector' => '.ajax-comments-reply-form-' . $node->nid . '-' . $pid . '-0');
    $commands[] = ajax_command_invoke('.ajax-comments-reply-form-' . $node->nid . '-' . $pid . '-0 .form-textarea' , 'focus');
  }

  return array('#type' => 'ajax', '#commands' => $commands);
}

/**
 * Create the key for caching a comment form.
 */
function _ajax_comments_cache_key($nid, $pid) {
  $key = 'ajax_comments_reply_form-' . $nid . '-' . $pid;

  if (!user_is_anonymous()) {
    $key .= '-' . session_id();
  }
  else {
    $key .= '-' . ip_address();
  }

  return $key;
}

/**
 * Callback for clicking "edit".
 */
function ajax_comments_edit($comment) {
  $node = node_load($comment->nid);

  // Build form.
  $form_build = drupal_get_form("comment_node_{$node->type}_form", $comment);
  $form = drupal_render($form_build);

  // Remove anchor
  $commands[] = ajax_command_remove('a#comment-' . $comment->cid);

  // Replace comment with form.
  $commands[] = ajax_command_replace('.comment-wrapper-' . $comment->cid, $form);

  // Disabling scrolling to element.
//  if (!variable_get('ajax_comments_disable_scroll', 0)) {
//    $commands[] = array('command' => 'ajaxCommentsScrollToElement', 'selector' => '.ajax-comments-reply-form-' . $comment->nid . '-' . $comment->pid . '-' . $comment->cid);
//  }

  return array('#type' => 'ajax', '#commands' => $commands);
}

/**
 * Callback for clicking "delete".
 */
function ajax_comments_delete($cid) {
  if (!($comment = comment_load($cid))) {
    return MENU_NOT_FOUND;
  }

  // Need to include comment module admin file for delete form.
  $form_state = array();
  $form_state['build_info']['args'] = array($comment);

  // Load this using form_load_include so it's cached properly and works in the
  // ajax callback.
  form_load_include($form_state, 'inc', 'comment', 'comment.admin');

  // Get child comments (replies on this comment)
  $form_state['storage']['cids'] = array();
  $query = db_select('comment', 'c');
  $query->addField('c', 'cid');
  $query->condition('c.nid', $comment->nid)->condition('c.thread', substr($comment->thread, 0, -1) . '.%', 'LIKE')->addTag('node_access');
  if (!user_access('administer comments')) {
    $query->condition('c.status', COMMENT_PUBLISHED);
  }
  $query->orderBy('c.cid', 'ASC');
  $cids = $query->execute()->fetchCol();
  // Save child comments ids if they are exist
  if (!empty($cids)) {
    $form_state['storage']['cids'] = $cids;
  }

  $form_build = drupal_build_form('comment_confirm_delete', $form_state);
  $form = drupal_render($form_build);

  // Hide contents.
  $commands[] = ajax_command_invoke('.comment-wrapper-' . $cid . ' >*', 'hide');

  // Put form inside main comment wrapper.
  $commands[] = ajax_command_prepend('.comment-wrapper-' . $cid, $form);

  return array('#type' => 'ajax', '#commands' => $commands);
}

/**
 * Removes "Your comment has been posted." or "Your comment has been queued.."
 *   from the status message.
 */
function ajax_comments_remove_status() {
  if (!empty($_SESSION['messages']['status'])) {
    $deleted = t('The comment and all its replies have been deleted.');
    $published = t('Your comment has been posted.');
    $not_published = t('Your comment has been queued for review by site administrators and will be published after approval.');
    foreach ($_SESSION['messages']['status'] as $key => $value) {
      if ($value == $published || $value == $not_published || $value = $deleted) {
        unset($_SESSION['messages']['status'][$key]);
      }
    }
    if (empty($_SESSION['messages']['status'])) {
      unset($_SESSION['messages']['status']);
      if (empty($_SESSION['messages'])) {
        unset($_SESSION['messages']);
      }
    }
  }
}

/**
 * Returns TRUE if this node uses ajax comments or if no nodes are selected.
 */
function ajax_comments_node_type_active($node_type) {
  $types = array_filter(variable_get('ajax_comments_node_types', array()));
  if (empty($types) || !empty($types[$node_type])) {
    return TRUE;
  }
  else {
    return FALSE;
  }
}

/**
 * Implements hook_theme().
 */
function ajax_comments_theme($existing, $type, $theme, $path) {
  return array(
    'ajax_comments_notify_text' => array(
      'variables' => array('type' => NULL, 'comment' => NULL),
    ),
  );
}

/**
 * Returns text to notify user their comment has been added.
 */
function theme_ajax_comments_notify_text($vars = array()) {
  $text = t('Your comment has been posted.');
  $status = 'status';
  // If the comment is unapproved, alter the message
  if (isset($vars['comment']) && !$vars['comment']->status) {
    $text = t('Your comment has been queued for review by site administrators and will be published after approval.');
    $status = 'warning';
  }
  if ($vars['type'] == 'delete') {
    $text = t('Your comment has been deleted');
  }
  elseif ($vars['type'] == 'preview') {
    $text = t('This is the preview for your comment. You must click SAVE or your comment will be lost.');
    $status = 'warning';
  }
  drupal_set_message($text, $status);
  return theme('status_messages');
}

/**
 * Returns comment sort order.
 *
 * comment_goodnes module and comment_sort_created compatibility:
 * 1 - Older first
 * 2 - Newer first
 */
function _ajax_comments_get_comment_sort_order($node) {
  return;
  $result = &drupal_static(__FUNCTION__);
  if (!isset($result)) {
    $result = 1;
    if (module_exists('comment_goodness')) {
      $result = variable_get('comment_default_sorting_' . $node->type, comment_goodness_OLDER_FIRST);
    }
    else if (module_exists('comment_sort_created')) {
      $result = variable_get('comment_sort_created_order_' . $node->type) == COMMENT_SORT_CREATED_OLDER_FIRST ? 1 : 2;
    }
    else if (module_exists('sort_comments')) {
      $result = variable_get('comment_default_sorting_' . $node->type, SORT_COMMENTS_OLDER_FIRST);
    }
  }
  return $result;
}
