You are here

media_browser_plus.module in Media Browser Plus 7.2

Same filename and directory in other branches
  1. 7.3 media_browser_plus.module
  2. 7 media_browser_plus.module

Adds fields to the media browser forms for better UX

File

media_browser_plus.module
View source
<?php

/**
 * @file
 * Adds fields to the media browser forms for better UX
 */

/** ***************************************** */

/** INCLUDES                                  */

/** ***************************************** */

// A registry of variable_get defaults.
require_once dirname(__FILE__) . '/includes/media_browser_plus.variables.inc';
require_once dirname(__FILE__) . '/includes/file_entity.admin.inc';

/**
 * Puts all selected media items into a zip archive and sends it as download.
 *
 * @TODO: check for internet sources etc. Only local files should be parsed.
 *
 * @param array $form
 *   The form structure.
 * @param array $form_state
 *   The form state.
 */
function media_browser_plus_download_images_submit($form, &$form_state) {
  if (isset($form_state['input']['selected_media']) && media_browser_plus_access('download media')) {
    $ids = array_keys($form_state['input']['selected_media']);

    // Only load those.
    $conditions[] = array(
      'property' => array(
        'fid',
        array(
          $ids,
        ),
        'IN',
      ),
    );
    $media_entities = media_browser_plus_load_multiple(array(
      'conditions' => $conditions,
      'apply_filter' => FALSE,
      'paging' => FALSE,
    ));

    // If possible avoid duplicate compression.
    if (function_exists('apache_setenv')) {
      @apache_setenv('no-gzip', '1');
    }

    // Create archive.
    $name = 'media-download-' . md5(microtime() . uniqid());
    $zip_file = '/tmp/' . $name . '.zip';
    $zip = new ZipArchive();
    $res = $zip
      ->open($zip_file, ZipArchive::CREATE);
    if ($res === TRUE && count($media_entities->results)) {
      foreach ($media_entities->results as $media) {
        $zip
          ->addFile(drupal_realpath($media->uri), $media->filename);
      }
      $zip
        ->close();
      header('Cache-Control: public');
      header('Pragma: public');
      header('Expires: 0');
      header('Cache-Control: must-revalidate, post-check=0, pre-check=0');
      header('Cache-Control: public');

      // header('Content-Description: File Transfer');
      header('Content-type: application/zip');
      header('Content-Disposition: attachment; filename=' . $zip_file);

      // header('Content-Transfer-Encoding: binary');
      header('Content-length: ' . filesize($zip_file));
      readfile($zip_file);
      unlink($zip_file);
      die;
    }
    else {
      drupal_set_message(t('Failed to create download archive'), 'error');
    }
  }
}

/**
 * Called by the JS fronted (ajax) to change the folder of a media object.
 */
function media_browser_plus_change_folder($form, &$form_state) {
  if (!isset($form_state['input']['media'])) {

    // @fixme Decide: die() or return.
    die('');
    return $form;
  }

  // Parse values.
  $folder = (int) str_replace('folder_load_', '', $form_state['input']['folder']);
  $media_id = (int) str_replace('edit-files-', '', $form_state['input']['media']);
  if (!$media_id) {

    // @fixme Decide: die() or return.
    die('');
    return $form;
  }
  $media = file_load($media_id);

  // Apply new folder.
  if (isset($media->field_folder[LANGUAGE_NONE][0]['tid'])) {
    $media->field_folder[LANGUAGE_NONE][0]['tid'] = $folder;
  }
  else {
    $media->field_folder = array(
      LANGUAGE_NONE => array(
        array(
          'tid' => $folder,
        ),
      ),
    );
  }

  // Save changes.
  media_browser_plus_move_file($folder, $media);

  // @fixme Decide: die() or return.
  die('');
  return $form;
}

/**
 * Called by the JS fronted (ajax) to get the media list for a given folder.
 */
