<?php
// $Id$

/**
 * @file
 * An example to define a simple field, widget, and formatter.
 * A module could define only a field, only a widget, only a
 * formatter, or any combination. Widgets and formatters must
 * declare what kind of field they work with, which can be any
 * existing field as well as any new field the module creates.
 */

//==========================================//
// DEFINING A FIELD
//==========================================//

/**
 * Implementation of hook_field_info().
 */
function pidfield_field_info() {
  return array(
    // The machine name of the field,
    // no more than 32 characters.
    'pidfield' => array(
      // The human-readable label of the field that will be
      // seen in the Manage fields screen.
      'label' => t('Fedora PID field'),
      // A description of what type of data the field stores.
      'description' => t('Store a reference to a PID in this site\'s Fedora repository.'),
      // An icon to use in Panels.
      'content_icon' => 'icon_content_text.png',
    ),
  );
}

/**
 * Implementation of hook_field_settings().
 */
function pidfield_field_settings($op, $field) {
  switch ($op) {
    // Create the form element to be used on the field
    // settings form. Field settings will be the same for
    // all shared instances of the same field and should
    // define the way the value will be stored
    // in the database.
    case 'form':
      $form = array();
      $form['max_length'] = array(
        '#type' => 'textfield',
        '#title' => t('Maximum length'),
        '#default_value' => is_numeric($field['max_length']) ? $field['max_length'] : 64,
        '#required' => FALSE,

        // Use #element_validate to validate the settings.
        '#element_validate' => array('_pidfield_length_validate'),
        '#description' => t('The maximum length of the field in characters. Must be a number between 1 and 255'),
      );
      return $form;

    // Return an array of the names of the field settings
    // defined by this module. These are the items that
    // CCK will store in the field definition
    // and they will be available in the $field array.
    // This should match the items defined in 'form' above.
    case 'save':
      return array('max_length');

    // Define the database storage for this field using
    // the same construct used by schema API. Most fields
    // have only one column, but there can be any number
    // of different columns. After the schema API values,
    // add two optional values to each column,
    //  'views', to define a Views field
    //  'sortable', to add a Views sort field
    case 'database columns':
      $columns['value'] = array(
        'type' => 'varchar',
        'length' => is_numeric($field['max_length']) ? $field['max_length'] : 64,
        'not null' => FALSE,
        'sortable' => TRUE,
        'views' => TRUE,
      );
      return $columns;

    // Optional: Make changes to the default $data array
    // created for Views. Omit this if no changes are
    // needed, use it to add a custom handler or make
    // other changes.
    case 'views data':
      // Start with the $data created by CCK
      // and alter it as needed. The following
      // code illustrates how you would retrieve
      // the necessary data.
      $data = content_views_field_views_data($field);
      $db_info = content_database_info($field);
      $table_alias = content_views_tablename($field);
      $field_data = $data[$table_alias][$field['field_name'] .'_value'];
      // Make changes to $data as needed here.
      return $data;
  }
}

/**
 * Custom validation of settings values.
 *
 * Create callbacks like this to do settings validation.
 */
function _pidfield_length_validate($element, &$form_state) {
  $value = $form_state['values']['max_length'];
  if ($value && !is_numeric($value)|| $value < 1 || $value > 255) {
    form_set_error('max_length', t('"Max length" must be a number between 1 and 64.'));
  }
}

/**
 * Implementation of hook_field().
 */
function pidfield_field($op, &$node, $field, &$items, $teaser, $page) {
  switch ($op) {
    // Do validation on the field values here. The widget
    // will do its own validation and you cannot make any
    // assumptions about what kind of widget has been used,
    // so don't validate widget values, only field values.
    case 'validate':
      if (is_array($items)) {
        foreach ($items as $delta => $item) {
          // The error_element is needed so that CCK can
          // set an error on the right sub-element when
          // fields are deeply nested in the form.
          $error_element = isset($item['_error_element']) ? $item['_error_element'] : '';
          if (is_array($item) && isset($item['_error_element'])) unset($item['_error_element']);
          if (!empty($item['value'])) {
            if (!empty($field['max_length']) && drupal_strlen($item['value']) > $field['max_length']) {
              form_set_error($error_element, t('%name: the value may not be longer than %max characters.', array('%name' => $field['widget']['label'], '%max' => $field['max_length'])));
            }
          }
        }
      }
      return $items;

    // This is where you make sure that user-provided
    // data is sanitized before being displayed.
    case 'sanitize':
      foreach ($items as $delta => $item) {
        $pid_field_text = check_plain($item['value']);
        $items[$delta]['safe'] = $pid_field_text;
      }
  }
}

