<?php


/**
 * Implementation of hook_apachesolr_document_handlers().
 *
 * @param string $type
 *   Entity type. 'node', 'comment', and so forth. Used to evaluate whether this module
 *   should be interested in creating documents.
 * @param string $namespace
 *   Usually the name of the module that is initiating indexing. In this case
 *   we want to register a handler if the namespace is 'apachesolr_search'.
 * @return array $handlers
 *   An array of strings that are function names. Each function returns a $document from
 *   an entity (of type $type).
 */
function apachesolr_commentsearch_apachesolr_document_handlers($type, $namespace) {
  if ($type == 'node' && $namespace == 'apachesolr_search') {
    return array('apachesolr_commentsearch_node_to_comments');
  }
}

function apachesolr_commentsearch_node_to_comments($node, $namespace) {
  $documents = array();
  $result = db_query("SELECT c.*, u.name AS registered_name FROM {comments} c INNER JOIN {users} u ON c.uid = u.uid WHERE c.nid = %d", $node->nid);
  while ($comment = db_fetch_object($result)) {
    $text = check_markup($comment->comment, $comment->format, FALSE);

    $document = new Apache_Solr_Document();
    // Comments have their status integers backwards compared to nodes.
    // Here we use the logic that the status of the comment is dependent both on the node and
    // the comment. If the node is published, we look to see if the comment is published, too.
    // If either the node or the comment are not published, the status of the comment
    // will get published as 0.
    $document->status = $node->status ? ($comment->status == COMMENT_PUBLISHED ? 1 : 0) : 0;
    if ($document->status == 0) {
      // don't index unpublished comments.
      continue;
    }
    $document->id = apachesolr_document_id($comment->cid, 'comment');
    $document->is_cid = $comment->cid;
    $document->site = url(NULL, array('absolute' => TRUE));
    $document->hash = apachesolr_site_hash();
    $document->entity = 'comment';

    // Since the nid of this comment is set, when the node gets deleted,
    // the comment will also get removed from the index. See apachesolr_delete_node_from_index()
    $document->nid = $comment->nid;
    $document->uid = $comment->uid;
    $title = empty($comment->subject) ? $node->title : $comment->subject;
    $document->title = apachesolr_clean_text($title);
    if (empty($node->language)) {
      // 'und' is the language-neutral code in Drupal 7.
      $document->language = 'und';
    }
    else {
      $document->language = $node->language;
    }
    $document->body = apachesolr_clean_text($text);
    $document->type = 'comment';
    $document->type_name = 'Comment';
    // A comment's timestamp is the time that it was created or last updated,
    // so we must use it for both the "created" and "changed" fields.
    $timestamp = apachesolr_date_iso($comment->timestamp);
    $document->created = $timestamp;
    $document->changed = $timestamp;
    $last_change = (isset($node->last_comment_timestamp) && $node->last_comment_timestamp > $node->changed) ? $node->last_comment_timestamp : $node->changed;
    $document->last_comment_or_change = apachesolr_date_iso($last_change);
    $document->name = htmlspecialchars(html_entity_decode($comment->name, ENT_NOQUOTES, 'UTF-8'), ENT_NOQUOTES, 'UTF-8');
    $path = "node/{$node->nid}";
    $document->url = url($path, array('absolute' => TRUE, 'fragment' => "comment-{$comment->cid}"));
    $document->path = $path;
    $documents[] = $document;
  }
  return $documents;
}

function apachesolr_commentsearch_apachesolr_modify_query(&$query, &$params, $caller) {
  $fls = array_filter(explode(',', $params['fl']));
  $fls[] = 'is_cid';
  $params['fl'] =  implode(',', $fls);
}

function apachesolr_commentsearch_apachesolr_process_results(&$results) {
  foreach ($results as $pos => $result) {
    if (isset($results[$pos]['extra']['comments'])) {
      unset($results[$pos]['extra']['comments']);
      unset($results[$pos]['extra']['cid']);
    }
  }
}

function apachesolr_commentsearch_apachesolr_search_result_alter(&$doc, &$extra) {
  if ($doc->type == 'comment') {
    $nid = $doc->nid;
    $extra['cid'] = $doc->is_cid;
    $node = node_load($nid);
    $query = apachesolr_commentsearch_page_count(comment_num_all($nid), $node, $doc->is_cid);
    $doc->path = url($doc->path, array('absolute' => TRUE, 'fragment' => "comment-{$doc->is_cid}", 'query' => $query));
  }
}

