<?php

/**
 * @file
 * Provides a debug mode for module ThemeKey.
 * @see themekey.module
 *
 * @author Markus Kalkbrenner | bio.logis GmbH
 *   @see http://drupal.org/user/124705
 */


/**
 * Implements hook_permission().
 */
function themekey_debug_permission() {
  return array(
    'themekey_debug_see_messages' => array(
      'title' => t('See ThemeKey debug messages'),
      'description' => t('Using this permission debug messages will be displayed to users in that role.'),
    ),
  );
}


/**
 * Iterates over all ThemeKey Properties and prints
 * out their current values.
 */
function themekey_debug_properties() {
  global $user;

  if (1 == $user->uid || user_access('themekey_debug_see_messages', $user) || variable_get('themekey_debug_non_admin_users', FALSE)) {
    module_load_include('inc', 'themekey', 'themekey_base');

    $properties = variable_get('themekey_properties', array());
    $message = t('These are the current values of all available ThemeKey Properties. By clicking the value you can start creating a corresponding Theme Switching Rule.') . '<ul>';
    $parameters = themekey_get_global_parameters();

    foreach ($properties as $property) {
      if (!isset($parameters[$property])) {
        themekey_property_value($parameters, $property);
      }

      $value = '';
      if (is_null($parameters[$property])) {
        if ('drupal:path' == $property) {
          $value = '<em>no debug information</em>';
        }
        else {
          $value = '<em>empty</em>';
        }
      }
      else {
        $values = is_array($parameters[$property]) ?   $parameters[$property] : array($parameters[$property]);
        $links = array();
        foreach ($values as $single_value) {
          // Don't use the l() function at this early stage of bootstrapping because it will initialize the theme engine. Use url() instead.
          $links[] = '<a href="' . url('admin/config/user-interface/themekey', array('fragment' => 'themekey_new_rule', 'query' => array('property' => $property, 'value' => $single_value))) . '">' . $single_value . '</a>';
        }

        $value = implode('<br />', $links);
      }
      $message .= '<li>' . $property . '<br />' . $value . '</li><br />';
    }
    $message .= '</ul>';
    themekey_set_debug_message($message, array(), FALSE);
  }
}


/**
 * Implements hook_menu().
 */
