<?php

/**
 * @file
 * This module allows the definition of bookable items.
 */

$mypath = drupal_get_path('module', 'simplereservation');

/**
 * Implements hook_help().
 */
function simplereservation_help($path) {
  $output = '';
  switch ($path) {
    case 'admin/help#simplereservation':
      $output = '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Simple Reservation module allows users to create any number of user-defined bookable items. The items may have a description and a comment.') . '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('<a href="@items_definition">Items definition</a>',
                           array('@items_definition' => url('admin/config'))
                           ) . '</dt>';
      $output .= '<dd>' . t('můžete přidávat nové a spravovat stávající položky k rezervaci. Jednotlivé je možno také dočasně zneplatnit.') . '</dd>';
      $output .= '<dt>' . t('<a href="@reservation">Reservation</a>',
                           array('@reservation' => url('admin/config'))
                           ) . '</dt>';
      $output .= '<dd>' . t('aktuální položky mohou uživatelé rezervovat stejně tak jako mohou prohlížet rezervace své i o statních uživatelů.') . '</dd>';
      $output .= '</dl>';
      return $output;

    break;
  }
}


/**
 * Implements hook_permission().
 */
function simplereservation_permission() {
  return array(
    'access simple reservations' => array(
      'title' => t('Access simple reservations'),
      'description' => t('Read all reservations.'),
    ),
    'add simple reservations' => array(
      'title' => t('Add simple reservations'),
      'description' => t('Add own reservations.'),
    ),
    'add simple reservations for others' => array(
      'title' => t('Add simple reservations for others'),
      'description' => t('Add reservations for other users.'),
    ),
    'edit own simple reservations' => array(
      'title' => t('Edit own simple reservations'),
      'description' => t('Edit own reservations.'),
    ),
    'edit simple reservations of others' => array(
      'title' => t('Edit simple reservations of others'),
      'description' => t('Edit reservations of other users.'),
    ),
    'delete own simple reservations' => array(
      'title' => t('Delete own simple reservations'),
      'description' => t('Delete own reservations.'),
    ),
    'delete simple reservations of others' => array(
      'title' => t('Delete simple reservations of others'),
      'description' => t('Delete reservations of other users.'),
    ),
    'unrestricted simple reservations' => array(
      'title' => t('Unrestricted simple reservations'),
      'description' => t('Add/edit reservations without any restrictions set in the Simple Reservation administration.'),
    ),
    'administer simple reservation system' => array(
      'title' => t('Administer simple reservation system'),
      'description' => t('Access the administration of the Simple Reservation system.'),
    ),
    'administer simple reservation triggers' => array(
      'title' => t('Administer simple reservation triggers'),
      'description' => t('Access the administration of the triggers for the Simple Reservation system.'),
    ),
  );
}


/**
 * Implements hook_menu_alter().
 */
function simplereservation_menu_alter(&$items) {
  // By default, the trigger system uses the module name
  // (i.e. example) as the access for the trigger
  // configuration menu item.  we want to change that.
  if (!empty($items['admin/structure/trigger/simplereservation'])) {
    $items['admin/structure/trigger/simplereservation']['access arguments'] = array('administer simple reservation triggers');
  }
}


/**
 * Implements hook_trigger_info().
 */
function simplereservation_trigger_info() {
  // Define triggers.
  $items = array(
    'simplereservation' => array(
      'simplereservation_new_reservation' => array(
        'label' => t('A new reservation has been created.'),
      ),
      'simplereservation_delete_reservation' => array(
        'label' => t('A new reservation has been deleted.'),
      ),
    ),
  );
  return $items;
}

/**
 * Invoke trigger.
 *
 * This function is a wrapper/helper for triggers/hooks
 *
 * @return bool
 *   Boolean, true or false if successful.
 */
function simplereservation_invoke_hook($hook = 'example', $op = NULL, $object = NULL) {
  // Perform hook invoke.
  module_invoke_all($hook, $op);
  // Call trigger/actions.
  if (function_exists('_trigger_get_hook_aids')) {
    $aids = _trigger_get_hook_aids($hook, $op);
  }
  $context = array(
    'hook' => $hook,
    'op' => $op,
  );
  if (!empty($aids)) {
    actions_do(array_keys($aids), $object, $context);
  }
  return TRUE;
}


/**
 * Implements hook_action_info_alter().
 */
function simplereservation_action_info_alter(&$info) {

  foreach ($info as $type => $data) {
    if (stripos($type, "user_") === 0 || stripos($type, "system_") === 0) {
      if (isset($info[$type]['hooks']['application'])) {
        array_merge($info[$type]['hooks']['simplereservation'], array('new_reservation', 'delete_reservation'));
      }
      else {
        $info[$type]['hooks']['simplereservation'] = array('new_reservation', 'delete_reservation');
      }
    }
  }
}


/**
 * Implements hook_menu().
 */
