<?php
// $Id: nodeblock.module,v 1.15 2010/01/06 16:46:58 tomot Exp $

/**
 * @file
 * Enables use of specified node types as custom blocks.
 */

/**
 * Utility function to tell whether a type is enabled as a node block
 */
function nodeblock_type_enabled($type) {
  if (is_object($type)) {
    $type = $type->type;
  }
  return variable_get('nodeblock_'. $type, 0) ? TRUE : FALSE;
}

/**
 * Implementation of hook_form_alter().
 */
function nodeblock_form_alter(&$form, $form_state, $form_id) {
  // content type settings form
  if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
    $form['workflow']['nodeblock'] = array(
      '#type' => 'radios',
      '#title' => t('Available as block'),
      '#default_value' => variable_get('nodeblock_'. $form['#node_type']->type, 0),
      '#options' => array(0 => t('Disabled'), 1 => t('Enabled')),
      '#description' => t('Should these nodes be made available as blocks?'),
    );
  }
  // node add/edit form
  elseif (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] .'_node_form' == $form_id) {
    $node = $form['#node'];
    // Add translation fallback field for nodeblock and translation enabled source nodes only
    if (nodeblock_type_enabled($node->type) && module_exists('translation') && translation_supported_type($node->type) && empty($node->translation_source)) {
      $form['nodeblock'] = array(
        '#type' => 'fieldset',
        '#title' => t('Block translation options'),
        '#tree' => true,
      );
      $form['nodeblock']['translation_fallback'] = array(
        '#type' => 'checkbox',
        '#title' => t('Enable translation fallback?'),
        '#description' => t('If checked, the source translation node will be used when a translation for the current language does not exist.  If unchecked, the block will not be displayed if a matching translation does not exist.'),
        '#default_value' => $node->nodeblock_translation_fallback,
      );
    }
  }
}

/**
 * Implementation of hook_nodeapi().
 */
function nodeblock_nodeapi(&$node, $op, $teaser, $page) {
  // do nothing if not enabled
  if (!nodeblock_type_enabled($node)) {
    return;
  }

  switch ($op) {
    case 'load':
      $tnid = $node->tnid ? $node->tnid : $node->nid;
      return array('nodeblock_translation_fallback' => variable_get('nodeblock_translation_fallback_'. $tnid, 1));

    case 'insert':
    case 'update':
      drupal_set_message(t('The block you just created is now available on the <a href="!url">block configuration page</a>.', array('!url' => url('admin/build/block'))));

      // set the translation fallback variable if set.
      if (isset($node->nodeblock['translation_fallback'])) {
        $tnid = $node->tnid ? $node->tnid : $node->nid;
        variable_set('nodeblock_translation_fallback_'. $tnid, $node->nodeblock['translation_fallback']);
      }
      _block_rehash();
      break;

    case 'delete':
      _block_rehash();
      break;
  }
}

/**
 * Implementation of hook_block().
 */
function nodeblock_block($op = 'list', $delta = 0, $edit = array()) {
  $types = node_get_types();
  if ($op == 'list') {
    foreach ($types as $type) {
      if (nodeblock_type_enabled($type)) {
        // Fetch all nodes of this type, excluding translations.
        $result = db_query("SELECT nid, title FROM {node} WHERE type = '%s' AND status = 1 AND (nid = tnid OR tnid = 0)", $type->type);
        while ($node = db_fetch_object($result)) {
          $blocks[$node->nid] = array('info' => $node->title .' (nodeblock)');
        }
      }
    }
    return $blocks;
  }
  elseif ($op == 'configure') {
    $defaults = variable_get('nodeblock_block_' . $delta, array('teaser' => 0, 'links' => 1));
    $form['teaser'] = array(
      '#title' => t('Show only node teaser'),
      '#type' => 'checkbox',
      '#default_value' => $defaults['teaser'],
    );
    $form['links'] = array(
      '#type' => 'checkbox',
      '#default_value' => $defaults['links'],
      '#title' => t('Include node links for "add comment", "read more" etc.'),
    );
    return $form;
  }
  else if ($op == 'save') {
    variable_set('nodeblock_block_' . $delta, array('teaser' => $edit['teaser'], 'links' => $edit['links']));
  }
  elseif ($op == 'view') {
    $node = node_load($delta);
    if (!node_access('view', $node)) {
      return;
    }
    $nodeblock_display = variable_get('nodeblock_block_' . $delta, array('teaser' => 0, 'links' => 1));

    // if the node type is translatable, try to load the node with the appropriate
    // language from the translation set.
    if (module_exists('translation') && translation_supported_type($node->type)) {
      global $language;
      $translations = translation_node_get_translations($node->tnid);
      if ($translations[$language->language]) {
        $node = node_load($translations[$language->language]->nid);
      }
      elseif (!$node->nodeblock_translation_fallback) {
        // if no translation was found, and not using the fallback option
        // return nothing, so the block doesn't display.
        return;
      }
      // otherwise we just use the main node
    }

    // Set a flag so that themes have more context.
    $node->nodeblock = TRUE;
    
    $block['subject'] = check_plain($node->title);
    $block['content'] = node_view($node, $nodeblock_display['teaser'], TRUE, $nodeblock_display['links']);

    return $block;
  }
}

/**
 * Implementation of hook_link().
 */
function nodeblock_link($type, $node = NULL, $teaser = FALSE) {
  $links = array();

  if ($type == 'node' && nodeblock_type_enabled($node)) {
    if (node_access('update', $node)) {
      $links['nodeblock_edit'] = array(
        'title' => t('Edit'),
        'href' => 'node/'. $node->nid .'/edit',
        'query' => drupal_get_destination(),
      );
    }
    if (module_exists('translation') && _translation_tab_access($node)) {
      $links['nodeblock_translate'] = array(
        'title' => t('Translate'),
        'href' => 'node/'. $node->nid .'/translate',
        'query' => drupal_get_destination(),
      );
    }
    if (user_access('administer blocks')) {
      $links['nodeblock_configure'] = array(
        'title' => t('Configure'),
        'href' => 'admin/build/block/configure/nodeblock/'. $node->nid,
        'query' => drupal_get_destination(),
      );
    }
  }

  return $links;
}

/**
 * Implementation of hook_preprocess_node().
 *
 * Add node-nodeblock-default to the suggested theme files for all nodeblock
 * enabled nodes. Note that the template is "unshifted" onto the template files
 * array. This gives the template file a lower priority than any node-nodetype
 * templates, but a higher priority than a generic node.tpl.php.
 */
function nodeblock_preprocess_node(&$variables) {
  if ($variables['node']->nodeblock) {
    array_unshift($variables['template_files'], 'node-nodeblock-default');
  }
}

/**
 * Implementation of hook_theme_registry_alter().
 *
 * Add nodeblock path to the 'theme paths' for the 'node' hook.  This allows us
 * to use node-nodeblock-default.tpl.php from the module directory. Note that 
 * the path is "unshifted" onto the theme paths array. This puts the module path
 * before the modules/node path, but since neither of these modules implements
 * the same templates, there is not problem.
 */
function nodeblock_theme_registry_alter(&$registry) {
  array_unshift($registry['node']['theme paths'], drupal_get_path('module', 'nodeblock'));
}
