<?php
// $Id: image.module,v 1.197.2.1 2006/07/13 15:42:33 walkah Exp $
// Modified to use filemanager.module
// by Mike Boone (contact me at: http://boonedocks.net/mailmike.php)
// Version 0.1, 2006-08-27
//
// Version History
// 0.1, 2006-08-27, first working version
//
// I borrowed some ideas from this code:
// http://cvs.drupal.org/viewcvs/drupal/contributions/sandbox/drewish/audio/audio.module?rev=1.55&view=markup
//
// currently this image.module code has problems if the same user tries to preview/submit multiple images the same time
// this version currently only allows for 3 image sizes: original, preview, and thumbnail
// this version also depends on a database table called image_fm, of this structure:
/*
CREATE TABLE image_fm (
  iid int(10) unsigned NOT NULL auto_increment,
  nid int(10) unsigned NOT NULL default '0',
  original int(10) unsigned NOT NULL default '0',
  preview int(10) unsigned NOT NULL default '0',
  thumbnail int(10) unsigned NOT NULL default '0',
  PRIMARY KEY  (iid)
) DEFAULT CHARSET=utf8;
*/

/*
  Provided under the GNU General Public License
  Contact me for use outside the bounds of that license
  
  ---------------------------------------------------------------    
  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.
    
  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
    
  The GNU General Public License can be found at:
  http://www.gnu.org/copyleft/gpl.html
  ---------------------------------------------------------------
*/


/**
 * Implementation of hook_file_areas()
 */
function image_filemanager_areas() {
  return array(array(
'area'=>'image','name'=>t('Image'),'description'=>t('Area where all image node files are stored.')));
}

/**
 * Implementation of hook_help
 */
function image_help($section) {
  switch (
$section) {
    case 
'admin/help#image':
      
$output '<p>'t('The image module is used to create and administer images for your site. Each image is stored as a post, with thumbnails of the original generated automatically. There are two default thumbnail sizes, thumbnail and preview. The thumbnail size is shown as the preview for image posts and when browsing image galleries. The preview is the default size when first displaying an image node.') .'</p>';
      
$output .= '<p>' .t('Image administration allows the image directory and the image sizes to be set.</p><p>
Image galleries are used to organize and display images in galleries.   The list tab allows users to edit existing image gallery names, descriptions, parents and relative position, known as a weight.  The add galleries tab allows you to create a new image gallery defining name, description, parent and weight.'
) .'</p>';
      
$output .= t('<p>You can</p>
<ul>
<li>view image handling messages in <a href="%admin-settings">administer &gt;&gt; settings</a>.</li>
<li>configure image sizes and file directories at <a href="%admin-settings-image">administer &gt;&gt; settings &gt;&gt; image</a>.</li>
<li>use the <a href="%external-http-drupal-org-project-img_assist">image assist module</a> to upload and insert images into posts.</li>
'
, array('%admin-settings' => url('admin/settings'), '%admin-image-galleries' => url('admin/image/galleries'), '%admin-settings-image' => url('admin/settings/image'), '%external-http-drupal-org-project-img_assist' => 'http://drupal.org/project/img_assist')) .'</ul>';
      
$output .= '<p>'t('For more information please read the configuration and customization handbook <a href="%image">Image page</a>.', array('%image' => 'http://www.drupal.org/handbook/modules/image/')) .'</p>';
      return 
$output;
    case 
'admin/modules#description':
    if (
module_exist('image') && !module_exist('filemanager'))
      
drupal_set_message(t("The '%fm' module must be enabled for Image (+filemanager) to work.  Please download it from the drupal modules site and enable it below.", Array('%fm'=>'Filemanager')), 'error');
      return 
t('Allows uploading of images.');
    case 
'node/add#image':
      return 
'<p>'t('An image (with thumbnail). This is ideal for publishing photographs or screenshots.') .'</p>';
  }
}

/**
 * Implementation of hook_node_info
 */
function image_node_info() {
  return array(
'image' => array('name' => t('image'), 'base' => 'image'));
}

/**
 * Implementation of hook_perm
 */
function image_perm() {
  return array(
'create images''view original images''edit own images');
}

/**
 * Implementation of hook_access
 */
