<?php

/**
 * @file
 * Show the site-wide contact forms in blocks.
 */

/**
 * Implements hook_block().
 */
function contact_form_blocks_block($op = 'list', $delta = 0, $edit = array()) {
  switch ($op) {
    case 'list':
      $blocks = array();
      foreach (contact_form_blocks_get_categories() as $cid => $name) {
        // Block info is escaped by Block module.
        $blocks[$cid]['info'] = t('Contact form: !name', array('!name' => $name));
      }
      return $blocks;

    case 'view':
      // Check if the user has access to the site-wide contact form.
      if (user_access('access site-wide contact form')) {
        return contact_form_blocks_block_view($delta);
      }
  }
}

/**
 * Implements hook_menu().
 */
function contact_form_blocks_menu() {
  $items['admin/settings/contact_form_blocks'] = array(
    'title' => 'Contact blocks',
    'description' => 'Contact blocks settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('contact_form_blocks_settings'),
    'access arguments' => array('administer site-wide contact form'),
  );
  return $items;
}

/**
 * Implements hook_forms().
 */
function contact_form_blocks_forms($form_id, $args) {
  $forms = array();
  // Only handle contact_mail_page_CID forms.
  if ($category = preg_match('@^contact_mail_page_\d+$@', $form_id)) {
    $forms[$form_id] = array(
      'callback' => 'contact_mail_page',
      'callback arguments' => array($category)
    );
  }
  return $forms;
}

/**
 * Returns block data for a contact form block.
 *
 * @param int $category
 *   The contact.cid of the contact form category from the database
 */
function contact_form_blocks_block_view($category) {
  module_load_include('inc', 'contact', 'contact.pages');

  $categories = contact_form_blocks_get_categories();
  $block['subject'] = check_plain($categories[$category]);

  // @see contact_site_page()
  if (!flood_is_allowed('contact', variable_get('contact_hourly_threshold', 3))) {
    $block['content'] = $output = t("You cannot send more than %number messages per hour. Please try again later.", array('%number' => variable_get('contact_hourly_threshold', 3)));
    return $block;
  }

  // Append the category ID to the contact_mail_page form_id to be able
  // to handle multiple contact forms on the same page.
  $block['content'] = drupal_get_form('contact_mail_page_'. $category, $category);

  // Add some modifications to the CSS
  drupal_add_css(drupal_get_path('module', 'contact_form_blocks') .'/contact_form_blocks.css');

  return $block;
}

/**
 * Implements hook_form_alter().
 *
 * contact_form_blocks_block_view() builds the regular contact_mail_page form
 * (routed via hook_forms()), but passes an additional $category argument. Since
 * Form API does not apply the regular auto-suggested #validate and #submit
 * callbacks for the base form ID and also does not invoke hook_form_alter() for
 * the base form ID, we need to do it manually here, so as to not break other
 * modules.
 * @see http://drupal.org/node/757154
 *
 * @todo Remove in D7; form alter, #validate, and #submit handlers are taken
 *   into account for sub-form_ids now. Therefore, this module can simply
 *   implement hook_form_contact_mail_page_alter() and adjust the category field
 *   according to the passed arguments in $form_state['build_info']['args'].
 */
function contact_form_blocks_form_alter(&$form, &$form_state, $form_id) {
  // Only handle contact_mail_page_CID forms.
  if (!preg_match('@^contact_mail_page_\d+@', $form_id)) {
    return;
  }
  // Prepend regular contact_mail_page form handlers.
  $form += array('#validate' => array(), '#submit' => array());
  array_unshift($form['#validate'], 'contact_mail_page_validate');
  array_unshift($form['#submit'], 'contact_mail_page_submit');

  // Also invoke regular hook_form_alter() implementations. This may look like a
  // hack, but effectively it is the same as Form API would do for the regular
  // $form_id; we are merely expanding a drupal_alter() with a drupal_alter().
  // @see drupal_prepare_form()
  $form_id = 'contact_mail_page';
  $data = &$form;
  $data['__drupal_alter_by_ref'] = array(&$form_state);
  drupal_alter('form_'. $form_id, $data);
  // __drupal_alter_by_ref is unset in the drupal_alter() function, we need
  // to repopulate it to ensure both calls get the data.
  $data['__drupal_alter_by_ref'] = array(&$form_state);
  drupal_alter('form', $data, $form_id);

  // Force selection of given contact category.
  // The 3rd form contructor argument is our passed $category.
  $category = $form['#parameters'][2];
  $form['cid']['#value'] = $category;
  $form['cid']['#access'] = FALSE;

  // Avoid default redirection of site-wide contact form to front page.
  $form['#redirect'] = FALSE;
}

/**
 * Implements hook_form_FORMID_alter().
 *
 * We additionally remove all categories from the regular site-wide contact form
 * that have been disabled in our module settings.
 */
function contact_form_blocks_form_contact_mail_page_alter(&$form, &$form_state) {
  if (isset($form['cid']['#options'])) {
    $categories = contact_form_blocks_get_categories();
    foreach ($form['cid']['#options'] as $cid => $name) {
      if (!isset($categories[$cid])) {
        unset($form['cid']['#options'][$cid]);
      }
    }
    // In case we also removed the #default_value, dynamically adjust it to use
    // the first available category.
    if (!isset($form['cid']['#options'][$form['cid']['#default_value']])) {
      reset($form['cid']['#options']);
      $form['cid']['#default_value'] = key($form['cid']['#options']);
    }
  }
}

/**
 * Returns contact form category names keyed by category ID.
 */
function contact_form_blocks_get_categories() {
  $categories = array();
  $result = db_query('SELECT cid, category FROM {contact} ORDER BY weight, category');
  while ($row = db_fetch_object($result)) {
    $categories[$row->cid] = $row->category;
  }
  return $categories;
}

/**
 * Form constructor for the module settings form.
 */
function contact_form_blocks_settings() {
  $categories = contact_form_blocks_get_categories();

  // Warning if no contact category being set
  if (empty($categories)) {
    drupal_set_message(t("You need to !link first before being able to set them here.", array('!link' => l("create contact form categories", "admin/build/contact/add"))));
    return array();
  }
  $form['contact_form_blocks_categories'] = array(
    '#type' => 'checkboxes',
    '#title' => t('Categories to be shown in the site wide contact form'),
    '#default_value' => variable_get('contact_form_blocks_site_wide_categories', array_keys($categories)),
    '#options' => array_map('check_plain', $categories),
  );

  return system_settings_form($form);
}
