<?php
// $Id: avatar_selection.module,v 1.1.2.22 2007/08/21 15:11:16 snpower Exp $

/**
 * Display help and module information
 * @param section which section of the site we're displaying help
 * @return help text for section
 */
function avatar_selection_help($path, $arg) {

  $output = '';

  switch ($path) {
    case "admin/help#avatar_selection":
      $output .= '<p>'. t("Allows the user to pick an avatar from a list.") .'</p>';
      return $output;
    case "admin/modules#description":
      return t("Allows the user to pick an avatar from a list.");
    case "admin/settings/avatar_selection/images":
      return t("Upload images to display as a user avatar.  These images can be anything you like, but it is recommended that you maintain a uniform icon size for all of your avatars.  Maximum dimensions are 85x85 and the maximum size is 30 kB");
  }

}

/**
 * Implementation of hook_perm().
 * Define the permissions this module uses
 */
function avatar_selection_perm() {
  return array('administer avatar selection', 'access avatars');
}


/**
 * Implementation of hook_access().
 */
function avatar_selection_access($op, $node) {
  if ($op == 'view') {
    return user_access('access avatars');
  }
  else if ($op == 'create' || $op == 'update' || $op == 'delete') {
    return user_access('administer avatar selection');
  }
}

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

  $items['admin/settings/avatar_selection'] = array(
    'title' => 'Avatar Selection',
    'description' => 'Allows the user to upload and delete avatars.',
    'page callback' => 'avatar_selection_settings_page',
    'access callback' => 'user_access',
    'access arguments' => array('administer avatar selection'),
  );
  $items['admin/settings/avatar_selection/config'] = array(
    'title' => 'Configure',
    'description' => 'Allows the user to configure avatar settings.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('avatar_selection_config_form'),
    'access callback' => 'user_access',
    'access arguments' => array('administer avatar selection'),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/settings/avatar_selection/images'] = array(
    'title' => 'Upload',
    'description' => 'Allows the user to upload avatars.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('avatar_selection_images_form'),
    'access callback' => 'user_access',
    'access arguments' => array('administer avatar selection'),
    'type' => MENU_LOCAL_TASK,
    'weight' => -9,
  );
  $items['admin/settings/avatar_selection/edit'] = array(
    'title' => 'Manage avatars',
    'description' => 'Allows the user to modify or delete an avatar from a list.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('avatar_selection_edit_form'),
    'access callback' => 'user_access',
    'access arguments' => array('administer avatar selection'),
    'type' => MENU_LOCAL_TASK,
  );

  return $items;
}

/**
 * Implementation of hook_form_alter().
 */