function image_access($op$node) {
  global 
$user;

  if (
$op == 'create' && user_access('create images')) {
    return 
TRUE;
  }

  if (
$op == 'update' || $op == 'delete') {
    if (
user_access('edit own images') && ($user->uid == $node->uid)) {
      return 
TRUE;
    }
  }
}

/**
 * Implementation of hook_settings
 */
function image_settings() {
  
_image_check_settings();

  
$form['image_updated'] = array('#type' => 'hidden''#value' => time());

  
$form['paths'] = array('#type' => 'fieldset''#title' => t('File paths'));
  
$form['paths']['image_default_path'] = array('#type' => 'textfield''#title' => t('Default image path'), '#default_value' => variable_get('image_default_path''images'), '#description' => t('Subdirectory in the directory "%dir" where pictures will be stored. Do not include trailing slash.', array('%dir' => theme('placeholder'variable_get('file_directory_path''files')))));

  
$form['sizes'] = array('#type' => 'fieldset''#title' => t('Image sizes'));
  
$form['sizes']['image_sizes'] = image_settings_sizes_form();

  return 
$form;
}

function 
image_settings_sizes_form() {
  
$sizes _image_get_sizes();

  
$form['#type'] = 'item';
  
$form['#description'] = t('Select various pixel dimensions, "thumbnail" and "preview" are required.');
  
$form['#tree'] = TRUE;
  
$form['#theme'] = 'image_settings_sizes_form';
  for (
$i 0$i 5$i++) {
    
$form[$i]['label'] = array('#type' => 'textfield''#default_value' => $sizes[$i]['label'], '#size' => 25);
    if (
in_array($sizes[$i]['label'], _image_required_sizes())) {
      
$form[$i]['label']['#attributes'] = array('disabled' => 'disabled');
      
$form[$i]['label']['#value'] = $sizes[$i]['label'];
    }
    
$form[$i]['width'] = array('#type' => 'textfield''#default_value' => $sizes[$i]['width'], '#size' => 5'#maxlength' => 5);
    
$form[$i]['height'] = array('#type' => 'textfield''#default_value' => $sizes[$i]['height'], '#size' => 5'#maxlength' => 5);
  }

  return 
$form;
}

function 
theme_image_settings_sizes_form(&$form) {
  
$header = array(t('Label'), t('Width'), t('Height'));
  foreach (
element_children($form) as $key) {
    
$row = array();
    
$row[] = form_render($form[$key]['label']);
    
$row[] = form_render($form[$key]['width']);
    
$row[] = form_render($form[$key]['height']);
    
$rows[] = $row;

  }
  
$output theme('table'$header$rows);
  
$output .= form_render($form);

  return 
$output;
}

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

  if (
$may_cache) {
    
$items[] = array('path' => 'node/add/image''title' => t('image'),
                     
'access' => user_access('create images'));
    
$items[] = array('path' => 'image/view''title' => t('image'),
                     
'access' => user_access('access content'),
                     
'type' => MENU_CALLBACK,
                     
'callback' => 'image_fetch');
  }

  return 
$items;
}

/**
 * Implements hook_cron. (deletes old temp images)
 */
// function image_cron()
// filemanager handles the deletion of temp files, so no cron work needed

/**
 * Implementation of hook_prepare().
 */