function media_browser_plus_thumbnailsJSON() {
  if (isset($_GET['folder'])) {
    $folder = (int) str_replace('folder_load_', '', $_GET['folder']);

    // Create conditions.
    $conditions = array();

    // Check for filter set by library.
    if (isset($_GET['filter'])) {
      $filter = drupal_json_decode($_GET['filter']);

      // Bugfix - $conditions = $filter;
      foreach ($filter as $key => $value) {

        // Checking each filter.
        $valid = TRUE;
        foreach ($value as $type => $params) {
          foreach ($params as $param) {
            if (is_array($param)) {
              $valid = !empty($param);
              foreach ($param as $media_type) {
                if (strlen(trim($media_type)) == 0) {
                  $valid = FALSE;
                  break;
                }
              }
            }
            else {
              if (strlen(trim($param)) == 0) {
                $valid = FALSE;
                break;
              }
            }
          }
        }
        if ($valid) {
          $conditions[] = $value;
        }
      }
    }

    // More conditions.
    if ($folder) {
      $conditions[] = array(
        'field' => array(
          'field_folder',
          'tid',
          array(
            $folder,
          ),
          'IN',
        ),
      );
    }
    elseif ($folder === 0) {

      // Get unsorted files. We can't use EFQ conditions because the field
      // tables are joined using inner join, what excludes unsorted files from
      // the whole query at all. Thus fetch the fids of the unsorted fields and
      // use this as condition.
      $query = db_select('file_managed')
        ->fields('file_managed', array(
        'fid',
        'fid',
      ))
        ->condition('uri', db_like('temporary://') . '%', 'NOT LIKE')
        ->isNull('entity_id');
      $query
        ->leftJoin('field_data_field_folder', 'folder', "entity_type = 'file' AND entity_id = file_managed.fid");
      $result = $query
        ->execute()
        ->fetchAll(PDO::FETCH_KEY_PAIR);
      $conditions[] = array(
        'property' => array(
          'fid',
          $result,
          'IN',
        ),
      );
    }
    $order = array(
      array(
        'property' => array(
          'fid',
          'DESC',
        ),
      ),
    );
    $media_entities = media_browser_plus_load_multiple(array(
      'conditions' => $conditions,
      'order' => $order,
    ));
    module_load_include('inc', 'media', 'includes/media.browser');
    foreach ($media_entities->results as $media) {
      media_browser_build_media_item($media);
    }
    $output = array(
      'media' => array_values($media_entities->results),
      'folder_loaded' => 'folder_load_' . $folder,
      'overall_count' => $media_entities->overall_count,
    );
    drupal_json_output($output);
    die;
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for media_add_upload_multiple().
 *
 * @deprecated Remove once >= Media7.x-2.0-unstable5 is wide spread.
 */
function media_browser_plus_form_media_add_upload_multiple_alter(&$form, &$form_state) {
  media_browser_plus_form_file_entity_add_upload_multiple_alter($form, $form_state);
}

/**
 * Implements hook_form_FORM_ID_alter() for file_entity_add_upload_multiple().
 */
function media_browser_plus_form_file_entity_add_upload_multiple_alter(&$form, &$form_state) {

  // This builds the tags textfield and adds the autocomplete handlers to it.
  // The #element_validate may not be necessary because this never triggers
  // hook_field_update() or hook_field_insert()
  $form['field_tags'] = _media_browser_plus_tag_form();
  $form['field_folder'] = _media_browser_plus_folder_form();

  // Maintain the order of the other form items.
  $form['upload']['#weight'] = 0;
  $form['submit']['#weight'] = 2;

  // Add an additional form submission callback that fires after the default.
  $form['#submit'][] = 'media_browser_plus_submit';
}

/**
 * Implements hook_form_FORM_ID_alter() for media_import().
 */
function media_browser_plus_form_media_import_alter(&$form, &$form_state) {
  $form['field_tags'] = _media_browser_plus_tag_form();
  $form['field_folder'] = _media_browser_plus_folder_form();

  // Change submit.
  $form['submit']['#weight'] = 2;
  $form['#submit'] = array(
    'media_browser_plus_media_import_submit',
  );
}

/**
 * Changing the media import standard submit to use our own batch process.
 */
function media_browser_plus_media_import_submit($form, &$form_state) {
  if ($form_state['values']['op'] == t('Confirm')) {
    $files = $form_state['storage']['files'];
    $batch = array(
      'title' => t('Importing Media'),
      'operations' => array(
        array(
          'media_browser_plus_media_import_batch_import_files',
          array(
            $files,
            $form_state['values'],
          ),
        ),
      ),
      'finished' => 'media_browser_plus_media_import_batch_complete',
    );
    if (!empty($form_state['values']['field_tags'])) {

      // Create any new taxonomy terms.
      foreach ($form_state['values']['field_tags'] as $i => &$item) {
        if ($item['tid'] == 'autocreate') {
          $term = (object) $item;
          unset($term->tid);
          taxonomy_term_save($term);
          $item['tid'] = $term->tid;
        }
      }
    }
    batch_set($batch);
    return;
  }
  $form_state['rebuild'] = TRUE;
}

/**
 * Batch process with the ability to apply the field values to the items.
 */
function media_browser_plus_media_import_batch_import_files($files, $form_values, &$context) {

  // Split up attributes.
  // list($files, $form_values) = $attributes;
  // Need to repeat a lot of code here just to add the fields :-(
  if (!isset($context['sandbox']['files'])) {

    // This runs the first time the batch runs.
    // This is stupid, but otherwise, I don't think it will work...
    $context['results'] = array(
      'success' => array(),
      'errors' => array(),
    );
    $context['sandbox']['max'] = count($files);
    $context['sandbox']['files'] = $files;
  }
  $files =& $context['sandbox']['files'];

  // Take a cut of files.  Let's do 10 at a time.
  $length = media_variable_get('import_batch_size', 10);
  if ($length > count($files)) {
    $length = count($files);
  }
  $to_process = array_splice($files, 0, $length);
  $image_in_message = '';
  foreach ($to_process as $file) {
    try {
      $file_obj = media_parse_to_file($file);
      $context['results']['success'][] = $file;

      // Adding fields here.
      $media = file_load($file_obj->fid);
      $media->field_folder[LANGUAGE_NONE][0] = array(
        'tid' => $form_values['field_folder'],
      );
      $media->field_tags[LANGUAGE_NONE] = $form_values['field_tags'];
      media_browser_plus_move_file($form_values['field_folder'], $media);
      if (!$image_in_message) {

        // @todo Is this load step really necessary? When there's time, test
        //   this, and either remove it, or comment why it's needed.
        $media = file_load($file_obj->fid);
        $image_in_message = file_view_file($media, 'media_preview');
      }
    } catch (Exception $e) {
      $context['results']['errors'][] = $file . ' Reason: ' . $e
        ->getMessage();
    }
  }
  $context['message'] = t('Importing') . theme('item_list', array(
    'items' => $to_process,
  ));

  // Just for kicks, show an image we are importing.
  $context['message'] .= drupal_render($image_in_message);
  $context['finished'] = ($context['sandbox']['max'] - count($files)) / $context['sandbox']['max'];
}

/**
 * Same completed batch method as in media.
 */
function media_browser_plus_media_import_batch_complete($success, $results, $operations) {
  if ($results['errors']) {
    drupal_set_message(filter_xss(theme('item_list', array(
      'items' => $results['errors'],
    ))), 'error');
  }
  if ($results['success']) {
    drupal_set_message(filter_xss(theme('item_list', array(
      'items' => $results['success'],
    ))));
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for media_internet().
 */
function media_browser_plus_form_media_internet_add_alter(&$form, &$form_state) {

  // Add an additional form submission callback that fires after the default.
  media_browser_plus_form_file_entity_add_upload_alter($form, $form_state);
}

/**
 * Form element validate handler for taxonomy term autocomplete element.
 *
 * Because media_browser_plus_form_file_entity_add_upload_multiple_alter() adds
 * a tags widget to a form that is not an entity editing form, but it is desired
 * for taxonomy_autocomplete_validate() to have access to the settings of the
 * field for which this widget is being added, this handler runs before
 * taxonomy_autocomplete_validate(), and adds the expected information to
 * $form_state, as expected by taxonomy_autocomplete_validate().
 */
function media_browser_plus_prepare_taxonomy_autocomplete_validate(&$element, &$form_state) {

  // Causes: Notice: Undefined index: #language in
  // media_browser_plus_prepare_taxonomy_autocomplete_validate()
  // (line 436 of ...sites/all/modules/media_browser_plus-HEAD/media_browser_plus.module).
  // @TODO: Fix.
  $form_state['field'][$element['#field_name']][$element['#language']]['field'] = field_info_field($element['#field_name']);

  // Fixes: undefined index #field_parents in field_widget_field().
  if (!isset($element['#field_parents'])) {
    $element['#field_parents'] = array();
  }
}

/**
 * Submit handler for the media browser forms that create new media entities.
 *
 * Enhances the media creation process by populating field content for the newly
 * created entities from user-submitted data and/or data available from a
 * remote provider.
 *
 * @see media_browser_plus_form_file_entity_add_upload_multiple_alter()
 * @see media_browser_plus_form_media_internet_add_alter()
 */
function media_browser_plus_submit($form, &$form_state) {

  // Grab the fids of the newly created media entities from the redirect query
  // string that was created by the form's primary submit handler, and load the
  // corresponding entities.
  $fids = NULL;
  if (isset($form_state['files'])) {
    foreach ($form_state['files'] as $i => $fid) {
      $fids[$i] = $fid->fid;
      $i++;
    }
  }
  elseif (isset($form_state['file'])) {
    $fids = $form_state['file']->fid;
  }
  elseif (isset($form_state['redirect'][1]['query']['fid'])) {

    // Compatibility mode.
    // @TODO: Remove once the latest versions of media and file_entity are wide
    // spread.
    $fids = $form_state['redirect'][1]['query']['fid'];
  }
  elseif (isset($form_state['storage']['upload'])) {
    $fids = $form_state['storage']['upload'];
  }
  if (!is_array($fids)) {
    $fids = array(
      $fids,
    );
  }
  $media_entities = file_load_multiple($fids);

  // If tags have been entered, apply them to each new entity.
  if (!empty($form_state['values']['field_tags'])) {

    // Create any new taxonomy terms.
    foreach ($form_state['values']['field_tags'] as $i => &$item) {
      if ($item['tid'] == 'autocreate') {
        $term = (object) $item;
        unset($term->tid);
        taxonomy_term_save($term);
        $item['tid'] = $term->tid;
      }
      unset($item);
    }
    foreach ($media_entities as $media) {
      $media->field_tags[LANGUAGE_NONE] = $form_state['values']['field_tags'];
    }
  }

  // Apply folder.
  foreach ($media_entities as $media) {
    $media->field_folder[LANGUAGE_NONE] = array(
      array(
        'tid' => $form_state['values']['field_folder'],
      ),
    );
  }

  // If the new media is from a 3rd party provider, and that provider also
  // provides MRSS data about the media, then populate the title and description
  // fields from that data.
  if (!empty($form_state['values']['embed_code'])) {
    $provider = media_internet_get_provider($form_state['values']['embed_code']);
    if ($data = _media_browser_plus_metadata($provider)) {
      foreach ($data as $field_name => $value) {
        $field = field_info_field($field_name);

        // Limiting value population only if the field is of type 'text' or
        // 'text_long' isn't as extensible as would be ideal, but we need some
        // protection against populating a field with incompatible content.
        if (isset($field) && in_array($field['type'], array(
          'text',
          'text_long',
        )) && isset($field['bundles']['media'])) {
          foreach ($media_entities as $media) {
            if (in_array($media->type, $field['bundles']['media']) && !isset($media->{$field_name}[LANGUAGE_NONE][0]['value'])) {
              $media->{$field_name}[LANGUAGE_NONE][0]['value'] = $value;
            }
          }
        }
      }
    }
  }
  foreach ($media_entities as $media) {
    media_browser_plus_move_file($form_state['values']['field_folder'], $media);
  }
  if (!empty($form_state['redirect']) && is_string($form_state['redirect']) && mb_strpos($form_state['redirect'], 'file/', 0, 'UTF-8') === 0) {

    // Path was set to file/%file, but we need to thoroughly check if we have
    // access to "admin/content/file", using a failsafe approach.
    $item = menu_get_item('admin/content/file');
    if ($item['access']) {
      $form_state['redirect'] = 'admin/content/file';
    }
  }
}

/**
 * Form submit handler for the media browser forms that edit media entities.
 *
 * Changes file's filesystem physical folder
 *
 * @see media_browser_plus_form_media_edit_alter()
 */
function media_browser_plus_edit_file_submit($form, &$form_state) {
  $media = $form_state['file'];
  $folder_id = $media->field_folder[LANGUAGE_NONE][0]['tid'];

  // Only save it if the folder id is changed.
  if ($form['field_folder'][LANGUAGE_NONE]['#default_value'][0] != $folder_id) {
    media_browser_plus_move_file($folder_id, $media);
  }
}

/**
 * Helper function to return metadata from a 3rd party media provider.
 *
 * Support for 3rd party metadata such as YouTube.
 *
 * @param object $provider
 *   A provider object as returned by media_internet_get_provider().
 *
 * @return array
 *   An array of media metadata available from the provider, keyed on field
 *   name.
 *
 * @see http://video.search.yahoo.com/mrss
 * @see media_internet_get_provider()
 * @see MediaInternetYouTubeHandler::getMRSS()
 */
function _media_browser_plus_metadata($provider) {

  // @todo This is early, experimental code, still subject to much change. For
  //   now, we assume $provider->getMRSS() returns a SimpleXML element. We'll
  //   want to change this assumption and have it return an array instead, but
  //   that requires fixing media_retrieve_xml() to handle XML namespaces
  //   properly.
  $data = array();
  if (is_callable(array(
    $provider,
    'getMRSS',
  )) && ($rss = $provider
    ->getMRSS())) {

    // MRSS is an extension of RSS, so the title field is available in the
    // default (ATOM) namespace.
    $data['media_title'] = (string) $rss->title;

    // The MRSS extensions are in their own namespace.
    $mrss = $rss
      ->children('http://search.yahoo.com/mrss/');
    $data['media_description'] = (string) $mrss->group->description;
  }
  $data = array_filter($data, 'strlen');
  return $data;
}

/**
 * Implements hook_preprocess_media_link().
 */
function media_browser_plus_preprocess_media_link(&$variables) {

  // Use the value of the title field, when there is one, as the link text for
  // all links that would otherwise default to the filename.
  // @todo Solve generically using the 'label' key of hook_entity_indo(). See
  //   http://drupal.org/node/910396.
  $media = file_load($variables['file']->fid);
  if (empty($variables['file']->description) && isset($media->media_title[LANGUAGE_NONE][0]['value'])) {
    $variables['file']->description = $media->media_title[LANGUAGE_NONE][0]['value'];
  }
}

/**
 * Implements hook_preprocess_media_thubmnail().
 */
function media_browser_plus_preprocess_media_thumbnail(&$variables) {

  // See media_browser_plus_preprocess_media_link(). Same thing here, but for
  // the links that appear underneath thumbnail previews.
  $media = $variables['element']['#file'];
  if (isset($media->media_title[LANGUAGE_NONE][0]['value'])) {
    $variables['element']['#name'] = $media->media_title[LANGUAGE_NONE][0]['value'];
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for media_add_upload().
 *
 * Altering the add file upload form the include folder and tag options
 *
 * @deprecated Remove once >= Media7.x-2.0-unstable5 is wide spread.
 */
function media_browser_plus_form_media_add_upload_alter(&$form, &$form_state) {
  media_browser_plus_form_file_entity_add_upload_alter($form, $form_state);
}

/**
 * Implements hook_form_FORM_ID_alter() for file_entity_add_upload().
 *
 * Altering the add file upload form the include folder and tag options
 */
function media_browser_plus_form_file_entity_add_upload_alter(&$form, &$form_state) {

  // Alter weight to display new forms in correct order.
  $form['file']['#weight'] = -5;
  $form['submit']['#weight'] = 5;
  $form['field_tags'] = _media_browser_plus_tag_form();
  $form['field_folder'] = _media_browser_plus_folder_form();
  $form['#submit'][] = 'media_browser_plus_submit';
}

/**
 * Implements hook_form_FORM_ID_alter() for file_entity_edit().
 *
 * Ensure the tagging form is below the folder form part.
 */
function media_browser_plus_form_file_entity_edit_alter(&$form, &$form_state) {

  // Setting the weight accordingly.
  if (isset($form['field_tags']['#weight'])) {
    $form['field_folder']['#weight'] = $form['field_tags']['#weight'] - 1;
  }
  $form['actions']['cancel'] = array(
    '#type' => 'submit',
    '#value' => t('Cancel'),
    '#weight' => 20,
    '#submit' => array(
      'media_browser_plus_edit_cancel',
    ),
  );
  $form['actions']['submit']['#submit'][] = 'media_browser_plus_edit_file_submit';
}

/**
 * Handles a cancelation of the file_entity_edit() form.
 *
 * Redirects the user to the appropriate location.
 */
function media_browser_plus_edit_cancel($form, &$form_state) {
  $destination = array();
  if (isset($_GET['destination'])) {
    $destination = drupal_get_destination();
    unset($_GET['destination']);
  }
  if (isset($destination['destination'])) {
    $parsed_url = parse_url($destination['destination']);
    parse_str($parsed_url['query'], $query);
    $form_state['redirect'] = array(
      $parsed_url['path'],
      array(
        'query' => $query,
      ),
    );
  }
}

/**
 * Returns the tag form element.
 */
function _media_browser_plus_tag_form() {
  return array(
    '#weight' => 1,
    '#language' => LANGUAGE_NONE,
    '#field_name' => 'field_tags',
    '#columns' => array(
      'tid',
    ),
    '#title' => t('Tags'),
    '#description' => t('Enter a comma-separated list of words to describe your media.'),
    '#required' => FALSE,
    '#delta' => 0,
    '#type' => 'textfield',
    '#default_value' => '',
    '#autocomplete_path' => 'taxonomy/autocomplete/field_tags',
    '#element_validate' => array(
      'media_browser_plus_prepare_taxonomy_autocomplete_validate',
      'taxonomy_autocomplete_validate',
    ),
    '#size' => 60,
  );
}

/**
 * Returns a select form item with a selectable media folders.
 */
function _media_browser_plus_folder_form() {
  $list = _media_browser_plus_folder_list();
  return array(
    '#type' => 'select',
    '#language' => LANGUAGE_NONE,
    '#title' => t('Media Folder'),
    '#field_name' => 'field_tags',
    '#weigth' => -2,
    '#options' => $list,
    '#description' => t('Select a folder for the media to be put in'),
  );
}

/**
 * Implements hook_menu().
 */
function media_browser_plus_menu() {
  $items['admin/content/file/change_folder'] = array(
    'title' => 'Change Folder',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_change_folder',
    ),
    'type' => MENU_CALLBACK,
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'edit media files',
    ),
    'file' => 'media_browser_plus.module',
  );
  $items['admin/content/file/filter'] = array(
    'title' => 'Media Filter',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_media_filter',
    ),
    'file' => 'includes/media_browser_plus.pages.inc',
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'filter media',
    ),
    'type' => MENU_LOCAL_ACTION,
    'context' => MENU_CONTEXT_INLINE,
  );
  $items['admin/content/file/thumbnailsJSON'] = array(
    'title' => 'Load Media Entities',
    'page callback' => 'media_browser_plus_thumbnailsJSON',
    'page arguments' => array(),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'view files',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'media_browser_plus.module',
  );
  $items['admin/config/media/media_browser_plus_settings'] = array(
    'title' => 'Media Browser Plus Settings',
    'description' => 'Change the behaviour and layout of the media browser plus UI',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_media_settings',
    ),
    'access arguments' => array(
      'administer files',
    ),
  );
  $items['admin/content/file/edit_multiple/%'] = array(
    'title' => 'Edit Media Items',
    'page callback' => 'media_browser_plus_edit_multiple_form',
    'page arguments' => array(
      4,
    ),
    'file' => 'includes/media_browser_plus.pages.inc',
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'edit media files',
    ),
  );
  $items['admin/content/file/delete_multiple/%'] = array(
    'title' => 'Delete Media Items',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_delete_multiple_form',
      4,
    ),
    'file' => 'includes/media_browser_plus.pages.inc',
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'edit media files',
    ),
  );

  // Folder management disabled until menu bug has been fixed.
  $items['admin/content/file/folder_list'] = array(
    'title' => 'Administer folders',
    'description' => 'Manage your media folders',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_folder_list',
    ),
    'file' => 'includes/media_browser_plus.folders.inc',
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'administer media folders',
    ),
  );
  $items['admin/content/file/add_folder'] = array(
    'title' => 'Add Folder',
    'description' => 'Add a new media folder',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_folder_add',
    ),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'administer media folders',
    ),
    'file' => 'includes/media_browser_plus.folders.inc',
  );
  $items['admin/content/file/folder/%media_browser_plus_folder/edit'] = array(
    'title' => 'Edit Folder',
    'description' => 'Edit media folder',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_folder_edit',
      4,
    ),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'administer media folders',
    ),
    'file' => 'includes/media_browser_plus.folders.inc',
  );
  $items['admin/content/file/folder/%media_browser_plus_folder/delete'] = array(
    'title' => 'Delete Folder',
    'description' => 'Delete media folder',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_folder_delete',
      4,
    ),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'administer media folders',
    ),
    'file' => 'includes/media_browser_plus.folders.inc',
  );
  $items['admin/content/file/%file/preview'] = array(
    'title' => 'Preview Media',
    'description' => 'Preview Media Item',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'media_browser_plus_media_preview',
      3,
    ),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'preview media',
    ),
    'file' => 'includes/media_browser_plus.pages.inc',
  );
  return $items;
}

