<?php

/**
 * @file
 * Defines a CCK field for source code with GeSHi syntax highlighting.
 *
 * @todo: is the GeSHi CSS file always loaded when needed?
 */

/**
 * Implementation of hook_theme().
 */
function geshifield_theme() {
  return array(
    'geshifield_textarea' => array(
       'arguments' => array('element' => NULL),
    ),
    'geshifield_formatter_default' => array(
       'arguments' => array('element' => NULL),
    ),
    'geshifield_formatter_nohighlighting' => array(
       'arguments' => array('element' => NULL),
    ),
    'geshifield_formatter_trimmed' => array(
       'arguments' => array('element' => NULL),
    ),
  );
}


/**
 * Implementation of hook_field_info().
 */
function geshifield_field_info() {
  return array(
    'geshifield' => array(
      // @todo: better label? "Source code field"?
      'label' => t('GeSHi field'),
      'description' => t('Source code text field with GeSHi syntax highlighting.'),
    )
  );
}

/**
 * Implementation of hook_field_settings().
 */
function geshifield_field_settings($op, $field) {
  switch ($op) {
    case 'database columns':
      $columns =  array(
        'sourcecode' => array(
          'type' => 'text',
          'size' => 'big',
          'not null' => FALSE,
          'sortable' => TRUE,
          'views' => TRUE, //@todo what does this do?
        ),
        'language' => array(
          'type' => 'varchar',
          'length' => 32,
          'not null' => FALSE,
          'sortable' => TRUE,
          'views' => TRUE, //@todo what does this do?
        ),
      );
      return $columns;
  }
}


/**
 * Implementation of hook_field().
 */
function geshifield_field($op, &$node, $field, &$items, $teaser, $page) {
  // Nothing to do here.
  // Typically only the validition operation is needed in this hook
  // but for geshifield even this is not needed.
}

/**
 * Implementation of hook_content_is_empty().
 */
function geshifield_content_is_empty($item, $field) {
  return empty($item['sourcecode']);
}

/**
 * Implementation of hook_content_diff_values().
 *
 * Provides support for viewing differences between node revisions.
 * More info: diff module (diff/node.inc), cck module
 * (cck/includes/content.diff.inc)
 */
function geshifield_content_diff_values($node, $field, $items) {
  $result = array();
  foreach ($items as $item) {
    if (isset($item['sourcecode']) && isset($item['language'])) {
      $result[] = t('[Language: !language]', array('!language' => $item['language']));
      foreach (explode("\n", $item['sourcecode']) as $i) {
        $result[] = $i;
      }
    }
  }
  return $result;
}

/**
 * Implementation of hook_widget_info().
 */
function geshifield_widget_info() {
  return array(
    'geshifield_textarea' => array(
      'label' => t('Source code text area'),
      'field types' => array('geshifield'),
      // Let CCK core handle multiple values.
      'multiple values' => CONTENT_HANDLE_CORE,
      'callbacks' => array(
        // Do not provide default values through CCK core's
        // default value handling. @todo: or should we?
        'default value' => CONTENT_CALLBACK_NONE,
      ),
    ),
  );
  // @todo provide a file upload widget too.
}

/**
 * Implementation of hook_elements().
 */
function geshifield_elements() {
  $elements = array(
    'geshifield_textarea' => array(
      '#input' => TRUE,
      '#process' => array('geshifield_textarea_process' ),
    ),
  );
  return $elements;
}

/**
 * Process callback for geshifield_textarea widget.
 */
function geshifield_textarea_process($element, $edit, &$form_state, $form) {
  module_load_include('inc', 'geshifilter');

  $defaults = $element['#value'];
  $field = content_fields($element['#field_name'], $element['#type_name']);

  $enabled_languages = _geshifilter_get_enabled_languages();
  // @todo: also add "no highlighting" options.

  $element['sourcecode'] = array(
    '#type' => 'textarea',
    '#title' => t('Source code'),
    '#default_value' => isset($defaults['sourcecode']) ? $defaults['sourcecode'] : '',
    '#required' => $element['#required'],
    '#rows' => $field['widget']['rows'],
    '#description' => filter_xss($field['widget']['description']),
  );

  $element['language'] = array(
    '#type' => 'select',
    '#title' => t('Syntax highlighting mode'),
    '#default_value' => isset($defaults['language']) ? $defaults['language'] : '',
    '#options' => $enabled_languages,
    '#description' => t('Select the syntax highlighting mode to use for the source code.'),
  );

  return $element;
}

/**
 * Theming function for the geshifield_textarea widget
 */
function theme_geshifield_textarea($element) {
  return theme( 'form_element', $element, $element['#children'] );
}

/**
 * Implementation of hook_widget_settings().
 */
function geshifield_widget_settings($op, $widget) {
  switch ($op) {
    case 'form':
      $form = array();
      $form['rows'] = array(
        '#type' => 'textfield',
        '#title' => t('Default number of rows in text area'),
        '#description' => t('The default number of rows to provide in the text area for entering the source code.'),
        '#default_value' => isset($widget['rows']) ? $widget['rows'] : 20,
        '#required' => TRUE,
      );
      // @todo add an option for the default language
      return $form;
      break;

    case 'validate':
      if (!is_numeric($widget['rows']) || intval($widget['rows']) != $widget['rows'] || $widget['rows'] <= 0 || $widget['rows'] > 100) {
        form_set_error('rows', t('The number of rows must be an integer between 1 and 100.'));
      }
      break;

    case 'save':
      return array('rows');
      break;
  }
}

/**
 * Implementation of hook_widget().
 */
function geshifield_widget(&$form, &$form_state, $field, $items, $delta = 0) {
  $element = array(
    '#type' => $field['widget']['type'],
    '#default_value' => isset($items[$delta]) ? $items[$delta] : '',
  );
  return $element;
}

/**
 * Implementation of hook_field_formatter_info().
 */
function geshifield_field_formatter_info() {
  $formatters = array(
    'default' => array(
      'label' => t('Default'),
      'field types' => array('geshifield'),
    ),
    'nohighlighting' => array(
      'label' => t('No syntax highlighting'),
      'field types' => array('geshifield'),
    ),
    'trimmed' => array(
      'label' => t('Trimmed'),
      'field types' => array('geshifield'),
    ),
  );
  return $formatters;
}


function theme_geshifield_formatter_default($element) {
  $output = '';
  module_load_include('inc', 'geshifilter', 'geshifilter.pages');
  if (isset($element['#item']['sourcecode'])) {
    $output .= geshifilter_geshi_process($element['#item']['sourcecode'], $element['#item']['language']);
  }
  return $output;
}

function theme_geshifield_formatter_nohighlighting($element) {
  $output = '';
  module_load_include('inc', 'geshifilter', 'geshifilter.pages');
  if (isset($element['#item']['sourcecode'])) {
    $output .= geshifilter_geshi_process($element['#item']['sourcecode'], 'text');
  }
  return $output;
}

function theme_geshifield_formatter_trimmed($element) {
  $output = '';
  module_load_include('inc', 'geshifilter', 'geshifilter.pages');
  if (isset($element['#item']['sourcecode'])) {
    $output .= geshifilter_geshi_process(node_teaser($element['#item']['sourcecode']), $element['#item']['language']);
  }
  return $output;
}