function avatar_selection_form_alter(&$form, $form_state, $form_id) {
  // we need the pager global variables
  global $user, $pager_total, $pager_page_array, $_GET;

  // If user pictures aren't enabled, nothing to do here.
  if (!variable_get('user_pictures', 0)) {
    return;
  }

  if (('user_edit' == $form_id && is_array($form['picture']))) {
    drupal_add_css(drupal_get_path('module', 'avatar_selection') .'/avatar_selection.css');
    $access = user_access('access avatars');
    $disable_upload = variable_get('avatar_selection_disable_user_upload', 0);
    $force_choose = variable_get('avatar_selection_force_user_avatar', 0);
    
    // If upload support has been disabled, remove the ability to upload and
    // delete pictures
    if ($disable_upload) {
      unset($form['picture']['picture_delete']);
      unset($form['picture']['picture_upload']);
    }

    // We fill the pager global variables to use the pager
    if (is_numeric($_GET['page'])) {
      $pager_page_array[0] = $_GET['page'];
    }
    else {
      $pager_page_array[0] = 0;
    }

    // If user has access to choose an avatar, show selection options
    $selects = _avatar_selection_image_list($pager_page_array[0], $user->roles, $user->og_groups);
    $pager_total[0] = ceil($selects['total']/variable_get('avatar_selection_avatar_per_page', 30));

    if ($access && count($selects['avatars'])) {
      $user_form = drupal_retrieve_form($form_id);
      $form['picture']['select_avatar'] = array(
        '#type' => 'radios',
        '#title' => $disable_upload ? t('Select an avatar') : t('Or simply select an icon'),
        '#options' => $selects['avatars'],
        '#default_value' => $user_form['_account']['#value']->picture,
        '#required' => $force_choose ? TRUE : FALSE,
        '#attributes' => array('class' => 'user_avatar_select'),
        '#suffix' => theme("pager"),
      ); 
    }

    // If user can't do either, remove the fielset altogether
    if (!$access && $disable_upload) {
      unset($form['picture']);
    }

    // Don't allow user to delete a selected avatar
    $path = '/avatar_selection/';
    if ($form['picture']['current_picture']['#value']
      && preg_match($path, $form['picture']['current_picture']['#value'])) {
      unset($form['picture']['picture_delete']);
    }


    drupal_add_js(drupal_get_path('module', 'avatar_selection') .'/js/avatar_selection.js', 'theme', 'header');
  }
  // If user is forced to choose an avatar, need to add avatar selection to the
  // registration form
  else if ('user_register' == $form_id) {
    // We fill the pager global variables to use the pager
    if (is_numeric($_GET['page'])) {
      $pager_page_array[0] = $_GET['page'];
    }
    else {
      $pager_page_array[0] = 0;
    }


    $user = drupal_anonymous_user();
    $force_choose = variable_get('avatar_selection_force_user_avatar_reg', 0);
    $selects = _avatar_selection_image_list($pager_page_array[0], $user->roles);
    $pager_total[0] = ceil($selects['total']/variable_get('avatar_selection_avatar_per_page', 30));
    if (count($selects['avatars'])) {
      drupal_add_css(drupal_get_path('module', 'avatar_selection') .'/avatar_selection.css');
      $form['picture'] = array(
        '#type' => 'fieldset', 
        '#title' => t('Picture'),
        '#weight' => 1,
      );
      $form['picture']['select_avatar'] = array(
        '#type' => 'radios', 
        '#title' => t('Select an avatar'),
        '#options' => $selects['avatars'],
        '#required' => $force_choose ? TRUE : FALSE,
        '#attributes' => array('class' => 'user_avatar_select'),
        '#suffix' => theme("pager"),
      );
    }
    drupal_add_js(drupal_get_path('module', 'avatar_selection') .'/js/avatar_selection.js', 'theme', 'header');
  }

  return $form;
}

/*
 * Implementation of hook_user().
 */
function avatar_selection_user($op, &$edit, &$user, $category = 'account') {
  global $form_state;

  switch ($op) {

    case 'validate':
      // If required, validate the uploaded picture.
      $validators = array(
        'file_validate_is_image' => array(),
        'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
        'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
      );

      $file = file_save_upload('picture_upload', $validators);

      if ($file) {
        // The image was saved using file_save_upload() and was added to the
        // files table as a temporary file. We'll make a copy and let the 
        // garbage collector delete the original upload.
        $info = image_get_info($file->filepath);
        $destination = variable_get('user_picture_path', 'pictures') .'/picture-'. $form['#uid'] .'.'. $info['extension'];
        if (file_copy($file, $destination, FILE_EXISTS_REPLACE)) {
          $form_state['values']['picture'] = $file->filepath;
        }
        else {
          form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
        }
      }
      
      elseif (!$file && $edit['select_avatar']) {
        $form_state['values']['picture'] = $edit['select_avatar'];
      }
      break;
  }
}