/**
 * Implements hook_menu_alter().
 *
 * @param array $items
 *   List of existing menu items.
 */
function media_browser_plus_menu_alter(&$items) {
  $items['admin/content/file']['access callback'] = 'media_browser_plus_access';
  $items['admin/content/file']['access arguments'] = array(
    'access media backend',
  );
  $items['admin/content/file/thumbnails']['access callback'] = array(
    'media_browser_plus_access',
  );
  $items['admin/content/file/thumbnails']['access arguments'] = array(
    'media grid view',
  );
  if (variable_get('media_browser_plus_thumbnails_as_default_browser', TRUE)) {
    $items['admin/content/file/list']['access callback'] = 'media_browser_plus_access';
    $items['admin/content/file/list']['access arguments'] = array(
      'media list view',
    );
    $items['admin/content/file/list'] += $items['admin/content/file/thumbnails'];
    $items['admin/content/file/list']['type'] = MENU_LOCAL_TASK | MENU_NORMAL_ITEM;
    $items['admin/content/file/thumbnails']['type'] = MENU_DEFAULT_LOCAL_TASK;
  }
}

/**
 * Implements hook_permission().
 */
function media_browser_plus_permission() {
  return array(
    'media grid view' => array(
      'title' => t('Grid View'),
      'description' => t('Allow users to use the grid view.'),
    ),
    'media list view' => array(
      'title' => t('List View'),
      'description' => t('Allow users to use the list view.'),
    ),
    'access media backend' => array(
      'title' => t('Access media backend'),
      'description' => t('Allow user to access the media backend according to their privileges.'),
    ),
    'upload media' => array(
      'title' => t('Upload media'),
      'description' => t('Allow user to add media.'),
    ),
    'download media files' => array(
      'title' => t('Download Files'),
      'description' => t('Allows the user to download the original file items.'),
    ),
    'filter media' => array(
      'title' => t('Filter Media'),
      'description' => t('Allows the user to filter the displayed media in the backend.'),
    ),
    'administer media folders' => array(
      'title' => t('Administer Media Folders'),
      // @TODO better description
      'description' => t('Allows the user to add, edite, delete and resort media folders.'),
    ),
    'preview media' => array(
      'title' => t('Preview media'),
      // @TODO better description
      'description' => t('Allows the user to view a configurable preview of the original media item.'),
    ),
    'edit media files' => array(
      'title' => t('Edit media files'),
      // @TODO better description
      'description' => t('Allows the user to edit the original media item.'),
    ),
  );
}

/**
 * Implements hook_library().
 */
function media_browser_plus_library() {
  $colorbox_path = variable_get('media_browser_plus_library_path', FALSE);
  if ($colorbox_path === FALSE) {
    $colorbox_path = module_exists('libraries') ? libraries_get_path('colorbox') : 'sites/all/libraries/colorbox';
    if (is_dir($colorbox_path . '/colorbox')) {
      $colorbox_path .= '/colorbox';
    }
  }
  else {
    $colorbox_path .= '/colorbox';
  }
  $stylesheet = variable_get('media_browser_plus_stylesheet', 'example1');
  $libraries['colorbox'] = array(
    'title' => 'Colorbox',
    'website' => 'http://colorpowered.com/colorbox/',
    'version' => '1.3.9',
    'js' => array(
      $colorbox_path . '/jquery.colorbox-min.js' => array(),
    ),
    'css' => array(
      $colorbox_path . '/' . $stylesheet . '/colorbox.css' => array(
        'type' => 'file',
        'media' => 'screen',
      ),
    ),
  );
  $path = drupal_get_path('module', 'media_browser_plus');
  $libraries['media_browser_plus'] = array(
    'title' => 'Media Browser Plus',
    'version' => '1',
    'js' => array(
      $path . '/js/media_browser_plus.admin.menu.js' => array(),
    ),
    'css' => array(
      $path . '/css/media_browser_plus.admin.css' => array(
        'type' => 'file',
        'media' => 'screen',
      ),
      $path . '/css/colorbox.css' => array(
        'type' => 'file',
        'media' => 'screen',
      ),
    ),
  );
  return $libraries;
}

/**
 * Checks if the user has the permission to download a file.
 *
 * @todo: this function may be obsolete in 2.x
 *
 * @param $field
 * @param string $entity_type
 *   The entity type.
 * @param string $entity
 *   Then entity.
 */