/**
 * Implementation of hook_content_is_empty().
 *
 * CCK has no way to know if something like a zero is
 * an empty value or a valid value, so return
 * TRUE or FALSE to a populated field $item array.
 * CCK uses this to remove empty multi-value elements
 * from forms.
 */
function pidfield_content_is_empty($item, $field) {
  if (empty($item['value'])) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Implementation of hook content_generate().
 *
 * Optional, provide dummy value for nodes created
 * by the Devel Generate module.
 */
function pidfield_content_generate($node, $field) {
  $node_field = array();
  // Generate a value that respects max_length.
  if (empty($field['max_length'])) {
    $field['max_length'] = 12;
  }
  $node_field['value'] = user_password($field['max_length']);
  return $node_field;
}

/**
 * Implementation of hook_token_list()
 * and hook_token_values().
 *
 * Optional, provide token values for this field.
 */
function pidfield_token_list($type = 'all') {
  if ($type == 'field' || $type == 'all') {
    $tokens = array();

    $tokens['pidfield']['raw']       = t('Just the PID itself.');
    $tokens['pidfield']['formatted'] = t('A PID with a hyperlink');

    return $tokens;
  }
}

function pidfield_token_values($type, $object = NULL) {
  if ($type == 'field') {
    $item = $object[0];

    $tokens['raw']  = $item['value'];
    $tokens['formatted'] = isset($item['view']) ? $item['view'] : '';
    return $tokens;
  }
}

//==========================================//
// DEFINING A FORMATTER
//==========================================//

/**
 * Implementation of hook_theme().
 */
function pidfield_theme() {
  return array(
    // Themes for the formatters.
    'pidfield_formatter_default' => array(
      'arguments' => array('element' => NULL),
    ),
    'pidfield_formatter_plain' => array(
      'arguments' => array('element' => NULL),
    ),
  );
}

/**
 * Implementation of hook_field_formatter_info().
 *
 * All fields should have a 'default' formatter.
 * Any number of other formatters can be defined as well.
 * It's nice for there always to be a 'plain' option
 * for the raw value, but that is not required.
 *
 */
function pidfield_field_formatter_info() {
  return array(
    // The machine name of the formatter.
    'default' => array(
      // The human-readable label shown on the Display
      // fields screen.
      'label' => t('Default'),
      // An array of the field types this formatter
      // can be used on.
      'field types' => array('pidfield'),
      // CONTENT_HANDLE_CORE:   CCK will pass the formatter
      // a single value.
      // CONTENT_HANDLE_MODULE: CCK will pass the formatter
      // an array of all the values. None of CCK's core
      // formatters use multiple values, that is an option
      // available to other modules that want it.
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
    'plain' => array(
      'label' => t('Plain text'),
      'field types' => array('pidfield'),
      'multiple values' => CONTENT_HANDLE_CORE,
    ),
  );
}

/**
 * Theme function for 'default' example field formatter.
 *
 * $element['#item']: the sanitized $delta value for the item,
 * $element['#field_name']: the field name,
 * $element['#type_name']: the $node->type,
 * $element['#formatter']: the $formatter_name,
 * $element'#node']: the $node,
 * $element['#delta']: the delta of this item, like '0',
 *
 */
function theme_pidfield_formatter_default($element) {
  $pid = $element['#item']['safe'];
  if(!empty($pid)) {
    return fedora_repository_get_items($pid);
  }
  return null;
}

/**
 * Theme function for 'plain' example field formatter.
 */
function theme_pidfield_formatter_plain($element) {
  return strip_tags($element['#item']['safe']);
}

//==========================================//
// DEFINING A WIDGET
//==========================================//

/**
 * Implementation of hook_widget_info().
 *
 * Here we indicate that the content module will handle
 * the default value and multiple values for these widgets.
 *
 * Callbacks can be omitted if default handing is used.
 * They're included here just so this module can be used
 * as an example for custom modules that might do things
 * differently.
 */
function pidfield_widget_info() {
  return array(
    // The machine name of the widget, no more than 32
    // characters.
    'pidfield_widget' => array(
      // The human-readable label of the field that will be
      // seen in the Manage fields screen.
      'label' => t('PID Field widget'),
      // An array of the field types this widget can be
      // used with.
      'field types' => array('pidfield'),
      // Who will handle multiple values, default is core.
      // 'CONTENT_HANDLE_MODULE' means the module does it.
      // See optionwidgets for an example of a module that
      // handles its own multiple values.
      'multiple values' => CONTENT_HANDLE_CORE,
      'callbacks' => array(
        // Who will create the default value, default is core.
        // 'CONTENT_CALLBACK_CUSTOM' means the module does it.
        // 'CONTENT_CALLBACK_NONE' means this widget has
        // no default value.
        'default value' => CONTENT_CALLBACK_DEFAULT,
      ),
    ),
  );
}

/**
 * Implementation of hook_widget_settings().
 */
function pidfield_widget_settings($op, $widget) {
  switch ($op) {
    // Create the form element to be used on the widget
    // settings form. Widget settings can be different
    // for each shared instance of the same field and
    // should define the way the value is displayed to
    // the user in the edit form for that content type.
    case 'form':
      $form = array();
      $size = (isset($widget['size']) && is_numeric($widget['size'])) ? $widget['size'] : 60;
      $form['size'] = array(
        '#type' => 'textfield',
        '#title' => t('Size of textfield'),
        '#default_value' => $size,
        '#element_validate' => array('_element_validate_integer_positive'),
        '#required' => TRUE,
      );
      return $form;

    // Return an array of the names of the widget settings
    // defined by this module. These are the items that
    // CCK will store in the widget definition and they
    // will be available in the $field['widget'] array.
    // This should match the items defined in 'form' above.
    case 'save':
      return array('size');
  }
}

/**
 * Implementation of hook_widget().
 *
 * Attach a single form element to the form.
 *
 * CCK core fields only add a stub element and builds
 * the complete item in #process so reusable elements
 * created by hook_elements can be plugged into any
 * module that provides valid $field information.
 *
 * Custom widgets that don't care about using hook_elements
 * can be built out completely at this time.
 *
 * If there are multiple values for this field and CCK is
 * handling multiple values, the content module will call
 * this function as many times as needed.
 *
 * @param $form
 *   the entire form array,
 *   $form['#node'] holds node information
 * @param $form_state
 *   the form_state,
 *   $form_state['values'][$field['field_name']]
 *   holds the field's form values.
 * @param $field
 *   the field array
 * @param $items
 *   array of default values for this field
 * @param $delta
 *   the order of this item in the array of
 *   subelements (0, 1, 2, etc)
 *
 * @return
 *   the form item for a single element for this field
 */
function pidfield_widget(&$form, &$form_state, $field, $items, $delta = 0) {

  $element['value'] = array(
    '#type' => 'textfield',
    '#title' => $field['widget']['label'],
    '#default_value' => isset($items[$delta]['value']) ? $items[$delta]['value'] : NULL,
    '#autocomplete_path' => $element['#autocomplete_path'],
    '#size' => !empty($field['widget']['size']) ? $field['widget']['size'] : 60,
    '#attributes' => array('class' => 'pidfield'),
    '#maxlength' => !empty($field['max_length']) ? $field['max_length'] : NULL,
  );

  // Used so that hook_field('validate') knows where to
  // flag an error in deeply nested forms.
  if (empty($form['#parents'])) {
    $form['#parents'] = array();
  }
  $element['_error_element'] = array(
    '#type' => 'value',
    '#value' => implode('][', array_merge($form['#parents'], array('value'))),
  );

  return $element;
}

function get_node_references_for_fedora_item($item) {
  $result = db_query("SELECT *
                      FROM {content_node_field} nf
                      INNER JOIN {content_node_field_instance} ni ON nf.field_name = ni.field_name
                      WHERE nf.type =  'pidfield'");
  while ($field = db_fetch_array($result)) {


     $db_info = content_database_info($field);





     $ids = db_query("SELECT nid FROM {". $db_info['table'] ."} WHERE ". $field['field_name'] ."_value=\"". $item->pid."\"");

     $results = array();
     while ($data = db_fetch_object($ids)) {
       //$additions[] = node_load($data->vid);

       $results[] = $data->nid;

       //$referred_node = node_load(array('nid'=>$data->nid) );

     }
     return $results;
  }

}

function fedora_pidfield_redirect_to_node($item) {
  $node_references = get_node_references_for_fedora_item($item);
  if (!empty($node_references)) {
    if (strstr( drupal_get_destination(), urlencode('fedora/repository'))) {
      drupal_goto(drupal_get_path_alias("node/".$node_references[0]));
    }
  }
}