<?php
// $Id:$

/**
 * @file
 * Create queues which can contain flagged content in arbitrary order.
 */

/*******************************************************************************
 * API functions
 ******************************************************************************/

/**
 * Get the position of all flagged content in a flag.
 * 
 * @param $flag
 *   The flag object.
 * @return
 *   Array with the flagged content's ID (fcid) as key and position as value. 
 *   Empty array if flag is empty.
 */
function flag_queue_get_flag_positions($flag, $reset = FALSE) {
  static $elements = array();
  if (empty($elements[$flag->fid]) || $reset) {
    $element = array();
    $result = db_query("SELECT fcid, content_id, position FROM {flag_queue} WHERE fid = %d ORDER BY position ASC", $flag->fid);
    while ($row = db_fetch_object($result)) {
      $element[$row->position] = $row;
    }
    if (!$element && flag_get_flag_counts($flag->fid ) > 1) {
      // There are already flagged content in the flag, but the haven't been 
      // positioned yet, so we add them here.
      $element = flag_get_flagged_content($flag->fid);   
    }
  }
  $elements[$flag->fid] = $element;
  return $elements[$flag->fid];
}

/**
 * Get the position of a flagged content.

 * @param $fcid
 *   fcid from {flag_content} table.
 * @return
 *   Get the position of a flagged content in a queue, or 0 if not found.
 */

function flag_queue_get_content_position($flag, $fcid) {
  $elements = flag_queue_get_flag_positions($flag);
  $key = array_search($fcid, $elements);
  return $key ? $key : 0;
}

/**
 * Set the position of all flagged contents in a flag queue.

 * @param $name
 *   The flag name.
 * @param $fid
 *   The flag ID.
 * @param $positions
 *   The order of the flagged content in the flag queue.
 * @return
 *   Get the position of a flagged content in a queue, or 0 if not found.
 */
function flag_queue_set_positions($flag, $elements = array()) {
  // Prepare the SQL.
  $sql = '';
  $args = array();
  // The position.
  $i = 1;
  foreach ($elements as $element) {
    if ($sql) {
      $sql .= ',';
    }      
    $sql .= ' (%d, %d, %d, %d)';
    $args[] = $flag->fid;
    $args[] = $element->fcid;
    $args[] = $element->content_id;
    $args[] = $i;
    ++$i;
  }
  if ($args) {
    // Delete existing values.
    db_query("DELETE FROM {flag_queue} WHERE fid = %d", $flag->fid);
    
    // Insert the new positioning of the elements.
    $sql = "INSERT INTO {flag_queue} (fid, fcid, content_id, position) VALUES $sql";
    db_query($sql, $args); 
  }
}

/*******************************************************************************
 * Hook implementations
 ******************************************************************************/

/**
 * Implementation of hook_perm().
 */
function flag_queue_perm() {
  return array(
   'attach queue behaviors to flag',
  );
}

/**
 * Implementation of hook_form_alter().
 */
function flag_queue_form_flag_form_alter(&$form, &$form_state) {
  // Check if flag already exists.
  if (($fid = !empty($form['#flag']->fid))) {    
    $flag = flag_get_flag(NULL, $fid);
  }
    
  $form['flag_queue'] = array(
    '#type' => 'fieldset',
    '#title' => t('Flag queue'),
    '#description' => t('Attach queue behaviors to the flag.'),
    '#access' => 'attach queue behaviors to flag',
  );  
  $form['flag_queue']['flag_queue'] = array(
    '#type' => 'checkbox',
    '#title' => t('Flag queue'),
    '#description' => t('Enable if this flag should also act as a queue.'),
    '#default_value' => !empty($flag->flag_queue) ? $flag->flag_queue : FALSE,
    '#access' => 'attach queue behaviors to flag',
  );  
}

/**
 * Implementation of hook_flag_default_options_alter().
 */
function flag_queue_flag_default_options_alter($options) {
  // Insert the flag queue option.
  $options += array('flag_queue' => '');
  return $options;
}

/**
 * Implementation of hook_flag().
 */
function flag_queue_flag($op, $flag, $content_id, $account) {
  // Re-position only if there more than a single flagged content.
  if (!empty($flag->flag_queue) && flag_get_flag_counts($flag->fid ) > 1) {
    $elements = flag_queue_get_flag_positions($flag);        
    if ($op == 'flag') {
      // Add content only if it doesn't already exist.
      $fcid = flag_get_fcid_from_content_id($content_id);
      $key = _flag_queue_get_element_key_by_fcid($elements, $fcid);  
      if ($key == -1) {
        array_push($elements, (object)array('fcid' => $fcid, 'content_id' => $content_id));
      }
    }
    else {
      // Unset the element that was unflagged.
      $fcid = _flag_queue_get_fcid_from_content_id($elements, $content_id);
      $key = _flag_queue_get_element_key_by_fcid($elements, $fcid);      
      unset($elements[$key]);
    }
    // Re-position all the flagged contents.    
    flag_queue_set_positions($flag, $elements);        
  }
}

/**
 * Implementation of hook_views_api().
 */
function flag_queue_views_api() {
  return array(
    'api' => 2.0,
    'path' => drupal_get_path('module', 'flag_queue'),
  );
}

function _flag_queue_get_fcid_from_content_id($elements, $content_id) {
  foreach ($elements as $element) {
    if ($element->content_id == $content_id) {
      return $element->fcid;
    }    
  }  
}

function _flag_queue_get_element_key_by_fcid($elements, $fcid) {
  $return = -1;
  foreach ($elements as $key => $element) {
    if ($element->fcid == $fcid) {
      $return = $key;
      break;
    }
  }
  return $return;
}