function themekey_debug_menu() {
  $items = array();
  $items['admin/config/user-interface/themekey/settings/debug'] = array(
    'title' => 'Debug',
    'access callback' => 'user_access',
    'access arguments' => array('administer themekey settings'),
    'file' => 'themekey_debug_admin.inc',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('themekey_debug_settings_form'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 10,
  );

  return $items;
}


/**
 * Implements hook_theme().
 */
function themekey_debug_theme() {
  $items = array(
    'themekey_debug_messages' => array(
      'template' => 'themekey-debug-messages',
      'variables' => array('messages' => array()),
    ),
  );
  return $items;
}


/**
 * Implements hook_init().
 *
 * Detects if hook_custom_theme() has been skipped because
 * a different module already initialized the theme engine.
 */
function themekey_debug_init() {
  if (variable_get('themekey_debug_trace_rule_switching', FALSE)) {
    if (!in_array('system', variable_get('themekey_compat_modules_enabled', array())) && path_is_admin($_GET['q']) && variable_get('admin_theme', '0')) {
      themekey_set_debug_message('"%admin_theme" is configured as administration theme at !link. This setting is more powerful than a corresponding ThemeKey rule.',
        array('%admin_theme' => variable_get('admin_theme', '0'), '!link' => l(t('!path', array('!path' => 'admin/appearance')), 'admin/appearance')), TRUE, TRUE);
    }

    $custom_theme_called = &drupal_static('themekey_custom_theme_called', FALSE);

    if (!$custom_theme_called) {
      themekey_set_debug_message("Consider to activate the module ThemeKey Compatibility to integrate a different theme switching module into ThemeKey's theme switching rule chain",
        array(), TRUE, TRUE);
      themekey_set_debug_message('Skipped rule checking because another module already initialized the theme engine.',
        array(), TRUE, TRUE);
    }
    else {
      global $theme;
      $themekey_custom_theme = &drupal_static('themekey_custom_theme', '');
      if (!empty($themekey_custom_theme) && 'default' != $themekey_custom_theme) {
        if ($theme != $themekey_custom_theme) {
          themekey_set_debug_message('Theme switching to custom theme "%custom_theme" did not work because theme has been set to "%theme" by another module.', array('%custom_theme' => $themekey_custom_theme, '%theme' => $theme), TRUE, TRUE);
        }
      }
      else {
        if (variable_get('theme_default', 'bartik') != $theme) {
          themekey_set_debug_message('ThemeKey did not switch the theme because no rule matched. But something else set the theme to "%theme".', array('%theme' => $theme), TRUE, TRUE);
        }
      }
    }
  }
}


/**
 * Implements hook_form_node_form_alter().
 *
 * Detects if custom theme has been skipped because
 * the adminstration theme is used for node editing.
 */
function themekey_debug_form_node_form_alter() {
  if (variable_get('themekey_debug_trace_rule_switching', FALSE)) {
    if (variable_get('node_admin_theme', '0')) {
      themekey_set_debug_message('As configured at !link adding or editing a node will use the administration theme %admin_theme.',
        array('%admin_theme' => variable_get('admin_theme', '0'), '!link' => l(t('!path', array('!path' => 'admin/appearance')), 'admin/appearance')), TRUE, TRUE);
    }
  }
}


/**
 * Implements hook_page_alter().
 *
 * Prints out debug messages at the end of the page.
 *
 * @return string
 */
function themekey_debug_page_alter(&$page) {
  if (variable_get('themekey_debug_show_property_values', FALSE)) {
    // add the properties to the end of debug messages
    themekey_debug_properties();
  }

  if ($messages = themekey_set_debug_message('flush')) {
    $page['page_bottom']['themekey']= array(
      '#type' => 'markup',
      '#markup' => $messages,
    );

    // Avoid caching of pages containing debug info in internal page cache
    drupal_page_is_cacheable(FALSE);
    // ... and external caches like varnish, boost, ...
    drupal_add_http_header('Status', '503 Service unavailable');
  }
}


/**
 * Replacement for drupal_set_message() during ThemeKey's initialization.
 * drupal_set_message() might inititialize the theme engine too early,
 * which causes ThemeKey to not switch the theme.
 *
 * themekey_debug_set_debug_message() put the untranslated messages on a
 * stack and hand them over to drupal_set_message() on demand.
 *
 * @param $msg
 *   the message as string. If the message is 'flush'
 *   all messages stored on the stack will be printed using
 *   drupal_set_message()
 *
 * @param $placeholder
 *   associative array of string replacments for $msg
 *   @see t()
 *
 * @param $translate
 *   boolean, if set to TRUE $msg will be handled by t()
 *   when handed over to drupal_set_message()
 */
function themekey_debug_set_debug_message($msg, $placeholder = array(), $translate = TRUE, $unshift = FALSE) {
  static $msg_stack = array();
  global $user, $theme;

  if (1 == $user->uid || user_access('themekey_debug_see_messages', $user) || variable_get('themekey_debug_non_admin_users', FALSE)) {
    if ('flush' == $msg) {
      $messages = array();
      if (variable_get('themekey_debug_trace_rule_switching', FALSE)) {
        $messages[] = t('Current theme: %theme', array('%theme' => $theme));
      }
      foreach ($msg_stack as $key => $msg) {
        $messages[] = filter_xss($msg['translate'] ? t($msg['msg'], $msg['placeholder']) : $msg['msg'], array('a', 'b', 'br', 'li', 'ul'));
        unset($msg_stack[$key]);
      }

      if (!empty($messages)) {
        return theme('themekey_debug_messages', array('messages' => $messages));
      }
    }
    else {
      $tmp = array(
        'msg' => $msg,
        'placeholder' => $placeholder,
        'translate' => $translate,
      );

      if ($unshift) {
        $tmp['msg'] = '<b>' . $tmp['msg'] . '</b>';
        array_unshift($msg_stack, $tmp);
      }
      else {
        $msg_stack[] = $tmp;
      }
    }
  }
}