function media_browser_plus_file_download_access($field, $entity_type, $entity) {

  // Only check against media entities.
  if ($entity_type == 'file') {

    // Check for media admin AND return true if found.
    return file_acces('view', $entity);

    // return media_browser_plus_media_access($entity);
  }
}

/**
 * Checks access to a given media entity.
 *
 * @todo: this function may be obsolete in 2.x
 *
 * @param object $media_entity
 */
function media_browser_plus_media_access($media_entity) {
  if (media_browser_plus_access('administer files')) {
    return TRUE;
  }

  // Start with ACCESS_ALLOW - by default media items are fully accessible.
  $access = MEDIA_ENTITY_ACCESS_ALLOW;

  // Collect all modules implementing hook_media_entity_access.
  foreach (module_implements('media_entity_access') as $module) {

    // And invoke the hook.
    $return = module_invoke($module, 'media_entity_access', $media_entity);

    // If no ALLOW or DENY was returned we assume IGNORE and check the next.
    if ($return != MEDIA_ENTITY_ACCESS_ALLOW && $return != MEDIA_ENTITY_ACCESS_DENY) {
      continue;
    }

    // If we have a DENY we can return a complete false here.
    if ($return === MEDIA_ENTITY_ACCESS_DENY) {
      return FALSE;
    }

    // Otherwise it is an ALLOW and we save it.
    $access = MEDIA_ENTITY_ACCESS_ALLOW;
  }

  // Check if we had one allow.
  return $access === MEDIA_ENTITY_ACCESS_ALLOW;
}

/**
 * Revokes the general 'view media' == 'download media' access rule.
 * @todo: this function may be obsolete in 2.x
 */
function media_browser_plus_file_download_access_alter(&$grants, $field, $entity_type, $entity = NULL) {
  if ($entity_type == 'file') {
    unset($grants['file']);
  }
}

/**
 * Implements hook_media_operations().
 */
function media_browser_plus_media_operations() {
  return array(
    'edit_multiple' => array(
      'label' => t('Edit'),
      'callback' => NULL,
      'redirect' => 'admin/content/file/edit_multiple/%fids',
    ),
  );
}

/**
 * Manages access for media browser plus actions.
 *
 * @param string $op
 *   The permission, such as "administer nodes", being checked for.
 *
 * @return boolean
 *   TRUE if the user has the permission.
 */
function media_browser_plus_access($op) {
  return user_access('administer files') || user_access($op);
}

/**
 * Implements of hook_load().
 *
 * Used to load media folders.
 */
function media_browser_plus_folder_load($id) {
  return taxonomy_term_load($id);
}

/**
 * Creates the folder media tree.
 */
function _media_browser_plus_folder_hierarchy_list($folders) {

  // Only do all the work if there's something to process.
  if (count($folders) == 0) {
    return t('No folders created yet');
  }

  // Create hierarchical structure.
  $path = base_path() . drupal_get_path('module', 'media_browser_plus');
  $pixel_img = '<img src="' . $path . '/images/pixel.gif" border="0" alt="">';

  // Check if there's a folder requested.
  $folder_id = isset($_REQUEST['folder']) ? (int) $_REQUEST['folder'] : NULL;

  // List items.
  $list_items = array();

  // Keeps an array with all the folders referenced into the list.
  $all_items = array();
  foreach ($folders as $folder) {
    $has_media = _media_browser_plus_folder_empty($folder->tid) || $folder->tid == 0;
    $all_items[$folder->tid] = array(
      'data' => '<div class="icon">' . $pixel_img . '</div><div class="drop">' . $folder->name . '</div>',
      'id' => 'folder_load_' . $folder->tid,
      'class' => array(
        'folder',
      ),
    );
    if (!$has_media) {
      $all_items[$folder->tid]['class'][] = 'empty';
    }
    if ($folder_id == $folder->tid) {
      $all_items[$folder->tid]['class'][] = 'selected';
    }

    // Check if this element has to be registered as a child in a parent item.
    if (!empty($folder->parents) && ($parent_tid = reset($folder->parents)) > 0 && isset($all_items[$parent_tid])) {

      // Set the children data for the parent. Since the parent is referenced
      // from the list into all_items the changes will be transfered.
      $all_items[$parent_tid]['children'][$folder->tid] =& $all_items[$folder->tid];
      $all_items[$parent_tid]['class']['parent'] = 'parent';
    }
    else {

      // Add referenced data into item list. Later extensions of potential
      // child elements will affect the whole structure.
      $list_items[$folder->tid] =& $all_items[$folder->tid];
    }
  }

  // Add folder for unsorted media if necessary.
  if (_media_browser_plus_has_unsorted_media()) {
    array_unshift($list_items, array(
      'data' => '<div class="icon">' . $pixel_img . '</div>' . t('Unsorted'),
      'id' => 'folder_load_0',
      'class' => array(
        'folder',
      ),
    ));
  }

  // If none of the folders was selected, just select the first one.
  if (empty($folder_id)) {
    reset($list_items);
    $list_items[key($list_items)]['class'][] = 'selected';
  }
  return theme('item_list', array(
    'items' => $list_items,
    'attributes' => array(
      'class' => array(
        'media-folder-list',
      ),
    ),
  ));
}

/**
 * Checks for unsorted (i.e. media not in folders) media.
 */
function _media_browser_plus_has_unsorted_media() {

  // EFQ doesn't work because the field table is used as base table and an inner
  // join is used?!
  // $query = new EntityFieldQuery('file');
  // $result = $query
  //   ->entityCondition('entity_type', 'file')
  //   ->propertyCondition('status', 1)
  //   ->fieldCondition('field_folder', 'tid', '', 'IS NULL')
  //   ->range(0, 1)
  //   ->execute();
  //
  // In favor of not unnecessarily loading file entities we use a raw query.
  // *eeeewwh*!
  $query = db_select('file_managed')
    ->fields('file_managed', array(
    'fid',
  ))
    ->condition('uri', db_like('temporary://') . '%', 'NOT LIKE')
    ->isNull('entity_id')
    ->range(0, 1);
  $query
    ->leftJoin('field_data_field_folder', 'folder', "entity_type = 'file' AND entity_id = file_managed.fid");
  $result = $query
    ->execute()
    ->fetchCol();
  return !empty($result);
}

/**
 * @todo Document what this function does.
 *
 * @param string $prefix_padding
 */
function _media_browser_plus_folder_list($prefix_padding = '-') {
  $vocabulary = taxonomy_vocabulary_machine_name_load('media_folders');
  $folders = taxonomy_get_tree($vocabulary->vid);
  $folders = _media_browser_plus_filter_folder_access($folders);

  // Fill list with padded folders.
  $list = array();
  foreach ($folders as $folder) {
    $pad = $folder->depth * strlen($prefix_padding) + strlen($folder->name);
    $list[$folder->tid] = str_pad($folder->name, $pad, $prefix_padding, STR_PAD_LEFT);
  }
  return $list;
}

/**
 * Loads media entities and allows filtering, sorting and paging.
 *
 * @param array $variables
 *   Holds an array with the following optional parameters
 * $ids
 *   one dimensional array of entity_ids
 * $conditions
 *   multidemsional array build like this:
 *   array(
 *     array('entity' => array('comlumn', 'value', 'condition')),
 *     array('property' => array('comlumn', 'value', 'condition')),
 *     array('field' => array('field_name', 'comlumn', 'value', 'condition')),
 *   )
 * $order
 *   multidemsional array build like this:
 *   array(array('entity' => array('comlumn', 'direction')),
 *         array('property' => array('comlumn', 'direction')),
 *         array('field' => array('comlumn', 'direction')))
 * $header
 *   table header used for sorting
 * $per_page
 *   items per page
 */