function simplereservation_menu() {
  global $user;
  $items = array();

  $items['admin/config/services/simplereservation'] = array(
    'title' => 'Simple Reservation',
    'description' => 'Manage the reservation system.',
    'type' => MENU_NORMAL_ITEM,
    'page callback' => 'drupal_get_form',
    'page arguments' => array('simplereservation_admin_page_form'),
    'access arguments' => array('administer simple reservation system'),
  );
  $items['admin/config/services/simplereservation/settings'] = array(
    'title' => 'Configuration Settings',
    'description' => 'Configure the reservation system.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('simplereservation_admin_page_form'),
    'access arguments' => array('administer simple reservation system'),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/config/services/simplereservation/items'] = array(
    'title' => 'Items',
    'description' => 'Configure the items which are available for reservation.',
    'page callback' => 'simplereservation_admin_main_page',
    'access arguments' => array('administer simple reservation system'),
    'type' => MENU_LOCAL_TASK,
  );
  $items['admin/config/services/simplereservation/delete/%'] = array(
    'title' => 'Delete item',
    'description' => 'Delete an item from the reservation system.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('simplereservation_item_delete_confirm', 5),
    'access arguments' => array('administer simple reservation system'),
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/services/simplereservation/edit/%'] = array(
    'title' => 'Edit item',
    'description' => 'Edit an item from the reservation system.',
    'page callback' => 'simplereservation_item_edit',
    'page arguments' => array(5),
    'access arguments' => array('administer simple reservation system'),
    'type' => MENU_CALLBACK,
  );
  $items['admin/config/services/simplereservation/showall/%'] = array(
    'title' => 'List Reservations',
    'description' => 'Display a list of all/upcoming reservations.',
    'page callback' => 'simplereservation_showall_reservations',
    'access arguments' => array('administer simple reservation system'),
    'type' => MENU_CALLBACK,
  );

  $items['simplereservation'] = array(
    'title' => 'Reservation',
    'description' => 'Main page of the simple reservation system.',
    'page callback' => 'simplereservation_main_view',
    'access arguments' => array('access simple reservations'),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['simplereservation/add'] = array(
    'title' => 'Add reservation',
    'description' => 'Add a reservation into the simple reservation system.',
    'page callback' => 'simplereservation_reservation_add',
    'access callback' => '_simplereservation_access',
    'access arguments' => array('add'),
    'type' => MENU_NORMAL_ITEM,
  );
  $items['simplereservation/edit'] = array(
    'title' => 'Edit reservation',
    'description' => 'Edit an existing reservation.',
    'page callback' => 'simplereservation_reservation_edit',
    'page arguments' => array(2),
    'access callback' => '_simplereservation_access',
    'access arguments' => array('edit', 2),
    'type' => MENU_CALLBACK,
  );
  $items['simplereservation/delete'] = array(
    'title' => 'Delete reservation',
    'description' => 'Delete a reservation from the reservation system.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('simplereservation_reservation_delete_confirm', 2),
    'access callback' => '_simplereservation_access',
    'access arguments' => array('delete', 2),
    'type' => MENU_CALLBACK,
  );
  return $items;
}

/**
 * Function checking correct access to module function.
 */
function _simplereservation_access($access, $res_number = NULL) {
  global $user;

  switch ($access) {
    case 'add':
      return (user_access('add simple reservations for others') || user_access('add simple reservations'));

      break;

    case 'edit':
      $own = 'edit own simple reservations';
      $others = 'edit simple reservations of others';

      break;

    case 'delete':
      $own = 'delete own simple reservations';
      $others = 'delete simple reservations of others';

      break;

    default:
      return FALSE;
  }

  $sql = "SELECT * FROM {simplereservation_reservation} where rid = :rid";
  $result = db_query($sql, array(':rid' => $res_number));
  $row = $result->fetchAssoc();
  return $res_number && (($row["uid"] == $user->uid || $row["for_uid"] == $user->uid) && user_access($own)) || user_access($others);
}


/**
 * Implements hook_theme().
 */
function simplereservation_theme() {

  return array(
    // Custom theme function for preprocessing variables.
    'simplereservation_theming' => array(
      'variables' => array(
        'config' => NULL,
      ),
    ),
    // Default block layout.
    'simplereservation_week' => array(
      'template' => 'simplereservation_week',
      'variables' => array(
        'config' => NULL,
        'reservations' => NULL,
      ),
    ),
  );
}


/**
 * Custom theme function for preprocessing the output.
 */
function theme_simplereservation_theming($variables) {
  $config = $variables['config'];
  drupal_add_css(drupal_get_path('module', 'simplereservation') . '/css/simplereservation.css');
  $variables = array('config' => NULL);

  $month = date_month_names();
  $week = (is_numeric(arg(1)) ? arg(1) : date('W'));
  $year = (is_numeric(arg(2)) ? arg(2) : date('o'));
  $week = (strlen($week) < 2 ? '0' . $week : $week);
  $now = date_now();
  $week_day = date_week_days_ordered(date_week_days(TRUE));

  $first_day = date_create("$year-W$week-1");
  $day = clone $first_day;
  date_modify($day, '-4 weeks');
  $config['prev_4week'] = (date_format($day, 'W')) . '/' . date_format($day, 'o');
  date_modify($day, '+3 weeks');
  $config['prev_week'] = (date_format($day, 'W')) . '/' . date_format($day, 'o');
  date_modify($day, '+2 weeks');
  $config['next_week'] = (date_format($day, 'W')) . '/' . date_format($day, 'o');
  date_modify($day, '+3 weeks');
  $config['next_4week'] = (date_format($day, 'W')) . '/' . date_format($day, 'o');
  $day = clone $first_day;
  date_modify($day, '+3 days');
  $config['month'] = $month[(int) date_format($day, 'm')];
  $config['week'] = $week;
  $config['year'] = $year;
  $day = clone $first_day;

  for ($i = 0; $i <= 7; $i++) {
    $week_dates[$i] = clone $day;
    date_modify($day, '+1 day');
  }

  // Move forwards to the last day of the week.
  $empty["rid"] = 0;
  $config["calendar"] = $week_dates;
  $reservations = array();
  $sql = "SELECT * FROM {simplereservation_reservation} ";
  $sql .= "INNER JOIN {simplereservation_item} ON iid=item_id ";
  $sql .= "WHERE (begin >= :today AND begin <= :tomorrow) ";
  $sql .= "OR (ending >= :today AND ending <= :tomorrow) ";
  $sql .= "OR (begin < :today AND ending > :tomorrow) ";
  $sql .= "ORDER BY begin";

  for ($day = 0; $day < 7; $day++) {
    $today = date_format($week_dates[$day], 'U');
    $tomorrow = date_format($week_dates[$day + 1], 'U');
    $result = db_query($sql, array(':today' => $today, ':tomorrow' => $tomorrow));

    $reservations[$day][0] = $empty;
    while ($row = $result->fetchAssoc()) {
      $reservations[$day][] = $row;
    }
  }

  // If there are reservable item.
  $sql = "SELECT COUNT(iid) as countiid FROM {simplereservation_item} where status = 1;";
  $result = db_query($sql);
  $row = $result->fetchAssoc();

  if ($row['countiid'] > 0) {
    return theme('simplereservation_week', array('config' => $config, 'reservations' => $reservations));
  }
  else {
    drupal_set_message(t('There are no items for reservation.'));
  }
}


/**
 * Main page to show reservations by week.
 */
function simplereservation_main_view() {
  $month = date_month_names();
  $week_day = date_week_days_ordered(date_week_days());
  $now = date_now();
  $output = '';
  $output .= theme('simplereservation_theming', array('config' => NULL));
  return $output;
}


/**
 * Delete confirmation function.
 */
function simplereservation_reservation_delete_confirm($form, &$form_state, $reservation) {
  $form = array(
    'rid' => array(
      '#type' => 'hidden',
      '#value' => $reservation['rid'],
    ),
  );
  return confirm_form($form,
    t('Are you sure you want to delete the reservation %rid?', array('%rid' => $reservation['rid'])),
    (empty($form_state['post']) ? 'simplereservation' : $_GET['q']),
    t('This action cannot be undone.'),
    t('Delete'),
    t('Cancel')
  );
}


/**
 * Handle the deletion.
 */
function simplereservation_reservation_delete_confirm_submit($form, &$form_state) {

  $sql = "DELETE FROM {simplereservation_reservation} WHERE rid=%d";
  db_delete('simplereservation_reservation')
  ->condition('rid', $form_state['values']['rid'])
  ->execute();

  drupal_set_message(t('The reservation has been deleted.'));

  // Trigger our trigger.
  simplereservation_invoke_hook('simplereservation', 'delete_reservation');

  // Go back to the administration of system-wide weather blocks.
  $form_state['redirect'] = 'simplereservation';
}


/**
 * Construct a form for simplereservation item.
 */
function simplereservation_add_edit_form($form, $form_id, $reservation) {
  // Check if any reservable item exists.
  if (!db_query("SELECT COUNT(iid) FROM {simplereservation_item}")->fetchField()) {
    drupal_set_message(t('Please create an item before You try to reserve nothing'));
    return;
  }

  // Get or setup Simplereservation main variable.
  global $user;
  $rid = 0;
  $wholedaysonly = variable_get('simplereservation_whole_days', FALSE);
  $timeresolution = variable_get('simplereservation_time_step', 15);
  $year_s = date("Y", $reservation["begin"]);
  $month_s = date("m", $reservation["begin"]);
  $day_s = date("d", $reservation["begin"]);
  $hour_s = date("H", $reservation["begin"]);
  $min_s = date("i", $reservation["begin"]);
  $year_e = date("Y", $reservation["ending"]);
  $month_e = date("m", $reservation["ending"]);
  $day_e = date("d", $reservation["ending"]);
  $hour_e = date("H", $reservation["ending"]);
  $min_e = date("i", $reservation["ending"]);
  $date_format = 'd.m.Y - H:i';

  // No date_increment if this is a whole-day-reservation.
  if ($reservation["whd"]) {
    $timeresolution = 0;
  }

  // Form construct.
  $form['datetime'] = array(
    '#type' => 'fieldset',
    '#title' => t('Date and Time for this reservation.'),
    '#collapsible' => FALSE,
    '#collapsed' => FALSE,
    '#tree' => TRUE,
  );

  $form['datetime']['start'] = array(
    '#type' => 'date_popup',
    '#date_year_range' => '0:+3',
    '#date_type' => DATE_DATETIME,
    '#date_timezone' => date_default_timezone(),
    '#date_increment' => $timeresolution,
    '#date_format' => $date_format,
    '#title' => t('Start'),
    '#default_value' => $year_s . '-' . $month_s . '-' . $day_s . ' ' . $hour_s . ':' . $min_s . ':00',
    '#description' => t('Start date and time of this reservation.'),
  );

  if ($wholedaysonly) {
    $form['datetime']['end'] = array(
      '#type' => 'hidden',
      '#value' => $year_e . '-' . $month_e . '-' . $day_e . ' 23:59',
    );
  }
  else {
    $form['datetime']['end'] = array(
      '#type' => 'date_popup',
      '#date_year_range' => '0:+3',
      '#date_type' => DATE_DATETIME,
      '#date_timezone' => date_default_timezone(),
      '#date_increment' => $timeresolution,
      '#date_format' => $date_format,
      '#title' => t('End'),
      '#default_value' => $year_e . '-' . $month_e . '-' . $day_e . ' ' . $hour_e . ':' . $min_e . ':00',
      '#description' => t('End date and time of this reservation.'),
    );
  }

  // Do not display this checkbox if there are only whole-day-reservations.
  if (!$wholedaysonly) {
    $form['datetime']['whole_day'] = array(
      '#type' => 'checkbox',
      '#title' => t('Reservation for the complete day'),
      '#description' => t('Enable this reservation if you want to reserve for the whole day. This overwrites the above hour/minute setting.'),
      '#default_value' => $reservation["whd"],
    );
  }

  // Get the bookable reservation items and fill them in a dropdown.
  $sql = "SELECT iid, name, description FROM  {simplereservation_item} where status=1 ORDER BY name;";
  $result = db_query($sql);
  foreach ($result as $record) {
    $period[$record->iid] = $record->name . " (" . $record->description . ")";
  }

  $form['item'] = array(
    '#type' => 'select',
    '#title' => t('Item'),
    '#default_value' => $reservation["item_id"],
    '#options' => $period,
    '#description' => t('The item you want to reserve.'),
  );
  $form['comment'] = array(
    '#type' => 'textfield',
    '#size' => 50,
    '#title' => t('Comment'),
    '#default_value' => $reservation["rcomment"],
    '#description' => t('You can add a comment for your reservation.'),
  );
  $username = '';
  if (isset($reservation["for_uid"])) {
    $account = user_load($reservation["for_uid"]);
    $username = $account->name;
  }
  if ((user_access('add simple reservations for others') || user_access('edit simple reservations of others') ||
     user_access('administer simple reservation system')) && user_access('access user profiles')) {
    $form['reservation_is_for'] = array(
      '#type' => 'textfield',
      '#title' => t('This reservation is for'),
      '#default_value' => $username,
      '#autocomplete_path' => 'user/autocomplete',
      '#size' => '50',
      '#description' => t('Add a name here if you want to reserve this item for somebody else.'),
    );
  }
  // Field reservation_is_for is hidden if user have not access to edit him.
  else {
    $form['reservation_is_for'] = array(
      '#type' => 'hidden',
      '#title' => t('This reservation is for'),
      '#default_value' => $username,
      '#autocomplete_path' => 'user/autocomplete',
      '#size' => '50',
      '#description' => t('Add a name here if you want to reserve this item for somebody else.'),
    );
  }
  $form['rid'] = array(
    '#type' => 'value',
    '#value' => $reservation['rid'],
  );
  if ($reservation['rid']) {
    if ((user_access('delete own simple reservations') && $reservation["uid"] == $user->uid) ||
    user_access('delete simple reservations of others')) {
      $form['delete'] = array(
        '#type' => 'submit',
        '#value' => t('Delete'),
      );
    }
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Save changes'),
    );
  }
  else {
    $form['submit'] = array(
      '#type' => 'submit',
      '#value' => t('Save this reservation'),
    );
  }
  return $form;
}


