<?php

/**
 * @file
 * Primarily Drupal hooks and global API functions to exclude node titles.
 *
 * This is the main module file for Exclude Node Title. 
 */

/**
 * Implements hook_permission().
 */ 
function exclude_node_title_permission() {
  return array(
    'administer exclude node title' => array(
      'title' => t('Administer exclude node title'),
    ),
    'exclude any node title' => array(
      'title' => t('Exclude any node title'),
    ),
    'exclude own node title' => array(
      'title' => t('Exclude own node title'),
    ),
    'use exclude node title' => array(
      'title' => t('Use exclude node title')
    ),
  );
}

/**
 * Implements hook_menu().
 */
function exclude_node_title_menu() {
  $items = array();
  $items['admin/config/content/exclude_node_title'] = array(
    'title' => 'Exclude Node Title',
    'description' => 'Exclude Node Title from display',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('exclude_node_title_admin_settings'),
    'access arguments' => array('administer exclude node title'),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'exclude_node_title.admin.inc',
  );
  return $items;
}

/**
 * Determines if node should be hidden and user
 * has permission to have the title hidden.
 * @param $node
 *   Can be a node object or integer value (nid)
 * @param $view_mode
 *   View mode, e.g. 'full', 'teaser'...
 * @return
 *   Returns boolean TRUE if should be hidden, FALSE when not
 */
function exclude_node_title($node, $view_mode) {
  return (user_access('use exclude node title') && _exclude_node_title($node, $view_mode));
}

/**
 * Implements hook_preprocess_overlay().
 */
function exclude_node_title_preprocess_overlay(&$vars) {
  exclude_node_title_preprocess_page($vars);
}

/**
 * Implements hook_preprocess_page().
 */
function exclude_node_title_preprocess_page(&$vars) {
  if (!user_access('use exclude node title') || (arg(0) == 'node' && arg(1) == 'add')) {
    return;
  }

  if (arg(0) == 'node' && is_numeric(arg(1))) {
    switch (arg(2)) {
      case 'edit':
        $view_mode = 'nodeform';
        break;
      case 'delete':
        return; // delete pages show you all information in title, we should not remove it
      default:
        $view_mode = 'full';
        break;
    }

    _exclude_node_title_preprocess($vars, arg(1), $view_mode);
  } else if (isset($vars['page']['content']['system_main']['#node_edit_form']) && $vars['page']['content']['system_main']['#node_edit_form'] == TRUE) {
    _exclude_node_title_preprocess($vars, $vars['page']['content']['system_main']['#node'], 'nodeform');
  }
}

/**
 * Implements hook_preprocess_node().
 */
function exclude_node_title_preprocess_node(&$vars) {
  if (user_access('use exclude node title')) {
    _exclude_node_title_preprocess($vars, $vars['node'], $vars['view_mode']);
  }
}

/**
 * Remove the title from the variables array.
 */
function _exclude_node_title_preprocess(&$vars, $node, $view_mode) {
  if (_exclude_node_title($node, $view_mode)) {
    $vars['title'] = '';
    if ($view_mode == 'nodeform') {
      // Also remove the field from the form
      $vars['page']['content']['system_main']['title']['#access'] = false;
    }
  }
}

/**
 * Implements hook_preprocess_search_result().
 */
function exclude_node_title_preprocess_search_result(&$vars) {
  if (user_access('use exclude node title') && variable_get('exclude_node_title_search', 0)) {
    $vars['title'] = '';
  }
}

/**
 * Implements hook_node_update().
 */
function exclude_node_title_node_update($node) {
  if (isset($node->exclude_node_title) && exclude_node_title_check_perm($node)) {
    exclude_node_title_set_flag($node, $node->exclude_node_title);
  }
}

/**
 * Implements hook_node_insert().
 */
function exclude_node_title_node_insert($node) {
  if (isset($node->exclude_node_title) && exclude_node_title_check_perm($node)) {
    exclude_node_title_set_flag($node, $node->exclude_node_title);
  }
}

/**
 * Implements hook_node_delete().
 */
