<?php

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


/**
 * hook_theme
 */
function nodeblock_theme($existing, $type, $theme, $path) {
  return array(
    'node__nodeblock__default' => array(
      'render element' => 'elements',
      'template' => 'node-nodeblock-default',
    ),
  );
}

/**
 * Utility function to tell whether a type is enabled as a node block
 */
function nodeblock_type_enabled($type) {
  $type = field_extract_bundle('node', $type);

  return variable_get('nodeblock_' . $type, 0);
}

/**
 * Utility function to retrieve default view mode
 */
function nodeblock_type_view_mode($type) {
  $type = field_extract_bundle('node', $type);
  return variable_get('nodeblock_view_mode_' . $type, 'full');
}

/**
 * Utility function to retrieve default node link setting
 */
function nodeblock_type_node_link($type) {
  $type = field_extract_bundle('node', $type);
  return variable_get('nodeblock_node_link_' . $type, 0);
}

/**
 * Utility function to retrieve default comment link setting
 */
function nodeblock_type_comment_link($type) {
  $type = field_extract_bundle('node', $type);
  return variable_get('nodeblock_comment_link_' . $type, 0);
}

/**
 * Utility function to retrieve variable settings for an individual block
 */
function nodeblock_block_variable_get($delta) {
  $defaults = array(
      'comment_link' => 'node_block_default', 
      'node_link' => 'node_block_default', 
      'view_mode' => 'node_block_default');
  
  $settings = variable_get('nodeblock_block_' . $delta, $defaults); 
  
  //Below adds backwards compatibility.
  $settings = array_merge ( $defaults, $settings);
  $update = FALSE;

  if(isset($settings['teaser'])) {
    if($settings['teaser'] == 1) {
      $settings['view_mode'] == 'teaser';    
    }
    unset($settings['teaser']);
    $update = TRUE;
  }
  if(isset($settings['links'])) {
    if($settings['links'] == 1) {
      $settings['node_link'] = 1;
      $settings['comment_link'] = 1;
    }
    unset($settings['links']);
    $update = TRUE;
  }
  if($update) {
    variable_set('nodeblock_block_' . $delta, $settings);
  }
  return $settings;
}


/**
 * Utility function to retrieve variable settings for an individual block with default values replaced
 */
function nodeblock_block_variable_get_values($delta, $type) {
  $type = field_extract_bundle('node', $type);
  $settings = nodeblock_block_variable_get($delta);
  foreach($settings as $setting => &$value) {  
    $value = ($value == 'node_block_default' && function_exists('nodeblock_type_'.$setting)) ? call_user_func('nodeblock_type_'.$setting, $type) :  $value;
  }
  return $settings;
}



/**
 * Implementation of hook_form_alter().
 */
function nodeblock_form_alter(&$form, &$form_state, $form_id) {

  if ($form_id == 'node_type_form') {
    // Get View Mode Options
    $view_modes = nodeblock_get_view_modes($form['#node_type']);
    
    $options = array(
        '0' => 'Hide',
        '1' => 'Show',
    );
    // Add group & form fields to node type form
      $form['nodeblock_settings'] = array(
          '#type' => 'fieldset',
          '#title' => t('Node Block Settings'),
          '#collapsible' => TRUE,
          '#collapsed' => TRUE,
          '#group' => 'additional_settings',
          '#attributes' => array(
          'class' => array('node-block-settings'),
          ),
          'nodeblock' => array(
          '#type' => 'radios',
          '#title' => t('Available as block'),
          '#default_value' => nodeblock_type_enabled($form['#node_type']),
          '#options' => array(0 => t('Disabled'), 1 => t('Enabled')),
          '#description' => t('Should these nodes be made available as blocks?'),
        ),
        'nodeblock_view_mode' => array(
          '#type' => 'select',
          '#title' => t('Default View Mode'),
          '#default_value' => nodeblock_type_view_mode($form['#node_type']),
          '#options' => $view_modes,
          '#description' => t("Select a default View Mode for Node Blocks of this Content Type. 'Disabled' View Modes will show the default View Mode until enabled on the 'Manage Fields' tab."),
        ),
        'nodeblock_node_link' => array(
          '#type' => 'select',
          '#title' => t('Default Links Display'),
          '#default_value' => nodeblock_type_node_link($form['#node_type']),
          '#options' => $options,
          '#description' => t("Select the default Node('Read More') link display for Node Blocks of this Content Type."),
        ),
        'nodeblock_comment_link' => array(
          '#type' => 'select',
          '#title' => t('Default Comments Display'),
          '#default_value' => nodeblock_type_comment_link($form['#node_type']),
          '#options' => $options,
          '#description' => t("Select the default Comment link display for Node Blocks of this Content Type."),
        ),
    );
  }
  // node add/edit form
  elseif (!empty($form['#node_edit_form'])) {    
    $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) && (empty($node->tnid) || $node->tnid == 0 || $node->tnid == $node->nid)) {
      $form['nodeblock'] = array(
        '#type' => 'fieldset',
        '#title' => t('Block translation options'),
        '#tree' => TRUE,
      );
      $nodeblock_translation_fallback = isset($node->nid) ? variable_get('nodeblock_translation_fallback_'.$node->nid, '0') : 0;
      $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' => $nodeblock_translation_fallback,
      );
    }
  }
}


/**
 * hook_node_delete
 */
