<?php
// $Id: image_attach.module,v 1.48 2009/06/20 18:28:42 sun Exp $

/**
 * @file image_attach.module
 */

define('IMAGE_ATTACH_HIDDEN', 'hidden');

/**
 * Implementation of hook_help().
 */
function image_attach_help($path, $arg) {
  switch ($path) {
    case 'admin/settings/modules#description':
      return t('Allows easy attaching of image nodes to other content types.');
  }
}

/**
 * Implementation of hook_menu()
 */
function image_attach_menu() {
  $items = array();

  $items['image_attach'] = array(
    'title' => 'Image attachment view',
    'page callback' => 'image_attach_view_image',
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );
  $items['admin/settings/image/image_attach'] = array(
    'title' => 'Image attach',
    'description' => 'Enable image attach for content.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('image_attach_admin_settings'),
    'access arguments' => array('administer site configuration'),
    'type' => MENU_LOCAL_TASK,
  );
  return $items;
}


function image_attach_admin_settings() {
  $form = array();

  $form['image_attach_existing'] = array(
    '#type' => 'radios',
    '#title' => t('Attach existing images'),
    '#default_value' => variable_get('image_attach_existing', 1),
    '#options' => array(
      0 => t('Disabled'),
      1 => t('Enabled')
    ),
    '#description' => t('When enabled, will allow existing image nodes to be attached instead of uploading new images.')
  );

  return system_settings_form($form);
}

/**
 * Implementation of hook_block().
 */
function image_attach_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
      $blocks[0] = array(
        'info'       => t('Attached images'),
        'status'     => TRUE,
        'weight'     => 0,
        'visibility' => 1,
        'pages'      => 'node/*',
      );
      return $blocks;

    case 'view':
      if ($delta == 0) {
        if (arg(0) == 'node' && is_numeric(arg(1))) {
          $node = node_load(arg(1));
          if (isset($node->iid) && $node->iid) {
            $image = node_load($node->iid);
            if (node_access('view', $image)) {
              $img = image_display($image, variable_get('image_attach_block_0_size', IMAGE_THUMBNAIL));
              return array(
                'subject' => t('Attached images'),
                'content' => l($img, "node/$node->iid", array('html' => TRUE)),
              );
            }
          }
        }
      }
      break;

    case 'configure':
      if ($delta == 0) {
        $image_sizes = array();
        foreach (image_get_sizes() as $key => $size) {
          $image_sizes[$key] = $size['label'];
        }
        $form['image_attach_block_0_size'] = array(
          '#type' => 'select',
          '#title' => t('Image size'),
          '#default_value' => variable_get('image_attach_block_0_size', IMAGE_THUMBNAIL),
          '#options' => $image_sizes,
          '#description' => t('This determines the size of the image that appears in the block.'),
        );
        return $form;
      }
      break;

    case 'save':
      if ($delta == 0) {
        variable_set('image_attach_block_0_size', $edit['image_attach_block_0_size']);
      }
      break;
  }
}



/**
 * implementation of hook_form_alter()
 */