function media_browser_plus_load_multiple($variables) {

  // Set up default parameter.
  $params = array(
    'ids' => array(),
    'conditions' => array(),
    'order' => array(),
    'header' => array(),
    'page' => -1,
    'per_page' => variable_get('media_media_per_page', 30),
    'paging' => TRUE,
    'ids_only' => FALSE,
    'count_only' => FALSE,
    'apply_filter' => TRUE,
  );

  // Override defaults.
  // @todo Is this loop really necessary. Something like
  // $params = $variables + $params; should work too, right?
  foreach ($variables as $key => $value) {
    if (isset($params[$key])) {
      $params[$key] =& $variables[$key];
    }
  }
  if ($params['apply_filter'] && isset($_SESSION['media-filter'])) {
    if (strlen($_SESSION['media-filter']['filename'])) {
      $params['conditions'][] = array(
        'property' => array(
          'filename',
          '%' . $_SESSION['media-filter']['filename'] . '%',
          'LIKE',
        ),
      );
    }
    if (count($_SESSION['media-filter']['type'])) {
      $params['conditions'][] = array(
        'property' => array(
          'type',
          explode(',', $_SESSION['media-filter']['type']),
          'IN',
        ),
      );
    }
    if (count($_SESSION['media-filter']['field_folder'])) {
      $params['conditions'][] = array(
        'field' => array(
          'field_folder',
          'tid',
          $_SESSION['media-filter']['field_folder'],
          'IN',
        ),
      );
    }
    if (count($_SESSION['media-filter']['field_tags'])) {
      foreach ($_SESSION['media-filter']['field_tags'] as $tag_id) {
        $params['conditions'][] = array(
          'field' => array(
            'field_tags',
            'tid',
            $tag_id,
            '=',
          ),
        );
      }
    }
  }

  // Another backward compatibility check.
  $hidden_stream_wrapper_function = 'media_get_hidden_stream_wrappers';
  if (function_exists('file_entity_get_hidden_stream_wrappers')) {
    $hidden_stream_wrapper_function = 'file_entity_get_hidden_stream_wrappers';
  }

  // Do not list temporary files.
  foreach (array_keys(call_user_func($hidden_stream_wrapper_function)) as $name) {
    $params['conditions'][] = array(
      'property' => array(
        'uri',
        $name . '%',
        'NOT LIKE',
      ),
    );
  }

  // Allow other modules to add/alter conditions.
  foreach (module_implements('media_access_conditions') as $module) {
    $params['conditions'] = array_merge(module_invoke($module, 'media_access_conditions'), $params['conditions']);
  }
  $query = new EntityFieldQuery();

  // Set entity type to media.
  $query
    ->entityCondition('entity_type', 'file');

  // EntityFieldQuery shouldn't check access against node_access.
  $query
    ->addTag('DANGEROUS_ACCESS_CHECK_OPT_OUT');

  // Parse ids if any have been passed.
  if (count($params['ids'])) {
    $query
      ->entityCondition('entity_id', $params['ids'], 'IN');
  }

  // Check for table header.
  if (count($params['header'])) {
    $query
      ->tableSort($params['header']);
  }

  // Parse conditions.
  foreach ($params['conditions'] as $condition) {

    // Look what type we have.
    $condition_keys = array_keys($condition);
    switch (array_pop($condition_keys)) {
      case 'entity':
        $query
          ->entityCondition($condition['entity'][0], $condition['entity'][1], $condition['entity'][2]);
        break;
      case 'property':
        $query
          ->propertyCondition($condition['property'][0], $condition['property'][1], $condition['property'][2]);
        break;
      case 'field':
        $query
          ->fieldCondition($condition['field'][0], $condition['field'][1], $condition['field'][2], $condition['field'][3]);
        break;
    }
  }

  // Parse order array.
  foreach ($params['order'] as $condition) {

    // Look what type we have.
    $condition_keys = array_keys($condition);
    switch (array_pop($condition_keys)) {
      case 'entity':
        $query
          ->entityOrderBy($condition['entity'][0], $condition['entity'][1]);
        break;
      case 'property':
        $query
          ->propertyOrderBy($condition['property'][0], $condition['property'][1]);
        break;
      case 'field':
        $query
          ->fieldOrderBy($condition['field'][0], $condition['field'][1], $condition['field'][2]);
        break;
    }
  }

  // Prepare result object.
  $res_object = new stdClass();
  if ($params['paging'] && !$params['count_only']) {

    // Doing a separate count query here, because including the internal pager
    // doesn't work but seems the only way to get a total result count.
    $count = clone $query;
    $count
      ->pager();
    $count
      ->execute();
    $res_object->overall_count = $count->pager['total'];

    // Using range here, because as said above the internal pager seems to be
    // bugged.
    $page = $params['page'];
    if ($page == -1) {
      $page = isset($_REQUEST['page']) ? $_REQUEST['page'] : 0;
    }
    $query
      ->range($page * $params['per_page'], $params['per_page']);

    // Adding the addition result fields.
    $res_object->page = $page;
    $res_object->pages = ceil($res_object->overall_count / variable_get('media_media_per_page', 30));
    $res_object->per_page = $params['per_page'];
  }

  // Count only query.
  if ($params['count_only']) {
    $query
      ->pager();
    $query
      ->execute();
    return $query->pager['total'];
  }
  $res_object->results = array();

  // Execute query and load results.
  $result = $query
    ->execute();
  if (!empty($result['file'])) {
    $res_object->results = $params['ids_only'] ? array_keys($result['file']) : entity_load('file', array_keys($result['file']));
  }
  return $res_object;
}

/**
 * Looks if a filter is active and filters the folders accordingly.
 *
 * @param array $folders
 *   The folders to filter.
 *
 * @return array
 *   The list with the filtered folders.
 */
function _media_browser_plus_filter_folders($folders) {

  // No filter active, return unchanged $folders array.
  $filtered_folders = $folders;
  if (isset($_SESSION['media-filter'])) {
    $folder_filtered = array();

    // Look through the tree and add elements that match filter.
    foreach ($folders as $item) {
      if (in_array($item->tid, $_SESSION['media-filter']['field_folder'])) {
        $folder_filtered[] = $item;
      }
    }
    $filtered_folders = $folder_filtered;
  }
  $filtered_folders = _media_browser_plus_filter_folder_access($filtered_folders);
  return $filtered_folders;
}

/**
 * @todo Document what this function does.
 *
 * @param array $folders
 *   The folders to scan.
 *
 * @return array
 *   List with the accessible folders.
 */
function _media_browser_plus_filter_folder_access($folders) {
  $temp_folders = $folders;
  $filtered_folders = array();
  foreach ($temp_folders as $item) {
    $access = TRUE;
    foreach (module_implements('media_folder_access') as $module) {
      $access = module_invoke($module, 'media_folder_access', $item);
      if ($access === FALSE) {
        break;
      }
      else {
        $access = TRUE;
      }
    }
    if ($access) {
      $filtered_folders[] = $item;
    }
  }
  return $filtered_folders;
}

/**
 * @todo Document what this function does.
 *
 * @param integer $page
 *   Current page.
 * @param integer $pages
 *   Total number of pages.
 */
function _media_browser_plus_pager($page, $pages) {

  // Get url for paging link.
  $destination = drupal_get_destination();
  $link = base_path() . '?q=admin/content/file/list';
  $sort = isset($_GET['sort']) ? '&sort=' . check_plain($_GET['sort']) : '';
  $order = isset($_GET['order']) ? '&order=' . check_plain($_GET['order']) : '';
  $url = $link . $sort . $order;

  // Create paging div inside buffer.
  $output = '<div id="media_paging_table" align="center">';

  // Calculate paging.
  $start = max(0, $page - ceil(variable_get('media_page_items_per_page') / 2));
  $end = min($pages, $start + variable_get('media_page_items_per_page'));
  if ($start > 0) {
    $output .= _media_browser_plus_pager_add_page_item($url, $start - 1, $page, '...');
  }

  // Create numbers.
  for ($i = $start; $i < $end; $i++) {
    $output .= _media_browser_plus_pager_add_page_item($url, $i, $page, $i + 1);
  }
  if ($pages > $i) {
    $output .= _media_browser_plus_pager_add_page_item($url, $i, $page, '...');
  }
  return $output . '</div>';
}

/**
 * @todo Document what this function does.
 *
 * @param string $url
 *   The base url.
 * @param integer $page
 *   The page number.
 * @param integer $current_page
 *   The current page number.
 * @param string $title
 *   The title of the link.
 */
function _media_browser_plus_pager_add_page_item($url, $page, $current_page, $title) {
  $page_item = '<a class="media_paging_page';
  if ($page == $current_page) {
    $page_item .= ' active_page';
  }
  $page_item .= '" href="' . $url . '&page=' . (int) $page . '">' . $title . '</a>';
  return $page_item;
}

/**
 * Creates the media browser plus settings form.
 */
function media_browser_plus_media_settings($form, &$form_state = array()) {
  $form = array(
    'media_per_page' => array(
      '#type' => 'textfield',
      '#title' => t('Media Items per page'),
      '#description' => t('Insert a number higher than one for the amount of media items displayed per page.'),
      '#default_value' => variable_get('media_media_per_page', 30),
      '#maxlength' => 4,
      '#required' => TRUE,
    ),
    'grid_window_height' => array(
      '#type' => 'textfield',
      '#title' => t('Grind Window Height'),
      '#default_value' => variable_get('media_grid_window_height', 400),
      '#description' => t('Set a maximum height of pixels for the media grid view.'),
      '#maxlength' => 4,
      '#required' => TRUE,
    ),
    'page_items_per_page' => array(
      '#type' => 'textfield',
      '#title' => t('Page Items per page'),
      '#default_value' => variable_get('media_page_items_per_page'),
      '#description' => t('Set how many page items you want in the paging navigation of each page.'),
      '#maxlength' => 4,
      '#required' => TRUE,
    ),
    'max_filesize' => array(
      '#type' => 'textfield',
      '#title' => t('Upload Maximum Filesize'),
      '#default_value' => media_variable_get('max_filesize'),
      '#description' => t('Standard unit is bytes and therefore can be left out. Otherwise use "NUMBER UNIT"'),
      '#maxlength' => 20,
      '#required' => TRUE,
    ),
    'root_folder' => array(
      '#type' => 'textfield',
      '#title' => t('Media Root folder'),
      '#default_value' => variable_get('media_root_folder'),
      '#description' => t("The root folder for files handled by the media module. <strong>Attention: Changing this will move all existing files in the file system too!</strong>"),
    ),
    'media_browser_plus_thumbnails_as_default_browser' => array(
      '#type' => 'checkbox',
      '#title' => t('Use thumbnails view as default.'),
      '#description' => t('If enabled the thumbnails view will displayed when accessing "admin/content/file".'),
      '#default_value' => variable_get('media_browser_plus_thumbnails_as_default_browser', TRUE),
    ),
  );
  $form['actions'] = array(
    '#type' => 'actions',
  );
  $form['actions']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save Changes'),
  );
  return $form;
}

/**
 * Saves the entered settings.
 */
function media_browser_plus_media_settings_submit($form, &$form_state) {

  // Change settings.
  variable_set('media_media_per_page', (int) $form_state['values']['media_per_page']);
  variable_set('media_grid_window_height', (int) $form_state['values']['grid_window_height']);
  variable_set('media_page_items_per_page', (int) $form_state['values']['page_items_per_page']);
  media_variable_set('max_filesize', trim($form_state['values']['max_filesize']));

  // Check if the root folder was changed.
  $old_root = variable_get('media_root_folder');
  $new_root = trim($form_state['values']['root_folder'], '/');

  // Move the files to the new root folder if necessary.
  if ($old_root != $new_root) {

    // Load folder handling functions.
    module_load_include('inc', 'media_browser_plus', 'includes/media_browser_plus.folders');
    media_browser_plus_move_root_folder($old_root, $new_root);
  }

  // Notify user.
  drupal_set_message(t('Media Browser Plus Settings changed successfully'));
}

/**
 * Validates the settings.
 */