/**
 * Check the submission of the reservation.
 *
 * This function checks, if it is possible to save the reservation. 
 * This is denied if the item which shall be reserved is booked already
 * during that time.
 * There is only one exception: If a item is already booked e.g. from 09:00,
 * then a new reservation ending at exactly 09:00 is allowed. 
 * Also, if an item is booked until e.g.11:34, a new reservation starting 
 * at 11:34 is allowed (in other words, a overlap of 1 minute is allowed).
 */
function simplereservation_add_edit_form_validate(&$form, &$form_state) {
  global $user;

  if ($form_state['values']['submit'] == t('Delete')) {
    return;
  }

  $fstart = $form_state['values']['datetime']['start'];
  $fend = $form_state['values']['datetime']['end'];

  if ((substr($fstart, 8, 2) == date("d")) AND (substr($fstart, 5, 2) == date("m")) AND (substr($fstart, 0, 4) == date("Y"))) {
    $reservation_start_today = TRUE;
  }
  else {
    $reservation_start_today = FALSE;
  }

  // If whole day reservation start today.
  // Start time is changed according to actual time and time step.
  if ($form_state['values']['datetime']['whole_day'] == 1 AND $reservation_start_today) {
    $reservations_time_step = variable_get('simplereservation_time_step');
    $actual_start_minute = date("i");
    $actual_start_hour = date("H");
    // If current time is XX:00 then time step is not important.
    if ($actual_start_minute == 0) {
      $reservations_time_step = 0;
      $rest = 0;
      $integer_rest = 0;
    }
    else {
      $integer_rest = floor($actual_start_minute / $reservations_time_step);
      $rest = $actual_start_minute % $reservations_time_step;
    }
    if ($rest == 0) {
      $start_hour = $actual_start_hour;
      $start_minute = $actual_start_minute;
    }
    else {
      if (($integer_rest + 1) * $reservations_time_step < 60) {
        $start_hour = $actual_start_hour;
        $start_minute = ($integer_rest + 1) * $reservations_time_step;
      }
      else {
        $start_hour = $actual_start_hour + 1;
        $start_minute = 0;
      }
    }

    $form_state['values']['datetime']['start'] = substr($form_state['values']['datetime']['start'], 0, 11) . $start_hour . ":" . $start_minute;
    $fstart = $form_state['values']['datetime']['start'];
  }

  if (variable_get('simplereservation_whole_days', FALSE)) {
    $start = mktime(0, 00, 1, substr($fstart, 5, 2), substr($fstart, 8, 2), substr($fstart, 0, 4));
    $end = mktime(23, 59, 0, substr($fend, 5, 2), substr($fend, 8, 2), substr($fend, 0, 4));
  }
  else {
    $start = mktime(substr($fstart, 11, 2), substr($fstart, 14, 2), substr($fstart, 17, 4), substr($fstart, 5, 2), substr($fstart, 8, 2), substr($fstart, 0, 4));
    $end = mktime(substr($fend, 11, 2), substr($fend, 14, 2), substr($fend, 17, 4), substr($fend, 5, 2), substr($fend, 8, 2), substr($fend, 0, 4));
  }

  $today = mktime(0, 0, 0, date("m"), date("d"), date("Y"));
  $now = mktime(date("H"), date("i"), date("s"), date("m"), date("d"), date("Y"));

  // Check for the restrictions set in the admin options.
  if (!user_access('unrestricted simple reservations')) {
    // But only if the user is not allowed to do anything he wants.
    $max = variable_get('simplereservation_max_reservations', 0);
    if ($max > 0) {
      $result = db_query("SELECT COUNT(rid) as countrid FROM {simplereservation_reservation} WHERE uid = :uid AND ending > :ending ", array(':uid' => $user->uid, ':ending' => $today));
      $row = $result->fetchAssoc();
      if ($row['countrid'] > $max) {
        form_set_error('simplereservation', t('You are not allowed to create more than MAX reservations!', array('MAX' => $max)));
      }
    }

    $max = variable_get('simplereservation_max_weeks', 0);
    if ($max > 0) {
      // End date is 2008 Oct. 11 00:00:00.
      $enddate = $start;
      $begindate = $today;
      $timestamp_diff = $enddate - $begindate + 1;
      // How many days between those two date.
      $week_diff = $timestamp_diff / 604800;

      if ($week_diff > $max) {
        form_set_error('simplereservation', t('You are not allowed to book more than MAX weeks in advance!', array('MAX' => $max)));
      }
    }
  }

  // Reservations in the past.
  if ($start < $now || $end < $now) {
    form_set_error('simplereservation', t('Begin or end of reservation is in the past!'));
  }
  // End time before start time.
  if ($start > $end) {
    form_set_error('simplereservation', t('End of reservation is before begin!'));
  }

  // Check for an existing  reservation DURING this reservation.
  $sql = "SELECT COUNT(rid) as countrid FROM {simplereservation_reservation} WHERE item_id = :itemid AND rid <> :rid ";
  $sql .= "AND ((begin <= :begin AND ending >= :ending) OR (begin >= :begin AND ending <= :ending))";
  $result = db_query($sql, array(
              ':itemid' => $form_state['values']['item'],
              ':rid' => $form_state['values']['rid'],
              ':begin' => $start,
              ':ending' => $end)
            );
  $row = $result->fetchAssoc();
  if ($row['countrid'] > 0) {
    form_set_error('simplereservation', t('The item is already reserved during that time!'));
  }
  // Check for an existing reservation at the BEGINNING of this reservation.
  $sql = "SELECT COUNT(rid) as countrid FROM {simplereservation_reservation} WHERE item_id = :itemid AND rid <> :rid ";
  $sql .= "AND begin <= :begin AND ending > :ending";
  $result = db_query($sql, array(
              ':itemid' => $form_state['values']['item'],
              ':rid' => $form_state['values']['rid'],
              ':begin' => $start,
              ':ending' => $start)
            );
  $row = $result->fetchAssoc();

  if ($row['countrid'] > 0) {
    form_set_error('simplereservation', t('The item is already reserved at the beginning of your reservation!'));
  }

  // Check for an existing reservation at the END of this reservation.
  $sql = "SELECT COUNT(rid) as countrid FROM {simplereservation_reservation} WHERE item_id = :itemid AND rid <> :rid ";
  $sql .= "AND begin < :begin AND ending >= :ending";
  $result = db_query($sql, array(
              ':itemid' => $form_state['values']['item'],
              ':rid' => $form_state['values']['rid'],
              ':begin' => $end,
              ':ending' => $end)
            );
  $row = $result->fetchAssoc();

  if ($row['countrid'] > 0) {
    form_set_error('simplereservation', t('The item is already reserved at the end of your reservation!'));
  }
}