function _avatar_selection_image_list($page, $user_roles = "", $og_groups = "") {
  $avatars = array();

  $how_many_avatars = variable_get('avatar_selection_avatar_per_page', 30);

  $dir = file_create_path('avatar_selection');
  $mask = '.*\.(gif|GIF|Gif|jpg|JPG|Jpg|jpeg|JPEG|Jpeg|png|PNG|Png)';
  $listings = file_scan_directory($dir, $mask, array('.', '..', 'CVS'), 0, FALSE);

  $result = db_query("SELECT avatar, access, og_access FROM {avatar_selection} avs");
  while ($avatar = db_fetch_object($result)) {
    $avs_image = $avatar->avatar;
    $avs_access = preg_split('/\s*,\s*/', $avatar->access);
    $og_access = preg_split('/\s*,\s*/', $avatar->og_access);
    $del_avatar = 1;

    // check the organic groups
    if (module_exists("og")) {
      if (!empty($avatar->og_access)) {
        if (!empty($og_groups)) {
          foreach ($og_groups as $gid => $grp) {
            if (in_array($gid, $og_access)) {
              $del_avatar = 2;
              break;
            }
          }
        }
        // delete it if it's not in one of the valid groups
        if ($del_avatar == 1) {
          unset($listings[$avs_image]);
        }
      }
    }

    // check the user roles
    if (!empty($avatar->access)) {
      if (!empty($user_roles)) {
        foreach ($user_roles as $rid => $role) {
          if (in_array($rid, $avs_access)) {
            $del_avatar = 0;
            break;
          }
        }
      }
      // delete it if it's not in a valid role
      if ($del_avatar != 0) {
        unset($listings[$avs_image]);
      }
    }
  }
 

  // we slice the array in order to retrieve only the necessary avatars
  $total_avatars = count($listings);
  $listings = array_slice($listings, $page*$how_many_avatars, $how_many_avatars);

  foreach ($listings as $listing) {
    $avatars[$dir .'/'. $listing->basename] = theme('image', file_create_url($dir .'/'. $listing->basename), $listing->basename, $listing->basename, NULL, FALSE);
  }

  $selects['avatars'] = $avatars;
  $selects['total'] = $total_avatars;

  return $selects;
}

function avatar_selection_settings_page($op = NULL, $aid = NULL) {

  switch ($op) {
    case 'edit':
      if (is_numeric($aid)) {
        $output = drupal_get_form('avatar_selection_config_form', $aid);
      }
      break;
    case 'upload':
      if (is_numeric($aid)) {
        $output = drupal_get_form('avatar_selection_images_form', $aid);
      }
      break;
    case 'list' :
      if (is_numeric($aid)) {
        $output = drupal_get_form('avatar_selection_edit_form');
      }
      break;
    default:
      $form[] = array(
        '#type' => 'fieldset',
        '#title' => t('Add another'),
      );
      $output = drupal_get_form('avatar_selection_config_form');
      break;
  }
  return $output;
}


/**
 * Define a form to configure the module settings
 */
function avatar_selection_config_form() {
  if (!variable_get('user_pictures', 0)) {
    drupal_set_message(t('User Pictures option is disabled.  You will need to enable this option before you can use the Avatar Selection module.  You may configure this setting on the <a href="@url">User settings</a> page.', array('@url' => url('admin/user/settings'))));
  }

  // To store how many avatars per page are displayed.
  $form['update']['avatar_per_page'] = array('#type' => 'textfield',
    '#title' => t('How many avatars per page'),
    '#description' => t('The number of avatars to show per page.'),
    '#default_value' => variable_get('avatar_selection_avatar_per_page', 30),
    '#size' => 3,
  );

  $form['update']['disable_user_upload'] = array('#type' => 'checkbox',
    '#title' => t('Disable users uploading pictures to profile'),
    '#description' => t('Allow users to pick their avatar from the selection but prevent them from uploading new avatars when editing their account.'),
    '#default_value' => variable_get('avatar_selection_disable_user_upload', FALSE),
    );
  $form['update']['force_set_image_reg'] = array('#type' => 'checkbox',
    '#title' => t('Force users to select an avatar image on user registration.'),
    '#description' => t('This only comes into effect on the user registration screen'),
    '#default_value' => variable_get('avatar_selection_force_user_avatar_reg', FALSE),
    );
  $form['update']['force_set_image'] = array('#type' => 'checkbox',
    '#title' => t('Force users to select an avatar image when editing their account'),
    '#description' => t('This only comes into effect when the user is editing their account details and image uploads are disabled.'),
    '#default_value' => variable_get('avatar_selection_force_user_avatar', FALSE),
    );


  $form['update']['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Update'),
  );

  return $form;
}

