<?php

require_once "includes/tripal_ds.inc";
require_once "includes/tripal_ds.ds.inc";
require_once "includes/tripal_ds.field_group.inc";
require_once "includes/tripal_ds.field_formatter.inc";
require_once "includes/tripal_ds.field_formatter.inc";

// Import the full Tripal_DS API into scope.
tripal_ds_import_api();

/**
 * Implements hook_init().
 *
 * Injects required javascript and css.
 */
function tripal_ds_init() {
  drupal_add_css(drupal_get_path('module', 'tripal_ds') . '/theme/css/tripal_ds.css');
  drupal_add_js(drupal_get_path('module', 'tripal_ds') . '/theme/js/tripal_ds.js');

  $theme_dir = url(drupal_get_path('module', 'tripal_ds') . '/theme');
  drupal_add_js("var ds_theme_dir  = '$theme_dir';", 'inline', 'header');
  // Icon fonts.
  drupal_add_css(drupal_get_path('module', 'tripal_ds') . '/theme/fonts/font-awesome-4.7.0/css/font-awesome.min.css');


}

/**
 * Implements hook_views_api().
 */
function tripal_ds_views_api() {
  return array(
     'api' => 3,
     'path' => drupal_get_path('module', 'tripal_ds') . '/includes/views',
  );
}
/**
 * Implements hook_menu().
 * Defines all menu items needed by Tripal DS
 *
 */
function tripal_ds_menu() {
  $items = array();
  // Adds a +Apply Tripal Display Suite option to 'Tripal Content Types' page.
  $items['admin/structure/bio_data/manage/%/display/apply'] = array(
    'title' => 'Apply Default Tripal Layout (will reset current layout)',
    'description' => t('Apply the Tripal Display Suite settings to this content type.'),
    'page callback' => 'drupal_get_form',
    'access arguments' => array('administer tripal'),
    'page arguments' => array('tripal_ds_update_layout_form', 4),
    'type' => MENU_LOCAL_ACTION,
  );
  // Adds a +Add Tripal Pane button to 'Tripal Content Types' page.
  $items['admin/structure/bio_data/manage/%/display/create'] = array(
    'title' => 'Create an empty Tripal Pane',
    'description' => t('Create a new empty tripal pane.'),
    'page callback' => 'drupal_get_form',
    'access arguments' => array('administer tripal'),
    'page arguments' => array('tripal_ds_pane_addition_button_form', 4),
    'type' => MENU_LOCAL_ACTION,
  );
  return $items;
}

/**
 * Implements hook_bundle_postcreate().
 *
 * This is a Triapl defined hook and is called in the TripalBundle::create()
 * function to allow modules to perform tasks when a bundle is created.
 *
 * @param $bundle
 */
function tripal_ds_bundle_postcreate($bundle) {
  $bundle_name = $bundle->name;
  $bundle_data_table = $bundle->data_table;
  $instances = field_info_instances('TripalEntity', $bundle_name);
  if($bundle_data_table == 'pub'){
    _ds_layout_pub_settings_info($bundle_name, $instances);
  }
  else {
    _ds_layout_settings_info($bundle_name, $instances);
  }

}

/**
 * Update the tripal_ds table when a tripal pane is deleted. This will remove
 * the link from the table of contents block.
 *
 * @param $bundle
 */
function tripal_ds_table_column_delete($bundle){
    $bundle_name = $bundle->name;
    db_delete('tripal_ds')
      ->condition('bundle', $bundle_name, '=')
      ->execute();
}
/**
 * Trigger the update to the tripal_ds table when a tripal pane is deleted.
 *
 * @param $bundle
 */
function tripal_ds_bundle_delete($bundle){
  tripal_ds_table_column_delete($bundle);
}


/**
 * Implements hook_ds_field_settings_alter()
 *
 * Upon save field groups are reviewed so that the tripal_ds table is update and
 * thus the table of contents block is be updated.
 *
 * @param $field_settings
 * @param $form
 * @param $form_state
 */
