<?php
// $Id: cmf.module,v 1.2.2.18 2009/08/12 15:38:48 nancyw Exp $
/**
 * @file
 * @brief Content management filter module file
 *
 * This file contains all the common functions used by the module.
 *
 * @attention Copyright (C) 2008 Nuno Veloso <nunoveloso18 (at) gmail (dot) com>
 * @author Nuno André Veloso Matias (http://www.nunoveloso.org)
 */

/**
 * Adding a new filter:
 *
 *  Add an entry to function cmf_filters.
 *    Note whether or not it should be shown on the user page and whether or not it has selection options.
 *  Add at least an unset to function cmf_filter_form.
 *    If additional code is needed, add it.
 *    If special string presentation is needed is needed, add it.
 *    Also select the appropriate field type.
 *  Add handling to cmf_filter_form_submit. For special things, update the IF for flatoptions.
 *  Add WHERE processing to cmf_build_filter_query.
 *  Make sure all the fields are present in cmf_perform_query.
 */

/**
 * Implementation of hook_help().
 */
function cmf_help($section, $arg) {
  switch ($section) {
    case "admin/help#cmf":
      return '<p>'. t('This module adds an easier way for administrators to filter the content on a Drupal site for administration purposes.') .'</p>'
        .'<p>'. t('It is an improvement over the content page in the administration area of Drupal. It can show on the same page nodes and comments and adds new filters like role and author.') .'</p>';
  }
}
/**
 * Implementation of hook_perm().
 */
function cmf_perm() {
  return array('filter and manage site content', 'view user content list');
}
/**
 * Implementation of hook_menu().
 */
function cmf_menu() {
  $items = array();

  $items['admin/content/filter'] = array(
    'title' => 'Content Management Filter',
    'description' => 'All-in-one advanced filter and management of your site content.',
    'page callback' => 'cmf_admin_content_page',
    'access arguments' => array('filter and manage site content'),
    );

  $items['user/%/cmf'] = array(
    'title' => 'CMF',
    'description' => 'User-specific content management filter',
    'page callback' => 'cmf_admin_content_page',
    'access callback' => '_cmf_userspace_perms',
    'access arguments' => array('view user content list', 'access user profiles'),
    'type' => MENU_LOCAL_TASK,
    );

  $items['cmf/userauto'] = array(
    'title' => 'User autocomplete',
    'page callback' => '_cmf_user_autocomplete',
    'access callback' => 'user_access',
    'access callback' => '_cmf_userspace_perms',
    'access arguments' => array('filter and manage site content', 'view user content list', 'access user profiles'),
    'type' => MENU_CALLBACK,
    );

  return $items;
}

/**
 * List node administration filters that can be applied.
 *
 * @param (optional) true if the filter to be built serves the user profile page
 * @return array with filter properties
 */
function cmf_filters($true = NULL) {
  // Make the array static so it is built only once per page load.
  static $filters;
  if (isset($filters)) {
    return $filters;
  }
  
  $filters = array();
  // Regular filters.
  $filters['status'] = array(
    'title' => t('node status'),
    'options' => array(
      'status-1' => t('published'),
      'status-0' => t('not published'),
      'promote-1' => t('promoted'),
      'promote-0' => t('not promoted'),
      'sticky-1'   => t('sticky'),
      'sticky-0' => t('not sticky'),
      ),
    );
  $filters['type'] = array('title' => t('node type'), 'options' => node_get_types('names'));

  // The taxonomy filter.
  if ($taxonomy = module_invoke('taxonomy', 'form_all', 1)) {
    $filters['category'] = array('title' => t('category'), 'options' => $taxonomy);
  }

  // Cmf filters.
  $filters['title'] = array('title' => t('title/subject'));
  $filters['body_contains'] = array('title' => t('Body contains'));
  $filters['created_after'] = array('title' => t('created after'));
  $filters['created_before'] = array('title' => t('created before'));

  if (module_exists('locale')) {
    $lang_codes = array('' => t('Neutral')) + locale_language_list('name');
    $filters['language'] = array('title' => t('language'), 'options' => $lang_codes);
  }

  // Don't show these on the user page.
  if (!$true) {
    $filters['user'] = array('title' => t('user list'), 'options' => cmf_get_users('names'));
    $filters['users'] = array('title' => t('user name'));
    $filters['role'] = array('title' => t('user role'), 'options' => cmf_get_roles('names'));
    $filters['blocked'] = array('title' => t('user status'), 'options' => array(1 => t('active'),
      0 => t('blocked')));
  }
  return $filters;
}