function image_attach_form_alter(&$form, $form_state, $form_id) {
  // Content type settings form.
  if ($form_id == 'node_type_form' && $form['#node_type']->type != 'image') {
    _image_check_settings();

    $image_sizes = array(IMAGE_ATTACH_HIDDEN => t('<Hidden>'));
    foreach (image_get_sizes() as $key => $size) {
      $image_sizes[$key] = $size['label'];
    }
    
    $form['image_attach'] = array(
      '#type' => 'fieldset',
      '#title' => t('Image Attach settings'),
      '#collapsible' => TRUE,
      '#collapsed' => TRUE,
    );
    $form['image_attach']['image_attach'] = array(
      '#type' => 'radios',
      '#title' => t('Attach images'),
      '#default_value' => variable_get('image_attach_'. $form['#node_type']->type, 0),
      '#options' => array(0 => t('Disabled'), 1 => t('Enabled')),
      '#description' => t('Should this node allows users to upload an image?'),
    );
    $form['image_attach']['image_attach_size_teaser'] = array(
      '#type' => 'select',
      '#title' => t('Teaser image size'),
      '#default_value' => variable_get('image_attach_size_teaser_'. $form['#node_type']->type, IMAGE_THUMBNAIL),
      '#options' => $image_sizes,
      '#description' => t("This determines the size of the image that appears when the node is displayed as a teaser. 'Hidden' will not show the image.")
    );
    $form['image_attach']['image_attach_weight_teaser'] = array(
      '#type' => 'weight',
      '#title' => t('Teaser image weight'),
      '#default_value' => variable_get('image_attach_weight_teaser_'. $form['#node_type']->type, 0),
      '#description' => t('This value determines the order of the image when displayed in the teaser.'),
    );
    $form['image_attach']['image_attach_size_body'] = array(
      '#type' => 'select',
      '#title' => t('Full node image size'),
      '#default_value' => variable_get('image_attach_size_body_'. $form['#node_type']->type, IMAGE_THUMBNAIL),
      '#options' => $image_sizes,
      '#description' => t("This determines the size of the image that appears when the full node is displayed. 'Hidden' will not show the image.")
    );
    $form['image_attach']['image_attach_weight_body'] = array(
      '#type' => 'weight',
      '#title' => t('Full node image weight'),
      '#default_value' => variable_get('image_attach_weight_body_'. $form['#node_type']->type, 0),
      '#description' => t('This value determines the order of the image when displayed in the body.'),
    );
  }
  // Node edit form.
  else if (isset($form['type']['#value']) && $form['type']['#value'] != 'image') {
    $type = $form['type']['#value'];
    // If enabled adjust the form.
    if ($form_id == $type .'_node_form' && variable_get('image_attach_'. $type, 0)) {
      $node = $form['#node'];
      _image_check_settings();
      $value = !empty($node->new_image) ? '#value' : '#default_value';
      $form['#attributes'] = array("enctype" => "multipart/form-data");

      $form['image_attach'] = array(
        '#type' => 'fieldset',
        '#title' => t('Attached images'),
        '#collapsible' => TRUE,
        '#collapsed' => empty($node->iid),
      );
      // Add a custom submit handler so we can handle image creation on-the-fly
      $form['#validate'][] = 'image_attach_validate'; 

      if (!empty($node->iid)) {
        $image = node_load($node->iid);
        $form['image_attach']['image_thumbnail'] = array(
          '#type' => 'item',
          '#title' => t('Thumbnail'),
          '#value' => image_display($image, 'thumbnail')
        );
      }
      if (variable_get('image_attach_existing', 1) && user_access('access content')) {
        $form['image_attach']['iid'] = array(
          '#type' => 'select',
          '#title' => t('Existing image'),
          '#options' => _image_attach_get_image_nodes(),
          $value => empty($node->iid) ? NULL : $node->iid,
          '#description' => t('Choose an image already existing on the server if you do not upload a new one.')
        );
        $form['image_attach'][] = array(
          '#type' => 'item',
          '#value' => t('-or-'),
          '#attributes' => array('class' => 'either-choice')
        );
      }
      else {
        $form['image_attach']['iid'] = array(
          '#type' => 'hidden',
          $value => empty($node->iid) ? NULL : $node->iid,
        );
      }
      $form['image_attach']['image'] = array(
        '#type' => 'file',
        '#title' => t('Upload image')
      );
      $form['image_attach']['image_title'] = array(
        '#type' => 'textfield',
        '#title' => t('Image title'),
        $value => '',
        '#description' => t('The title the image will be shown with.')
      );
    }
  }
}

/**
 * Capture node form submission and immediately create an image if one has been
 * uploaded.
 * Note that the new image nodes are created even on preview. Taking several
 * attempts may create trash.
 */
function image_attach_validate($form, &$form_state) {
  $validators = array(
    'file_validate_is_image' => array(),
  );
  if ($file = file_save_upload('image', $validators)) {
    $image_title = $_POST['image_title'] ? $_POST['image_title'] : basename($file->filepath);
    // This func now does all the things to initialize an image properly
    $image = image_create_node_from($file->filepath, $image_title, '');
    if ($image && !form_get_errors()) {
      drupal_set_message(t("Created new image to attach to this node. !image_link", array('!image_link' => l($image_title, 'node/'. $image->nid) )));
      form_set_value($form['image_attach']['iid'], $image->nid, $form_state);
    }
  }
}

/**
 * Implementation of hook_nodeapi().
 */