/**
 * Define a form to upload the avatar images.
 */
function avatar_selection_images_form() {
  if (!variable_get('user_pictures', 0)) {
    drupal_set_message(t('User Pictures option is disabled.  You will need to enable this option before you can use the Avatar Selection module.  You may configure this setting on the <a href="@url">User settings</a> page.', array('@url' => url('admin/user/settings'))));
  }

  $form['#attributes']['enctype'] = 'multipart/form-data';

  $form['picture_upload'] = array('#type' => 'file', 
    '#title' => t('Upload image'), 
    '#size' => 48, 
    '#description' => t('A new avatar image.  Maximum dimensions are %dimensions and the maximum size is %size kB.  Images must have one of the following extensions (case sensitive): png, jpg, jpeg, gif, PNG, JPG, JPEG, GIF.', array('%dimensions' => variable_get('user_picture_dimensions', '85x85'), '%size' => variable_get('user_picture_file_size', '30'))) .' '.  variable_get('user_picture_guidelines', ''),
  );
  $form['permissions'] = array(
    '#type' => 'fieldset', 
    '#title' => t('Permissions'),
    '#weight' => 1,
  );
  $form['permissions']['access'] = array('#type' => 'checkboxes',
    '#title' => t('User Roles'),
    '#options' => avatar_selection_handler_filter_role(),
    '#description' => t('Only the checked roles will be able to see this avatar icon; if no roles are checked, access will not be restricted.'),
  );
  if (module_exists("og")) {
    $form['permissions']['og_access'] = array('#type' => 'checkboxes',
      '#title' => t('Organic Groups'),
      '#options' => og_all_groups_options(),
      '#description' => t('Only users in the checked organic groups will be able to see this avatar icon; if no groups are checked, access will not be restricted.'),
    );
  }

  $form['attach'] = array(
    '#type' => 'submit',
    '#value' => t('Upload'),
    '#weight' => 10,
  );

  return $form;
}