/**
 * Called when user goes to example.com/admin/content/filter
 *
 * @return the HTML generated from the $form data structure
 */
function cmf_admin_content_page() {
  if (!isset($_SESSION['cmf_content_kind'])) {
    $_SESSION['cmf_content_kind'] = 'node';
  }
  if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
    $true = TRUE;
  }
  $output = drupal_get_form('cmf_filter_form', $true);
  // Call the form first, to allow for the form_values array to be populated.
  switch ($_SESSION['cmf_content_kind']) {
    case 'node':
      if ($_POST['operation'] == 'delete' && $_POST['nodes']) {
        return drupal_get_form('node_multiple_delete_confirm', $_POST['nodes']);
      }
      else {
        $output .= drupal_get_form('cmf_admin_nodes_form');
      }
      break;

    case 'comment':
      if ($_POST['operation'] == 'delete' && $_POST['comments']) {
        // The next line is because of http://drupal.org/node/521354.
        module_load_include('inc', 'comment', 'comment.admin');
        return drupal_get_form('comment_multiple_delete_confirm');
      }
      else {
        $output .= drupal_get_form('cmf_admin_comments_form');
      }
      break;

    case 'both':
      $output .= drupal_get_form('cmf_admin_both_form');
  }
  return $output;
}
/**
 * FILTERS
 */
/**
 * Defines the form for content administration filters.
 *
 * @ingroup forms
 * @see cmf_filter_form_submit()
 *
 * @param (optional) true if the filter to be built serves the user profile page
 * @return array with forms properties
 */