/**
 * Handle the submission of the reservation.
 */
function simplereservation_add_edit_form_submit($form, &$form_state) {
  global $user;
  $fstart = $form_state['values']['datetime']['start'];
  $fend = $form_state['values']['datetime']['end'];

  if (variable_get('simplereservation_whole_days', FALSE)) {
    $start = mktime(0, 00, 01, substr($fstart, 5, 2), substr($fstart, 8, 2), substr($fstart, 0, 4));
    $end = mktime(23, 59, 0, substr($fend, 5, 2), substr($fend, 8, 2), substr($fend, 0, 4));
  }
  else {
    $start = mktime(substr($fstart, 11, 2), substr($fstart, 14, 2), substr($fstart, 17, 4), substr($fstart, 5, 2), substr($fstart, 8, 2), substr($fstart, 0, 4));
    if ($form_state['values']['datetime']['whole_day']) {
      $end = mktime(23, 59, 0, substr($fend, 5, 2), substr($fend, 8, 2), substr($fend, 0, 4));
    }
    else {
      $end = mktime(substr($fend, 11, 2), substr($fend, 14, 2), substr($fend, 17, 4), substr($fend, 5, 2), substr($fend, 8, 2), substr($fend, 0, 4));
    }
  }

  $account = array_shift(user_load_multiple(array(), array('name' => $form_state['values']['reservation_is_for'])));

  $values = array(
    'item_id' => $form_state['values']['item'],
    'uid' => $user->uid,
    'for_uid' => $account->uid,
    'begin' => $start,
    'ending' => $end,
    'rcomment' => $form_state['values']['comment'],
    'whd' => $form_state['values']['datetime']['whole_day'],
  );

  if ($form_state['values']['rid'] > 0) {
    // Update existing reservation.
    $values['rid'] = $form_state['values']['rid'];
    drupal_write_record('simplereservation_reservation', $values, 'rid');
    watchdog('reservation', 'Reservation %rid updated by %name.', array('%rid' => $values['rid'], '%name' => $user->name));
  }
  else {
    // Add new reservation.
    drupal_write_record('simplereservation_reservation', $values);
    watchdog('reservation', 'New reservation %rid added by %name.', array('%rid' => $values['rid'], '%name' => $user->name));
  }
  drupal_set_message(t('The reservation has been saved.'));

  // Trigger our trigger.
  simplereservation_invoke_hook('simplereservation', 'new_reservation');

  $redir_to_week = 'simplereservation'.date("/W/o", $start);

  $form_state['redirect'] = $redir_to_week;
}