function media_browser_plus_media_settings_validate($form, &$form_state) {

  // Validate settings.
  $value = (int) $form_state['values']['media_per_page'];
  if ($value <= 0) {
    form_set_error('Media Settings', t('Illegal value for "Media Items per page"'));
  }
  $value = (int) $form_state['values']['grid_window_height'];
  if ($value <= 100) {
    form_set_error('Media Settings', t('Illegal value for "Grind Window Height"'));
  }
  $value = (int) $form_state['values']['page_items_per_page'];
  if ($value <= 2) {
    form_set_error('Media Settings', t('Illegal value for "Page Items per page"'));
  }
  $value = parse_size(trim($form_state['values']['max_filesize']));
  if ($value === 0) {
    form_set_error('Media Settings', t('Illegal value for "Upload Maximum Filesize"'));
  }
}

/**
 * Implements hook_field_attach_presave().
 *
 * Makes sure all media are in a folder.
 */
function media_browser_plus_field_attach_presave($entity_type, $entity) {
  if ($entity_type != 'file') {
    return;
  }

  // Look for folder and set default if none found
  // $media->field_folder[LANGUAGE_NONE] = array(array('tid' => $form_state['values']['field_folder']));
  if (!isset($entity->field_folder) || !isset($entity->field_folder[LANGUAGE_NONE]) || !count($entity->field_folder[LANGUAGE_NONE]) || !isset($entity->field_folder[LANGUAGE_NONE][0]['tid']) || (int) $entity->field_folder[LANGUAGE_NONE][0]['tid'] == 0) {

    // sSt default folder is no folder or incorrect value.
    $root = media_browser_plus_get_media_root_folder();
    $entity->field_folder = array();
    $entity->field_folder[LANGUAGE_NONE] = array(
      array(
        'tid' => $root->tid,
      ),
    );
  }
}

/**
 * Check if a given folder has media in it (does include current filter).
 *
 * @param integer $folder_id
 *   Id of the folder to check.
 */
function _media_browser_plus_folder_empty($folder_id) {

  // Save paging values.
  $gp = isset($_GET['page']) ? $_GET['page'] : NULL;
  $pp = isset($_POST['page']) ? $_POST['page'] : NULL;

  // Set media condition.
  $condition = array(
    array(
      'field' => array(
        'field_folder',
        'tid',
        array(
          $folder_id,
        ),
        'IN',
      ),
    ),
  );
  $variables = array(
    'conditions' => $condition,
    'per_page' => 1,
    'ids_only' => TRUE,
  );
  $media = media_browser_plus_load_multiple($variables);

  // Restore paging values if necessary.
  if ($gp) {
    $_GET['page'] = $gp;
  }
  if ($pp) {
    $_POST['page'] = $pp;
  }

  // Check if media has been found in the folder.
  return $media->overall_count > 0;
}

/**
 * @todo Document what this function does.
 *
 * @param string $tags
 *   Comma separated string of the tags.
 * @param bool $tids_only
 *   Return the term ids instead term entities.
 * @param bool $auto_create
 *   Create missing tags on the fly.
 *
 * @return array
 *   List of term entities or term ids.
 */
function media_browser_plus_load_tag_terms($tags, $tids_only = TRUE, $auto_create = FALSE) {
  $vocabulary = taxonomy_vocabulary_machine_name_load('tags');
  $select = $tids_only ? 'tid, name' : '*';
  $all_tags = array();
  $found_tags = array();
  $found_terms = array();
  $terms = explode(',', $tags);
  foreach ($terms as $tag) {

    // Check if tag exists.
    // @todo Would an EntityFieldQuery be appropriate?
    // http://drupal.org/node/916776
    $results = db_query('SELECT ' . $select . ' FROM {taxonomy_term_data} ttd WHERE ttd.name = :name AND ttd.vid = :vocabulary', array(
      'name' => check_plain(trim($tag)),
      'vocabulary' => $vocabulary->vid,
    ));
    foreach ($results as $result) {
      $term = taxonomy_term_load($result->tid);
      if ($tids_only) {
        $found_terms[] = array(
          'tid' => $term->tid,
        );
      }
      else {
        $found_terms[] = get_object_vars($term);
      }
      $found_tags[] = trim($tag);
    }
    $all_tags[] = trim($tag);
  }
  if ($auto_create) {
    foreach (array_diff($all_tags, $found_tags) as $id => $tag) {
      $term = new stdClass();
      $term->name = $tag;
      $term->vid = $vocabulary->vid;
      if (strlen(trim($term->name))) {
        taxonomy_term_save($term);
        if ($tids_only) {
          $found_terms[] = array(
            'tid' => $term->tid,
          );
        }
        else {
          $found_terms[] = get_object_vars($term);
        }
      }
    }
  }
  return $found_terms;
}

/**
 * Loads and (if $autocreate is set) creates the default media folder object.
 *
 * @return object|FALSE
 *   The folder term or FALSE if not found.
 */
function media_browser_plus_get_media_root_folder($autocreate = FALSE) {
  $root_folder = FALSE;
  $vocabulary = taxonomy_vocabulary_machine_name_load('media_folders');
  if ($vocabulary) {

    // Fetch the media root term.
    $results = taxonomy_get_term_by_name('Media Root', 'media_folders');
    if (!empty($results)) {
      $root_folder = reset($results);
    }
    elseif ($autocreate) {
      $root_folder = new stdClass();
      $root_folder->name = 'Media Root';
      $root_folder->description = 'default media folder';
      $root_folder->vid = $vocabulary->vid;
      $root_folder->weight = '-10';

      // Save (default folder) term.
      taxonomy_term_save($root_folder);
    }
  }
  return $root_folder;
}

/**
 * Implements hook_media_browser_plugin_info().
 */
function media_browser_plus_media_browser_plugin_info() {
  $plugins = array();
  $plugins['library_plus'] = array(
    'title' => t('Library Plus'),
    'weight' => 10,
    'class' => 'MediaBrowserPlusLibrary',
    'handler' => array(
      'path' => drupal_get_path('module', 'media_browser_plus') . '/includes',
      'file' => 'MediaBrowserPlusLibrary.inc',
      'class' => 'MediaBrowserPlusLibrary',
    ),
    'access callback' => 'media_browser_plus_access',
    'access arguments' => array(
      'view files',
    ),
  );
  return $plugins;
}

/**
 * Creates the Extended Library for the media browser popup.
 *
 * @param array $form
 *   The form structure.
 * @param array $form_state
 *   The form state.
 * @param bool $multiselect
 *   Allow multiple selection.
 * @param array $types
 *   The allowed file types.
 *
 * @return array
 *   The form extended with the necessary library stuff.
 */
function media_browser_plus_library_browser($form, &$form_state, $multiselect, $types) {
  $path = drupal_get_path('module', 'media_browser_plus');

  // Assemble library from grid view.
  $form['#attached']['library'][] = array(
    'media_browser_plus',
    'media_browser_plus',
  );
  $form['#attached']['library'][] = array(
    'media_browser_plus',
    'colorbox',
  );

  // Set base href for javascript requests.
  $settings = media_browser_plus_main_view_javascript_settings();
  $settings['media_browser_plus']['multiselect'] = $multiselect;
  $settings['media_browser_plus']['folder_dnd_enabled'] = FALSE;

  // Setting filter condition.
  $filter = array(
    array(
      'property' => array(
        'type',
        $types,
        'IN',
      ),
    ),
  );
  $settings['media_browser_plus']['filter'] = drupal_json_encode($filter);

  // Attach settings.
  $form['#attached']['js'][] = array(
    'type' => 'setting',
    'data' => $settings,
  );

  // Check access rights.
  if (!media_browser_plus_access('media grid view')) {
    drupal_access_denied();
    return array();
  }

  // Adding grid view js and css.
  $form['#attached']['js'][] = $path . '/js/media_browser_plus.admin.js';
  $form['#attached']['js'][] = $path . '/js/media_browser_plus.library.js';
  drupal_add_library('system', 'ui.draggable');
  drupal_add_library('system', 'ui.droppable');

  // Removing options form part.
  unset($form['options']);
  if (!media_browser_plus_access('media list view') || !media_browser_plus_access('media grid view')) {
    unset($form['switch']);
  }

  // Add main grid view window.
  $form['admin'] = media_browser_plus_grid_view_form(TRUE, $multiselect, $form_state);

  // Append media basket only for multi select.
  if ($multiselect) {
    $form['media-basket'] = media_browser_plus_media_basket_form(TRUE, $form_state);
  }
  return $form;
}

/**
 * Deleting all field data attached to the media entity.
 *
 * @todo: This should actually be done in media module
 *
 * @param object $file
 *   The file object to delete.
 */
function media_browser_plus_file_delete($file) {
  $media = file_load($file->fid);
  module_invoke_all('entity_delete', $media, 'file');
  field_attach_delete('file', $media);
}

/**
 * Appends main grid view form.
 */