function cmf_filter_form(&$form_state, $true = NULL) {
  $session = &$_SESSION['cmf_overview_filter'];
  $session = is_array($session) ? $session : array();
  $filters = cmf_filters($true);
  drupal_add_css(drupal_get_path('module', 'cmf') .'/cmf.css');

  // General settings display (max rows & content kind).
  $form['general'] = array('#type' => 'fieldset',
    '#title' => t('General Settings'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    );

  $form['general']['max-rows'] = array(
    '#type' => 'textfield',
    '#title' => t('Max rows'),
    '#size' => 5,
    '#default_value' => isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50,
    '#prefix' => '<div class="container-inline">',
    '#suffix' => '</div>',
    );

  $form['general']['show_nid'] = array(
    '#type' => 'radios',
    '#title' => t('Show node ID'),
    '#options' => array(0 => t('No'), 1 => t('Yes')),
    '#default_value' => isset($_SESSION['cmf_show_nid']) ? $_SESSION['cmf_show_nid'] : 0,
    '#prefix' => '<div class="container-inline"><div class="cmf-radios">',
    '#suffix' => '</div></div><div class="clear-block"></div>',
    );

  $form['general']['kind'] = array(
    '#type' => 'select',
    '#title' => t('Content'),
    '#options' => array('node' => t('node'), 'comment' => t('comment'), 'both' => t('both')),
    '#default_value' => isset($_SESSION['cmf_content_kind']) ? $_SESSION['cmf_content_kind'] : 'node',
    '#prefix' => '<div class="container-inline">',
    );


  $form['general']['buttons']['apply'] = array(
    '#type' => 'submit',
    '#value' => t('Apply'),
    '#suffix' => '</div>',
    );

  $i = 0;
  $form['filters'] = array('#type' => 'fieldset',
    '#title' => t('Show only items where'),
    '#theme' => 'node_filters',
    );

  foreach ($session as $filter) {
    list($type, $value) = $filter;
    // Special handling by type of filter.
    switch ($type) {
      case 'category':
        // Load term name from DB rather than search and parse options array.
        $value = taxonomy_get_term($value);
        $value = $value->name;
        break;

      case 'body_contains':
      case 'title':
        // Add quotes.
        $value = "'". $value ."'";
        break;

      case 'created_after':
      case 'created_before':
        // Format as human date.
        $value = format_date($value, 'custom', 'M j, Y', 0);
        break;

      default:
        if (isset($filters[$type]['options'])) {
          $value = $filters[$type]['options'][$value];
        }
    }

    // Add applicable filter verbiage. Note '%' does check_plain.
    $trans_strings = array('%filter_name' => $filters[$type]['title'], '%filter_value' => $value);
    if ($type == 'title' || $type == 'body_contains') {
      if ($i++) {
        $form['filters']['current'][] = array('#value' => t('<em>and</em> where <strong>%filter_name</strong> contains <strong>%filter_value</strong>', $trans_strings));
      }
      else {
        $form['filters']['current'][] = array('#value' => t('<strong>%filter_name</strong> contains <strong>%filter_value</strong>', $trans_strings));
      }
    }
    else {
      if ($i++) {
        $form['filters']['current'][] = array('#value' => t('<em>and</em> where <strong>%filter_name</strong> is <strong>%filter_value</strong>', $trans_strings));
      }
      else {
        $form['filters']['current'][] = array('#value' => t('<strong>%filter_name</strong> is <strong>%filter_value</strong>', $trans_strings));
      }
    }

    // Remove the respective option if it is already being filtered on.
    if ($type == 'type'
      || $type == 'title'
      || $type == 'created_before'
      || $type == 'created_after'
      || $type == 'language'
      || $type == 'blocked'
      || $type == 'role') {
      unset($filters[$type]);
    }
    // Additional unset for 'users'.
    if ($type == 'user') {
      unset($filters['users']);
    }
  }

  // Prepare select boxes.
  foreach ($filters as $key => $filter) {
    $names[$key] = $filter['title'];
    switch ($key) {
      case 'users':
        $form['filters']['status'][$key] = array(
          '#type' => 'textfield',
          '#autocomplete_path' => 'cmf/userauto',
          );
        break;

      case 'body_contains':
      case 'title':
        $form['filters']['status'][$key] = array(
          '#type' => 'textfield',
          );
        break;

      case 'created_before':
        $form['filters']['status'][$key] = array(
          '#type' => 'date',
          '#default_value' => array('year' => date('Y'), 'month' => 12, 'day' => 31),
          '#validate' => 'date_validate',
          '#prefix' => '<div class="date-inline">',
          '#suffix' => '</div>',
          );
        break;

      case 'created_after':
        $form['filters']['status'][$key] = array(
          '#type' => 'date',
          '#default_value' => array('year' => date('Y'), 'month' => 1, 'day' => 1),
          '#validate' => 'date_validate',
          '#prefix' => '<div class="date-inline">',
          '#suffix' => '</div>',
          );
        break;

      default:
        $form['filters']['status'][$key] = array(
          '#type' => 'select',
          '#options' => $filter['options'],
          );
    }
  }

  // Building radio buttons.
  $keyz = array_keys($names);
  $form['filters']['filter'] = array(
    '#type'          => 'radios',
    '#options'       => $names,
    '#default_value' => $keyz[0],
    '#attributes' => array('class' => 'multiselect'),
    );

  // Building buttons depending on the filter state.
  $form['filters']['buttons']['submit'] = array(
    '#type'  => 'submit',
    '#value' => (count($session) ? t('Refine') : t('Filter')),
    );

  if (count($session)) {
    $form['filters']['buttons']['undo'] = array(
      '#type'  => 'submit',
      '#value' => t('Undo'),
    );
    $form['filters']['buttons']['reset'] = array(
      '#type'  => 'submit',
      '#value' => t('Reset'),
    );
  }
  return $form;
}

/**
 * Handle post-validation form submission.
 *
 * @ingroup forms
 * @see cmf_filter_form()
 *
 * @param the ID of the passed form
 * @param array with the form properties values
 */
function cmf_filter_form_submit($form, &$form_state) {
  $filters = cmf_filters();
/* TODO The 'op' element in the form values is deprecated.
   Each button can have #validate and #submit functions associated with it.
   Thus, there should be one button that submits the form and which invokes
   the normal form_id_validate and form_id_submit handlers. Any additional
   buttons which need to invoke different validate or submit functionality
   should have button-specific functions. */
  switch ($form_state['values']['op']) {
    case t('Filter'):
    case t('Refine'):
      if (isset($form_state['values']['filter'])) {
        $filter = $form_state['values']['filter'];
        // Convert AJAX search value to select box value.
        switch ($filter) {
          case 'users':
            $users = cmf_get_users('name');
            $uid = db_result(db_query('SELECT uid FROM {users} WHERE name = "%s"', $form_state['values']['users']));
            $form_state['values']['user'] = $uid;
            $filter = 'user';
            break;

          case 'body_contains':
          case 'title':
            $string = $form_state['values']['title'];
            $filters[$filter]['options'][$string] = $string;
            break;

          case 'created_before':
          case 'created_after':
            $string = gmmktime(0, 0, 0, $form_state['values'][$filter]['month'], $form_state['values'][$filter]['day'], $form_state['values'][$filter]['year']);
            $filters[$filter]['options'][$string] = $string;
            $form_state['values'][$filter] = $string;
            break;
        }

        // Flatten the options array to accommodate hierarchical/nested options.
        $flat_options = form_options_flatten($filters[$filter]['options']);
        if (isset($flat_options[$form_state['values'][$filter]])
          || $filter == 'created_before'
          || $filter == 'created_after'
          || $filter == 'body_contains'
          || $filter == 'title') {
          $_SESSION['cmf_overview_filter'][] = array($filter, $form_state['values'][$filter]);
        }
      }
      break;

    case t('Undo'):
      array_pop($_SESSION['cmf_overview_filter']);
      break;

    case t('Reset'):
      $_SESSION['cmf_overview_filter'] = array();
      break;

    case t('Apply'):
      $_SESSION['cmf_max_rows'] = $form_state['values']['max-rows'];
      $_SESSION['cmf_show_nid'] = $form_state['values']['show_nid'];
      $_SESSION['cmf_content_kind'] = $form_state['values']['kind'];

      if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
        $form_state['redirect'] = 'user/'. arg(1) .'/cmf';
      }
      else {
        $form_state['redirect'] = 'admin/content/filter';
      }
      break;
  }
}