function tripal_ds_ds_field_settings_alter(&$field_settings, $form, $form_state){
  // Get the form info from the bundle about to be saved.
  $tripal_entity_object = $form_state['build_info']['args']['1'];
  // Grab the bundle.
  $bundle_id = $tripal_entity_object->name;
  // Grab the field groups from the bundle.
  $updated_field_groups = $form_state['field_group'];
  // Grab the fields from the bundle.
  $fields = $form_state['values']['fields'];

  // Delete the menu items associated with the bundle id.
  db_delete('tripal_ds')
    ->condition('bundle', $bundle_id, '=')
    ->execute();

  // Traverse the updated field_groups grabbing the tripal pane items.
  $tripal_pane_field_groups = array();
  $i = 0;
  foreach($updated_field_groups as $updated_field_group){
    if($updated_field_group->format_type == 'tripalpane'){
      $tripal_pane_field_groups += [ $i => $updated_field_group->group_name];
      $i++;
    }
  }

  // Now grab the labels of the tripalpane.
  foreach($updated_field_groups as $updated_field_group){
    foreach($tripal_pane_field_groups as $tripal_pane_field_group){
      if($updated_field_group->group_name == $tripal_pane_field_group){
        if($fields[$tripal_pane_field_group]['region'] !== 'hidden'){
          tripal_ds_bundle_menu_item($bundle_id, $updated_field_group->label, $tripal_pane_field_group, 'tripalentity');
        }
      }
    }
  }
  // Update the menu items weight.
  tripal_ds_toc_order($bundle_id, $form_state['values']['fields']);
}

/**
 *
 * Trigger the update to the tripal_ds table when a tripal pane is deleted.
 *
 * @param $bundle_name
 * @param $field_label
 * @param $field_name
 * @param $entity_type
 */
function tripal_ds_bundle_menu_item($bundle_name, $field_label, $field_name, $entity_type){
  //Check the record does not already exist
  $tripal_ds_rows = db_select('tripal_ds', 'ds')
    ->fields('ds', array('tripal_ds_field_name', 'tripal_ds_field_label', 'bundle'))
    ->condition('bundle', $bundle_name, '=')
    ->condition('tripal_ds_field_label', $field_label, '=')
    ->condition('tripal_ds_field_name', $field_name, '=')
    ->execute()->fetchAll();
  if(!empty($tripal_ds_rows)){
    foreach ($tripal_ds_rows as $tripal_ds_row){
      if(($field_label == $tripal_ds_row->tripal_ds_field_label) && ($field_name == $tripal_ds_row->tripal_ds_field_name) && ($bundle_name == $tripal_ds_row->bundle)) {
        // Do not write the field to the table
        drupal_set_message("Could not update the bundle menu because that field already exists.", 'error');
      }
    }
  }
  else {
    //Write to the tripal_ds table to record the new tripal pane.
    $field_for_table = new stdClass();
    $field_for_table->tripal_ds_field_name = $field_name;
    $field_for_table->tripal_ds_field_label = $field_label;
    $field_for_table->entity_type = $entity_type;
    $field_for_table->bundle = $bundle_name;
    drupal_write_record('tripal_ds', $field_for_table);

  }
}

/**
 * Implements hook_ds_layout_info() to define layouts from code in a module for
 * display suite.
 *
 * Defines the Tripal Feature Layout option.
 *
 */
function tripal_ds_ds_layout_info() {
  $path = drupal_get_path('module', 'tripal_ds');

  $layouts = array(
    'tripal_ds_feature' => array(
      'label' => t('Tripal Feature Layout'),
      'path' => $path . '/theme/templates',
      'regions' => array(
        'left' => t('Left'),
        'right' => t('Right'),
      ),
      'css' => TRUE,
    ),
  );

  return $layouts;
}

/**
 * Implements hook_form()
 *
 * Adds a confirmation message to applying default layout option in 'Manage
 * Display'.
 *
 * @param $form
 * @param $form_state
 * @param $bundle_name
 *
 * @return mixed
 */