/**
 * Edit existing reservation.
 */
function simplereservation_reservation_edit($reservation_number) {

  // Load data for old reservation to edit.
  $sql = "SELECT * FROM {simplereservation_reservation} WHERE rid = :rid";
  $result = db_query($sql, array(':rid' => $reservation_number));
  $reservation_load = $result->fetchAssoc();

  $reservation = array(
    'rid' => $reservation_load['rid'],
    'uid' => $reservation_load['uid'],
    'for_uid' => $reservation_load['for_uid'],
    'begin' => $reservation_load['begin'],
    'ending' => $reservation_load['ending'],
    'whd' => $reservation_load['whd'],
    'item_id' => $reservation_load['item_id'],
    'rcomment' => $reservation_load['rcomment'],
  );
  if ((isset($_POST['op']) && $_POST['op'] == t('Delete')) || !empty($_POST['confirm'])) {
    return drupal_get_form('simplereservation_reservation_delete_confirm', $reservation);
  }
  return drupal_get_form('simplereservation_add_edit_form', $reservation);
}


/**
 * Prepare reservation data to fill new form.
 */
function simplereservation_reservation_add($year = NULL, $month = NULL, $day = NULL) {
  $year = (isset($year) ? $year : date("Y", REQUEST_TIME));
  $month = (isset($month) ? $month : date("m", REQUEST_TIME));
  $day = (isset($day) ? $day : date("d", REQUEST_TIME));

  $reservation = array(
    'rid' => 0,
    'begin' => mktime(7, 0, 0, $month, $day, $year),
    'ending' => mktime(14, 0, 0, $month, $day, $year),
    'whd' => variable_get('simplereservation_whole_days', FALSE),
    'item_id' => 0,
    'rcomment' => '',
  );
  return drupal_get_form('simplereservation_add_edit_form', $reservation);
}


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

  $blocks['upcoming_reservations'] = array(
    'info' => t('10 upcoming reservations.'),
    'cache' => DRUPAL_NO_CACHE,
  );

  return $blocks;
}