/**
 * Theme cmf administration filter form.
 *
 * @themable
 */
function theme_cmf_filter_form($form) {
  return '<div id="cmf_header">'. drupal_render($form['general']) .'</div>'
    .'<div id="node-admin-filter">'. drupal_render($form['filters']) .'</div>'
    . drupal_render($form);
}

/**
 *  QUERIES
 */
/**
 * Build the variable parts of the query to be performed regarding the filter status.
 *
 * @return associative array with WHERE JOIN query parts and respective arguments
 */
function cmf_build_filter_query() {
  $filters = cmf_filters();
  // Build query
  $where = $args = array();
  $join = '';
  foreach ($_SESSION['cmf_overview_filter'] as $index => $filter) {
    list($key, $value) = $filter;
    switch ($key) {
      case 'status':
        // Note: no exploitable hole as $key/$value have already been checked when submitted
        list($key, $value) = explode('-', $value, 2);
        $where[] = 'n.'. $key .' = %d';
        break;

      case 'category':
        $table = "tn$index";
        $where[] = "$table.tid = %d";
        $join .= "INNER JOIN {term_node} $table ON n.nid = $table.nid ";
        break;

      case 'type':
        $where[] = "n.type = '%s'";
        break;

      case 'user':
        $where[] = "u.uid = %d";
        break;

      case 'role':
        $where[] = "u.uid = ur.uid AND ur.rid = %d";
        $join .= "INNER JOIN {users_roles} ur ON u.uid = ur.uid ";
        break;

      case 'title':
        $where[] = "LOWER(n.title) LIKE LOWER('%%%s%%')";
        break;

      case 'body_contains':
        $where[] = "LOWER(r.body) LIKE LOWER('%%%s%%')";
        break;

      case 'created_before':
        $where[] = "n.created <= %d";
        break;

      case 'created_after':
        $where[] = "n.created >= %d";
        break;

      case 'language':
        $where[] = "n.language ='%s'";
        break;

      case 'users':
        $where[] = "u.name = '%s'";
        break;

      case 'blocked':
        $where[] = "u.status = %d AND u.uid != 0";
        break;
    }
    $args[] = $value;
  }
  $where = count($where) ? 'WHERE '. implode(' AND ', $where) : '';
  return array('where' => $where, 'join' => $join, 'args' => $args);
}

