<?php

/**
 * @file
 * Hooks and functions for the 'conventional' (version D5/D6/D7.1) Workflow Node, remnants of nodeapi.
 */

// Includes the hooks for the 'conventional' (version D5/D6/D7.1) Node API.
module_load_include('inc', 'workflow', 'workflow.node.type_map');
module_load_include('inc', 'workflow', 'workflow.deprecated');

/**
 * Implements hook_ctools_plugin_directory().
 *
 * This lets ctools know to scan my module for a content_type plugin file
 * Detailed docks in ctools/ctools.api.php
 *
 * This is used to integrate WorkflowNode with Panels. See d.o. #1511694, #2187731
 */
function workflownode_ctools_plugin_directory($owner, $plugin_type) {
  if ($owner == 'ctools' && !empty($plugin_type)) {
    return "plugins/$plugin_type";
  }
}

/**
 * Theme the current workflow state as top line of History tab.
 */
function theme_workflow_current_state($variables) {
  $state = $variables['state'];
  return '<div class="workflow-current-state '
    . 'workflow-current-sid-' . intval($variables['sid']) . ' '
    . drupal_html_class($state)
    . '">'
    . t('Current state: <span class="state">@state</span>', array('@state' => $state))
    . '</div>';
}

/**
 * Implements hook_node_load().
 */
function workflow_node_load($nodes, $types) {
  // Get which types have workflows associated with them.
  $workflow_types = workflow_get_workflow_type_map();

  // Leave early if nodes do not have workflow.
  if (!$workflow_types || !array_intersect_key($workflow_types, array_flip($types))) {
    return;
  }

  // Read the current state for all nodes.
  $states = workflow_get_workflow_node_by_nid(array_keys($nodes));

  foreach ($nodes as $nid => $node) {
    // If it's not a workflow type, quit immediately.
    if (!array_key_exists($node->type, $workflow_types)) {
      continue;
    }
    // Nodes that existed before the workflow was defined may not have a state.
    $workflow_node = isset($states[$nid]) ? $states[$nid] : NULL;
    if (!$workflow_node) {
      if ($workflow = workflow_get_workflows_by_type($node->type, 'node')) {
        $node->workflow = $workflow->getCreationSid();
        $node->workflow_stamp = $node->created;
      }
      else {
        // Is this possible?
      }
    }
    else {
      $node->workflow = $workflow_node->sid;
      $node->workflow_stamp = $workflow_node->stamp;
    }
  }

  // As of workflow 7.x-2.x, the scheduled transition is not loaded. See issue #2138591.
}

/**
 * Implements hook_node_view().
 */
function workflow_node_view($node, $view_mode, $langcode) {
  global $user;

  $entity_type = 'node'; // This hook is only for nodes.
  $field_name = ''; // This hook is only for workflow_node.
  $entity_bundle = $node->type;

  // Skip if there are no Node API workflows.
  if (!workflow_get_workflow_type_map_by_type($entity_bundle)) {
    return;
  }
  // Check permission, so that even with state change rights,
  // the form can be suppressed from the node view (#1893724).
  if (!user_access('show workflow state form', $user)) {
    return;
  }

  $field_name = ''; // An explicit var is needed.
  $current_sid = workflow_node_current_state($node, $entity_type, $field_name);
  $current_state = workflow_state_load_single($current_sid);

  // Show current state at the top of the node display.
  $field = $instance = array();
  $node->content['workflow_current_state'] = workflow_state_formatter($entity_type, $node, $field, $instance, $current_sid);
  $node->content['workflow_current_state']['#weight'] = -99;

  if ($current_state && $current_state->showWidget('node', $node, '', $user, FALSE)) {
    $form = array();
    $workflow = $current_state->getWorkflow();

    // Show the current state and the Workflow form to allow state changing.
    // N.B. This part is replicated in hook_node_view, workflow_tab_page, workflow_vbo.
    if ($workflow) {
      $field = _workflow_info_field($field_name, $workflow);
      // $field = reset(_workflow_info_fields($entity, $entity_type));
      // $field_name = $field['field_name'];
      $field_id = $field['id'];
      $instance = field_info_instance($entity_type, $field_name, $entity_bundle);
      // If no instance is found, restore the array.
      if (!is_array($instance)) {
        $instance = array();
      }

      if (!$field['id']) {
        // This is a Workflow Node workflow. Set widget options as in v7.x-1.2
        $field['settings']['widget']['comment'] = isset($workflow->options['comment_log_node']) ? $workflow->options['comment_log_node'] : 1; // vs. ['comment_log_tab'];
        $field['settings']['widget']['current_status'] = FALSE;
      }
    }

    // By including the nid in the form id.
    $form = drupal_get_form('workflow_transition_form_' . $node->nid, $field, $instance, $entity_type, $node);
    $form['#weight'] = 99;

    $node->content['workflow'] = $form;
  }
}