/**
 * Implements hook_block_view().
 */
function simplereservation_block_view($block_name = '') {
  if ($block_name == 'upcoming_reservations') {
    $block = array(
      'subject' => t('Upcoming reservations'),
      'content' => simplereservation_upcoming_reservations(),
    );

    return $block;
  }
}


/**
 * Retrieve upcoming reservations.
 */
function simplereservation_upcoming_reservations($num_items = 10) {
  $output = '';
  $path = drupal_get_path('module', 'simplereservation');
  $now = mktime(date("H"), date("i"), date("s"), date("m"), date("d"), date("Y"));
  $reservations = array();
  $sql = "SELECT * FROM {simplereservation_reservation} ";
  $sql .= "INNER JOIN {simplereservation_item} ";
  $sql .= "ON iid=item_id ";
  $sql .= "WHERE begin >= :now  ";
  $sql .= "OR ending >= :now  ";
  $sql .= "OR (begin <= :now AND ending > :now) ";
  $sql .= "ORDER BY begin LIMIT 10";

  $result = db_query($sql, array(':now' => $now));

  while ($row = $result->fetchAssoc()) {
    $reservations[] = $row;
  }
  $output = "";
  if (is_array($reservations) && count($reservations)) {
    $i = 0;
    $j = 0;
    // Max 5 days or 10 reservations to show.
    while ($i < 5 AND $j < 10) {
      $curr_date = date("d.m.Y", time() + $i * 86400);
      $curr_date_begin = mktime(0, 0, 0, substr($curr_date, 3, 2), substr($curr_date, 0, 2), substr($curr_date, 6, 4));
      $curr_date_end = mktime(23, 59, 59, substr($curr_date, 3, 2), substr($curr_date, 0, 2), substr($curr_date, 6, 4));
      $output .= "&nbsp;<b>" . $curr_date . "</b><br>";
      foreach ($reservations as $res_row) {
        if (!(($res_row["begin"] < $curr_date_begin AND $res_row["ending"] < $curr_date_begin) OR ($res_row["begin"] > $curr_date_end AND $res_row["ending"] > $curr_date_end))) {
          $from = user_load($res_row["uid"]);

          if (($res_row["ending"] - $res_row["begin"] == 61140) OR ($res_row["whd"] == 1)) {
            $output .= '<small><b>' . t('whole day') . '</b>&nbsp;';
          }
          else {
            if ($res_row["begin"] < $curr_date_begin) {
              $output .= '<small><b> ... ';
            }
            else {
              $output .= '<small><b>' . date("H:i", $res_row["begin"]);
            }
            $output .= " - ";

            if ($res_row["ending"] > $curr_date_end) {
              $output .= ' ... </b>&nbsp;';
            }
            else {
              $output .= date("H:i", $res_row["ending"]) . '</b>&nbsp;';
            }
          }

          $output .= "<a title=\"" . $res_row["description"] . "\">" . $res_row["name"] . "</a>";
          $output .= " " . t("by") . " " . $from->name;
          if ($res_row["rcomment"] != "") {
            $output .= " (" . $res_row["rcomment"] . ")";
          }
          ++$j;
          $output .= "</small><br>";
        }
      }
      unset($res_row);
      $i++;
    }
  }

  return $output;
}


/**
 * ADMINISTRATION
 */

/**
 * Admin main page.
 */