/**
 * Build the header of the result table.
 *
 * @return array respecting tablesort_sql()
 */
function cmf_build_header() {
  $header = array();
  if (user_access('filter and manage site content')) {
    $header[] = theme('table_select_header_cell');
  }

  if ($_SESSION['cmf_show_nid']) {
    $header[] = array('data' => t('ID'), 'field' => 'nid');
  }

  switch ($_SESSION['cmf_content_kind']) {
    case 'node':
      $header[] = array('data' => t('Title'), 'field' => 'title');
      $header[] = array('data' => t('Kind'));
      $header[] = array('data' => t('Node Type'), 'field' => 'type');
      if (!(arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0)) {
        $header[] = array('data' => t('Author'), 'field' => 'username');
      }
      $header[] = array('data' => t('Status'), 'field' => 'status');
      $header[] = array('data' => t('Time'), 'field' => 'created', 'sort' => 'desc');
      if (module_exists('locale')) {
        $header[] = array('data' => t('Language'), 'field' => 'language');
      }
      break;

    case 'comment':
      $header[] = array('data' => t('Subject'), 'field' => 'subject');
      $header[] = array('data' => t('Kind'));
      $header[] = array('data' => t('Node Type'), 'field' => 'type');
      if (!(arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0)) {
        $header[] = array('data' => t('Author'), 'field' => 'username');
      }
      $header[] = array('data' => t('Status'), 'field' => 'status');
      $header[] = array('data' => t('Time'), 'field' => 'created', 'sort' => 'desc');
      break;

    case 'both':
      $header[] = array('data' => t('Title') .'/'. t('Subject'), 'field' => 'title');
      $header[] = array('data' => t('Kind'));
      $header[] = array('data' => t('Node Type'), 'field' => 'type');
      if (!(arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0)) {
        $header[] = array('data' => t('Author'), 'field' => 'username');
      }
      $header[] = array('data' => t('Node Status'), 'field' => 'status');
      $header[] = array('data' => t('Time'), 'field' => 'created', 'sort' => 'desc');
      if (module_exists('locale')) {
        $header[] = array('data' => t('Language'), 'field' => 'language');
      }
      break;
  }
  if (user_access('filter and manage site content')) {
    $header[] = array('data' => t('Operations'));
  }

  return $header;
}

/**
 * Permform adjusted query.
 *
 * @param array respecting tablesort_sql()
 * @return result of permormed query
 */