function image_prepare(&$node$field_name) {
  
// clear the session variable
  
if (sizeof($_POST)==0) {
    unset(
$_SESSION['image_images']);
  }
  
  
$node->images['new_file'] = false;
  
  if (
is_null($field_name)) {
    
$field_name 'image';
  }
  if (
$file file_check_upload($field_name)) {
    if (!
image_get_info($file->filepath)) {
      
form_set_error($field_namet('Uploaded file is not a valid image'));
      return;
    } else {
      
$arySizes _image_get_sizes();

      
// determine extension
      
switch($file->filemime) {
        case 
'image/gif':
          
$strExt='gif';break;
        case 
'image/png':
          
$strExt='png';break;
        case 
'image/jpeg':
        case 
'image/jpg':
        case 
'image/pjpeg':
        default:
          
$strExt='jpg';
      }
    
      
// add original
      
$node->images=array();
      
// want to use the node ID here, but it's not available yet, so choosing random string
      //$strFilename=$node->nid . '.' . $strExt;
      
$strFilenameBase=str_replace('.','',uniqid('bird-',true));
      
$strFilename=$strFilenameBase '_original.' $strExt;
      
$node->images['original']=module_invoke('filemanager''add_file''images'$file->filepath,
        
$strFilename$file->filemimefalsefalse);

      
// add other sizes
      
foreach ($arySizes as $ary1Size) {
        
$strFilename=$strFilenameBase  '_' $ary1Size['label'] . '.' $strExt;
        
$node->images[$ary1Size['label']]=module_invoke('filemanager''add_file''images'$file->filepath,
        
$strFilename$file->filemimefalsefalse);
        
// resize the non-originals
        
$strFilePath module_invoke('filemanager''create_path'$node->images[$ary1Size['label']], truefalse);

        
// resizing to itself seems to work, at least for the image toolkit I'm using
        
image_scale($strFilePath$strFilePath$ary1Size['width'], $ary1Size['height']);
      
        
// not using the parameters of the resized file (file size, dimensions) so this line isn't necessary
        // $node->images[$ary1Size['label']]=module_invoke('filemanager', 'get_file_info', $strFilePath);
      
}
      
$node->images['new_file'] = true;
    
      
$_SESSION['image_images']=$node->images;
    }
  } elseif (isset(
$_SESSION['image_images'])) {
    
$node->images=$_SESSION['image_images'];
  } else {
    
$_SESSION['image_images']=$node->images;
  }
}

/**
 * Implementation of hook_link.
 */
function image_link($type$node$main 0) {
  
$links = array();
  
  if (
$type == 'node' && $node->type == 'image' && !$main) {
    
$request = ($_GET['size']) ? $_GET['size'] : 'preview';
    foreach (
_image_get_sizes() as $size) {
      if (
$node->images[$request] != $node->images[$size['label']]) {
        
$links[] = l($size['label'], 'node/' $node->nidNULL'size=' urlencode($size['label']));
      }
    }
    if (
user_access('view original images') && ($node->images[$request] != $node->images['original'])) {
      
$links[] = l(t('original'), 'node/' $node->nidNULL'size=original');
    }
  }

  return 
$links;
}

/**
 * Implementation of hook_block.
 *
 * Offers 2 blocks: latest image and random image
 */
function image_block($op$delta 0) {
  switch (
$op) {
    case 
'list':
      
$block[0]['info'] = t('Latest image');
      
$block[1]['info'] = t('Random image');

      return 
$block;
    case 
'view':
      if (
user_access('access content')) {
        switch(
$delta) {
          case 
0:
            
$images image_get_latest();
            
$block['subject'] = t('Latest image');
            
$block['content'] = l(image_display($images[0], 'thumbnail'), 'node/'.$images[0]->nid, array(), NULLNULLFALSETRUE);
            break;
          case 
1:
            
$images image_get_random();
            
$block['subject'] = t('Random image');
            
$block['content'] = l(image_display($images[0], 'thumbnail'), 'node/'.$images[0]->nid, array(), NULLNULLFALSETRUE);
            break;
        }
      }
      return 
$block;
  }
}

function 
image_form_add_thumbnail($form_id$edit) {
  
$node = (object)($edit);
  
_image_populate_images($node,true);
  if (
$node->images['thumbnail']) {
    
$form = array('#type' => 'item''#title' => t('Thumbnail'), '#value' => image_display($node'thumbnail'), '#weight' => -10);
  }
  return 
$form;
}

/**
 * Implementation of hook_form
 */
function image_form(&$node, &$param) {
  
_image_check_settings();

  
$form['#attributes'] = array("enctype" => "multipart/form-data");
  
$form['title'] = array('#type' => 'textfield''#title' => t('Title'), '#size' => 60'#maxlength' => 128'#required' => TRUE'#default_value' => $node->title);
  
  
$form['thumbnail']['#after_build'] = array('image_form_add_thumbnail');
  
  
$form['image'] = array('#type' => 'file''#title' => t('Image'), '#description' => t('Click "Browse..." to select an image to upload.'), '#weight' => -3);
  
$form['body'] = array('#type' => 'textarea''#title' => t('Body'), '#rows' => 20'#default_value' => $node->body);
  
$form['format'] = filter_form($node->format);

  return 
$form;
}

/**
 * Implementation of hook_validate().
 */
