<?php

/**
 * Implement hook_ckeditor_plugin
 */
function entityfilter_ckeditor_plugin()
{
  return array(
    'entityfilter' => array(
      'name' => 'entityfilter',
      'desc' => t('Allows the referencing of properties on entities'),
      'path' => drupal_get_path('module', 'entityfilter') . '/ckeditor/'
    )
  );
}

/**
 * Implements hook_preprocess_html()
 *
 * FIXME - This needs altering so that we only include the drupal.ajax when we
 * actually need it (when there's a CKEDITOR on the page)
 */
function entityfilter_preprocess_html()
{
  // We need to include our misc/ajax.js, else we can't be sure if it's included when we need it.
  drupal_add_library('system', 'drupal.ajax');
}

/**
 * Implements hook_menu().
 */
function entityfilter_menu()
{
  $items['ckeditor/entityfilter'] = array(
    'title' => 'entityfilter',
    'page callback' => 'entityfilter_get_suggesions',
    'access arguments' => array(
      'access content'
    ),
    'type' => MENU_CALLBACK,
    'delivery callback' => 'drupal_json_output',
    'file' => 'entityfilter.ajax.inc'
  );
  return $items;
}

/**
 * Implements hook_filter_info()
 */
function entityfilter_filter_info()
{
  return array(
    'entityfilter' => array(
      'title' => t('Entity property input filter'),
      'description' => t('Allows you to dynamically reference the properties of an entity, including the label.'),
      'process callback' => 'entityfilter_filter',
      'tips callback' => 'entityfilter_filter_tips'
    )
  );
}

/**
 * Tips callback for the above filter.
 */
function entityfilter_filter_tips()
{
  return 'Dynamically generate entity property text using <strong>[entity:<em>{entity type}</em>:<em>{entity ID}</em>(:<em>{property name - defaults to label}</em>)]</strong> e.g:' . theme('item_list', array(
    'items' => array(
      '[entity:taxonomy_term:3:name] would be converted to the name of term 3 e.g. "Banana"',
      '[entity:user:2:name] would be converted to the name of user 2 e.g. "Mike Hunt"'
    )
  )) . 'Current valid entities are: ' . implode('; ', array_keys(array_merge(entity_get_info(), entityfilter_get_entity_aliases()))) . '.';
}

/**
 * Return an array defining the aliases for entity names.  This is mainly used
 * to tweak the taxonomy_term and taxonomy_vocabulary entity names.
 */
function entityfilter_get_entity_aliases($reset = false)
{
  $aliases = drupal_static(__FUNCTION__, false, $reset);
  if (!$aliases) {
    $data = cache_get('entityfilter_aliases');
    if ($data) {
      $aliases = $data->data;
    } else {
      $aliases = array(
        'term' => 'taxonomy_term',
        'vocabulary' => 'taxonomy_vocabulary'
      );
      drupal_alter('entityfilter_entity_aliases', $aliases);
      cache_set('entityfilter_aliases', $aliases);
    }
  }
  return $aliases;
}

/**
 * Look for our special code, and replace the shizzle!
 */
function entityfilter_filter($text, $filter)
{
  if (preg_match_all('/\[entity[^\]]*]/i', $text, $matches)) {
    if (count($matches[0])) {
      $aliases = entityfilter_get_entity_aliases();
      foreach ($matches[0] as $match) {
        $replaced = false;
        // Wrap everything in a try/catch block to ensure that users can not
        // WSOD a site just be entering a property that doesn't exist (or
        // something similar).
        try {
          // Get the bits and bobs we're looking for.
          $match_parts = explode(':', substr($match, 1, -1));
          // Default to label.
          if (count($match_parts) == 3) {
            $match_parts[] = 'label';
          }
          // If we have the right number of parts, we try to load the entity.
          if (count($match_parts) == 4) {
            $entity_type = isset($aliases[$match_parts[1]]) ? $aliases[$match_parts[1]] : $match_parts[1];
            // check the entity_type is a valid entity name
            if (entity_get_info($entity_type)) {
              // We try to load the entity.
              $entity = entity_load($entity_type, array(
                $match_parts[2]
              ));
              if ($entity) {
                // We have an entity, the user did something right.
                $entity = array_pop($entity);
                // Load an entity wrapper
                $wrapper = entity_metadata_wrapper($entity_type, $entity);
                // Find the property we want if we have "label".
                if ($match_parts[3] == 'label') {
                  $entity_info = entity_get_info($entity_type);
                  $match_parts[3] = isset($entity_info['entity keys']['label']) ? $entity_info['entity keys']['label'] : 'name';
                }
                $value = $wrapper->{$match_parts[3]}->value();
                if ($value && is_string($value)) {
                  $replaced = true;
                  $text = str_replace($match, $value, $text);
                } else if (is_array($value) && isset($value['value']) && is_string($value['value'])) {
                  $replaced = true;
                  $text = str_replace($match, $value['value'], $text);
                }
              }
            }
          }
        } catch (Exception $e) {;
        }
        if (!$replaced) {
          // Note, we only show the error message if the user is logged in.  We
          // do this to ensure that the page can still be cached, as pages with
          // errors on are not cached (I think).
          if (user_is_logged_in()) {
            drupal_set_message(t('Error processing entity filter "@match"', array(
              '@match' => $match
            )), 'error', false);
          }
          // Show the match wrapped in an error class so that it's obvious to
          // the user where they have fucked up.
          $text = str_replace($match, '<span class="error">' . $match . '</span>', $text);
        }
      }
    }
  }
  return $text;
}
