<?php

/**
 * @file
 * Adds social network links to the content.
 *
 * This module is the enhanced version of Service Links 1.x developed
 * by Fredrik Jonsson, rewritten and improved to fit the new purposes:
 * extend easily the number of services supported and provide APIs to
 * print links everywhere within any content.
 * At the @link http://servicelinks.altervista.org/?q=service home page
 * @endlink a web interface helps to create a module including the
 * services not availables in the standard package.
 *
 * @author: Fabio Mucciante (TheCrow)
 */

define('SERVICE_LINKS_STYLE_NONE', 0);
define('SERVICE_LINKS_STYLE_TEXT', 1);
define('SERVICE_LINKS_STYLE_IMAGE', 2);
define('SERVICE_LINKS_STYLE_IMAGE_AND_TEXT', 3);
define('SERVICE_LINKS_STYLE_EMPTY', 4);
define('SERVICE_LINKS_STYLE_FISHEYE', 5);

define('SERVICE_LINKS_SHORT_URL_USE_NEVER', 0);
define('SERVICE_LINKS_SHORT_URL_USE_WHEN_REQUESTED', 1);
define('SERVICE_LINKS_SHORT_URL_USE_ALWAYS', 2);

define('SERVICE_LINKS_SHORT_URL_TYPE_NODE', 1);
define('SERVICE_LINKS_SHORT_URL_TYPE_SERVICE', 2);
define('SERVICE_LINKS_SHORT_URL_TYPE_REDIRECT_DOMAIN', 3);
define('SERVICE_LINKS_SHORT_URL_TYPE_REDIRECT_ALL', 4);

define('SERVICE_LINKS_TAG_TITLE_NODE', 0);
define('SERVICE_LINKS_TAG_TITLE_OVERRIDE', 1);
define('SERVICE_LINKS_TAG_TITLE_TOKEN', 2);

define('SERVICE_LINKS_VISIBILITY_NOT_LISTED', 0);
define('SERVICE_LINKS_VISIBILITY_ONLY_LISTED', 1);
define('SERVICE_LINKS_VISIBILITY_PHP', 2);

/**
 * Implements hook_help().
 */
function service_links_help($path, $arg) {
  switch ($path) {
    case 'admin/help#service_links':
      return '<p>'. t('Display links to social sharing websites like Digg, del.icio.us, reddit, Technorati etc.') .'</p>';
      break;
  }
}

/**
 * Implements hook_hook_info().
 */
function service_links_hook_info() {
  $hooks = array(
    'service_links' => array(
      'group' => 'service_links',
    ),
    'service_links_alter' => array(
      'group' => 'service_links',
    ),
  );

  return $hooks;
}

/**
 * Implements hook_permission().
 */
