<?php
/**
 * @file
 *  Implements the necessary hooks and processing to provide nivo slider functionality to media galleries.
 */
 
// The default path to the nivo slider directory.
define('MEDIA_NIVO_SLIDER_PATH', 'sites/all/libraries/nivo-slider');

require_once(dirname(__FILE__) . '/media_nivo_slider.fields.inc');

/**
 * Implements hook_menu().
 */
function media_nivo_slider_menu() {
  $items['admin/config/media/media-nivo-slider'] = array(
    'title' => 'Media Nivo Slider',
    'description' => 'Manage Media Nivo Slider configurations',
    'access arguments' => array('administer nivo slider'),
    'page callback' => 'media_nivo_slider_admin',
    'file' => 'media_nivo_slider.admin.inc',
    'type' => MENU_NORMAL_ITEM,
  );
  
  $items['admin/config/media/media-nivo-slider/add'] = array(
    'title' => 'Create a Nivo Slider Configuration',
    'access arguments' => array('administer nivo slider'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('media_nivo_slider_config'),
    'file' => 'media_nivo_slider.admin.inc',
    'type' => MENU_LOCAL_ACTION,
  );
  
  $items['admin/config/media/media-nivo-slider/edit/%'] = array(
    'title' => 'Edit a Nivo Slider Configuration',
    'access arguments' => array('administer nivo slider'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('media_nivo_slider_config', 5),
    'file' => 'media_nivo_slider.admin.inc',
    'type' => MENU_CALLBACK,
  );
  
  $items['admin/config/media/media-nivo-slider/delete/%'] = array(
    'title' => 'Delete a Nivo Slider Configuration',
    'access arguments' => array('administer nivo slider'),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('media_nivo_slider_config_delete', 5),
    'file' => 'media_nivo_slider.admin.inc',
    'type' => MENU_CALLBACK,
  );
  
  return $items;
}

/**
 * Implements hook_permission().
 */
function media_nivo_slider_permission() {
  return array(
    'administer nivo slider' => array(
      'title' => t('Administer Nivo Slider'), 
      'description' => t('Create/Edit Nivo Slider configurations.'),
    ),
  );
}

/**
 * Implements hook_form_FORM_ID_alter().
 * Collects the Media Nivo Slider fields into a fieldset for better organization.
 */
function media_nivo_slider_form_media_gallery_node_form_alter(&$form, &$form_state) {   
  // Create fieldset container for nivo slider settings.
  $form['media_nivo_slider'] = array(
    '#type' => 'fieldset',
    '#title' => 'Media Nivo Slider',
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
    '#group' => 'additional_settings',
    '#attached' => array(),
    '#weight' => -90,
    '#attributes' => array(
      'class' => array('media-nivo-slider-form'),
    ),
  );

  // Build an array of the fields to group into a vertical tab.
  $fieldset = array(
    'media_nivo_slider_block',
    'media_nivo_slider_config',
  );

  // Build up the fieldset.
  foreach ($fieldset as $id) {
    $form['media_nivo_slider'][$id] = $form[$id];
    $form[$id] = array('#language' => $form[$id]['#language']);
  }
  
  // Attach form javascript for setting the fieldset summary.
  $form['#attached']['js'][] = drupal_get_path('module', 'media_nivo_slider') . '/js/media_nivo_slider.form.js';
}

/**
 * Implements hook_block_info().
 */
function media_nivo_slider_block_info() {
  $blocks = array();

  // Define a block for each media gallery node that is configured to expose one.
  $query = new EntityFieldQuery();
  $query->entityCondition('entity_type', 'node');
  $query->entityCondition('bundle', 'media_gallery');
  $query->fieldCondition('media_nivo_slider_block', 'value', 1);
  $result = $query->execute();
  
  if (!empty($result['node'])) {
    // There is no reason to waste going through a full node_load_multiple()
    // when we only need the titles.
    $nids = array_keys($result['node']);
    $node_titles = db_select('node', 'n')
      ->fields('n', array('nid', 'title'))
      ->condition('nid', $nids, 'IN')
      ->execute()
      ->fetchAllKeyed();
    
    foreach ($node_titles as $nid => $title) {
      $blocks[$nid]['info'] = t('Media Nivo Slider: @title', array('@title' => $title));
    }
  }

  return $blocks;
}

/**
 * Implements hook_block_view().
 */
function media_nivo_slider_block_view($delta = '') {  
  // Load the gallery node.
  $node = node_load($delta);
  
  // Load the Nivo Slider configuration.
  $config = db_select('media_nivo_slider', 'ns')
    ->fields('ns')
    ->condition('cid', $node->media_nivo_slider_config[LANGUAGE_NONE][0]['value'])
    ->execute()
    ->fetchObject();

  $settings = unserialize($config->settings);

  // Add the necessary nivo slider CSS and JS.
  $library_path = libraries_get_path('nivo-slider');
  drupal_add_css($library_path . '/nivo-slider.css');
  drupal_add_css($library_path . '/themes/' . $settings['slider_theme'] . '/' . $settings['slider_theme'] . '.css', array('basename' => 'media_nivo_slider_theme.css'));
  drupal_add_js($library_path . '/jquery.nivo.slider.pack.js');
  drupal_add_js(drupal_get_path('module', 'media_nivo_slider') . '/js/media_nivo_slider.js');

  $block['subject'] = check_plain($node->title);
  if (empty($node->media_gallery_media_original)) {
    // Bail out now if there won't be any media items to show.
    $block['content'] = t('No content available.');
  }
  else {
    // Collect an array of file IDs associated with this gallery.
    // Media Gallery's media_gallery_media field, by default, is locked
    // and not multi-lingual. For now we will assume the fields are language
    // neutral.
    $node = clone $node;
    $node->media_gallery_media = $node->media_gallery_media_original;
    $files = &$node->media_gallery_media[LANGUAGE_NONE];
    $gallery_fids = array();
    
    foreach ($files as $file) {
      $gallery_fids[] = $file['fid'];
    }

    $images = array();
    $media_items = media_multi_load(implode(' ', $gallery_fids));
    
    foreach ($media_items as $media) {
      // Short-circuit the loop so as not to add any non-image media items that may be in the gallery.
      if ($media->type != 'image') {
        continue;
      }
      
      $slide = array();

      // Get the image information so we can set the width and height of the image.
      $image_info = image_get_info($media->uri);

      // If image_get_info returned false, we either don't have an image or the file doesn't exist.
      // Skip this image, and log a warning.
      if ($image_info === FALSE) {
        watchdog('Media Nivo', t('Media file @file_uri, is not an image or does not exist.', array('@file_uri' => $media->uri)));
        continue;
      }

      // Start constructing the image tag.
      // Build the variables array.
      $variables = array(
        'path' => $media->uri, 
        'width' => $image_info['width'] . 'px',
        'height' => $image_info['height'] . 'px',
      );
      
      // Set the image caption if ones been set.
      if (isset($media->media_nivo_slider_image_caption[LANGUAGE_NONE][0]['value'])) {
        $variables['title'] = $media->media_nivo_slider_image_caption[LANGUAGE_NONE][0]['value'];
      }
      
      // Build the image tag, using a image style if one has been set.
      if (isset($settings['image_style']) && $settings['image_style'] != '_none') {
        $variables['style_name'] = $settings['image_style'];
        
        // Load the specified image_style.
        $style = image_style_load($variables['style_name']);

        // Check if the image style derivative for this image exists, if not create it.
        $image_style_file = image_style_path($variables['style_name'], $variables['path']);
        if (!file_exists($image_style_file)) {
          image_style_create_derivative($style, $variables['path'], $image_style_file);
        }

        // Get the image dimensions after the image style has been applied.
        $image_style_info = image_get_info($image_style_file);

        // Update the theme variables.
        $variables['width'] = $image_info['width'] . 'px';
        $variables['height'] = $image_info['height'] . 'px';

        // Create the image tag.
        $slide['image'] = theme('image_style', $variables);
      }
      else {               
        // Create the image tag.
        $slide['image'] = theme('image', $variables);
      }

      // Set the image link if one has been set.
      if (isset($media->media_nivo_slider_image_link[LANGUAGE_NONE][0]['value'])) {
        $slide['link'] = url($media->media_nivo_slider_image_link[LANGUAGE_NONE][0]['value'], array('absolute' => TRUE));
      }
      
      // Add the slide to the images set.
      $images[] = $slide;
    }

    // Clean the node title and use it for the slider id
    $slider_id = drupal_html_class(check_plain($node->title));
    
    // Build array of theme parameters.
    $theme_params = array(
      'slider_id' => $slider_id, 
      'images' => $images,
      'slider_theme' => $settings['slider_theme'],
      'ribbon' => $settings['ribbon'],
    );    
    
    // Display the block.
    $block['content'] = theme('media_nivo_slider_block', $theme_params);
    
    // Build parameter array.
    $js_params = array(
      'effect' => $settings['transition'],
      'slices' => $settings['slices'],
      'boxCols' => $settings['box_columns'],
      'boxRows' => $settings['box_rows'],
      'animSpeed' => $settings['transition_speed'],
      'pauseTime' => $settings['pause_length'],
      'directionNav' => $settings['direction_nav'],
      'directionNavHide' => $settings['direction_nav_hide'],
      'controlNav' => $settings['control_nav'],
      'controlNavThumbs' => $settings['control_nav_thumbs'],
      'controlNavThumbsFromRel' => $settings['control_nav_rel'],
      'controlNavThumbsSearch' => $settings['control_nav_search'],
      'controlNavThumbsReplace' => $settings['control_nav_replace'],
      'keyboardNav' => $settings['keyboard_nav'],
      'pauseOnHover' => $settings['pause_slideshow'],
      'manualAdvance' => $settings['manual_advance'],
      'captionOpacity' => $settings['caption_opacity'],
      'prevText' => $settings['direction_nav_prev_txt'],
      'nextText' => $settings['direction_nav_next_txt'],
      'randomStart' => $settings['random_start'],
      'beforeChange' => (isset($settings['before_change']) ? json_encode($settings['before_change']) : ''),
      'afterChange' => (isset($settings['after_change']) ? json_encode($settings['after_change']) : ''),
      'slideshowEnd' => (isset($settings['slideshow_end']) ? json_encode($settings['slideshow_end']) : ''),
      'lastSlide' => (isset($settings['last_slide']) ? json_encode($settings['last_slide']) : ''),
      'afterLoad' => (isset($settings['after_load']) ? json_encode($settings['after_load']) : ''),
    );
    
    // Add the slider parameters to the Drupal.settings javascript variable list.
    drupal_add_js(array('media_nivo_slider' => array($slider_id => $js_params)), 'setting');
  }

  return $block;
}

/**
 * Implements hook_node_update().
 */
function media_nivo_slider_node_update($node) {
  // If the media gallery node is being saved and is configured to not provide
  // a nivo slider block, remove all blocks associated with it from the database.
  _media_nivo_slider_block_cleanup($node);
}

/**
 * Implements hook_node_delete().
 */
function media_nivo_slider_node_delete($node) {
  // If the media gallery node is being deleted, remove all blocks associated with it from the database.
  _media_nivo_slider_block_cleanup($node, 'delete');
}

/**
 * Implements hook_theme().
 */
function media_nivo_slider_theme() {
  return array(
    'media_nivo_slider_block' => array(
      'template' => 'media-nivo-slider-block',
      'variables' => array('slider_id' => NULL, 'images' => NULL),
    ),
  );
}

/**
 * Helper function to cleanup a nodes associated nivo slider blocks on block disable or gallery delete.
 */
function _media_nivo_slider_block_cleanup($node, $op = 'update') {
  if ($node->type == 'media_gallery') {
    if ($op == 'delete' || empty($node->media_nivo_slider_block[LANGUAGE_NONE][0]['value'])) {
      db_delete('block')
        ->condition('module', 'media_nivo_slider')
        ->condition('delta', $node->nid)
        ->execute();
    }
  }
}