function tripal_ds_update_layout_form($form, &$form_state, $bundle_name) {
  $form = array();
  $form['bundle_name'] = array(
    '#type' => 'value',
    '#value' => $bundle_name,
  );

  $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));
  $bundle_label = $bundle->label;

  return confirm_form($form,
    t('Please confirm you would like to apply this layout: ' . $bundle_label),
    'admin/structure/bio_data/manage/' . $bundle_name . '/display',
    t('This action cannot be undone.'),
    t('Yes, apply layout'),
    t('No, cancel')
  );
}

/**
 * Implements hook_form_submit()
 *
 * Deletes all existing settings associated with a bundle's display settings
 * so that the default layout is applied cleanly.
 *
 * @param $form_state
 * @param $form
 */
function tripal_ds_update_layout_form_submit($form, &$form_state) {
  $bundle_name = $form_state['build_info']['args'][0];
  $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));

  //Build the identifier to check against ds_layout_settings.
  $ds_identifier = 'TripalEntity|'.$bundle_name.'|default';

  //Check to see if the layout already exists.
  $result = db_select('ds_layout_settings', 'ds')
    ->fields('ds')
    ->condition('id', $ds_identifier, '=')
    ->execute()
    ->fetchField();
  //Check to see if there are any field groups associated with the bundle.
  $result_fg = db_select('field_group', 'fg')
    ->fields('fg')
    ->condition('bundle', $bundle_name, '=')
    ->execute()
    ->fetchField();
  //Check to see if there are any tripal ds fields associated with the bundle.
  $result_tds = db_select('tripal_ds', 'tds')
    ->fields('tds')
    ->condition('bundle', $bundle_name, '=')
    ->execute();

  //Check to see if there are any field settings associated with the bundle.
  $result_fs = db_select('ds_field_settings', 'fs')
    ->fields('fs')
    ->condition('bundle', $bundle_name, '=')
    ->execute();

  //If the layout exists, delete it.
  if(!empty($result)) {
    db_delete('ds_layout_settings')
      ->condition('id', $ds_identifier, '=')
      ->execute();
  }
  //Then delete the field_group_fields associated with the identifier.
  if(!empty($result_fg)) {
    db_delete('field_group')
      ->condition('bundle', $bundle_name, '=')
      ->execute();
  }
  //Then delete the ds_field_settings associated with the identifier.
  if(!empty($result_tds)) {
    db_delete('ds_field_settings')
      ->condition('bundle', $bundle_name, '=')
      ->execute();
  }
  //Then delete the tripal_ds menu item.
  if(!empty($result_fs)) {
    db_delete('tripal_ds')
      ->condition('bundle', $bundle_name, '=')
      ->execute();
  }

  //Now you can build the layout fresh.
  $instances = field_info_instances('TripalEntity', $bundle_name);
  $bundle_data_table = $bundle->data_table;
  if($bundle_data_table == 'pub'){
    $success = _ds_layout_pub_settings_info($bundle_name, $instances);
  }
  else {
    $success = _ds_layout_settings_info($bundle_name, $instances);
  }

  if ($success) {
    drupal_set_message("Layout applied successfully and saved.");
  }
  else {
    drupal_set_message("Could not apply layout.", 'error');
  }

  drupal_goto("admin/structure/bio_data/manage/$bundle_name/display");
}

/**
 * Implements hook_form()
 *
 * Creates the button that creates an empty tripal pane.
 *
 * @param $form
 * @param $form_state
 * @param $bundle_name
 * @return mixed
 */
function tripal_ds_pane_addition_button_form($form, &$form_state, $bundle_name) {
  $form = array();
  $form['bundle_name'] = array(
    '#type' => 'value',
    '#value' => $bundle_name,
  );
  $form['field_name'] = array(
    '#type' => 'textfield',
    '#title' => t('Tripal Panel Label'),
    '#required' => TRUE,
    '#description' => "Please enter the label for the new Tripal Pane",
    '#size' => 20,
    '#maxlength' => 50,
  );

  $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));
  $bundle_label = $bundle->label;

  return confirm_form($form,
    t('Please confirm you would like to create a new field for: ' . $bundle_label),
    'admin/structure/bio_data/manage/' . $bundle_name . '/display',
    t('Create new Tripal Pane'),
    t('Yes'),
    t('No, cancel')
  );
}