function image_validate(&$node) {
  if (!isset(
$node->images) && !isset($_SESSION['image_images'])) {
    
form_set_error('image't('A problem occurred with your image upload. Please try again.'));
  }
}

function 
image_submit(&$node) {
  if (isset(
$_SESSION['image_images'])) $node->images=$_SESSION['image_images'];
  unset(
$_SESSION['image_images']);
}

/**
 * Implementation of hook_view
 */
function image_view(&$node$teaser 0$page 0) {
  
$request = ($_GET['size']) ? $_GET['size'] : 'preview';
  
$request check_plain($request);
  
$node node_prepare($node$teaser);
  
$node->teaser theme('image_teaser'$node);
  
$node->body theme('image_body'$node$request);
}

/**
 * Implementation of hook_load
 */
function image_load(&$node) {
  
_image_populate_images($node,false);
}

// load the image data into the node
function _image_populate_images(&$node,$bInForm=false) {
  
// if $bInForm is true, we assume we're in the form and will use the session data if we have it
  
$node->images = array();

  if (isset(
$_SESSION['image_images']) && $bInForm) {
    
$node->images=$_SESSION['image_images'];
  } elseif (!empty(
$node->nid)) {
    
$result db_query("SELECT original, preview, thumbnail FROM image_fm WHERE nid=%d;"$node->nid);
    if (
$data db_fetch_object($result)) {
      
$node->images['original'] = module_invoke('filemanager''get_file_info'$data->original);
      
$node->images['preview'] = module_invoke('filemanager''get_file_info'$data->preview);
      
$node->images['thumbnail'] = module_invoke('filemanager''get_file_info'$data->thumbnail);
    }
  }
}

/**
 * Implementation of hook_insert
 */
function image_insert($node) {
  
// promote the image files and create the data record in image_fm
  // could rename the files to the node ID number here, but not worrying about it now
  
foreach ($node->images as $label => $image) {
    
module_invoke('filemanager''promote_working'$image);
  }

  
// store the data in our custom table so we know the filemanager IDs of the various sizes
  
db_query("INSERT INTO image_fm (nid, original, preview, thumbnail) ".
    
"VALUES (%d, %d, %d, %d)",
    
$node->nid$node->images['original']->fid$node->images['preview']->fid$node->images['thumbnail']->fid);
}

/**
 * Implementation of hook_update
 */
function image_update($node) {
  
// handle replaced image
  
if ($node->images['new_file']) {
    
// grab original image fids from the image_fm table
    
$result db_query("SELECT iid, original, preview, thumbnail FROM image_fm WHERE nid=%d;"$node->nid);
    if (
$data db_fetch_object($result)) {
      
// delete the old filemanager images
      
$fileTemp module_invoke('filemanager''get_file_info'$data->original);
      
module_invoke('filemanager''delete'$fileTemp);
      
$fileTemp module_invoke('filemanager''get_file_info'$data->preview);
      
module_invoke('filemanager''delete'$fileTemp);
      
$fileTemp module_invoke('filemanager''get_file_info'$data->thumbnail);
      
module_invoke('filemanager''delete'$fileTemp);

      
// promote the image files and create the data record in 
      // could rename the files to the node ID number here, but not worrying about it now
      
foreach ($node->images as $label => $image) {
        
module_invoke('filemanager''promote_working'$image);
      }

      
// replace the fids in the image_fm record
      
db_query("UPDATE image_fm SET original=%d, preview=%d, thumbnail=%d WHERE nid=%d",
        
$node->images['original']->fid$node->images['preview']->fid$node->images['thumbnail']->fid$node->nid);
    }
  }
}

/**
 * Implementation of hook_delete.
 */
function image_delete($node) {
  
// delete from image_fm table
  
db_query("DELETE FROM image_fm WHERE nid=%d"$node->nid);
  
  
// delete from filemanager
  
foreach ($node->images as $label => $image) {
    
module_invoke('filemanager''delete'$image);
  }
}

/**
 * Create an <img> tag for an image.
 */