/**
 * Implements hook_node_insert().
 *
 * This is executed after saving data to the database.
 * We cannot use hook_node_presave, because workflow_execute_transition() needs the nid.
 */
function workflow_node_insert($node) {
  global $user;
  if (!isset($node->workflow_field)) {
    // Initializing the state of the node in case no widget on Node form.
    if ($workflow = workflow_get_workflows_by_type($node->type, 'node')) {
      $comment = t('Set to initial state.');
      $force = TRUE;
      $creation_sid = $workflow->getCreationSid();

      // Get the initial state for this node.
      // Due to permissions, it might be different for each user.
      $new_sid = $workflow->getFirstSid('node', $node, null, $user, $force);

      $transition = new WorkflowTransition();
      $transition->setValues('node', $node, null, $creation_sid, $new_sid, $user->uid, REQUEST_TIME, $comment);

      // Force it to transition to the first state and get a history record.
      workflow_execute_transition('node', $node, null, $transition, $force);
    }
  }
  return workflow_node_update($node);
}

/**
 * Implements hook_node_update().
 */
function workflow_node_update($node) {
  if (!isset($node->workflow_field)) {
    // For this type_map, user did not want a form here.
    return;
  }

  $form = array();

  // Retrieve the data from the form.
  // Add form values (field, instance, entity_type, entity), then form input.
  $form_state = array();
  $form_state['values']['workflow_field'] = $node->workflow_field;
  $form_state['values']['workflow_instance'] = $node->workflow_instance;
  $form_state['values']['workflow_entity_type'] = 'node';
  // Careful: take the fresh node here, not the one that is in the form.
  $form_state['values']['workflow_entity'] = $node;
  // For some reason, the Workflow Form does not return the form in a 'workflow' array.
  // @todo: correct this (use '#tree => TRUE'), or filter on 'workflow' elements.
  $form_state['input'] = (array) $node;

  workflow_transition_form_submit($form, $form_state);
}

/**
 * Implements hook_node_delete().
 */
function workflow_node_delete($node) {
  if (!empty($node->workflow)) {
    // Call field_info_field().
    // Generates pseudo data for workflow_node to re-use Field API.
    $field = _workflow_info_field($field_name = '', $workflow = NULL);
    $instance = array();
    $items[0]['value'] = $node->workflow;

    $workflow_field = new WorkflowItem($field, $instance, 'node', $node);
    $workflow_field->delete($items);
  }
}

/**
 * Implements hook_comment_insert().
 */
function workflow_comment_insert($comment) {
  workflow_comment_update($comment);
}

/**
 * Implements hook_comment_update().
 */
function workflow_comment_update($comment) {
  // Retrieve the data from the form.
  if (!isset($comment->workflow_field)) {
    // For this type_map, user did not want a form here.
    return;
  }

  $form = array();

  // Retrieve the data from the form.
  // Add form values (field, instance, entity_type, entity), then form input.
  $form_state = array();
  $form_state['values']['workflow_field'] = $comment->workflow_field;
  $form_state['values']['workflow_instance'] = $comment->workflow_instance;
  $form_state['values']['workflow_entity_type'] = $comment->workflow_entity_type;
  $form_state['values']['workflow_entity'] = $comment->workflow_entity;
  // For some reason, the Workflow Form does not return the form in a 'workflow' array.
  // @todo: correct this, or filter on 'workflow' elements.
  $form_state['input'] = (array) $comment;

  workflow_transition_form_submit($form, $form_state);
}