function apachesolr_commentsearch_apachesolr_theme_breadcrumb_alter(&$breadcrumb_name) {
  // While the goal here is to hijack nearly every breadcrumb generation, we
  // can't do it if it's a ckk facet. That would step on the toes of
  // date facets, etc. So reverse the logic from apachesolr_search_apachesolr_theme_breadcrumb_alter
  // and only alter non-cck breadcrumbs.
  $matches = preg_split('/_cck_/', $fieldname);
  if (!empty($matches[1])) {
    $breadcrumb_name = 'apachesolr_commentsearch_breadcrumb_type';
  }
}

/**
 * Removes the comment from the index if the comment is deleted or unpublished.
 *
 * apachesolr_comment() is responsible for updating the comment's node.
 *
 * @see apachesolr_comment()
 */
function apachesolr_commentsearch_comment($edit, $op) {
  switch ($op) {
    case 'delete':
    case 'unpublish':
      apachesolr_commentsearch_delete_comment_from_index($edit);
      break;
  }
}

/**
 * Removes a comment from the index.
 *
 * @param object $comment
 *   The comment to remove.
 *
 * @return boolean
 *   TRUE if comment removed from index, FALSE otherwise.
 *
 * @see apachesolr_delete_node_from_index()
 */
function apachesolr_commentsearch_delete_comment_from_index($comment) {
  static $failed = FALSE;
  if ($failed) {
    return FALSE;
  }
  try {
    $solr = apachesolr_get_solr();
    $solr->deleteById(apachesolr_document_id($comment->cid, 'comment'));
    apachesolr_index_set_last_updated(time());
    return TRUE;
  }
  catch (Exception $e) {
    watchdog('Apache Solr', nl2br(check_plain($e->getMessage())), NULL, WATCHDOG_ERROR);
    // Don't keep trying queries if they are failing.
    $failed = TRUE;
    return FALSE;
  }
}

/**
 * Return the human readable text for a content type.
 */
function theme_apachesolr_commentsearch_breadcrumb_type($field) {
  $type = $field['#value'];
  if ($type == 'comment') {
    return t('Comment');
  }
  return node_get_types('name', $type);
}

/**
 * Implementation of hook_theme().
 */
function apachesolr_commentsearch_theme() {
  return array(
    'apachesolr_commentsearch_breadcrumb_type' => array(
      'arguments' => array('field' => NULL),
    ),
  );
}

/**
 * Calculate page number for first new comment.
 *
 * @param $num_comments
 *   Number of comments.
 * @param $node
 *   The node to whom the comments belong.
 * @param $cid
 *   The cid of the comment we're looking for.
 * @return
 *   "page=X" if the page number is greater than zero; NULL otherwise.
 */
function apachesolr_commentsearch_page_count($num_comments, $node, $cid) {
  $comments_per_page = _comment_get_display_setting('comments_per_page', $node);
  $mode = _comment_get_display_setting('mode', $node);
  $order = _comment_get_display_setting('sort', $node);
  $pagenum = NULL;
  $flat = in_array($mode, array(COMMENT_MODE_FLAT_COLLAPSED, COMMENT_MODE_FLAT_EXPANDED));
  if ($num_comments <= $comments_per_page || ($flat && $order == COMMENT_ORDER_NEWEST_FIRST)) {
    // Only one page of comments or flat forum and newest first.
    // First new comment will always be on first page.
    $pageno = 0;
  }
  else {
    if ($flat) {
      // Flat comments and oldest first.
      $count = $num_comments;
    }
    else {
      // Threaded comments. See the documentation for comment_render().
      if ($order == COMMENT_ORDER_NEWEST_FIRST) {
        // Newest first: find the last thread with new comment
        $result = db_query('(SELECT cid, thread FROM {comments} WHERE nid = %d AND status = 0 ORDER BY timestamp DESC) ORDER BY thread', $node->nid);
      }
      else {
        // Oldest first: find the first thread with new comment
        $result = db_query('(SELECT thread FROM {comments} WHERE nid = %d AND status = 0 ORDER BY timestamp DESC) ORDER BY SUBSTRING(thread, 1, (LENGTH(thread) - 1))', $node->nid);
      }
      $count = 0;
      while ($row = db_fetch_object($result)) {
        $count++;
        if ($row->cid == $cid) {
          break;
        }
      }
    }
    $pageno =  $count / $comments_per_page;
  }
  if ($pageno >= 1) {
    $pagenum = "page=". intval($pageno);
  }
  return $pagenum;
}