function simplereservation_admin_main_page() {
  $output = '';
  $path = 'admin/config/services/simplereservation/';

  $header = array(
    t('Name'),
    t('Description'),
    t('Comment'),
    t('Status'),
    array(
      'data' => t('Operations'),
      'colspan' => 2,
    ),
  );

  $rows = array();

  // Get all the reservation items from the database.
  $items = db_select('simplereservation_item', 's')
    ->fields('s', array('iid', 'name', 'description', 'comment', 'status'))
    ->orderBy('name')
    ->execute()
    ->fetchAll();

  // Loop through the reservation items and add them to the table.
  foreach ($items as $item) {
    $rows[] = array(
      check_plain($item->name),
      check_plain($item->description),
      check_plain($item->comment),
      ($item->status ? t('available') : t('not available')),
      l(t('Edit'), $path . 'edit/' . $item->iid),
      l(t('Delete'), $path . 'delete/' . $item->iid),
    );
  }

  if (!$rows) {
    $rows[] = array(
      array(
        'data' => t('No items available.'),
        'colspan' => 5,
      ),
    );
  }

  $build['item_table'] = array(
    '#theme' => 'table',
    '#header' => $header,
    '#rows' => $rows,
  );

  $build['item_links'] = array(
    'first_para' => array(
      '#type' => 'markup',
      '#markup' => l(t('Create new item'), $path . 'edit/-1') . '<br/>' .
      l(t('Show all reservations'), $path . 'showall/all') . '<br/>' .
      l(t('Show all upcoming reservations'), $path . 'showall/upcoming') . '<br/><br/>',
    ),
  );

  return $build;
}


/**
 * General settings form.
 */
function simplereservation_admin_page_form() {
  $form = array();

  $form['simplereservation_max_reservations'] = array(
    '#type' => 'textfield',
    '#size' => 5,
    '#title' => t('Maximum number of reservations per person'),
    '#default_value' => variable_get('simplereservation_max_reservations', 0),
    '#required' => TRUE,
    '#description' => t('This setting defines the maximum number of reservations a user can make (not counting passed reservations). Enter 0 for an unlimited number. Administrators are not affected by this setting.'),
  );
  $form['simplereservation_max_weeks'] = array(
    '#type' => 'textfield',
    '#size' => 5,
    '#title' => t('Maximum number of weeks a user can book in advance'),
    '#default_value' => variable_get('simplereservation_max_weeks', 0),
    '#required' => TRUE,
    '#description' => t('Enter 0 for an unlimited number. Administrators are not affected by this setting.'),
  );
  $form['simplereservation_time_step'] = array(
    '#type' => 'textfield',
    '#size' => 5,
    '#title' => t('Resolution for the hours and minutes for the reservations'),
    '#default_value' => variable_get('simplereservation_time_step', 15),
    '#required' => TRUE,
    '#description' => t('If you enter e.g. 15, a reservation can only be done in a quarter hourly basis, e.g. 9:00, 9:15, 9:30, ...'),
  );
  $form['simplereservation_whole_days'] = array(
    '#type' => 'checkbox',
    '#title' => t('Reservations for whole days only'),
    '#description' => t('When you enable this box, reservations can only be done for whole days from 0:00 until 23:59.'),
    '#default_value' => variable_get('simplereservation_whole_days', FALSE),
  );

  return system_settings_form($form);
}


/**
 * General settings form validation.
 */
function simplereservation_admin_page_form_validate($form, &$form_state) {
  $max_reservations = $form_state['values']['simplereservation_max_reservations'];
  if (!is_numeric($max_reservations) OR !($max_reservations >= 0 AND $max_reservations <= 9999)) {
    form_set_error('simplereservation_max_reservations', 'Maximum number of reservation - enter number between 0 and 9999');
  }
  $max_weeks = $form_state['values']['simplereservation_max_weeks'];
  if (!is_numeric($max_weeks) OR !($max_weeks >= 0 AND $max_weeks <= 54)) {
    form_set_error('simplereservation_max_weeks', 'Maximum number of weeks - enter number between 0 and 54');
  }
  $time_step = $form_state['values']['simplereservation_time_step'];
  if (!is_numeric($time_step) OR !($time_step >= 0 AND $time_step <= 30)) {
    form_set_error('simplereservation_time_step', 'Resolution - enter number between 0 and 30');
  }
}

/**
 * Show a configuration page.
 */
function simplereservation_item_edit($iid) {
  $output = drupal_get_form('simplereservation_item_form', $iid);
  return $output;
}


/**
 * Construct the configuration form for items.
 */