function exclude_node_title_node_delete($node) {
  if (isset($node->exclude_node_title) && $node->exclude_node_title == 1 ) {
    exclude_node_title_set_flag($node, 0);
  }
}

/**
 * Check permission to change node title exclusion.
 */
function exclude_node_title_check_perm($node) {
  global $user;
  if (user_access('exclude any node title'))
    return TRUE;
  if (!user_access('exclude own node title'))
    return FALSE;
  return !strcmp($node->name, $user->name);
}

/**
 * Implements hook_form_alter().
 */
function exclude_node_title_form_alter(&$form, &$form_state, $form_id) {
  if (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) {
    // exclude for title
    if (user_access('use exclude node title')) {
      if (_exclude_node_title($form['#node'], 'nodeform')) {
        drupal_set_title('');
      }
    }
    // --------------
    // make sure user have permissions correct
    if (!exclude_node_title_check_perm($form['#node'])) {
      return FALSE;
    }
    
    // don't bother to add form element if the content type isn't configured
    // to be excluded by user...
    if (variable_get('exclude_node_title_content_type_value_' . $form['#node']->type) == 'user') {
      $weight = $form['title']['#weight'] + 0.1;
      $form['exclude_node_title'] = array(
        '#type' => 'checkbox',
        '#title' => t('Exclude title from display'),
        '#required' => FALSE,
        '#default_value' => (!empty($form['nid']['#value']) ? in_array($form['nid']['#value'], variable_get('exclude_node_title_nid_list', array())) : FALSE ),
        '#weight' => $weight,
      );
      if (module_exists('translation') && variable_get('exclude_node_title_translation_sync', TRUE) == TRUE && translation_supported_type($form['#node']->type) && !empty($form['nid']['#value'])) {
        // get tnid
        $tnid = db_select('node', 'n')
          ->fields('n', array('tnid'))
          ->condition('nid', $form['nid']['#value'])
          ->execute()
          ->fetchAssoc();
        if ($tnid['tnid'] != $form['nid']['#value']) {
          $form['exclude_node_title']['#description'] = t("Check !here if you don't have title disabled in the source language of this node.", array('!here' => l(t('here'), 'node/' . $tnid['tnid'] . '/edit')));
        }
      }
    }
  }
}

/**
 * Set exclude_node_title flag for the given node.
 */
function exclude_node_title_set_flag($node, $value = 1) {
  $exclude_list = variable_get('exclude_node_title_nid_list', array());
  $is_excluded = array_search($node->nid, $exclude_list);
  if ($value == 1 && $is_excluded === FALSE) {
    $exclude_list[] = $node->nid;
    variable_set('exclude_node_title_nid_list', $exclude_list);
    return;
  }
  if ($value == 0 && $is_excluded !== FALSE) {
    unset($exclude_list[$is_excluded]);
    variable_set('exclude_node_title_nid_list', $exclude_list);
    return;
  }
}

/**
 * Implements hook_field_attach_delete_bundle().
 */
function exclude_node_title_field_attach_delete_bundle($entity_type, $bundle, $instances) {
  // when deleting a content type, we make sure and clean our variable :)
  if ($entity_type == 'node') {
    variable_del('exclude_node_title_content_type_value_' . $bundle);
    variable_del('exclude_node_title_content_type_modes_' . $bundle);
  }
}

/**
 * Tells if node should get hidden or not.
 * @param $param
 *   Can be a node object or integer value (nid)
 * @return
 *   Returns boolean TRUE if should be hidden, FALSE when not
 */