function avatar_selection_edit_form($form_state) {
  // we need the pager global variables
  global $pager_total, $pager_page_array, $_GET;
  $form = array();

  if (!variable_get('user_pictures', 0)) {
    drupal_set_message(t('User Pictures option is disabled.  You will need to enable this option before you can use the Avatar Selection module.  You may configure this setting on the <a href="@url">User settings</a> page.', array('@url' => url('admin/user/settings'))));
  }

  drupal_add_css(drupal_get_path('module', 'avatar_selection') .'/avatar_selection.css');

  // We fill the pager global variables to use the pager
  if (!empty($_GET['page']) && is_numeric($_GET['page'])) {
    $pager_page_array[0] = $_GET['page'];
  }
  else {
    $pager_page_array[0] = 0;
  }

  $selects = _avatar_selection_image_list($pager_page_array[0]);
  $pager_total[0] = ceil($selects['total']/variable_get('avatar_selection_avatar_per_page', 30));
  if (!count($selects['avatars'])) {
    drupal_set_message(t('There are no images configured.'));
  } 

  else {

    if (!isset($form_state)) {
      $step = "list";
    }
    else {
      $step = "edit";
    }
    $form['step'] = array(
      '#type' => 'hidden',
      '#value' => $step,
    );


    if ($step == "list") {

      $form['select_avatar'] = array(
        '#type' => 'radios',
        '#title' => t('Select an avatar to edit'),
        '#options' => $selects['avatars'],
        '#required' => TRUE,
        '#attributes' => array('class' => 'user_avatar_select'),
        '#suffix' => theme("pager"),
      ); 

      $form['search'] = array(
        '#type' => 'submit',
        '#value' => t('Edit'),
        '#submit' => array('avatar_selection_edit_list_form_submit'),
      );

      drupal_add_js(drupal_get_path('module', 'avatar_selection') .'/js/avatar_selection.js', 'theme', 'header');

    }
    elseif ($step == "edit") {
      $roles = avatar_selection_handler_filter_role();

      $result = db_query("SELECT avatar, access, og_access FROM {avatar_selection} avs WHERE avatar = '%s'", $form_state['values']['select_avatar']);
      while ($avatar = db_fetch_object($result)) {
        $avs_access = preg_split('/\s*,\s*/', $avatar->access);
        $og_access = preg_split('/\s*,\s*/', $avatar->og_access);
      }

      $image = theme('image', $form_state['values']['select_avatar']);
      $form['avatar_image'] = array('#value' => $image);
      $form['select_avatar'] = array(
        '#type' => 'hidden',
        '#default_value' => $form_state['values']['select_avatar'],
      );

      $form['permissions'] = array(
        '#type' => 'fieldset', 
        '#title' => t('Permissions'),
        '#weight' => 1,
      );
      $form['permissions']['access'] = array(
        '#type' => 'checkboxes',
        '#title' => t('User Roles'),
        '#default_value' => $avs_access,
        '#options' => $roles,
        '#description' => t('Only the checked roles will be able to see this avatar icon; if no roles are checked, access will not be restricted.'),
      );

      if (module_exists("og")) {
        $form['permissions']['og_access'] = array('#type' => 'checkboxes',
          '#title' => t('Organic Groups'),
          '#default_value' => $og_access,
          '#options' => og_all_groups_options(),
          '#description' => t('Only users in the checked organic groups will be able to see this avatar icon; if no groups are checked, access will not be restricted.'),
        );
      }

      $form['update'] = array(
        '#type' => 'submit',
        '#value' => t('Update'),
        '#weight' => 9,
        '#submit' => array('avatar_selection_edit_update_form_submit'),
      );
      $form['delete'] = array(
        '#type' => 'submit',
        '#value' => t('Delete'),
        '#weight' => 10,
        '#submit' => array('avatar_selection_edit_delete_form_submit'),
      );
    }

  }
  
  return $form;
}


/**
 * Validate the submission.
 *
 * Check whether:
 * if any of the settings have changed
 */
function avatar_selection_config_form_validate($form, &$form_state) {
  $error = FALSE;

  if ($form_state['values']['op'] == t('Update')) {
    if (!is_numeric($form_state['values']['avatar_per_page'])) {
      form_set_error('avatar_per_page', t('Must be a number.'));
      $error = TRUE;
    }
  }
}



/**
 * Validate the submission.
 *
 * Check whether:
 * Delete has been chosen AND a checkbox has been selected
 */

function avatar_selection_delete_form_validate($form, &$form_state) {
  if ($form_state['values']['op'] == t('Delete')) {
    if (count(array_filter($form_state['values']['images'])) == 0) {
      form_set_error('images', t('Please select images to delete.'));
    }
  }
}

function avatar_selection_config_form_submit($form, &$form_state) {
  $op = $form_state['values']['op'];

  if ($op == t('Update')) {
    // save system variables
    variable_set('avatar_selection_disable_user_upload', $form_state['values']['disable_user_upload']);
    variable_set('avatar_selection_force_user_avatar_reg', $form_state['values']['force_set_image_reg']);
    variable_set('avatar_selection_force_user_avatar', $form_state['values']['force_set_image']);
    variable_set('avatar_selection_avatar_per_page', $form_state['values']['avatar_per_page']);
    drupal_set_message(t('Configuration has been updated.'));
  }
}