/**
 * Implements hook_field_extra_fields().
 */
function workflow_field_extra_fields() {
  $extra = array();

  // Get all workflows by content types.
  $types = array_filter(workflow_get_workflow_type_map());

  // Add the extra fields to each content type that has a workflow.
  foreach ($types as $type => $wid) {
    $extra['node'][$type] = array(
      'form' => array(
        'workflow' => array(
          'label' => t('Workflow'),
          'description' => t('Workflow module form'),
          'weight' => 99,    // Default to bottom.
        ),
      ),
      'display' => array(
        'workflow_current_state' => array(
          'label' => t('Workflow: Current State'),
          'description' => t('Current workflow state'),
          'weight' => -99,   // Default to top.
        ),
        'workflow' => array(
          'label' => t('Workflow: State Change Form'),
          'description' => t('The form for controlling workflow state changes.'),
          'weight' => 99,    // Default to bottom.
        ),
      ),
    );
  }

  return $extra;
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 *
 * Shows the form only on Node Edit forms.
 */
function workflow_form_node_form_alter(&$form, &$form_state, $form_id) {
  _workflow_form_alter($form, $form_state, $form_id);
}

/**
 * Implements hook_form_BASE_FORM_ID_alter().
 *
 * Shows the form only on Comment forms.
 */
function workflow_form_comment_form_alter(&$form, &$form_state, $form_id) {
  _workflow_form_alter($form, $form_state, $form_id);
}

/**
 * Helper function to implement hook_form_alter().
 *
 * Is now a subfunction of workflow_form_BASE_FORM_ID_alter().
 * This is more performant (copared to 7.x-1.2 and before), since it is called
 * only on form with correct BASE_FORM_ID.
 *
 * @see http://bryanbraun.com/2013/08/17/using-hook-form-base-form-id-alter
 */
function _workflow_form_alter(&$form, &$form_state, $form_id) {
  // Set node to #node if available or load from nid value.
  $node = isset($form['#node']) ? $form['#node'] : node_load($form['nid']['#value']);
  $bundle = $node->type;
  $entity = $node;
  $entity_type = 'node';
  $field_name = '';

  // Skip if there are no Node API workflows.
  if (!workflow_get_workflow_type_map_by_type($bundle)) {
    return;
  }
  if ($workflow = workflow_get_workflows_by_type($bundle, 'node')) {
    $workflow_entities = variable_get('workflow_' . $bundle, array());
    // Abort if the entity type of the form is not in the list that the user
    // wants to display the workflow form on.
    if (!in_array($form['#entity_type'], $workflow_entities)) {
      return;
    }
/*
      $form['#wf'] = $workflow;
      $form['workflow'] = array(
        '#type' => 'fieldset',
        '#title' => check_plain($label),
        '#collapsible' => TRUE,
        '#collapsed' => FALSE,
        '#weight' => 10,
      );
 */

    // Emulate a Field API interface.
    // Show the current state and the Workflow form to allow state changing.
    // N.B. This part is replicated in hook_node_view and workflow_tab_page.
    if ($workflow) {
      $field = _workflow_info_field($field_name, $workflow);
      // $field = reset(_workflow_info_fields($entity, $entity_type));
      $field_name = $field['field_name'];
      $field_id = $field['id'];
      $instance = field_info_instance($entity_type, $field_name, $bundle);

      if (!$field['id']) {
        // This is a Workflow Node workflow. Set widget options as in v7.x-1.2
        $field['settings']['widget']['comment'] = isset($workflow->options['comment_log_node']) ? $workflow->options['comment_log_node'] : 1; // vs. ['comment_log_tab'];
        $field['settings']['widget']['current_status'] = TRUE;
      }
    }

    // Do not include the default 'Update Workflow' button, since we are already in an Edit form.
    $instance['widget']['settings']['submit_function'] = '';

    // Include the 'workflow form'. $form is modified by reference.
    $form = workflow_transition_form($form, $form_state, $field, $instance, $entity_type, $entity);
  }
}