function nodeblock_node_delete($node) {
  if(variable_get('nodeblock_block_' . $node->nid, false)) {
    variable_del('nodeblock_block_' . $node->nid);
  }

  if (isset($node->nodeblock['translation_fallback'])) {
    $tnid = !empty($node->tnid) ? $node->tnid : $node->nid;
    if(variable_get('nodeblock_translation_fallback_' . $tnid, false)) {
      variable_del('nodeblock_translation_fallback_' . $tnid);
    }  
  }
  _block_rehash();
}
/**
 * hook_node_update
 */
function nodeblock_node_update($node) {
  _nodeblock_insert_update($node);
}

/**
 * hook_node_insert
 */
function nodeblock_node_insert($node) {
  _nodeblock_insert_update($node);
}

/**
 * consolidation of node insert/update code since behavior should be the same
 */
function _nodeblock_insert_update($node) {
  if (!nodeblock_type_enabled($node)) {
    nodeblock_node_delete($node);
    return;
  }
  if ($node->status) {
    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/structure/block'))));
  }
  if(!variable_get('nodeblock_block_' . $node->nid, false)) {
    variable_set('nodeblock_block_' . $node->nid, array('view_mode' => 'node_block_default', 'node_link' => 'node_block_default'));
  }
  // 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();
}

/**
 * hook_block_info
 */
function nodeblock_block_info() {
  $blocks = array();
  $blocks2 = array();
  $types = node_type_get_types();
  foreach ($types as $type) {
    if (nodeblock_type_enabled($type)) {
      // Fetch all nodes of this type, excluding translations.
      $request = db_select('node', 'n')
        ->fields('n', array('nid', 'title'))
        ->condition('n.type', $type->type)
        ->condition('n.status', 1)
        ->condition(db_or()->where('n.nid = n.tnid')->condition('n.tnid', 0));
      $result = $request->execute();
      foreach ($result as $node) {
        $blocks[$node->nid] = array('info' => $node->title . ' (nodeblock)');
      }
    }
  }
  return $blocks;
}

/**
 * hook_block_view
 */
function nodeblock_block_view($delta = '') {
  $node = node_load($delta);
  if (!node_access('view', $node)) {
    return;
  }
  $settings = nodeblock_block_variable_get_values($delta, $node->type);
  $lang = LANGUAGE_NONE;
  // 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);
    $lang = $language->language;
    $nodeblock_translation_fallback = variable_get('nodeblock_translation_fallback_'.$node->nid, '0');

    if (!empty($translations[$language->language])) {
      $node = node_load($translations[$language->language]->nid);
    }
    else if($node->language == $language->language){

    }
    elseif (!$nodeblock_translation_fallback && isset($node->language) && $node->language != 'und' ) {
      // 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, $settings['view_mode'], $lang);
  
  if(!(bool)$settings['node_link'] && isset($block['content']['links']['node'])) {
    unset($block['content']['links']['node']);
  }
  if(!(bool)$settings['comment_link'] && isset($block['content']['links']['comment'])) {
    unset($block['content']['links']['comment']);
  }  
  return $block;
}

/**
 * hook_block_configure
 */
function nodeblock_block_configure($delta = '') {

  $defaults = nodeblock_block_variable_get($delta);
  
  $node = node_load($delta);
  $entity_info = entity_get_info('node');
  $view_modes = array();
  $view_modes['node_block_default'] = t('Default');
  $view_modes += nodeblock_get_view_modes($node->type);  
  $options = array(
      'node_block_default' => 'Default',
      '0' => 'Hide',
      '1' => 'Show',
  );
  
   // Add a Node Block Group
  $form['nodeblock'] = array(
    '#type' => 'fieldset',
    '#title' => t('Node Block Settings'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
    '#attributes' => array(
      'class' => array('node-block-settings'),
    ),
    '#weight' => 0,
    'view_mode' => array(
      '#type' => 'select',
      '#options' => $view_modes,
      '#title' => t('View mode'),
      '#default_value' => $defaults['view_mode'],
      '#group' => 'nodeblock',
    ),
    'node_link' => array(
      '#type' => 'select',
      '#options' => $options,
      '#default_value' => $defaults['node_link'],
      '#title' => t('Node Link Display'),
      '#group' => 'nodeblock',
    ),
    'comment_link' => array(
      '#type' => 'select',
      '#options' => $options,
      '#default_value' => $defaults['comment_link'],
      '#title' => t('Node Comments Display'),
      '#group' => 'nodeblock',
    ),
  );
  return $form;
}

/**
 * hook_block_save
 */
function nodeblock_block_save($delta = '', $edit = array()) {
  variable_set('nodeblock_block_' . $delta, array('view_mode' => $edit['view_mode'], 'node_link' => $edit['node_link'], 'comment_link' => $edit['comment_link']));
}

/**
 * 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 (isset($variables['node']->nodeblock)) {
    array_unshift($variables['theme_hook_suggestions'], 'node__nodeblock__default');
  }
}

/**
 * Checks for all available View Modes, then checks which are available for the given content type.
 */
function nodeblock_get_view_modes($type) {
    $bundle = field_extract_bundle('node', $type);
    $entity_info = entity_get_info('node');
    $view_modes = field_view_mode_settings('node', $bundle);
    $options = array();
    $options_dis = array();
    if (!empty($entity_info['view modes'])) {
      foreach ($entity_info['view modes'] as $mode => $settings) {
        if (!empty($view_modes[$mode]['custom_settings'])) {
          $options[$mode] = $settings['label'];
        }
        else {
           $options_dis[$mode] = $settings['label'] . ' (Disabled)';
        }
      }
    }
    if (empty($options)) {
      $options = array(
        'node_block_default' => t('Default'),
        'teaser' => t('Teaser'),
        'full' => t('Full node')
      );
    }
    $options += $options_dis;
    return $options;
}