function image_display(&$node$label 'preview'$attributes = array()) {
  
// we are assuming the preview/thumbnails have been successfully created during the prepare
  // and will not need to be regenerated now

  
if (empty($node->images[$label])) {
    return;
  }

  
$strFilePath module_invoke('filemanager''create_path'$node->images[$label], $node->images[$label]->workingfalse);
  
$info image_get_info($strFilePath);
  
$attributes['class'] = "image $label". (isset($attributes['class']) ? " "$attributes['class'] : "");
  
$attributes['width'] = $info['width'];
  
$attributes['height'] = $info['height'];

  
$strURL=module_invoke('filemanager''url'$node->images[$label], $node->images[$label]->workingfalse);
  return 
theme('image_display'$node$label$strURL$attributes);
}

/**
 * Fetches an image file, allows "shorthand" image urls such of the form:
 * image/view/$nid/$label
 * (e.g. image/view/25/thumbnail or image/view/14)
 */
function image_fetch($nid 0$size 'preview') {
  if (
$nid) {
    
$node node_load(array('nid' => $nid));
    if (
$node->images[$size]) {
      
$file $node->images[$size];
      
module_invoke('filemanager','transfer',$file,$file->working);
      
file_transfer($file$headers);
    }
  }
}

/**
 * Theme a teaser
 */
function theme_image_teaser($node) {
 return 
l(image_display($node'thumbnail'), 'node/'$node->nid, array(), NULLNULLFALSETRUE) . $node->teaser;
}

/**
 * Theme a body
 */
function theme_image_body($node$size) {
 return 
image_display($node$size) . $node->body;
}

/**
  * Theme an img tag for displaying the image.
  */
function theme_image_display($node$label$url$attributes) {
  return 
'<img src="'check_url($url) .'" alt="'check_plain($node->title) .'" title="'check_plain($node->title) .'" 'drupal_attributes($attributes) .' />';
}

/**
 * Fetch a random N image(s) - optionally from a given term.
 */
function image_get_random($count 1$tid 0) {
  if (
$tid != 0) {
    
$result db_query_range(db_rewrite_sql("SELECT n.nid FROM {term_node} tn LEFT JOIN {node} n ON n.nid=tn.nid WHERE n.type='image' AND n.status=1 AND tn.tid=%d ORDER BY RAND()"), $tid0$count);
  }
  else {
    
$result db_query_range(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.type='image' AND n.status=1 ORDER BY RAND()"), 0$count);
  }
  
$output = array();
  while (
$nid db_fetch_object($result)) {
    
$output[] = node_load(array('nid' => $nid->nid));
  }
  return 
$output;
}

/**
 * Fetch the latest N image(s) - optionally from a given term.
 */
function image_get_latest($count 1$tid 0) {
  if (
$tid != 0) {
    
$result db_query_range(db_rewrite_sql("SELECT n.nid FROM {term_node} tn LEFT JOIN {node} n ON n.nid=tn.nid WHERE n.type='image' AND n.status=1 AND tn.tid=%d ORDER BY n.changed DESC"), $tid0$count);
  }
  else {
    
$result db_query_range(db_rewrite_sql("SELECT n.nid FROM {node} n WHERE n.type='image' AND n.status=1 ORDER BY changed DESC"), 0$count);
  }
  
$output = array();
  while (
$nid db_fetch_object($result)) {
    
$output[] = node_load(array('nid' => $nid->nid));
  }
  return 
$output;
}

/**
 * Verify the image module and toolkit settings.
 */
function _image_check_settings() {
  
// TODO: maybe some sort of filemanager check here?

  // Sanity check : make sure we've got a working toolkit
  
if (!image_get_toolkit()) {
    
drupal_set_message(t('Make sure you have a working image toolkit installed and enabled, for more information see: %settings', array('%settings' => l(t('the settings page'), 'admin/settings'))), 'error');
    return 
false;
  }
  return 
true;
}


/**
 * Helper function to return the defined sizes (or proper defaults).
 */
function _image_get_sizes() {
  
$sizes variable_get('image_sizes', array(array('width' => 100'height' => 100'label' => 'thumbnail'),
                                             array(
'width' => 640'height' => 640'label' => 'preview')));
  return 
array_filter($sizescreate_function('$size''return !empty($size["label"]);'));
}

function 
_image_required_sizes() {
  return array(
'thumbnail''preview''original');
}

function 
_image_get_dimensions($label) {
  foreach (
_image_get_sizes() as $size) {
    if (
$size['label'] == $label) {
      return 
$size;
    }
  }
  return array();
}