function _exclude_node_title($param, $view_mode = 'full') {
  if (!($node_info = _exclude_node_title_get_node($param))) {
    return FALSE;
  }

  // get exclude settings
  static $exclude_settings;
  if (!isset($exclude_settings)) {
    foreach (_node_types_build()->names as $key => $val) {
      $exclude_settings[$key] = array(
        'type'  => variable_get('exclude_node_title_content_type_value_' . $key, 'none'),
        'modes' => variable_get('exclude_node_title_content_type_modes_' . $key, array()),
      );
    }
  }

  if (!isset($exclude_settings[$node_info['node_type']]['type'])) {
    return FALSE;
  }

  switch ($exclude_settings[$node_info['node_type']]['type']) {
    case 'all':
      return !empty($exclude_settings[$node_info['node_type']]['modes'][$view_mode]);

    case 'user':
      if (!$node_info['nid'])
        return FALSE;

      // we look for the nid list
      $nid_exclude_list = variable_get('exclude_node_title_nid_list', array());
      $nid_list = array($node_info['nid'] => $node_info['nid']);

      if (module_exists('translation') && variable_get('exclude_node_title_translation_sync', TRUE) == TRUE && translation_supported_type($node_info['node_type'])) {
        // get tnid
        $tnid = db_select('node', 'n')
          ->fields('n', array('tnid'))
          ->condition('nid', $node_info['nid'])
          ->execute()
          ->fetchAssoc();
        $tlist = translation_node_get_translations($tnid['tnid']);

        if (is_array($tlist)) {
          foreach ($tlist as $tlang => $tnode) {
            $nid_list[$tnode->nid] = $tnode->nid;
          }
        }
      }

      foreach ($nid_list as $item_nid) {
        if (in_array($item_nid, $nid_exclude_list)) {
          return !empty($exclude_settings[$node_info['node_type']]['modes'][$view_mode]);
        }
      }

      return FALSE;
      
    case 'none':

    default:
      return FALSE;
      break;
  }
}

/**
 * Helper function to _exclude_node_title() that extracts node information from $param.
 * @param $param
 *   Can be a node object or integer value (nid)
 * @return
 *   Returns an array with node id and node type, or FALSE if there were errors.
 */
function _exclude_node_title_get_node($param) {
    // we accept only integer and object
    if (!is_object($param) && !is_numeric($param)) {
        return FALSE;
    }

    // if numeric, load the node with nid
    if (is_numeric($param)) {
        $node = node_load(intval($param));
        if (!is_object($node)) {
            return FALSE;
        }
    }
    else if (is_object($param)) {
        $node = $param;
        unset($param); // memory cleanup
    }

    // Check that the node exists 
    if (!isset($node) || !isset($node->type))
        return FALSE;

    $node_type = $node->type;
    $nid = isset($node->nid)? $node->nid : FALSE;
    unset($node); // memory cleanup

    return array('nid' => $nid, 'node_type' => $node_type);
}

/**
 * Implements hook_field_extra_fields().
 */
function exclude_node_title_field_extra_fields() {
  $extra = array();

  foreach (node_type_get_types() as $type) {
    $exclude_type = variable_get('exclude_node_title_content_type_value_' . $type->type, 'none');
    if ($exclude_type != 'user')
        continue;

    $extra['node'][$type->type]['form'] = array(
      'exclude_node_title' => array(
        'label' => t('Exclude Node Title'),
        'description' => t('Exclude node title from display.'),
        'weight' => 0,
        'visible' => TRUE,
      ),
    );
  }
  
  return $extra;
}

/**
 * Implements hook_ds_fields_info_alter().
 */
function exclude_node_title_ds_fields_info_alter(&$fields, $entity_type) {
  if ($entity_type == 'node') {
    $fields['title']['function'] = '_exclude_node_title_ds_render_field';
    $fields['title']['properties']['settings']['exclude node title settings'] = array(
      'type' => 'select',
      'options' => array('No', 'Yes'),
      'description' => t('Use the settings for the Exclude Node Title module for the title. Set to "off" to always show title.'),
    );
    $fields['title']['properties']['default']['exclude node title settings'] = 1;
  }
}

/*
 * Render the field obeying exclude node title settings.
 */
function _exclude_node_title_ds_render_field($field) {
  $settings = isset($field['formatter_settings']) ? $field['formatter_settings'] : array();
  $settings += $field['properties']['default'];
  if ($settings['exclude node title settings'] && _exclude_node_title($field['entity']->nid, $field['view_mode'])) {
    $field['entity']->title = '';
  }
  return ds_render_field($field);
}