function cmf_perform_query($header, $kind = NULL) {
  $filter = cmf_build_filter_query();
  if (is_null($kind)) {
    $kind = $_SESSION['cmf_content_kind'];
  }

  $where = ' '. $filter['where'];
  if (arg(0) == 'user' && is_numeric(arg(1)) && arg(1) > 0) {
    $where .= ' AND u.uid = '. arg(1);
  }
  $cwhere = str_replace(array('n.title', 'n.uid', 'r.body'), array('c.subject', 'c.uid', 'c.comment'), $where);

  switch ($kind) {
    case 'node':
      return pager_query('SELECT n.nid, n.title, n.type, n.status, n.created, '
        .'n.changed, n.promote, n.sticky, n.moderate, n.language, '
        .'u.name AS username, u.uid, r.body '
        .'FROM {node} n '
        .'JOIN {node_revisions} r ON r.vid = n.vid '
        .'INNER JOIN {users} u ON n.uid = u.uid '
        . $filter['join']
        . $where
        . tablesort_sql($header),
        isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, NULL, $filter['args']
        );
      break;

    case 'comment':
      return pager_query('SELECT c.cid, c.subject, c.nid, c.comment, c.timestamp AS created, '
        .'c.status, c.name, c.homepage, u.name AS username, u.uid, n.type, c.comment AS body '
        .'FROM {comments} c '
        .'INNER JOIN {node} n ON c.nid = n.nid '
        .'INNER JOIN {users} u ON u.uid = c.uid '
        . $filter['join']
        . $cwhere
        . tablesort_sql($header),
        isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, NULL, $filter['args']
      );
      break;

    case 'both':
      $args = array_merge($filter['args'], $filter['args']);
      $count_query = 'SELECT ('
        .'SELECT COUNT(*) FROM {node} n '
        .'JOIN {node_revisions} r ON r.vid = n.vid '
        .'INNER JOIN {users} u ON n.uid = u.uid '
        . $filter['join']
        . $where
        .') + ('
        .'SELECT COUNT(*) FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid '
        .'INNER JOIN {users} u ON u.uid = c.uid '
        . $filter['join']
        . $cwhere
        .') AS count';
      return pager_query('SELECT 0 AS cid, n.nid, n.title, NULL AS comment, n.type, n.status, n.created, '
        .'n.changed, n.promote, n.sticky, n.moderate, n.language, '
        .'u.name AS username, u.uid, r.body '
        .'FROM {node} n '
        .'JOIN {node_revisions} r ON r.vid = n.vid '
        .'INNER JOIN {users} u ON n.uid = u.uid '
        . $filter['join']
        . $where
        .' UNION SELECT c.cid, c.nid, c.subject AS title, c.comment, n.type, c.status, c.timestamp AS created, '
        .'0 AS changed, 0 AS promote, 0 AS sticky, 0 AS moderate, "" AS language, '
        .'u.name AS username, u.uid, c.comment AS body '
        .' FROM {comments} c INNER JOIN {node} n ON c.nid = n.nid INNER JOIN {users} u ON u.uid = c.uid '
        . $filter['join']
        . $cwhere
        . tablesort_sql($header),
        isset($_SESSION['cmf_max_rows']) ? $_SESSION['cmf_max_rows'] : 50, 0, $count_query, $args
      );
      break;
  }
}

/**
 *  RESULTS
 */
module_load_include('inc', 'cmf', '/node');
module_load_include('inc', 'cmf', '/comment');
module_load_include('inc', 'cmf', '/both');

/*
 *  AUX
 */
/**
 * Builds a list of available users.
 *
 * @param the format in which to return the list
 * @return array of all available users
 */
function cmf_get_users($op) {
  switch ($op) {
    case 'names':
      $result = db_query('SELECT uid, name FROM {users} WHERE uid <> 0 ORDER BY name');
      break;
  }

  $users = array();
  $users[0] = variable_get('anonymous', t('anonymous'));
  while ($account = db_fetch_object($result)) {
    $users[$account->uid] = $account->name;
  }

  return $users;
}

/**
 * Menu callback; Retrieve a JSON object containing autocomplete suggestions for existing users.
 */
function _cmf_user_autocomplete($string = '') {
  $matches = array();
  if ($string) {
    $result = db_query("SELECT name FROM {users} WHERE LOWER(name) LIKE LOWER('%s%%')", $string);
    while ($account = db_fetch_object($result)) {
      $matches[$account->name] = check_plain($account->name);
    }
  }

  drupal_json($matches);
}