function service_links_permission() {
  return array(
    'access service links' => array(
      'title' => t('Access to Service Links'),
      //'description' => t('Allow users to act with the services loaded'),
    ),
    'use PHP for service visibility' => array(
      'title' => t('Use PHP for Service visibility'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function service_links_menu() {
  $items = array();

  $items['admin/config/services/service-links'] = array(
    'title' => 'Service Links',
    'description' => 'Control which and where service links should be active.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('service_links_admin_settings'),
    'access arguments' => array('administer site configuration'),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'service_links.admin.inc',
  );

 $items['admin/config/services/service-links/general'] = array(
    'title' => 'General Settings',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );

  $items['admin/config/services/service-links/services'] = array(
    'title' => 'Services',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('service_links_admin_services'),
    'access arguments' => array('administer site configuration'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'service_links.admin.inc',
  );

  return $items;
}

/**
 * Implements hook_node_view().
 */
function service_links_node_view($node, $view_mode) {
  static $view_modes_allowed;
 
  if (!isset($view_modes_allowed)) {
    $view_modes_allowed = array_filter(variable_get('service_links_node_view_modes', array()));
  }

  if ((arg(2) != 'edit') && service_links_show($node) && user_access('access service links')) {

    $node->service_links = service_links_render($node, TRUE);

    if (!empty($view_modes_allowed) && (in_array($view_mode, $view_modes_allowed))) {

      $node->service_links_rendered = theme('service_links_node_format', array(
        'links' => $node->service_links,
        'label' => variable_get('service_links_label_in_node', t('Bookmark/Search this post with')),
        'view_mode' => $view_mode,
        'node_type' => $node->type,
      ));
  
      $node->content['service_links'] = array(
        '#markup' => $node->service_links_rendered,
        '#weight' => variable_get('service_links_weight_in_node', 10),
      );
    }

    _service_links_link($node, $view_mode);
  }
}

/**
 * Create an array of links for the link section.
 */
function _service_links_link($node, $view_mode) {
  static $view_modes_allowed;
 
  if (!isset($view_modes_allowed)) {
    $view_modes_allowed = array_filter(variable_get('service_links_link_view_modes', array()));
  }

  if (in_array($view_mode, $view_modes_allowed)) {
    $links = $node->service_links;
    if (!empty($links)) {
      $node->content['links']['node']['#links'] = array_merge($node->content['links']['node']['#links'], $links);
    }
  }
}

/**
 * Implements hook_block_info().
 */
function service_links_block_info() {
  $blocks['service_links'] = array(
    'info' => t('Service links'),
    'cache' => DRUPAL_NO_CACHE,
  );
  $blocks['service_links_fisheye'] = array(
    'info' => t('Service links with FishEye effect'),
    'cache' => DRUPAL_NO_CACHE,
  );
  $blocks['service_links_not_node'] = array(
    'info' => t('Service links for not-node pages'),
    'cache' => DRUPAL_NO_CACHE,
  );

  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function service_links_block_view($delta = '') {
  $node = menu_get_object('node');
  $block = array();

  if (user_access('access service links') && (isset($node))) {
    if (service_links_show($node)) {
      switch ($delta) {
        case 'service_links':
          $block['subject'] = t('Bookmark/Search this post');
          $style = variable_get('service_links_block_style', SERVICE_LINKS_STYLE_IMAGE_AND_TEXT);
          $block['content'] = theme('service_links_block_format', array('items' => service_links_render($node, FALSE, $style), 'style' => $style));
          break;
        case 'service_links_fisheye':
          $block['subject'] = t('Bookmark/Search this post');
          $block['content'] = theme('service_links_fisheye_format', array('items' => service_links_render($node, FALSE, SERVICE_LINKS_STYLE_FISHEYE)));
          break;
      }
    }
    return $block;
  }
  elseif (user_access('access service links') && (!isset($node))) {
    switch ($delta) {
      case 'service_links_not_node':
        $block['subject'] = t('Bookmark/Search this post');
        $options = array(
          'style' => variable_get('service_links_block_not_node_style', SERVICE_LINKS_STYLE_IMAGE_AND_TEXT),
          'link_to_front' => variable_get('service_links_block_not_node_front', FALSE),
        );
        $block['content'] = theme('service_links_block_format', array(
          'items' => service_links_render(NULL, FALSE, $options),
          'style' => $options['style'],
        ));
        break;
    }
    return $block;
  }
}

/**
 * Implements hook_block_configure().
 */
function service_links_block_configure($delta = '') {
  $form = array();
  switch ($delta) {
    case 'service_links':
      $form['service_links_block_style'] = array(
        '#type' => 'select',
        '#title' => t('Style'),
        '#description' => t('How the service links will appear in the block.'),
        '#default_value' => variable_get('service_links_block_style', SERVICE_LINKS_STYLE_IMAGE_AND_TEXT),
        '#options' => array(
          SERVICE_LINKS_STYLE_TEXT => t('Text'),
          SERVICE_LINKS_STYLE_IMAGE => t('Image'),
          SERVICE_LINKS_STYLE_IMAGE_AND_TEXT => t('Image and Text'),
        ),
      );
      break;
    case 'service_links_fisheye':
      $form['service_links_path_fisheye'] = array(
        '#type' => 'textfield',
        '#title' => t('Alternative icon folder'),
        '#size' => 60,
        '#description' => t('If you have alternative icons write here the path without trailing slash'),
        '#default_value' => service_links_expand_path(NULL, 'fisheye'),
      );
      break;
    case 'service_links_not_node':
      $form['service_links_block_not_node_style'] = array(
        '#type' => 'select',
        '#title' => t('Style'),
        '#description' => t('How the service links will appear in the block.'),
        '#default_value' => variable_get('service_links_block_not_node_style', SERVICE_LINKS_STYLE_IMAGE_AND_TEXT),
        '#options' => array(
          SERVICE_LINKS_STYLE_TEXT => t('Text'),
          SERVICE_LINKS_STYLE_IMAGE => t('Image'),
          SERVICE_LINKS_STYLE_IMAGE_AND_TEXT => t('Image and Text'),
        ),
      );

      $form['service_links_block_not_node_front'] = array(
        '#type' => 'checkbox',
        '#title' => t('Link always to the front page'),
        '#description' => t('If selected the services will link always to the front page %front.', array('%front' => url('<front>', array('absolute' => TRUE)))),
        '#default_value' => variable_get('service_links_block_not_node_front', FALSE),
      );
      break;
  }

  return $form;
}

/**
 * Implements hook_block_save().
 */
function service_links_block_save($delta = '', $edit = array()) {
  switch ($delta) {
    case 'service_links':
      variable_set('service_links_block_style', $edit['service_links_block_style']);
      break;
    case 'service_links_fisheye':
      variable_set('service_links_path_fisheye', $edit['service_links_path_fisheye']);
      break;
    case 'service_links_not_node':
      variable_set('service_links_block_not_node_style', $edit['service_links_block_not_node_style']);
      variable_set('service_links_block_not_node_front', $edit['service_links_block_not_node_front']);
      break;
  }
}

/**
 * Implements hook_theme().
 */
function service_links_theme() {
  return array(
    'service_links_build_link' => array(
      'variables' => array(
        'text' => NULL,
        'url' => array(),
        'image' => NULL,
        'nodelink' => FALSE,
        'style' => NULL,
        'attributes' => array(),
      ),
      'file' => 'service_links.theme.inc',
    ),
    'service_links_node_format' => array(
      'variables' => array(
        'links' => NULL,
        'label' => NULL,
        'view_mode' => NULL,
        'node_type' => NULL
      ),
      'file' => 'service_links.theme.inc',
    ),
    'service_links_block_format' => array(
      'variables' => array('items' => NULL, 'style' => SERVICE_LINKS_STYLE_IMAGE_AND_TEXT),
      'file' => 'service_links.theme.inc',
    ),
    'service_links_fisheye_format' => array(
      'variables' => array('items' => NULL),
      'file' => 'service_links.theme.inc',
    ),
    'service_links_drag_table' => array(
      'render element' => 'form',
    ),
  );
}

/**
 * Remove a service from the list if the related module is disabled
 * and can't provide the correct values.
 */
function service_links_array_filter($services) {
  $result = array();

  foreach ($services as $service_id => $service) {
    if ($service === 1) {
      drupal_set_message(t('The service having id "@id" is missing, reactivate its module or save again the list of services.', array('@id' => $service_id)), 'warning', FALSE);
    }
    else {
      $result[$service_id] = $service;
    }
  }

  return $result;
}

/**
 * Discover all available service links by invoking hook_service_links().
 *
 * @param $services
 *   If NULL, will retrieve all service link information. If an array is passed,
 *   will only obtain information for the given keyed links.
 * @param $reset
 *   Resets the Service Links cache.
 *
 * @return
 *   An array containing information for all the requested services.
 */
function service_links_get_links($services = NULL, $reset = FALSE) {
  $links = &drupal_static(__FUNCTION__, NULL);
  if (!isset($links) || $reset) {
    // Retrieve the links from the cache.
    if (!$reset && ($cache = cache_get('service_links_get_links')) && !empty($cache->data)) {
      $links = $cache->data;
    }
    else {
      // Create the repository of links.
      $links = array();
      foreach (module_implements('service_links') as $module) {
        $module_links = module_invoke($module, 'service_links');
        foreach ($module_links as $name => $link) {
          $link['module'] = $module;
          $links[$name] = $link;
        }
      }
      // Allow alteration of the links.
      drupal_alter('service_links', $links);

      // Save the links in the cache.
      cache_set('service_links_get_links', $links);
    }
  }

  // If desired, return only the wanted services.
  if (isset($services)) {
    // Detect a manual request and populate the array correctly.
    if (is_numeric(key($services))) {
      $services = array_combine($services, array_fill(0, count($services), 1));
    }

    // Provide only the services requested.
    $services = array_merge($services, array_intersect_key($links, $services));

    // Remove the unknown services.
    $services = service_links_array_filter($services);
  }

  return isset($services) ? $services : $links;
}

/**
 * Create short links using predefined settings.
 */
function service_links_short_url($url, $nid = NULL) {
  switch (variable_get('service_links_short_links_type', SERVICE_LINKS_SHORT_URL_TYPE_NODE)) {
    case SERVICE_LINKS_SHORT_URL_TYPE_NODE:
      if (empty($nid)) {
        return $url;
      }
      else {
        // With alias = true doesn't change the path.
        return url("node/$nid", array('absolute' => TRUE, 'alias' => TRUE));
      }
    case SERVICE_LINKS_SHORT_URL_TYPE_SERVICE:
      if (module_exists('shorten')) {
        $turl = shorten_url($url);
      }
      else {
        $turl = drupal_http_request('http://tinyurl.com/api-create.php?url=' . urlencode($url));
        $turl = (isset($turl->data) && ($turl->code == 200)) ? $turl->data : $url;
      }
      return $turl;
    case SERVICE_LINKS_SHORT_URL_TYPE_REDIRECT_DOMAIN:
      $burl = variable_get('service_links_domain_redirect', NULL);
      return url($url, array('absolute' => TRUE, 'base_url' => $burl));
    case SERVICE_LINKS_SHORT_URL_TYPE_REDIRECT_ALL:
      $burl = variable_get('service_links_domain_redirect', NULL);
      if (empty($nid)) {
        return url($url, array('absolute' => TRUE, 'base_url' => $burl));
      }
      else {
        return url("node/$nid", array('absolute' => TRUE, 'alias' => TRUE, 'base_url' => $burl));
      }
  }
}

/**
 * Function that render all the selected services.
 *
 * @param $node
 *   Contains the content structured as a node object.
 *   Use the node_load() function to build one or set
 *   NULL this variable to consider the current page.
 * @param $nodelink
 *   (optional) It determines the kind of render.
 *   If TRUE the function return an array of items 
 *   compatible with the standard Drupal link section.
 *   If FALSE return an array of HTML links.
 *   Default is FALSE.
 * @param $options
 *   (optional) Can assume the value of a valid service
 *   style either an array containing the settings 
 *   to override (look at _service_links_load_settings()
 *   for more details).
 *
 * @return
 *   An array of HTML links if $nodelink = FALSE, an array
 *   of structured links to be themed with theme_links() 
 *   if $nodelink = TRUE.
 */
function service_links_render($node, $nodelink = FALSE, $options = NULL) {
  $links = array('weight' => array(), 'link' => array());
  $settings = _service_links_load_settings();

  if (empty($settings['link_show'])) {
    return array();
  }

  if (isset($options)) {
    if (!is_array($options)) {
      $options = array('style' => $options);
    }  
    $settings = array_merge($settings, $options);
  }

  _service_links_get_tags($node, $settings);

  // Services are filtered in _service_links_load_settings().
  $services = service_links_get_links($settings['link_show']);

  foreach ($services as $service_id => $service) {
    // Load the position.
    $links['weight'][] = isset($settings['link_weight'][$service_id]) ? $settings['link_weight'][$service_id] : 0;

    // Render the Service.
    $links['link'] += _service_links_render($service_id, $service, $settings, $nodelink, $node);
  }

  if (!empty($links['link'])) {
    array_multisort($links['weight'], $links['link']);
  }

  return !empty($links['link']) ? $links['link'] : array();
}

/**
 * This function render only the services requested
 * by their id.
 *
 * @param $service_ids
 *   The list of requested services, can be just a
 *   string, for a single services, or an array of
 *   id, don't need enable them on the admin page.
 * @param $node
 *   Contains the content structured as a node object.
 *   Use the node_load() function to build one or set
 *   NULL this variable to consider the current page.
 * @param $nodelink
 *   (optional) It determines the kind of render.
 *   If TRUE the function return an array of items 
 *   compatible with the standard Drupal link section.
 *   If FALSE return an array of HTML links.
 *   Default is FALSE.
 * @param $options
 *   (optional) Can assume the value of a valid service
 *   style either an array containing the settings 
 *   to override (look at _service_links_load_settings()
 *   for more details).
 *
 * @return
 *   An array of HTML links if $nodelink = FALSE, an array
 *   of structured links to be themed with theme_links() 
 *   if $nodelink = TRUE.
 */
function service_links_render_some($service_ids, $node = NULL, $nodelink = FALSE, $options = NULL) {
  if (is_array($service_ids)) {
    $services = service_links_get_links($service_ids);
  }
  else {
    $services = service_links_get_links(array($service_ids));
  }

  if (empty($services)) {
    return array();
  }

  $settings = _service_links_load_settings();
  if (isset($options)) {
    if (!is_array($options)) {
      $options = array('style' => $options);
    }  
    $settings = array_merge($settings, $options);
  }

  _service_links_get_tags($node, $settings);

  $links = array();
  foreach ($services as $service_id => $service) {
    $links += _service_links_render($service_id, $service, $settings, $nodelink, $node);
  }

  return $links;
}

/**
 * The common render function used privately.
 */
function _service_links_render($service_id, $service, $settings, $nodelink, $node = NULL) {
  if (isset($service['preset'])) {
    if (function_exists($function = $service['preset'])) {
      $function($service, $settings, $node);
    }
  }

  // On Drupal 7 this tag should be filled before the split otherwise will be lost.
  $service['link'] = str_replace('<front-page>', $settings['subst']['front-page'], $service['link']);

  if (strpos($service['link'], '=') === FALSE) {
    $service['url'] = array($service['link']);
  }
  else {
    $service['url'] = preg_split('/\?/', $service['link']);
  }

  if (count($service['url']) > 1) {
    $service['url'][1] = service_links_get_query($service['url'][1]);
    $service['url'][1] = str_replace($settings['tag'], $settings['subst'], $service['url'][1]);
  }
  else {
    $service['url'][0] = str_replace($settings['tag'], $settings['subst'], $service['url'][0]);
  }

  $service['attributes']['title'] = t($service['description']);
  $class = str_replace(array('][', '_', ' '), '-', 'service_links-'. $service_id);
  $service['attributes']['class'] = isset($service['attributes']['class']) ? array_merge($service['attributes']['class'], array($class)) : array($class);
  $service['attributes'] += $settings['attributes'];

  $service['icon'] = isset($service['icon']) ? $service['icon'] : "$service_id.png";

  $service_id = str_replace('_', '-', 'service_links_'. $service_id);

  // Check if a predefined style should be imposed.
  if (empty($service['style'])) {
    $service['style'] = $settings['style'];
  }

  // Add the related JavaScript and CSS.
  if (isset($service['javascript'])) {
    _service_links_add_js($service['javascript']);
  }
  if (isset($service['css'])) {
    drupal_add_css(service_links_expand_path($service['css'], 'css'));
  }

  // Invoke callback function.
  if (isset($service['callback'])) {
    if (function_exists($function = $service['callback'])) {
      $function($service, $settings['subst']);
    }
  }

  // Create the HTML.
  $link = theme('service_links_build_link', array(
    'text' => t($service['name']),
    'url' => $service['url'],
    'image' => $service['icon'],
    'nodelink' => $nodelink,
    'style' => $service['style'],
    'attributes' => $service['attributes'],
  ));

  return array($service_id => $link);
}

/**
 * Load correctly the needed javascripts.
 */
function _service_links_add_js($javascript) {
  global $is_https;
  static $external_js;

  if (!is_array($javascript)) {
    $javascript = array($javascript);
  }

  if (!isset($external_js)) {
    $external_js = array();
  }

  foreach ($javascript as $js) {
    if (strpos($js, '://') !== FALSE) {
      if ($is_https) {
        // Ensure that we embed the https js library.
        $js = str_replace('http://', 'https://', $js);
      }

      if (!in_array($js, $external_js)) {
        drupal_add_js($js, array('type' => 'external'));
        $external_js[] = $js;
      }
    }
    else {
      drupal_add_js(service_links_expand_path($js, 'javascript'));
    }
  }
}

/**
 * Fill an array with tags and the content to substitute.
 */
function _service_links_get_tags($node, &$settings) {
  if (!empty($node)) {
    $title = _service_links_get_node_title($node, $settings); 

    $path = _service_links_get_node_path($node);
    $url = url("$path", array('absolute' => TRUE, 'query' => service_links_get_query($settings['text_to_append'])));

    $query = drupal_get_path_alias("node/{$node->nid}");

    $body = field_get_items('node', $node, 'body');
    $teaser = $body ? strip_tags(text_summary($body[0]['value'])) : '';

    $nid = $node->nid;
  }
  elseif (isset($settings['data'])) {
    $title = isset($settings['data']['title']) ? $settings['data']['title'] : '';
    $url = isset($settings['data']['url']) ? $settings['data']['url'] : '';
    $query = isset($settings['data']['query']) ? $settings['data']['query'] : '';
    $teaser = isset($settings['data']['teaser']) ? $settings['data']['teaser'] : '';
    $nid = isset($settings['data']['node_id']) ? $settings['data']['node_id'] : NULL;
  }
  else {
    $title = drupal_get_title();

    $url = _service_links_get_page_url(NULL, $settings);

    // The query shouldn't follow the front_page alias but point the original page.
    $query = drupal_get_normal_path($_GET['q']);
    
    $teaser = '';
    $nid = NULL;
  }

  $source = variable_get('site_name', 'Drupal');

  $long_url = $url;

  $front_page = url('<front>', array('absolute' => TRUE));
  if ((variable_get('clean_url', 0) == 0) && (strpos($front_page, '?q=') === FALSE)) {
    $front_page .= '?q=';
  }
  else {
    // Ensure a trailing slash on multilingual sites with clean url on.
    $front_page = preg_replace('/([0-9a-z-_]+)$/i', '\1/', $front_page);
  }

  switch ($settings['short_links_use']) {
    case SERVICE_LINKS_SHORT_URL_USE_NEVER:
      $short_url = $url;
      break;
    case SERVICE_LINKS_SHORT_URL_USE_WHEN_REQUESTED:
      $short_url = service_links_short_url($url, $nid);
      break;
    case SERVICE_LINKS_SHORT_URL_USE_ALWAYS:
      $short_url = service_links_short_url($url, $nid);
      $url = $short_url;
      break;
  }

  $settings['tag'] = array(
    'raw-encoded-title' => '<raw-encoded-title>',
    'raw-encoded-url' => '<raw-encoded-url>',
    'raw-encoded-teaser' => '<raw-encoded-teaser>',
    'raw-encoded-short-url' => '<raw-encoded-short-url>',
    'raw-encoded-long-url' => '<raw-encoded-long-url>',
    'raw-encoded-query' => '<raw-encoded-query>',
    'raw-encoded-source' => '<raw-encoded-source>',
    'encoded-title' => '<encoded-title>',
    'encoded-url' => '<encoded-url>',
    'encoded-teaser' => '<encoded-teaser>',
    'encoded-short-url' => '<encoded-short-url>',
    'encoded-long-url' => '<encoded-long-url>',
    'encoded-query' => '<encoded-query>',
    'encoded-source' => '<encoded-source>',
    'teaser' => '<teaser>',
    'short-url' => '<short-url>',
    'long-url' => '<long-url>',
    'source' => '<source>',
    'node-id' => '<node-id>',
    'query' => '<query>',
    'url' => '<url>',
    'title' => '<title>',
    'front-page' => '<front-page>',
  );
  $settings['subst'] = array(
    //'raw-encoded-title' => rawurlencode($title),
    'raw-encoded-title' => $title,
    //'raw-encoded-url' => rawurlencode($url),
    'raw-encoded-url' => $url,
    //'raw-encoded-teaser' => rawurlencode($teaser),
    'raw-encoded-teaser' => $teaser,
    //'raw-encoded-short-url' => rawurlencode($short_url),
    'raw-encoded-short-url' => $short_url,
    //'raw-encoded-long-url' => rawurlencode($long_url),
    'raw-encoded-long-url' => $long_url,
    //'raw-encoded-query' => rawurlencode($query),
    'raw-encoded-query' => $query,
    //'raw-encoded-source' => rawurlencode($source),
    'raw-encoded-source' => $source,
    //'encoded-title' => urlencode($title),
    'encoded-title' => $title,
    //'encoded-url' => urlencode($url),
    'encoded-url' => $url,
    //'encoded-teaser' => urlencode($teaser),
    'encoded-teaser' => $teaser,
    //'encoded-short-url' => urlencode($short_url),
    'encoded-short-url' => $short_url,
    //'encoded-long-url' => urlencode($long_url),
    'encoded-long-url' => $long_url,
    //'encoded-query' => urlencode($query),
    'encoded-query' => $query,
    //'encoded-source' => urlencode($source),
    'encoded-source' => $source,
    //Not needed
    'teaser' => $teaser,
    'short-url' => $short_url,
    'long-url' => $long_url,
    'source' => $source,
    'node-id' => $nid,
    'query' => $query,
    'url' => $url,
    'title' => $title,
    'front-page' => $front_page,
  );
}

/**
 * Return the url for not-node pages.
 */
function _service_links_get_page_url($node, $settings) {
  if ($settings['link_to_front'] || drupal_is_front_page()) {
    $url = url('<front>', array('absolute' => TRUE, 'query' => service_links_get_query($settings['text_to_append'])));
  }
  else {
    $url = url($_GET['q'], array('absolute' => TRUE, 'query' => service_links_get_query($settings['text_to_append'])));
  }

  return $url; 
}

/**
 * Return the properly title.
 */
function _service_links_get_node_title($node, $settings) {
  $title = isset($node->title) ? $node->title : '';

  switch ($settings['title_override']) {
    case SERVICE_LINKS_TAG_TITLE_NODE:
      break;
    case SERVICE_LINKS_TAG_TITLE_OVERRIDE:
      $title = str_replace('<title>', $title, $settings['title_text']);
      break;
    case SERVICE_LINKS_TAG_TITLE_TOKEN:
      $title = token_replace($settings['title_text'], array('node' => $node));
      break;
  }

  return $title;
}

/**
 * Detect if the node is used as front page and provide
 * the path to use.
 */
function _service_links_get_node_path($node) {
  static $front_page;

  if (!isset($front_page)) {
    $front_page = variable_get('site_frontpage', 'node');
  }

  $path = "node/$node->nid";
  if (($path == $front_page) || (isset($node->uri) && ((object)$node->uri['path'] == $front_page))) {
    $path = '<front>';
  }

  return $path;
}

/**
 * Check if the service links should be displayed for the content type,
 * for category or one of the other selected options.
 */
function service_links_show($node) {
  $links_show = FALSE;
  $category_type = FALSE;
  global $user;

  if (!_service_links_match_path()) {
    return FALSE;
  }

  if (in_array(strtolower(arg(0)), array('print', 'printpdf', 'printmail'))) {
    return FALSE;
  }

  if (variable_get('service_links_hide_for_author', FALSE) && ($user->uid == $node->uid)) {
    return FALSE;
  }

  if (variable_get('service_links_hide_if_unpublished', FALSE) && ($node->status == '0')) {
    return FALSE;
  }

  $node_type = in_array($node->type, variable_get('service_links_node_types', array()), TRUE);
  if (module_exists('taxonomy') && !empty($node->field_tags)) {
    $categories_allowed = variable_get('service_links_category_types', array());
    $language = isset($node->field_tags[$node->language]) ? $node->language : 'und';

    foreach ($node->field_tags[$language] as $term) {
      $category_type |= in_array($term['tid'], $categories_allowed, FALSE);
    }
  }
  if ($node_type || $category_type) {
    $links_show = TRUE;
  }

  return $links_show;
}

/**
 * Match the current path with the list or the code
 * inserted in the configuration page.
 */
function _service_links_match_path() {
  static $page_match;

  if (isset($page_match)) {
    return $page_match;
  }

  $pages = variable_get('service_links_page_match_for_node', '');
  $visibility = variable_get('service_links_visibility_for_node', SERVICE_LINKS_VISIBILITY_NOT_LISTED);
  if (!empty($pages)) {
    // Convert path to lowercase. This allows comparison of the same path
    // with different case. Ex: /Page, /page, /PAGE.
    $pages = drupal_strtolower($pages);

    if ($visibility < SERVICE_LINKS_VISIBILITY_PHP) {
      $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));
      // Compare with the internal and path alias (if any).
      $page_match = drupal_match_path($path, $pages);
      if ($path != $_GET['q']) {
        $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
      }
      // When $visibility has a value of 0, the links are displayed on
      // all pages except those listed in $pages. When set to 1, it
      // is displayed only on those pages listed in $pages.
      $page_match = !($visibility xor $page_match);
    }
    elseif (module_exists('php')) {
      $page_match = php_eval($pages);
    }
    else {
      $page_match = FALSE;
    }
  }
  else {
    $page_match = TRUE;
  }

  return $page_match;
}

/**
 * Load the static settings and keep clear the render function.
 */
function _service_links_load_settings() {
  static $settings = NULL;

  if (!isset($settings)) {
    $settings['short_links_use'] = variable_get('service_links_short_links_use', SERVICE_LINKS_SHORT_URL_USE_NEVER);

    $settings['attributes'] = array('rel' => 'nofollow');
    if (variable_get('service_links_new_window', 0)) {
      $settings['attributes'] += array('target' => '_blank');
    }
    $settings['style'] = variable_get('service_links_style', SERVICE_LINKS_STYLE_TEXT);

    $settings['link_weight'] = variable_get('service_links_weight', array());
    $settings['link_show'] = array_filter(variable_get('service_links_show', array()));

    $settings['text_to_append'] = strip_tags(variable_get('service_links_append_to_url', ''));

    $settings['title_override'] = variable_get('service_links_override_title', SERVICE_LINKS_TAG_TITLE_NODE);
    $settings['title_text'] = variable_get('service_links_override_title_text', '<title>');

    $settings['link_to_front'] = FALSE;
  }

  return $settings;
}

/**
  * Expand the path around a filename depending from the context.
 *
 * @param $filename
 *   If NULL the function return only the path with trailing slash.
 * @param $context
 *   Define what path should consider this function.
 * @param $default
 *   Concerning the image path is useful define a default path if
 *   the alternative is not set up.
 *
 * @return
 *   A string with the full filename or the path.
 */
function service_links_expand_path($filename = NULL, $context = 'icons', $default = 'preset') {
  static $sl_paths;
  static $sl_checkpath;

  if (strpos($filename, '/') !== FALSE) {
    return $filename;
  }

  if (!isset($sl_paths)) {
    $sl_paths['base'] = drupal_get_path('module', 'service_links');

    $sl_paths += array(
      'preset' => $sl_paths['base'] .'/images',
      'javascript' => $sl_paths['base'] .'/js',
      'css' => $sl_paths['base'] .'/css',
    );

    $sl_checkpath = array(
      'preset' => FALSE,
      'javascript' => FALSE,
      'css' => FALSE,
    );
  }

  if (!isset($sl_paths[$context])) {
    $sl_paths[$context] = variable_get("service_links_path_{$context}", '');
    if (empty($sl_paths[$context])) {
      $sl_paths[$context] = $sl_paths[$default];
    }

    $sl_checkpath[$context] = variable_get("service_links_check_{$context}", FALSE);
  }

  if (isset($filename)) {
    if ($sl_checkpath[$context]) {
      if (file_exists($sl_paths[$context] .'/'. $filename)) {
        return $sl_paths[$context] .'/'. $filename;
      }
      else {
        return $sl_paths[$default] .'/'. $filename;
      }
    }
    else {
      return $sl_paths[$context] .'/'. $filename;
    }
  }
  else {
    return $sl_paths[$context];
  }
}

/**
 * Split a query string in the properly array.
 */
function service_links_get_query($query_str) {
  if (empty($query_str)) {
    return NULL;
  }
  $result = array();

  // parse_str() replaces dots and squares with underscores.
  $query_str = explode('&', $query_str);
  foreach($query_str as $q) {
    $key_value = explode('=', $q);
    $result[$key_value[0]] = isset($key_value[1]) ? $key_value[1] : '';
  }

  return $result;
}

/**
 * Implements hook_views_api().
 */
function service_links_views_api() {
  return array(
    'api' => 2,
    'path' => drupal_get_path('module', 'service_links'),
  );
}
