<?php

/**
 * @file
 * Profile hooks and logic.
 */

/**
 * Implements hook_exit().
 */
function archibald_kickstart_exit() {
  if (
    !variable_get('archibald_kickstart_installed_roles', FALSE) &&
    node_type_load('archibald_lomch_description')
  ) {
    module_load_install('archibald_kickstart');
    _archibald_kickstart_install_user_roles();
    variable_set('archibald_kickstart_installed_roles', TRUE);
  }
}

/**
 * Implements hook_profile_details().
 */
function archibald_kickstart_profile_details() {
  return array(
    // Skip the locale step, but implement our own later on. We achieve this by
    // telling Drupal our profile is always installed in English.
    'language' => 'en',
  );
}

/**
 * Implements hook_block_view_alter().
 */
function archibald_kickstart_block_view_alter(&$data, $block) {
  if ($block->module == 'lang_dropdown' && $block->delta == 'language_content') {
    // Give a better block title. We set it in code so we can use the interface
    // translations.
    $data['subject'] = t("Content language");
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for install_configure_form().
 */
function archibald_kickstart_form_install_configure_form_alter(&$form, $form_state) {
  // Hide some messages from various modules that are too chatty.
  drupal_get_messages('status');
  drupal_get_messages('warning');

  // Warn about the Transliterator library, if necessary. If this installation
  // profile was downloaded from drupal.org, Transliterator is not included.
  // This is because it is not GPL-compatible, hence drupal.org cannot host it.
  // However, if this was built locally using Drush and the build-local.make
  // file, the library will be included.
  if (function_exists('libraries_load')) {
    $library_info = libraries_load('Transliterator');
    if (!$library_info['installed']) {
      drupal_set_message(st("Please note that in order to use Archibald you will have to perform one final step manually, which is to download the <a href='!link'>Transliterator</a> library. The reason this library is not included with Archibald Kickstart is that it is not GPL-compatible. It is still free, and you can download it for no extra cost. At the end of the installation, please go to your site's status report page for more information, or read the README.txt file that ships with the Archibald module.", array(
        '!link' => 'https://github.com/Behat/Transliterator',
      )), 'warning');
    }
  }

  // Pre-populate the site name.
  $form['site_information']['site_name']['#default_value'] = st("Archibald Kickstart");

  // Use "admin" as the default username.
  $form['admin_account']['account']['name']['#default_value'] = 'admin';

  // Hide Update Notifications.
  $form['update_notifications']['#access'] = FALSE;
  $form['update_notifications']['#default_value'] = FALSE;

  // Define a default email address if we can guess a valid one.
  $email = 'admin@' . $_SERVER['HTTP_HOST'];
  if (valid_email_address($email)) {
    $form['site_information']['site_mail']['#default_value'] = $email;
    $form['admin_account']['account']['mail']['#default_value'] = $email;
  }
}

/**
 * Implements hook_install_tasks().
 */
function archibald_kickstart_install_tasks(&$install_state) {
  // If this profile is installed via automated systems (like Drush), we skip
  // all install tasks. They would only break the process.
  if (empty($install_state['interactive'])) {
    return;
  }

  $tasks['archibald_kickstart_setup_languages'] = array(
    'display_name' => st("Setup languages"),
    'type' => 'form',
  );
  if (!empty($install_state['parameters']['archibald_kickstart_setup_languages_finished'])) {
    $tasks['archibald_kickstart_setup_languages']['run'] = INSTALL_TASK_SKIP;
  }

  $tasks['archibald_kickstart_import_translations'] = array(
    'display_name' => st("Import translations"),
    'type' => 'batch',
  );
  if (!empty($install_state['parameters']['archibald_kickstart_import_translations_finished'])) {
    $tasks['archibald_kickstart_import_translations']['run'] = INSTALL_TASK_SKIP;
  }

  $tasks['archibald_kickstart_setup_private_fs'] = array(
    'display_name' => st("Setup a private file system"),
    'type' => 'form',
  );
  if (!empty($install_state['parameters']['archibald_kickstart_setup_private_fs_finished'])) {
    $tasks['archibald_kickstart_setup_private_fs']['run'] = INSTALL_TASK_SKIP;
  }

  $tasks['archibald_kickstart_setup_partner'] = array(
    'display_name' => st("Setup a partner"),
    'type' => 'form',
  );
  if (!empty($install_state['parameters']['archibald_kickstart_setup_partner_finished'])) {
    $tasks['archibald_kickstart_setup_partner']['run'] = INSTALL_TASK_SKIP;
  }

  $tasks['archibald_kickstart_setup_curricula_modules'] = array(
    'display_name' => st("Choose curricula modules"),
    'type' => 'form',
  );
  if (!empty($install_state['parameters']['archibald_kickstart_setup_curricula_modules_finished'])) {
    $tasks['archibald_kickstart_setup_curricula_modules']['run'] = INSTALL_TASK_SKIP;
  }

  $tasks['archibald_kickstart_import_curricula_data'] = array(
    'display_name' => st("Import curricula data"),
    'type' => 'batch',
  );
  if (
    !empty($install_state['parameters']['archibald_kickstart_import_curricula_data_finished']) &&
    !empty($install_state['parameters']['archibald_kickstart_setup_curricula_modules_finished']) &&
    !variable_get('archibald_kickstart_curricula_modules', FALSE)) {
    $tasks['archibald_kickstart_import_curricula_data']['run'] = INSTALL_TASK_SKIP;
  }

  $tasks['archibald_kickstart_import_vocabulary_data'] = array(
    'display_name' => st("Import languages and terms of use"),
    'type' => 'batch',
  );
  if (!empty($install_state['parameters']['archibald_kickstart_import_vocabulary_data_finished'])) {
    $tasks['archibald_kickstart_import_vocabulary_data']['run'] = INSTALL_TASK_SKIP;
  }

  return $tasks;
}

/**
 * Install task: setup languages.
 */
function archibald_kickstart_setup_languages($form, &$form_state, &$install_state) {
  $t = get_t();

  $form['languages'] = array(
    '#type' => 'checkboxes',
    '#title' => $t("Activate languages"),
    '#options' => array(
      'de' => $t("German"),
      'fr' => $t("French"),
      'it' => $t("Italian"),
      'rm' => $t("Rhaeto-Romance"),
    ),
    '#default_value' => array_keys(language_list()),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => $t("Save and continue"),
  );

  return $form;
}

/**
 * Submission callback for archibald_kickstart_setup_languages().
 */
function archibald_kickstart_setup_languages_submit($form, &$form_state) {
  $t = get_t();
  $install_state = &$form_state['build_info']['args']['install_state'];

  array_map(function($langcode) {
    locale_add_language($langcode);
  }, array_filter($form_state['values']['languages']));

  $install_state['parameters']['archibald_kickstart_setup_languages_finished'] = TRUE;

  if (variable_get('language_count', 1) == 1) {
    // No languages were added. Skip the import.
    $install_state['parameters']['archibald_kickstart_import_translations_finished'] = TRUE;
  }
}

/**
 * Install task: import translations.
 */
function archibald_kickstart_import_translations($form, &$form_state, &$install_state) {
  $t = get_t();
  $install_state['parameters']['archibald_kickstart_import_translations_finished'] = TRUE;

  module_load_include('fetch.inc', 'l10n_update');
  $options = _l10n_update_default_update_options();
  $langcodes = language_list();
  unset($langcodes['en']);
  $batch = l10n_update_batch_update_build(array(), array_keys($langcodes), $options);
  $batch['operations'][] = array(
    'archibald_kickstart_refresh_strings_and_import',
    array(array('default', 'field', 'taxonomy')),
  );
  return $batch;
}

/**
 * Install task: setup a private file system.
 */
function archibald_kickstart_setup_private_fs($form, &$form_state, &$install_state) {
  // Previous step is too chatty.
  drupal_get_messages('status');

  $t = get_t();

  // Re-use what the System module provides.
  module_load_include('inc', 'system', 'system.admin');
  $system_form = system_file_system_settings();
  $form['file_private_path'] = $system_form['file_private_path'];
  $form['file_private_path']['#required'] = TRUE;
  $form['file_private_path']['#description'] .= ' ' . $t("A private file system is necessary to securely store partner data, like the private key and the encryption key to encrypt passphrases.");

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => $t("Save and continue"),
  );

  return $form;
}

/**
 * Submission callback for archibald_kickstart_setup_private_fs().
 */
function archibald_kickstart_setup_private_fs_submit($form, &$form_state) {
  $t = get_t();
  $install_state = &$form_state['build_info']['args']['install_state'];

  // Store the private file path.
  variable_set('file_private_path', $form_state['values']['file_private_path']);

  // In order to use the private:// wrapper in the next steps, we need to clear
  // the file wrapper cache, and reload.
  drupal_static_reset('file_get_stream_wrappers');
  file_get_stream_wrappers();

  // Now that we have it, we can generate an encryption key.
  module_load_install('archibald');
  if (!archibald_install_generate_encryption_key()) {
    drupal_set_message($t("Could not generate an encryption key. This is required to create a content partner. Once the installation is finished, please go to the site status report for more information."), 'error');

    $install_state['parameters']['archibald_kickstart_setup_partner_finished'] = TRUE;
  }
  else {
    drupal_set_message($t("Successfully generated an encryption key for encrypting partner authentication data."), 'status');
  }

  $install_state['parameters']['archibald_kickstart_setup_private_fs_finished'] = TRUE;
}

/**
 * Install task: setup a default partner.
 */
function archibald_kickstart_setup_partner($form, &$form_state, &$install_state) {
  $t = get_t();

  // Add a field to choose the API, defaulting to the one chosen by Archibald.
  $form['archibald_api_url'] = array(
    '#type' => 'textfield',
    '#title' => $t("API URL"),
    '#required' => TRUE,
    '#default_value' => variable_get('archibald_api_url', ''),
  );

  // We cannot re-use what Archibald provides; build our own, but keep it
  // simple.
  $form['display_name'] = array(
    '#type' => 'textfield',
    '#title' => $t("Display name"),
    '#required' => TRUE,
  );

  $form['username'] = array(
    '#type' => 'textfield',
    '#title' => $t("Username"),
    '#required' => TRUE,
  );

  $form['private_key'] = array(
    '#type' => 'file',
    '#title' => $t("Private key"),
  );

  $form['passphrase'] = array(
    '#type' => 'password',
    '#title' => $t("Passphrase"),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => $t("Save and continue"),
  );

  return $form;
}

/**
 * Validation callback for archibald_kickstart_setup_partner().
 */
function archibald_kickstart_setup_partner_validate($form, &$form_state) {
  $t = get_t();

  if (!$file = file_save_upload('private_key', array(
    'file_validate_extensions' => 'txt pem key',
  ), 'private://')) {
    form_set_error('file', $t("You must provide a private key."));
  }
  $form_state['values']['uploaded_file'] = $file;

  // Set the URL here, as we are about to use it. We will not set it in the
  // submission callback.
  variable_set('archibald_api_url', $form_state['values']['archibald_api_url']);

  // Check if the partner can authenticate with these values.
  try {
    $client = archibald_get_client(
      variable_get('archibald_api_version', NULL),
      variable_get('archibald_api_url', NULL),
      $form_state['values']['username'],
      $file->fid,
      $form_state['values']['passphrase']
    );

    $client->authenticate();
  }
  catch (Exception $e) {
    form_set_error('username', t("The connection failed. Please check your partner credentials. Error message: @message", array(
      '@message' => $e->getMessage(),
    )));
  }
}

/**
 * Submission callback for archibald_kickstart_setup_partner().
 */
function archibald_kickstart_setup_partner_submit($form, &$form_state) {
  $t = get_t();
  $install_state = &$form_state['build_info']['args']['install_state'];

  // We do not set the 'archibald_api_url' variable here; we already set it in
  // the validation callback. See archibald_kickstart_setup_partner_validate().

  // Save the partner by using Archibald's partner form submission. We need to
  // adapt the form state a bit.
  module_load_include('inc', 'entity', 'includes/entity.ui');
  $partner = new ArchibaldPartnerEntity(array(), 'archibald_partner');
  $partner->is_new = TRUE;
  $partner_form = drupal_get_form('archibald_partner_form');
  $partner_form['#entity'] = $partner;
  $partner_form_state = array(
    'entity_type' => 'archibald_partner',
    'archibald_partner' => $partner,
    'values' => array(
      'is_default' => 1,
      'update_remotely' => FALSE,
      'passphrase' => $form_state['values']['passphrase'],
      'partner_display_name' => array(LANGUAGE_NONE => array(
        array('value' => $form_state['values']['display_name']),
      )),
      'partner_username' => array(LANGUAGE_NONE => array(
        array('value' => $form_state['values']['username']),
      )),
      'partner_privatekey' => array(LANGUAGE_NONE => array(
        array(
          'fid' => $form_state['values']['uploaded_file']->fid,
          'display' => 0,
        ),
      )),
    ),
  );
  archibald_partner_form_submit($partner_form, $partner_form_state);
  drupal_get_messages('status');

  $install_state['parameters']['archibald_kickstart_setup_partner_finished'] = TRUE;
}

/**
 * Install task: setup curricula modules.
 */
function archibald_kickstart_setup_curricula_modules($form, &$form_state, &$install_state) {
  $t = get_t();

  $form['curricula'] = array(
    '#type' => 'checkboxes',
    '#title' => $t("Choose curricula modules"),
    '#description' => $t("You can choose curricula modules to enable by default. You can always change this later."),
    '#options' => array(
      'archibald_stdlehr' => $t("Classification System"),
      'archibald_per' => $t("Plan d'études romand"),
      'archibald_lp21' => $t("Lehrplan 21"),
    ),
    '#default_value' => array('archibald_stdlehr'),
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => $t("Save and continue"),
  );

  return $form;
}

/**
 * Submission callback for archibald_kickstart_setup_curricula_modules().
 */
function archibald_kickstart_setup_curricula_modules_submit($form, &$form_state) {
  $t = get_t();
  $install_state = &$form_state['build_info']['args']['install_state'];

  $modules = array_keys(array_filter($form_state['values']['curricula']));
  if (!empty($modules)) {
    module_enable($modules, TRUE);

    // Remove the messages saying manual steps are required to import the data.
    drupal_get_messages('status');

    // Store the modules temporarily.
    variable_set('archibald_kickstart_curricula_modules', $modules);
  }
  else {
    // SKip data import.
    $install_state['parameters']['archibald_kickstart_import_curricula_data_finished'] = TRUE;
  }

  $install_state['parameters']['archibald_kickstart_setup_curricula_modules_finished'] = TRUE;
}

/**
 * Install task: import curricula modules' data.
 */
function archibald_kickstart_import_curricula_data($form, &$form_state, &$install_state) {
  $t = get_t();

  $install_state['parameters']['archibald_kickstart_import_curricula_data_finished'] = TRUE;

  if ($modules = variable_get('archibald_kickstart_curricula_modules', FALSE)) {
    // Make sure we remove the variable; we don't need it anymore.
    variable_del('archibald_kickstart_curricula_modules');
    $batch = array(
      'operations' => array(),
      'finished' => 'archibald_kickstart_import_curricula_data_batch_finished',
    );

    if (in_array('archibald_per', $modules)) {
      $batch['operations'] = array_merge($batch['operations'], array(
        array('archibald_per_batch_load_data_step1', array()),
        array('archibald_per_batch_load_data_step2', array()),
        array('archibald_per_batch_load_data_step3', array()),
        array('archibald_per_batch_load_data_step4', array()),
      ));
    }

    foreach ($modules as $module) {
      if ($module != 'archibald_per') {
        $batch['operations'][] = array(
          'archibald_kickstart_import_curricula_data_batch_op',
          array($module),
        );
      }
    }

    return $batch;
  }
}

/**
 * Batch operation: load curriculum data.
 */
function archibald_kickstart_import_curricula_data_batch_op($module, &$context) {
  $t = get_t();

  switch ($module) {
    case 'archibald_lp21':
      archibald_lp21_load_data(TRUE);
      $context['message'] = $t("Downloading %curricula data", array(
        '%curricula' => $t("Lehrplan 21"),
      ));
      break;

    case 'archibald_stdlehr':
      archibald_stdlehr_load_data(TRUE);
      $context['message'] = $t("Downloading %curricula data", array(
        '%curricula' => $t("Classification System"),
      ));
      break;
  }

  $context['finished'] = 1;
}

/**
 * Batch finish callback.
 */
function archibald_kickstart_import_curricula_data_batch_finished() {
  // Remove success messages.
  drupal_get_messages('status');
}

/**
 * Install task: import vocabularies.
 */
function archibald_kickstart_import_vocabulary_data($form, &$form_state, &$install_state) {
  $t = get_t();
  $install_state['parameters']['archibald_kickstart_import_vocabulary_data_finished'] = TRUE;

  $path = drupal_get_path('module', 'archibald');
  return array(
    'operations' => array(
      array('archibald_batch_import_vocabularies', array('languages')),
      array('archibald_batch_import_vocabularies', array('licenses')),
    ),
    'file' => "$path/includes/archibald.admin.inc",
  );
}

/**
 * Implements hook_update_status_alter().
 *
 * Disable reporting of projects that are in the distribution, but only
 * if they have not been updated manually.
 */
function archibald_kickstart_update_status_alter(&$projects) {
  $bad_statuses = array(
    UPDATE_NOT_SECURE,
    UPDATE_REVOKED,
    UPDATE_NOT_SUPPORTED,
  );

  $make_filepath = drupal_get_path('profile', 'archibald_kickstart') . '/drupal-org.make';
  if (!file_exists($make_filepath)) {
    return;
  }

  $make_info = drupal_parse_info_file($make_filepath);
  foreach ($projects as $project_name => $project_info) {
    // Never unset the drupal project to avoid hitting an error with
    // _update_requirement_check(). See http://drupal.org/node/1875386.

    // Never unset the archibald_kickstart project. We want them to update.
    if ($project_name == 'archibald_kickstart') {
      continue;
    }

    // Hide bad releases (insecure, revoked, unsupported).
    if (
      isset($project_info['status']) &&
      in_array($project_info['status'], $bad_statuses)
    ) {
      unset($projects[$project_name]);
    }
    // Hide projects shipped with Archibald Kickstart if they haven't been
    // manually updated.
    elseif (isset($make_info['projects'][$project_name]['version'])) {
      $version = $make_info['projects'][$project_name]['version'];
      if (strpos($version, 'dev') !== FALSE || (DRUPAL_CORE_COMPATIBILITY . '-' . $version == $project_info['info']['version'])) {
        unset($projects[$project_name]);
      }
    }
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for update_manager_update_form.
 */
function archibald_kickstart_form_update_manager_update_form_alter(&$form, &$form_state, $form_id) {
  if (
    isset($form['projects']['#options']) &&
    isset($form['projects']['#options']['archibald_kickstart'])
  ) {
    if (count($form['projects']['#options']) > 1) {
      unset($form['projects']['#options']['archibald_kickstart']);
    }
    else {
      unset($form['projects']);

      // Hide Download button if there's no other (disabled) projects to update.
      if (!isset($form['disabled_projects'])) {
        $form['actions']['#access'] = FALSE;
      }

      $form['message']['#markup'] = t("All of your projects are up to date.");
    }
  }
}

/**
 * Refresh and import translations.
 *
 * Refreshes the translation strings and imports the translations
 * that ship with Archibald. This is necessary, especially for fields, as Drupal
 * does not refresh translation groups.
 *
 * @param array $groups
 *     The groups we want to refresh.
 */
function archibald_kickstart_refresh_strings_and_import($groups) {
  module_load_include('inc', 'i18n_string', 'i18n_string.admin');
  $archibald_path = drupal_get_path('module', 'archibald');

  foreach (array_keys(language_list()) as $langcode) {
    foreach ($groups as $group) {
      // Start by refreshing string data.
      $context = NULL;
      _i18n_string_batch_refresh_prepare($group, $context);
      _i18n_string_batch_refresh_list($group, $context);
      _i18n_string_batch_refresh_callback($group, $context);

      // Reset the source paths.
      $sources = array();

      // Drupal core translations ship with our profile; other translations
      // ship with Archibald.
      if ($group == 'default') {
        $sources = array(
          "profiles/opigno_lms/translations/{$langcode}.po",
          "{$archibald_path}/translations/archibald.{$langcode}.po",
        );
      }
      else {
        $sources = array("{$archibald_path}/translations/{$group}.{$langcode}.po");
      }

      foreach ($sources as $source) {
        if (file_exists($source)) {
          // Copy the file, overwriting old ones.
          $path = file_unmanaged_copy($source, NULL, FILE_EXISTS_REPLACE);

          // Load it. If it didn't exist yet, create it.
          $files = file_load_multiple(array(), array('uri' => $path));
          $file = reset($files);
          if (empty($file)) {
            $file = (object) array(
              // Keep it as a temporary file, so Drupal can GC it.
              'status' => 0,
              'uri' => $path,
              'filename' => @end(explode('/', $source)),
            );
            $file = file_save($file);
          }

          // Import the PO file, overwriting existing translations.
          _locale_import_po($file, $langcode, LOCALE_IMPORT_OVERWRITE, $group);
        }
      }
    }
  }
}