/**
 * Implements hook_form_submit()
 *
 * @param $form_state
 * @param $form
 */
function tripal_ds_pane_addition_button_form_submit($form, &$form_state) {
  $bundle_name = $form_state['build_info']['args'][0];
  //Build the rest of the passed variables.
  $field_name = $form_state['input']['field_name'];
  $field_label = $form_state['input']['field_name'];

  tripal_ds_create_field($field_label, $field_name, $bundle_name);
  drupal_goto("admin/structure/bio_data/manage/$bundle_name/display");
}


/**
 * When called the function will add field_groups to the existing tripal_ds
 * layout in the correct regions.
 *
 * @param $bundle_name
 *  The name of the bundle the pane is being added to.
 * @param $field_name
 *  The machine name for the field.
 * @param $tripal_pane_name
 *  The machine name for the tripal pane.
 */
function tripal_ds_update_ds_layout($bundle_name, $field_name, $tripal_pane_name) {
  //Build the identifier to check against ds_layout_settings.
  $ds_identifier = 'TripalEntity|'.$bundle_name.'|default';

  //Check to see if the layout already exists.
  $result = db_select('ds_layout_settings', 'ds')
    ->fields('ds', array('settings'))
    ->condition('ds.id', $ds_identifier, '=')
    ->execute()
    ->fetchObject();

  //If the layout exists unserialize it.
  if(!empty($result)) {
    $layout_info = $result->settings;
    $layout_info = unserialize($layout_info);
    //Count the number of rows in the region and add the field to the region.
    $index = count($layout_info['regions']['right']);
    //Now add the tripal pane and field to the right region and field array.
    if(!empty($field_name)){
      $layout_info['regions']['right'][$index] = $field_name;
      $incremented_index = $index++;
      $layout_info['fields'][$field_name] = 'right';
    }
    if(!empty($tripal_pane_name)){
      if(!empty($incremented_index)){
        $layout_info['regions']['right'][$incremented_index] = $tripal_pane_name;
        $layout_info['fields'][$tripal_pane_name] = 'right';
      }
      else {
        $layout_info['regions']['right'][$index] = $tripal_pane_name;
        $layout_info['fields'][$tripal_pane_name] = 'right';
      }
    }
    //Update the ds_layout_settings table with the new layout info.
    drupal_write_record('ds_layout_settings', $layout_info);
  }
}
/*
 * Code for the view of the menu items

    //get tripal entity id from url then run it against tripal entity db
    //and grab the bundle id, then pass bundle id to view
    $url = current_path();
    $url_exploded = explode("/", $url);
    $tripal_entity_id = (int)$url_exploded[1];

    $result = db_select('tripal_entity', 'te')
      ->fields('te', array('bundle'))
      ->condition('id', $tripal_entity_id, '=')
      ->execute()
      ->fetchField();
*/

/**
 * Implements hook_field_display_alter().
 * Alters the display settings of a field before it gets displayed.
 *
 * Hides the empty tripal panes if the content type has been set to hide empty
 * fields. This option is found in the edit tab of the tripal content type with
 * a title 'Field Display'.
 *
 * @param $display
 * @param $context
 */