function image_attach_nodeapi(&$node, $op, $teaser, $page) {
  // Make sure that if an image is deleted it is detached from any nodes.
  if ($node->type == 'image') {
    switch ($op) {
      case 'delete':
        db_query("DELETE FROM {image_attach} WHERE iid=%d", $node->nid);
    }
    return;
  }
  else if (variable_get('image_attach_'. $node->type, 0) == 0) {
    return;
  }
  switch ($op) {
    case 'insert':
    case 'update':
      if (isset($node->iid)) {
        db_query("DELETE FROM {image_attach} WHERE nid=%d", $node->nid);
        if ($node->iid > 0) {
          db_query("INSERT INTO {image_attach} (nid, iid) VALUES (%d, %d)", $node->nid, $node->iid);
        }
      }
      break;

    case 'delete':
      db_query("DELETE FROM {image_attach} WHERE nid=%d", $node->nid);
      break;

    case 'load':
      $iid = db_result(db_query("SELECT iid FROM {image_attach} WHERE nid=%d", $node->nid));
      return array('iid' => $iid);

    // Pass the body and teaser objects to the theme again to add the images
    case 'view':
      if ($node->iid) {
        $teaser_or_body = $teaser ? 'teaser' : 'body';
        $node->content['image_attach'] = array(
          '#value' => theme("image_attach_{$teaser_or_body}", $node),
          '#weight' => variable_get("image_attach_weight_{$teaser_or_body}_{$node->type}", 0),
        );
      }
      break;

    case 'rss item':
      $ret = array();
      if ($node->iid && $image = node_load($node->iid)) {
        $info = image_get_info(file_create_path($image->images[IMAGE_PREVIEW]));
        $ret[] = array(
          'key' => 'enclosure',
          'attributes' => array(
            'url' => url("image/view/{$node->iid}/". IMAGE_PREVIEW, array('absolute' => TRUE)),
            'length' => $info['file_size'],
            'type' => $info['mime_type'],
          )
        );
      }
      return $ret;
  }
}

/**
 * Fetch an array of all candidate referenced nodes, for use in presenting the selection form to the user.
 */
function _image_attach_get_image_nodes() {
  $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, n.sticky FROM {node} n WHERE n.status = 1 AND n.type = 'image' ORDER BY n.sticky DESC, n.title ASC"));
  $rows = array(0 => t('None'));
  while ($node = db_fetch_object($result)) {
    $rows[$node->nid] = $node->title;
  }
  return $rows;
}


/**
 * Views 2 API handler
 * 
 */

function image_attach_views_api() {
return array(
  'api' => 2,
  'path' => drupal_get_path('module', 'image_attach'),
);
}


function image_attach_views_handlers() {
  return array(
  'info' => array(
    'path' => drupal_get_path('module', 'image_attach'),
    ),
  'handlers' => array(
    'image_attach_views_handler_field_iid' => array(
     'parent' => 'views_handler_field',
     ),
    ),
  );
}


/**
 * Implementation of hook_theme() registry.
 **/
function image_attach_theme() {
  return array(
    'image_attach_teaser' => array(
      'arguments' => array('node' => new stdClass()),
    ),
    'image_attach_body' => array(
      'arguments' => array('node' => new stdClass()),
    ),
  );
}

/**
 * Theme the teaser.
 *
 * Override this in template.php to include a case statement if you want different node types to appear differently.
 * If you have additional image sizes you defined in image.module, you can use them by theming this function as well.
 */
function theme_image_attach_teaser($node) {
  $img_size = variable_get('image_attach_size_teaser_'. $node->type, 'thumbnail');

  if ($img_size != IMAGE_ATTACH_HIDDEN) {
    drupal_add_css(drupal_get_path('module', 'image_attach') .'/image_attach.css');

    $image = node_load($node->iid);
    if (!node_access('view', $image)) {
      // If the image is restricted, don't show it as an attachment.
      return NULL;
    }
    $class = 'image-attach-teaser' . ($image->status ? '' : ' image-unpublished');
    $info = image_get_info(file_create_path($image->images[$img_size]));

    $output = '<div style="width: ' . $info['width'] . 'px" class="' . $class . '">';
    $output .= l(image_display($image, $img_size), "node/$node->nid", array('html' => TRUE));
    $output .= '</div>'."\n";

    return $output;
  }
}

/**
 * Theme the body
 */
function theme_image_attach_body($node) {
  $img_size = variable_get('image_attach_size_body_'. $node->type, IMAGE_THUMBNAIL);

  if ($img_size != IMAGE_ATTACH_HIDDEN) {
    drupal_add_css(drupal_get_path('module', 'image_attach') .'/image_attach.css');

    $image = node_load($node->iid);
    if (!node_access('view', $image)) {
      // If the image is restricted, don't show it as an attachment.
      return NULL;
    }
    $class = 'image-attach-body' . ($image->status ? '' : ' image-unpublished');
    $info = image_get_info(file_create_path($image->images[$img_size]));

    $output = '<div style="width: ' . $info['width'] . 'px" class="' . $class . '">';
    $output .= l(image_display($image, $img_size), "node/$node->iid", array('html' => TRUE));
    $output .= '</div>'."\n";

    return $output;
  }
}