function avatar_selection_images_form_submit($form, &$form_state) {
  $op = $form_state['values']['op'];

  if ($op == t('Upload')) {
    // Save uploaded files
    $dir = file_create_path('avatar_selection');
    $is_writable = file_check_directory($dir, 1);

    if ($is_writable) {
      // If required, validate the uploaded picture.
      $validators = array(
        'file_validate_is_image' => array(),
        'file_validate_image_resolution' => array(variable_get('user_picture_dimensions', '85x85')),
        'file_validate_size' => array(variable_get('user_picture_file_size', '30') * 1024),
      );

      if ($file = file_save_upload('picture_upload', $validators, $dir, FILE_EXISTS_RENAME)) {

        if (image_get_info($file->filepath)) {
          $og = '';
          file_copy($file, $dir, FILE_EXISTS_RENAME);
          $access = implode(', ', array_keys(array_filter($form_state['values']['access'])));
          if (module_exists("og")) {
            $og = implode(', ', array_keys(array_filter($form_state['values']['og_access'])));
          }
          _avatar_selection_save_avatar_info($file->filepath, $access, $og);
          drupal_set_message(t('New image saved.'));
        }
        else {
          file_delete($file->filepath);
          drupal_set_message('Uploaded file does not appear to be a valid image file. Please try again.');
        }
      }
      else {
        form_set_error('picture_upload', t("Failed to upload the picture image; the %directory directory doesn't exist or is not writable.", array('%directory' => variable_get('user_picture_path', 'pictures'))));
      }
    }
    else {
      form_set_error('picture_upload', t('Directory not writable: '. $dir));
    }
  }
}

function avatar_selection_edit_list_form_submit($form, &$form_state) {
  $form_state['rebuild'] = TRUE;
}


function avatar_selection_edit_update_form_submit($form, &$form_state) {
  $access = implode(', ', array_keys(array_filter($form_state['values']['access'])));
  if (module_exists("og")) {
    $og = implode(', ', array_keys(array_filter($form_state['values']['og_access'])));
  }
  _avatar_selection_save_avatar_info($form_state['values']['select_avatar'], $access, $og);
  drupal_set_message(t('Image updated.'));
}


function avatar_selection_edit_delete_form_submit($form, &$form_state) {
  $image = $form_state['values']['select_avatar'];
  avatar_selection_image_delete($image);
}

function avatar_selection_image_delete($image) {
  if (file_check_location($image, file_create_path('avatar_selection'))) {
    $result = db_query("DELETE FROM {avatar_selection} WHERE avatar = '%s'", $image);
    file_delete($image);
    if (!image_get_info($image)) {
      drupal_set_message(t('Image deleted.'));
    }
  }
}
/**
 * Implementation of hook_file_download().
 *
 * Ensure that user pictures (avatars) are always downloadable.
 */
function avatar_selection_file_download($file) {
  if (user_access('access content')) { 
    $data = explode('/', $file);
    $icon = array_pop($data);
    $folder = implode('/', $data);
    if ('avatar_selection' == $folder) {
      $info = image_get_info(file_create_path($file));
      return array(
        'Content-type: '. $info['mime_type'],
        'Content-length: '. $info['file_size'],
      );
    }
    else {
      return null;
    }
  }
}

/*
 * Create a list of roles.
 */
function avatar_selection_handler_filter_role() {
  $rids = array();
  $result = db_query("SELECT r.rid, r.name FROM {role} r ORDER BY r.name");
  while ($obj = db_fetch_object($result)) {
    $rids[$obj->rid] = $obj->name;
  }
  return $rids;
}


/*
 * function to save avatar icon details to the avatar_selection table
 */
function _avatar_selection_save_avatar_info($filepath, $access, $og = "") {

  switch ($GLOBALS['db_type']) {
    case 'mysqli':
    case 'mysql':
      $result = db_query("REPLACE INTO {avatar_selection} (avatar, access, og_access) VALUES('%s', '%s', '%s')", $filepath, $access, $og);
      break;

    case 'pgsql':
      $result = db_query("DELETE FROM {avatar_selection} WHERE avatar = '%s'", $filepath);
      $result = db_query("INSERT INTO {avatar_selection} (avatar, access, og_access) VALUES('%s', '%s', '%s')", $file->filepath, $access, $og);
      break;
  }

}