/**
 * Builds a list of available roles
 *
 * @param the format in which to return the list
 * @return array of all available roles
 */
function cmf_get_roles($op) {
  switch ($op) {
    case 'names':
      $result = db_query('SELECT rid, name FROM {role} ORDER BY name');
      break;
  }
  $roles = array();
  while ($role = db_fetch_object($result)) {
    $roles[$role->rid] = $role->name;
  }

  return $roles;
}

/**
 * Get the html code of an image
 *
 * @param the pretended image
 * @return html tag img
 */
function _cmf_get_img($action, $title) {
  $path =  base_path() . drupal_get_path('module', 'cmf') .'/images/'. $action .'.png';
  if ($title == NULL) {
    $html = '<img src="'. $path .'" alt="untitled image" />';
  }
  else {
    $html = '<img src="'. $path .'" title="'. $title .'" alt="'. $title .'" />';
  }
  return $html;
}

/**
 * Theme (node) type cell on table result.
 *
 * @ingroup themable
 *
 * @param 0 or node type key
 * @return formated (node) type
 */
function theme_cmf_type($type) {
  return db_result(db_query('SELECT name FROM {node_type} WHERE type = "%s"', $type));
}

/**
 * Implementation of hook_theme().
 *
 * @ingroup themable
 */
function cmf_theme() {
  return array(
    'cmf_filter_form' => array(
      'arguments' => array('form' => NULL)
      ),
    'cmf_user' => array(
      'arguments' => array('uid' => NULL)
      ),
    'cmf_type' => array(
      'arguments' => array('type' => NULL)
      ),
    'cmf_admin_nodes_form' => array(
     'file' => 'node.inc',
     'arguments' => array('form' => NULL)
      ),
    'cmf_admin_comments_form' => array(
      'file' => 'comment.inc',
      'arguments' => array('form' => NULL)
      ),
    'cmf_admin_both_form' => array(
      'file' => 'both.inc',
      'arguments' => array('form' => NULL)
      ),
  );
}

/**
 * Theme user cell on table result.
 *
 * @ingroup themable
 *
 * @param user ID
 * @return clickable username with status
 */
function theme_cmf_user($uid) {
  if ($uid == 0) {
    return variable_get('anonymous', t('anonymous'));
  }
  $result = db_query('SELECT name, status FROM {users} WHERE uid = %d', $uid);
  $user = db_fetch_array($result);
  $url_alias = _cmf_get_user_path($uid);

  $url = $url_alias ? $url_alias : 'user/'. $uid;
  if ($user['status']) {
    $output .= l($user['name'], $url, array());
  }
  else {
    $output .= l(_cmf_get_img('blocked', t('blocked')) .' '. $user['name'], $url, array('html' => TRUE));
  }
  return $output;
}

/**
 * Get the alias path to a user profile
 *
 * @param user ID
 * @return the relative URL of the user profile
 */
function _cmf_get_user_path($uid) {
  return db_result(db_query("
    SELECT dst
    FROM {url_alias}
    WHERE src = '%s';",
    'user/'. $uid
  ));
}

/**
 * Check user permissions to see menu item under example.com/user/UID/cmf
 *
 * @param access strings
 * @param access strings
 * @return boolean
 */
function _cmf_userspace_perms($manage_access, $view_access) {
  $args = func_get_args();
  $allow = FALSE;
  foreach ($args as $perm) {
    $allow |= user_access($perm);
  }
//  return (user_access($manage_access) || user_access($view_access));
  return $allow;
}

/**
 * Get the term for a forum node
 *
 * @param node ID
 * @return the name and forum description
 */
function _cmf_get_forum($nid) {
  $path = array();
  $node = node_load($nid);
  $parents = taxonomy_get_parents_all($node->tid);
  foreach ($parents as $parent) {
    $path[] = $parent->name;
  }
  return implode(' > ', array_reverse($path));
}