function media_browser_plus_grid_view_form($library_mode = FALSE, $multiselect = FALSE, &$form_state = array()) {

  // Load the media folders.
  $vocabulary = taxonomy_vocabulary_machine_name_load('media_folders');
  $folders = taxonomy_get_tree($vocabulary->vid);
  $folders = _media_browser_plus_filter_folders($folders);
  $folders = _media_browser_plus_folder_hierarchy_list($folders);
  form_load_include($form_state, 'inc', 'media_browser_plus', 'includes/file_entity.admin');

  // Build the folder form.
  $form['admin']['folder'] = array(
    '#type' => 'markup',
    '#markup' => '<div id="folder" style="height:' . variable_get('media_grid_window_height', 400) . 'px;">' . $folders . ' </div>',
  );
  $form['admin']['files']['#prefix'] = '<div class="media-display-thumbnails media-clear clearfix">' . '<ul class="media-list-thumbnails" style="height:' . variable_get('media_grid_window_height', 400) . 'px;">';

  // Setting up the header.
  $header = array(
    array(
      'data' => t('Folders'),
      'width' => '200',
    ),
    array(
      'data' => t('Media Files'),
      'width' => '*',
    ),
  );

  // And the data.
  $form['buttons'] = array();
  $form['buttons']['selection_assets'] = array(
    '#type' => 'markup',
    '#markup' => '<a href="#media_folder_table" id="media_main_view_select_all" >' . t('Select All') . '</a>' . '<a href="#media_folder_table" id="media_main_view_deselect_all" >' . t('Deselect All') . '</a>',
  );
  if (!$library_mode) {
    if (media_browser_plus_access('view files')) {
      $form['buttons']['view_media'] = array(
        '#type' => 'button',
        '#attributes' => array(
          'id' => 'media_buttons_view',
        ),
        '#value' => t('View'),
      );
    }
    if (media_browser_plus_access('preview media')) {
      $form['buttons']['preview_media'] = array(
        '#type' => 'button',
        '#attributes' => array(
          'id' => 'media_buttons_preview',
        ),
        '#value' => t('Preview'),
      );
    }
    if (media_browser_plus_access('edit media files')) {
      $form['buttons']['edit_media'] = array(
        '#type' => 'submit',
        '#attributes' => array(
          'id' => 'media_buttons_edit',
        ),
        '#submit' => array(
          'media_browser_plus_edit_multiple_redirect',
        ),
        '#validate' => array(
          'media_browser_plus_file_entity_admin_files_validate',
        ),
        '#value' => t('Edit'),
      );
    }
    if (media_browser_plus_access('edit media files')) {

      // edit-submit
      $form['buttons']['delete_media'] = array(
        '#type' => 'submit',
        '#submit' => array(
          'media_browser_plus_delete_multiple_redirect',
        ),
        '#validate' => array(
          'media_browser_plus_file_entity_admin_files_validate',
        ),
        '#value' => t('Delete'),
      );
    }
  }
  $form['buttons']['select_media'] = array(
    '#type' => 'button',
    '#attributes' => array(
      'id' => 'media_buttons_select',
    ),
    '#value' => t('Add to Media Basket'),
  );
  if ($library_mode && !$multiselect) {

    // Remove select/deselect all.
    unset($form['buttons']['selection_assets']);

    // Change "Add to media basket" to process with selection.
    $form['buttons']['select_media'] = _media_browser_plus_media_basket_select_button();
  }
  $options = array(
    array(
      'categories' => array(
        'data' => drupal_render($form['admin']['folder']),
      ),
      'media' => array(
        'data' => '<div class="media-display-thumbnails media-clear clearfix">' . '<ul class="media-list-thumbnails" id="media-thumb-list" style="height: ' . variable_get('media_grid_window_height', 400) . 'px;">' . '</ul></div>',
      ),
    ),
    array(
      'categories' => array(
        'data' => '',
      ),
      'media' => array(
        'data' => '',
        'id' => array(
          'media_browser_plus_pages',
        ),
      ),
    ),
  );

  // If no library mode with single selection add media basket buttons.
  if (!$library_mode || $multiselect) {
    $options[] = array(
      'categories' => array(
        'data' => '',
      ),
      'media' => array(
        'data' => drupal_render($form['buttons']),
        'id' => array(
          'media_browser_plus_selection_panel',
        ),
      ),
    );
  }

  // Table setup.
  $table = array(
    'header' => $header,
    'rows' => $options,
    'attributes' => array(
      'id' => 'media_folder_table',
      'class' => array(
        'mbp-item-list',
      ),
    ),
    'empty' => t('No media added yet.'),
  );

  // Return themed table.
  $output = array(
    '#type' => 'markup',
    '#markup' => theme('table', $table),
    'buttons' => $form['buttons'],
  );
  if ($library_mode && !$multiselect) {
    $output['#markup'] .= drupal_render($form['buttons']);
  }
  return $output;
}

/**
 * Returns default javascript settings.
 */
function media_browser_plus_main_view_javascript_settings() {
  global $base_url;

  // Gather environment data.
  $path = drupal_get_path('module', 'media_browser_plus');
  $url = rtrim(url('', array(
    'absolute' => TRUE,
  )), '/') . '/';

  // Create default settings.
  $settings = array(
    'media_browser_plus' => array(
      'filter_active' => isset($_SESSION['media-filter']),
      'url' => $url,
      'images_url' => $base_url . '/' . $path . '/images/',
      'page' => isset($_GET['page']) ? $_GET['page'] : 0,
      'per_page' => variable_get('media_media_per_page', 30),
      'page_items_per_page' => variable_get('media_page_items_per_page'),
      'folder_management_url' => url('admin/content/file/folder_list'),
      'multiselect' => TRUE,
      // Texts.
      'messages' => array(
        'only_one_selection_allowed' => t('Only one media item may be selected'),
      ),
      // Access settings.
      'folder_dnd_enabled' => media_browser_plus_access('edit media files'),
      'manage_folders' => media_browser_plus_access('administer media folders'),
      'filter_allowed' => media_browser_plus_access('filter media'),
      'add_files' => media_browser_plus_access('upload media'),
    ),
  );
  return $settings;
}

/**
 * Appends the media basket.
 */
function media_browser_plus_media_basket_form($library_mode = FALSE, &$form_state = array()) {
  $header = array(
    array(
      'data' => t('Media Basket'),
    ),
  );
  $form['basket_actions'] = array();
  $form['basket_actions']['selection_assets'] = array(
    '#type' => 'markup',
    '#markup' => '<a href="#media_basket_table" id="media_basket_remove_all" >' . t('Remove All') . '</a>',
  );
  form_load_include($form_state, 'inc', 'media_browser_plus', 'includes/file_entity.admin');
  if ($library_mode) {
    $form['basket_actions']['select'] = _media_browser_plus_media_basket_select_button();
  }
  else {
    if (media_browser_plus_access('download media files')) {
      $form['basket_actions']['download'] = array(
        '#type' => 'submit',
        '#value' => t('Download'),
        '#attributes' => array(
          'id' => 'perform_download',
        ),
        '#limit_validation_errors' => array(),
        '#validate' => array(
          'media_browser_plus_file_entity_admin_files_validate',
        ),
        '#submit' => array(
          'media_browser_plus_download_images_submit',
        ),
      );
    }
  }
  $options = array(
    array(
      'media' => array(
        'data' => '<ul id="media-basket-list" class="media-list-thumbnails"></ul>',
      ),
    ),
    array(
      'media' => array(
        'data' => drupal_render($form['basket_actions']),
        'id' => array(
          'media_browser_plus_basket_panel',
        ),
      ),
    ),
  );
  $table = array(
    'header' => $header,
    'rows' => $options,
    'attributes' => array(
      'id' => 'media_basket_table',
      'class' => array(
        'mbp-item-list',
      ),
    ),
    'empty' => t('No media added yet.'),
  );
  return array(
    '#type' => 'markup',
    '#markup' => theme('table', $table),
    'basket_actions' => $form['basket_actions'],
  );
}

/**
 * Appends the hidden preview form.
 */
function media_browser_plus_media_preview_form() {
  $header = array(
    array(
      'data' => t('Media Preview'),
      'id' => array(
        'media-preview-label',
      ),
    ),
  );
  $form['preview_actions'] = array(
    'previous' => array(
      '#type' => 'submit',
      '#value' => t('previous'),
      '#attributes' => array(
        'id' => 'previous_preview_item',
      ),
    ),
    'select' => array(
      '#type' => 'submit',
      '#value' => t('Select'),
      '#attributes' => array(
        'id' => 'select_preview_item',
      ),
    ),
    'next' => array(
      '#type' => 'submit',
      '#value' => t('next'),
      '#attributes' => array(
        'id' => 'next_preview_item',
      ),
    ),
  );
  $options = array(
    array(
      'media' => array(
        'data' => '',
        'id' => array(
          'media_browser_plus_preview_content',
        ),
      ),
    ),
    array(
      'media' => array(
        'data' => drupal_render($form['preview_actions']),
        'id' => array(
          'media_browser_plus_preview_panel',
        ),
      ),
    ),
  );
  $table = array(
    'header' => $header,
    'rows' => $options,
    'attributes' => array(
      'id' => 'media-preview-table',
    ),
    'empty' => t('No media added yet.'),
  );
  return array(
    '#type' => 'markup',
    '#markup' => '<div id="media-preview-table-container" style="display: none;">' . theme('table', $table) . '</div>',
    'preview_actions' => $form['preview_actions'],
  );
}

/**
 * @todo Document what this is for!
 *
 * @return array
 *   Form element.
 */
function _media_browser_plus_media_basket_select_button() {
  return array(
    '#type' => 'submit',
    '#value' => t('Continue with Selection'),
    '#attributes' => array(
      'id' => 'proceed_with_select',
    ),
    '#limit_validation_errors' => array(),
    '#validate' => array(
      'media_browser_plus_file_entity_admin_files_validate',
    ),
  );
}

/**
 * Construct the path of a media_folder term.
 *
 * @param object|NULL $term
 *   Containing term id and term name. If left empty the root folder will be
 *   returned.
 *
 * @return string
 *   The path to the requested folder. Doesn't have a trailing slash.
 */
function media_browser_plus_construct_dir_path($term = NULL) {
  $path = variable_get('file_default_scheme', 'public') . '://';
  if ($root_folder = variable_get('media_root_folder')) {
    $path .= $root_folder . '/';
  }
  $root_folder_term = media_browser_plus_get_media_root_folder();
  if ($term) {
    $parents = array_reverse(taxonomy_get_parents_all($term->tid));
    if (is_array($parents) && !empty($parents)) {
      foreach ($parents as $parent) {

        // @TODO Shouldn't we sanitize this?!? There can be special chars!
        $folder_name = $parent->name;
        if ($parent->tid != $root_folder_term->tid) {
          $path .= $folder_name . '/';
        }
      }
    }
  }
  return rtrim($path, '/');
}

/**
 * Cut-paste a directory with its children into a new filesystem location.
 *
 * @param string $source
 *   The current folder path.
 * @param string $destination
 *   The path we want the folder moved to.
 */
function media_browser_plus_move_physical_folder($source, $destination) {
  $destination = drupal_realpath($destination);
  $source = drupal_realpath($source);
  $jail = drupal_realpath(variable_get('file_default_scheme', 'public') . '://');

  // @todo Please avoid an error by checking the preconditions instead.
  $files = @scandir($source);
  if ($files && count($files) > 2) {
    $transfer = new FileTransferLocal($jail);
    $transfer
      ->copyDirectory($source, $destination);
    $transfer
      ->removeDirectory($source);
  }
  else {

    // The folder is empty so just delete and create the new one.
    drupal_rmdir($source);
    file_prepare_directory($destination, FILE_CREATE_DIRECTORY);
  }
  return TRUE;
}