function tripal_ds_field_display_alter(&$display, $context){
  if ($context['entity_type'] == 'TripalEntity') {
    $field_name = $context['field']['field_name'];
    $bundle = $context['entity']->bundle;
    $bundle_info = tripal_load_bundle_entity(array('name' => $bundle));
    $hide_variable = tripal_get_bundle_variable('hide_empty_field', $bundle_info->id, 'hide');

    if ($field_name && ($hide_variable == 'hide')) {
      $item = field_get_items('TripalEntity', $context['entity'], $field_name);
      $field = field_info_field($field_name);
      if ($item) {
        if (tripal_field_is_empty($item[0], $field)) {
          $parent_field_info = tripal_ds_find_field_group_parent($field_name, 'TripalEntity', $bundle, $context);
          if (!empty($parent_field_info)) {
            foreach ($parent_field_info as $parent_key => $parent_field){
               // We want to use JavaScript to remove the fields rather than
               // CSS to hide them so that when users theme the table of
               // contents using CSS they aren't theming empty rows.
               drupal_add_js('jQuery(document).ready(function () { jQuery("#' . $parent_field_info[$parent_key] . '").parents(".views-row").remove() });', 'inline');
            }
          }
        }
      }
    }
  }
}



/**
 * Identifies field_group parents to find tripal_panes and return that
 * information to the function that calls it.
 *
 * @param $field_name
 * @param $entity_type
 * @param $bundle
 *
 * @return array
 */
function tripal_ds_find_field_group_parent($field_name, $entity_type, $bundle, $context){
  $field_groups_to_hide = array();
  $increment = 0;

  // Get the field groups associated with this bundle.
  $fg_for_bundle = db_select('field_group', 'fg')
    ->fields('fg')
    ->condition('bundle', $bundle, '=')
    ->condition('entity_type', $entity_type, '=')
    ->execute()->fetchAll();

  // Run through the field groups looking for the provided $field_name
  foreach ($fg_for_bundle as $field_groups => $field_group) {
   $field_group_data = unserialize($field_group->data);
   // There is a separate function to deal with tables, so disregard.
    if ($field_group_data['format_type'] == 'table'){
      // Do nothing
    }
    elseif (!empty($field_group_data['children'][0])) {
      $children = $field_group_data['children'];
      //If there is more than one child all need to be checked.
      if (count($children) > 1) {
        foreach ($children as $kids => $child) {
          // Now check if each child if empty.
          $item = field_get_items('TripalEntity', $context['entity'], $child);
          $field = field_info_field($child);
          if(!tripal_field_is_empty($item[0], $field)){
            //If any of the fields are not empty do not add the parent.
            break 2;
          }
          else {
            continue;
          }
        }
        $field_groups_to_hide[$increment] = $field_group->group_name;
      }
      elseif($children[0] == $field_name) {
        $field_groups_to_hide[$increment] = $field_group->group_name;
      }
    }
    $increment++;
  }
  // Remove duplicate values.
  $field_groups_to_hide = array_unique($field_groups_to_hide);
  return $field_groups_to_hide;

}

/**
 * Updates the tripal_ds table with weight information of field_groups on
 * save of "manage display' of content type. Weight is what is used to order
 * the menu items.
 *
 * @param $bundle
 * @param array $fields
 */
function tripal_ds_toc_order($bundle, $fields = array()){
  // Find all menu items associated with the bundle id.
  $menu_items = db_select('tripal_ds', 'ds')
    ->fields('ds')
    ->condition('bundle', $bundle, '=')
    ->execute()->fetchAll();

  // Now find all menu items in the $fields array
  foreach ($menu_items as $menu_items => $menu_item) {
    $toc_field_name = $menu_item->tripal_ds_field_name;
    // Compare the field name from the table with the fields in the array.
    if (array_key_exists($toc_field_name, $fields)) {
      $weight = $fields[$toc_field_name]['weight'];
      //If a weight is returned update the tripal_ds table.
      if(!empty($weight)){
        db_update('tripal_ds')
          ->fields(array(
            'weight' => $weight,
          ))
          ->condition('bundle', $bundle, '=')
          ->condition('tripal_ds_field_name', $toc_field_name, '=')
          ->execute();
      }
    }
  }
}

/**
 * Imports all of the Tripal_DS API into scope.
 *
 *
 */
function tripal_ds_import_api() {
  module_load_include('inc', 'tripal_ds', 'api/tripal_ds.pane.api');
}