<?php

/**
 * Maximum username length.
 */
define('TWITTER_USERNAME_MAX_LENGTH', 16);

/**
 * Implements hook_element_info().
 * Define 'twitter_username' field type.
 */
function twitter_username_element_info() {
  $elements = array();
  $elements['twitter_username'] =  array(
    '#input' => TRUE,
    '#process' => array('twitter_username_field_process'),
    '#theme_wrappers' => array('form_element'),
  );
  return $elements;
}

function twitter_username_field_process($element, $form_state, $complete_form) {
  $element['twitter_username'] = array(
    '#type' => 'textfield',
    '#default_value' => isset($element['#value']['twitter_username']) ? check_plain($element['#value']['twitter_username']) : NULL,
    '#required' => $element['#required'],
    '#maxlength' => TWITTER_USERNAME_MAX_LENGTH,
    '#size' => TWITTER_USERNAME_MAX_LENGTH,
    '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
    '#delta' => $element['#delta'],
    '#field_prefix' => "@",
  );
  return $element;
}

/**
 * Implements hook_field_info().
 */
function twitter_username_field_info() {
  return array(
    'twitter_username' => array(
      'label' => t("Twitter username"),
      'description' => t("Store a twitter username, and provide formatters, prefixed by @"),
      'settings' => array('max_length' => TWITTER_USERNAME_MAX_LENGTH),
      'instance_settings' => array('text_processing' => 0),
      'default_widget' => 'twitter_username',
      'default_formatter' => 'twitter_username_default',
      'instance_settings' => array(
        'validate_existance' => FALSE,
      ),
    ),
  );
}

/**
 * Implements hook_field_is_empty().
 */
function twitter_username_field_is_empty($item, $field) {
  return empty($item['twitter_username']);
}

/**
 * Implements hook_field_validate().
 */
function twitter_username_field_validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
  foreach ($items as $delta => $item) {
    if (!empty($item['twitter_username'])) {
      // Ensure the username contains only valid characters.
      if (!preg_match('/^[A-Za-z0-9_]+$/', $item['twitter_username'])) { // '/^\w+$/'
        $errors[$field['field_name']][$langcode][$delta][] = array(
          'error' => "twitter_username_invalid",
          'message' => t("Invalid twitter username (alphanumerics only)"),
        );
      }
      // Ensure the username is actually registered.
      elseif ($instance['settings']['validate_existance']) {
        // Query the Twitter User page.
        // Since v1.1, we could not request the API with OAuth token.
        $url = url(
          'https://twitter.com/' .$item['twitter_username'],
          array('external' => TRUE)
        );
        $response = drupal_http_request($url, array('method'=>'HEAD'));

        // HTTP status code 404 means the username doesn't exist.
        if ($response->code == 404) {
          $errors[$field['field_name']][$langcode][$delta][] = array(
            'error' => 'twitter_username_not_found',
            'message' => t("The twitter username doesn't exist."),
          );
        }
        // Log and display an  error if we get an unexpected status code.
        elseif ($response->code != 200) {
          $vars = array(
            '%code' => $response->code,
            '%username' => $item['twitter_username'],
          );
          drupal_set_message(t("The Twitter API returned the unexpected status code %code. That means it's not guaranteed the username %username actually exists.", $vars), 'warning');
          watchdog('twitter_username', "The Twitter API returned the unexpected status code %code. That means it's not guaranteed the username %username actually exists.", $vars, WATCHDOG_WARNING, $url);
        }
      }
    }
  }
}

/**
 * Implements hook_field_widget_info().
 */
function twitter_username_field_widget_info() {
  return array(
    'twitter_username' => array(
      'label' => t("Twitter username"),
      'field types' => array('twitter_username'),
      'multiple values' => FIELD_BEHAVIOR_DEFAULT,
    ),
  );
}

/**
 * Implements hook_field_widget_form().
 */
function twitter_username_field_widget_form(&$form, &$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $element += array(
    '#type' => $instance['widget']['type'],
    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
  );
  return $element;
}

/**
 * Implements hook_field_widget_error().
 */
function twitter_username_field_widget_error($element, $error, $form, &$form_state) {
  form_error($element, $error['message']);
}

/**
 * Implements hook_field_instance_settings_form().
 */
function twitter_username_field_instance_settings_form($field, $instance) {
  $form['validate_existance'] = array(
    '#type' => 'checkbox',
    '#title' => t('Ensure the twitter username exists'),
    '#description' => t('Use the Twitter API to ensure the username actually exists. Note that this is an expensive network call. To avoid timeouts only use this when you have a limited amount of field values. If the Twitter API is not reachable a watchdog error will be logged and the name accepted.'),
    '#default_value' => $instance['settings']['validate_existance'],
  );

  return $form;
}

/**
 * Implements hook_field_formatter_info().
 * Defines 2 types of formatters, plain text and link.
 */
function twitter_username_field_formatter_info() {
  return array(
    'twitter_username_default' => array(
      'label' => t("Twitter username, as plain text"),
      'field types' => array('twitter_username'),
    ),
    'twitter_username_link' => array(
      'label' => t("Twitter username, as link"),
      'field types' => array('twitter_username'),
    ),
  );
}

/**
 * Implements hook_field_formatter_view().
 */
function twitter_username_field_formatter_view($entity_type, $entity, $field, $instance, $langcode, $items, $display) {
  $element = array();
  foreach ($items as $delta => $item) {
    $element[$delta]['#markup'] = theme('twitter_username_formatter_' . $display['type'], array('element' => $item));
  }
  return $element;
}

/**
 * Implements hook_theme().
 * Defines a theme function by formatter, to allow overrides.
 */
function twitter_username_theme() {
  return array(
    'twitter_username_formatter_twitter_username_default' => array(
      'variables' => array('element' => NULL),
    ),
    'twitter_username_formatter_twitter_username_link' => array(
      'variables' => array('element' => NULL),
    ),
  );
}

function theme_twitter_username_formatter_twitter_username_default($vars) {
  $twitter_username = check_plain($vars['element']['twitter_username']);
  return "@" . $twitter_username;
}

function theme_twitter_username_formatter_twitter_username_link($vars) {
  $twitter_username = check_plain($vars['element']['twitter_username']);
  return l("@" . $twitter_username, 'http://twitter.com/' . $twitter_username);
}