function simplereservation_item_form($form, $dummy, $iid) {
  if ($iid > 0) {
    $result = db_query("SELECT name, description, comment, status FROM {simplereservation_item} WHERE iid = :iid", array(':iid' => $iid));
    $row = $result->fetchAssoc();
  }
  else {
    $row = array(
      'name' => 'Name',
      'description' => 'A description',
      'comment' => 'A comment',
      'status' => 1,
    );
  }

  $form['name'] = array(
    '#title' => t('Name of the item'),
    '#type' => 'textfield',
    '#size' => '20',
    '#default_value' => $row['name'],
    '#description' => t('A (unique) short name to identify the item, e.g. "Room 12", "Number 42" or a registration number.'),
    '#required' => TRUE,
  );
  $form['description'] = array(
    '#title' => t('Description of the item'),
    '#type' => 'textfield',
    '#size' => '50',
    '#default_value' => $row['description'],
    '#description' => t('More detailed information to describe the item.'),
  );
  $form['comment'] = array(
    '#title' => t('Comment'),
    '#type' => 'textfield',
    '#size' => '50',
    '#default_value' => $row['comment'],
    '#description' => t('e.g. "non-smoking", "diesel" or something.'),
  );
  $form['iid'] = array(
    '#type' => 'value',
    '#value' => $iid,
  );
  $form['status'] = array(
    '#type' => 'checkbox',
    '#title' => t('This item is available for reservation'),
    '#description' => t('If you disable this, the item will not show in the reservation list and will not available for reservation. You can use this to prepare a list of items or to prevent an item from reservation if it is e.g. broken.'),
    '#default_value' => $row['status'],
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  return $form;
}


/**
 * Check the items form submission.
 */
function simplereservation_item_form_validate($form, &$form_state) {
  if ($form_state['values']['iid'] < 0) {
    // Check if the new item name do not already exist.
    $result = db_query("SELECT name, description, comment, status FROM {simplereservation_item} WHERE name = :name", array(':name' => $form_state['values']['name']));
    $row = $result->fetchAssoc();
    if ($row > 0) {
      form_set_error('simplereservation', t('An item with that name exists already. Choose diferent name'));
    }
  }

  if ($form_state['values']['iid'] >= 0) {
    // Check if the name do not already exist.
    $result = db_query("SELECT name, description, comment, status FROM {simplereservation_item} WHERE name = :name AND iid <> :iid", array(':name' => $form_state['values']['name'], ':iid' => $form_state['values']['iid']));
    $row = $result->fetchAssoc();
    if ($row > 0) {
      form_set_error('simplereservation', t('An item with that name exists already. Choose diferent name or leave old item name.'));
    }
  }

}

/**
 * Handle the item form submission.
 */
function simplereservation_item_form_submit($form, &$form_state) {
  $iid = $form_state['values']['iid'];

  // Update of a existing item.
  if ($iid > 0) {
    db_update('simplereservation_item')
      ->condition('iid', $form_state['values']['iid'])
      ->fields(array(
        'name' => $form_state['values']['name'],
        'description' => $form_state['values']['description'],
        'comment' => $form_state['values']['comment'],
        'status' => $form_state['values']['status'],
      ))
      ->execute();
    drupal_set_message(t('The item has been saved.'));
  }

  // Create new item.
  else {
    $id = db_insert('simplereservation_item')
      ->fields(array(
        'name' => $form_state['values']['name'],
        'description' => $form_state['values']['description'],
        'comment' => $form_state['values']['comment'],
        'status' => $form_state['values']['status'],
      ))
      ->execute();
    drupal_set_message(t('The item has been saved.'));
  }
  $form_state['redirect'] = 'admin/config/services/simplereservation/items';
}


/**
 * Item delete form.
 */
function simplereservation_item_delete_confirm($form, &$form_state, $iid) {
  $result = db_query("SELECT * FROM {simplereservation_item} WHERE iid = :iid", array(':iid' => $iid));
  $row = $result->fetchAssoc();

  $form = array();
  $form['iid'] = array(
    '#type' => 'hidden',
    '#value' => $iid,
  );
  return confirm_form($form,
    t('Are you sure you want to delete the item %name?', array('%name' => $row['name'])),
    'admin/config/simplereservation',
    t('This action cannot be undone.'),
    t('Delete'),
    t('Cancel'));
}


/**
 * Handle the deletion of a item.
 */
function simplereservation_item_delete_confirm_submit($form, &$form_state) {

  db_delete('simplereservation_item')
  ->condition('iid', $form_state['values']['iid'])
  ->execute();
  drupal_set_message(t('The item has been deleted.'));

  // Go back to the administration.
  $form_state['redirect'] = 'admin/config/services/simplereservation/items';
}


/**
 * Show all (upcoming) reservations.
 */
function simplereservation_showall_reservations() {
  $output = '';
  $today = mktime(date("H"), date("i"), date("s"), date("m"), date("d"), date("Y"));

  $reservations = array();
  $sql = "SELECT * FROM {simplereservation_reservation} ";
  $sql .= " INNER JOIN {simplereservation_item}";
  $sql .= " ON iid=item_id ";
  if (arg(4) == 'upcoming') {
    $sql .= " WHERE begin >= :begin  ";
    $sql .= " OR ending >= :ending  ";
    $sql .= " OR (begin <= begin AND ending > :ending) ";
  }
  $sql .= " ORDER BY begin;";

  if (arg(4) == 'upcoming') {
    $result = db_query($sql, array(':begin' => $today, ':ending' => $today));
  }
  else {
    $result = db_query($sql);
  }

  while ($row = $result->fetchAssoc()) {
    $reservations[] = $row;
  }

  if (is_array($reservations) && count($reservations)) {
    $output = '<table>';

    $aktdatum = (date("d.m.Y", $reservations[0]["begin"]));
    $output .= '<tr><td colspan="2"><span class="reservation-date">&nbsp;<b>' . $aktdatum . '</b>&nbsp;</span></td></tr>';

    foreach ($reservations as $reservation) {
      if ($reservation["rid"] > 0) {
        $from = user_load($reservation["uid"]);

        if ((date("d.m.Y", $reservation["begin"])) != $aktdatum) {
          $aktdatum = (date("d.m.Y", $reservation["begin"]));
          $output .= '<tr><td colspan="2"><span class="reservation-date">&nbsp;<b>' . $aktdatum . '</b>&nbsp;</span></td></tr>';
        }
        if ($reservation["ending"] - $reservation["begin"] == 86339) {
          $output .= '<tr><td>' . t('whole day');
        }
        else {
          // From Begin.
          $output .= '<tr><td>' . (date("H:i", $reservation["begin"]));
          $output .= ' - ';
          // To End.
          $output .= date("H:i", $reservation["ending"]);
        }
        $output .= "</td><td><a  title=\"" . $reservation["description"] . "\">" . $reservation["name"] . "</a></b>";
        $output .= " " . t("booked by") . " " . l($from->name, 'user/' . $from->uid);
        if ($reservation["for_uid"] != 0) {
          $foruid = user_load($reservation["for_uid"]);
          $output .= ' for ' . l($foruid->name, 'user/' . $foruid->uid);
        }
        if ($reservation["rcomment"] != "") {
          $output .= " (" . $reservation["rcomment"] . ")";
        }
      }
      $output .= '</td></tr>';
    }
    $output .= '</table>';
  }
  else {
    $outout = 'There are no reservations';
  }
  return $output;
}