/**
 * Moves and saves permanently a media file.
 *
 * Every media file that is saved or updated,should pass through this to make
 * sure the filesystem location is the same with the folder term.
 *
 * @param int $tid
 *   The folder's term id.
 * @param object $media
 *   The media object.
 * @param int $replace
 *   Replace behavior when the destination file already exists.
 */
function media_browser_plus_move_file($tid, $media, $replace = FILE_EXISTS_RENAME) {

  // Don't change the uri for media files with external source.
  if (strpos($media->uri, 'public') === FALSE && strpos($media->uri, 'private') === FALSE) {
    file_save($media);
  }
  else {

    // Media translation module does need this since it allows the creation of
    // file references which shouldn't move the referenced file itself when
    // moved. See http://drupal.org/node/1331818 for details.
    if (module_exists('media_translation') && media_translation_is_virtual_file($media->fid)) {
      file_save($media);
      return;
    }
    $folder = media_browser_plus_folder_load($tid);
    $path = media_browser_plus_construct_dir_path($folder);
    if (dirname($media->uri) !== $path) {
      file_prepare_directory($path, FILE_CREATE_DIRECTORY);
      file_move($media, $path, $replace);
    }
  }
}

/**
 * Implements hook_taxonomy_term_presave().
 *
 * @see media_browser_plus_taxonomy_term_update()
 */
function media_browser_plus_taxonomy_term_presave($term) {

  // Figure out if this is a folder term and if so store the current file path
  // for further processing in media_browser_plus_taxonomy_term_update().
  $vocabulary = taxonomy_vocabulary_machine_name_load('media_folders');
  if (!empty($term->tid) && !empty($vocabulary) && $term->vid == $vocabulary->vid) {
    $term->media_browser_plus_original_path = media_browser_plus_construct_dir_path($term);
  }
}

/**
 * Implements hook_taxonomy_term_insert().
 */
function media_browser_plus_taxonomy_term_insert($term) {
  if ($term->vocabulary_machine_name == 'media_folders') {
    $dir = media_browser_plus_construct_dir_path($term);
    if (file_prepare_directory($dir, FILE_CREATE_DIRECTORY)) {
      drupal_set_message(t('Folder %term_name created successfully', array(
        '%term_name' => $term->name,
      )));
    }
    else {
      drupal_set_message(t('Folder %term_name created successfully as term but failed to create as physical folder.Please do it manually', array(
        '%term_name' => $term->name,
      )), 'warning');
    }
  }
}

/**
 * Implements hook_taxonomy_term_update().
 *
 * @see media_browser_plus_taxonomy_term_presave()
 */
function media_browser_plus_taxonomy_term_update($term) {

  // Check if this is a folder term and the source path is set.
  if (!empty($term->media_browser_plus_original_path)) {
    module_load_include('inc', 'media_browser_plus', '/includes/media_browser_plus.folders');

    // Update physical folder.
    $destination = media_browser_plus_construct_dir_path($term);
    media_browser_plus_move_subfolder($term, $term->media_browser_plus_original_path, $destination);
  }
}

/**
 * Implements hook_taxonomy_term_delete().
 */
function media_browser_plus_taxonomy_term_delete($term) {

  // Figure out if this is a folder term and if so handle the related files.
  $vocabulary = taxonomy_vocabulary_machine_name_load('media_folders');
  if (!empty($vocabulary) && $term->vid == $vocabulary->vid) {

    // Create an array of all the folders to handle.
    $folders = array(
      '0:' . $term->tid => $term,
    );

    // Fetch all sub-folders.
    $tree = taxonomy_get_tree($term->vid, $term->tid);
    foreach ($tree as $subterm) {
      $folders[$subterm->depth + 1 . ':' . $subterm->tid] = $subterm;
    }

    // Ensure the order for processing is right.
    krsort($folders);
    foreach ($folders as $folder) {

      // Fetch all files from the folder.
      $conditions = array();
      $conditions[] = array(
        'field' => array(
          'field_folder',
          'tid',
          $folder->tid,
          '=',
        ),
      );
      $options = array(
        'apply_filter' => FALSE,
        'count_only' => FALSE,
        'paging' => FALSE,
        'conditions' => $conditions,
      );
      $folder_path = media_browser_plus_construct_dir_path($folder);
      if ($files = media_browser_plus_load_multiple($options)) {
        $all_files_deleted = TRUE;
        if (!empty($files->results)) {
          foreach ($files->results as $file) {
            if (!file_delete($file)) {
              $all_files_deleted = FALSE;
            }
          }
        }

        // Also delete the folder when it's empty.
        if ($all_files_deleted) {
          if (!@drupal_rmdir($folder_path)) {
            drupal_set_message(t('Unable to delete the folder (!path) on the disk', array(
              '!path' => $folder_path,
            )), 'error');
          }
        }
      }
    }
  }
}

Functions

Namesort descending Description
media_browser_plus_access Manages access for media browser plus actions.
media_browser_plus_change_folder Called by the JS fronted (ajax) to change the folder of a media object.
media_browser_plus_construct_dir_path Construct the path of a media_folder term.
media_browser_plus_download_images_submit Puts all selected media items into a zip archive and sends it as download.
media_browser_plus_edit_cancel Handles a cancelation of the file_entity_edit() form.
media_browser_plus_edit_file_submit Form submit handler for the media browser forms that edit media entities.
media_browser_plus_field_attach_presave Implements hook_field_attach_presave().
media_browser_plus_file_delete Deleting all field data attached to the media entity.
media_browser_plus_file_download_access Checks if the user has the permission to download a file.
media_browser_plus_file_download_access_alter Revokes the general 'view media' == 'download media' access rule. @todo: this function may be obsolete in 2.x
media_browser_plus_folder_load Implements of hook_load().
media_browser_plus_form_file_entity_add_upload_alter Implements hook_form_FORM_ID_alter() for file_entity_add_upload().
media_browser_plus_form_file_entity_add_upload_multiple_alter Implements hook_form_FORM_ID_alter() for file_entity_add_upload_multiple().
media_browser_plus_form_file_entity_edit_alter Implements hook_form_FORM_ID_alter() for file_entity_edit().
media_browser_plus_form_media_add_upload_alter Deprecated Implements hook_form_FORM_ID_alter() for media_add_upload().
media_browser_plus_form_media_add_upload_multiple_alter Deprecated Implements hook_form_FORM_ID_alter() for media_add_upload_multiple().
media_browser_plus_form_media_import_alter Implements hook_form_FORM_ID_alter() for media_import().
media_browser_plus_form_media_internet_add_alter Implements hook_form_FORM_ID_alter() for media_internet().
media_browser_plus_get_media_root_folder Loads and (if $autocreate is set) creates the default media folder object.
media_browser_plus_grid_view_form Appends main grid view form.
media_browser_plus_library Implements hook_library().
media_browser_plus_library_browser Creates the Extended Library for the media browser popup.
media_browser_plus_load_multiple Loads media entities and allows filtering, sorting and paging.
media_browser_plus_load_tag_terms @todo Document what this function does.
media_browser_plus_main_view_javascript_settings Returns default javascript settings.
media_browser_plus_media_access Checks access to a given media entity.
media_browser_plus_media_basket_form Appends the media basket.
media_browser_plus_media_browser_plugin_info Implements hook_media_browser_plugin_info().
media_browser_plus_media_import_batch_complete Same completed batch method as in media.
media_browser_plus_media_import_batch_import_files Batch process with the ability to apply the field values to the items.
media_browser_plus_media_import_submit Changing the media import standard submit to use our own batch process.
media_browser_plus_media_operations Implements hook_media_operations().
media_browser_plus_media_preview_form Appends the hidden preview form.
media_browser_plus_media_settings Creates the media browser plus settings form.
media_browser_plus_media_settings_submit Saves the entered settings.
media_browser_plus_media_settings_validate Validates the settings.
media_browser_plus_menu Implements hook_menu().
media_browser_plus_menu_alter Implements hook_menu_alter().
media_browser_plus_move_file Moves and saves permanently a media file.
media_browser_plus_move_physical_folder Cut-paste a directory with its children into a new filesystem location.
media_browser_plus_permission Implements hook_permission().
media_browser_plus_prepare_taxonomy_autocomplete_validate Form element validate handler for taxonomy term autocomplete element.
media_browser_plus_preprocess_media_link Implements hook_preprocess_media_link().
media_browser_plus_preprocess_media_thumbnail Implements hook_preprocess_media_thubmnail().
media_browser_plus_submit Submit handler for the media browser forms that create new media entities.
media_browser_plus_taxonomy_term_delete Implements hook_taxonomy_term_delete().
media_browser_plus_taxonomy_term_insert Implements hook_taxonomy_term_insert().
media_browser_plus_taxonomy_term_presave Implements hook_taxonomy_term_presave().
media_browser_plus_taxonomy_term_update Implements hook_taxonomy_term_update().
media_browser_plus_thumbnailsJSON Called by the JS fronted (ajax) to get the media list for a given folder.
_media_browser_plus_filter_folders Looks if a filter is active and filters the folders accordingly.
_media_browser_plus_filter_folder_access @todo Document what this function does.
_media_browser_plus_folder_empty Check if a given folder has media in it (does include current filter).
_media_browser_plus_folder_form Returns a select form item with a selectable media folders.
_media_browser_plus_folder_hierarchy_list Creates the folder media tree.
_media_browser_plus_folder_list @todo Document what this function does.
_media_browser_plus_has_unsorted_media Checks for unsorted (i.e. media not in folders) media.
_media_browser_plus_media_basket_select_button @todo Document what this is for!
_media_browser_plus_metadata Helper function to return metadata from a 3rd party media provider.
_media_browser_plus_pager @todo Document what this function does.
_media_browser_plus_pager_add_page_item @todo Document what this function does.
_media_browser_plus_tag_form Returns the tag form element.