<?php
/**
 * @file
 * Basic functionality for stocks
 */

require_once 'api/tripal_stock.DEPRECATED.inc';

require_once 'theme/tripal_stock.theme.inc';

require_once 'includes/tripal_stock.admin.inc';
require_once 'includes/tripal_stock.chado_node.inc';

/**
 * @defgroup tripal_stock Stock Module
 * @ingroup tripal_modules
 * @{
 * Integrates the Chado Stock module with Drupal Nodes & Views
 *
 * The Tripal Stock Module provides functionality for adding, editing, deleting and accessing chado
 * stocks. The stock module was designed to store information about stock collections in a
 * laboratory. What is called a stock could also be called a strain or an accession. There is a lot
 * in common between a Drosophila stock and a Saccharomyces strain and an Arabidopsis line. They all
 * come from some taxon, have genotypes, physical locations in the lab, some conceivable
 * relationship with a publication, some conceivable relationship with a sequence feature (such as a
 * transgene), and could be described by some ontology term. For more information about the chado
 * Stock Module see the GMOD Wiki Page (http://gmod.org/wiki/Chado_Stock_Module)
 * @}
 */

/**
 * Implements hook_menu().
 * Adds menu items for the tripal_stock
 *
 * @return
 *   Menu definitions for the tripal_stock
 *
 * @ingroup tripal_stock
 */
function tripal_stock_menu() {
  $items = array();

  // the menu link for addressing any stock (by name, uniquename, synonym)
  $items['stock/%'] = array(
    'page callback' => 'tripal_stock_match_stocks_page',
    'page arguments' => array(1),
    'access arguments' => array('access chado_stock content'),
    'type' => MENU_LOCAL_TASK,
  );

  //Administrative settings menu-----------------

  $items['admin/tripal/legacy/tripal_stock'] = array(
    'title' => 'Stocks',
    'description' => 'A stock is the physical entities of an organism, either living or preserved.',
    'page callback' => 'tripal_stock_admin_stock_view',
    'access arguments' => array('administer tripal stock'),
    'type' => MENU_NORMAL_ITEM
  );

  $items['admin/tripal/legacy/tripal_stock/configuration'] = array(
    'title' => 'Settings',
    'description' => 'Settings for Chado Stocks',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('tripal_stock_admin'),
    'access arguments' => array('administer tripal stock'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 5
  );

  $items['admin/tripal/legacy/tripal_stock/sync'] = array(
    'title' => ' Sync',
    'description' => 'Sync stocks from Chado with Drupal',
    'page callback' => 'drupal_get_form',
    //'page arguments' => array('tripal_stock_sync_form'),
    'page arguments' => array('chado_node_sync_form', 'tripal_stock', 'chado_stock'),
    'access arguments' => array('administer tripal stock'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 0
  );

  $items['admin/tripal/legacy/tripal_stock/chado_stock_toc'] = array(
    'title' => ' TOC',
    'description' => 'Manage the table of contents for stock nodes.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('tripal_core_content_type_toc_form', 'chado_stock'),
    'access arguments' => array('administer tripal stock'),
    'type' => MENU_LOCAL_TASK,
    'file' =>  'includes/tripal_core.toc.inc',
    'file path' => drupal_get_path('module', 'tripal_core'),
    'weight' => 3
  );

  $items['admin/tripal/legacy/tripal_stock/help'] = array(
    'title' => 'Help',
    'description' => 'Basic Description of Tripal Stock Module Functionality',
    'page callback' => 'theme',
    'page arguments' => array('tripal_stock_help'),
    'access arguments' => array('administer tripal stock'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 10
  );

  return $items;
}

/**
 * Implements hook_search_biological_data_views().
 *
 * Adds the described views to the "Search Data" Page created by Tripal Views
 */
function tripal_stock_search_biological_data_views() {
  return array(
    'tripal_stock_user_stocks' => array(
      'machine_name' => 'tripal_stock_user_stocks',
      'human_name' => 'Stocks',
      'description' => 'A stock is the physical entities of an organism, either living or preserved.',
      'link' => 'chado/stock'
    ),
  );
}

/**
 * Implements Menu wildcard_load hook
 *
 * Allows the node ID of a chado stock to be dynamically
 *   pulled from the path. The node is loaded from this node ID
 *   and supplied to the page as an arguement. This is an example
 *   of dynamic argument replacement using wildcards in the path.
 *
 * @param $nid
 *   The node ID passed in from the path
 *
 * @return
 *   The node object with the passed in nid
 *
 * @ingroup tripal_stock
 */
function cs_node_load($nid) {
  if (is_numeric($nid)) {
    $node = node_load($nid);
    if ($node->type == 'chado_stock') {
      return $node;
    }
  }

  return FALSE;
}

/**
 * Implements hook_permission().
 * Set the permission types that the chado stock module uses
 *
 * @return
 *   Listing of the possible permission catagories
 *
 * @ingroup tripal_stock
 */
function tripal_stock_permission() {
  return array(
    /*
    'access chado_stock content' => array(
      'title' => t('View Stocks'),
      'description' => t('Allow users to view stock pages.'),
    ),
    'create chado_stock content' => array(
      'title' => t('Create Stocks'),
      'description' => t('Allow users to create new stock pages.'),
    ),
    'delete chado_stock content' => array(
      'title' => t('Delete Stocks'),
      'description' => t('Allow users to delete stock pages.'),
    ),
    'edit chado_stock content' => array(
      'title' => t('Edit Stocks'),
      'description' => t('Allow users to edit stock pages.'),
    ),
    'administer tripal stock' => array(
      'title' => t('Administer Stocks'),
      'description' => t('Allow users to administer all stocks.'),
    ),
    */
  );
}

/**
 * Implement hook_node_access().
 *
 * This hook allows node modules to limit access to the node types they define.
 *
 *  @param $node
 *  The node on which the operation is to be performed, or, if it does not yet exist, the
 *  type of node to be created
 *
 *  @param $op
 *  The operation to be performed
 *
 *  @param $account
 *  A user object representing the user for whom the operation is to be performed
 *
 *  @return
 *  If the permission for the specified operation is not set then return FALSE. If the
 *  permission is set then return NULL as this allows other modules to disable
 *  access.  The only exception is when the $op == 'create'.  We will always
 *  return TRUE if the permission is set.
 *
 * @ingroup tripal_stock
 */

function tripal_stock_node_access($node, $op, $account) {
  $node_type = $node;
  if (is_object($node)) {
    $node_type = $node->type;
  }

  if($node_type == 'chado_stock') {
    if ($op == 'create') {
      if (!user_access('create chado_stock content', $account)) {
        return NODE_ACCESS_DENY;
      }
      return NODE_ACCESS_ALLOW;
    }
    if ($op == 'update') {
      if (!user_access('edit chado_stock content', $account)) {
        return NODE_ACCESS_DENY;
      }
    }
    if ($op == 'delete') {
      if (!user_access('delete chado_stock content', $account)) {
        return NODE_ACCESS_DENY;
      }
    }
    if ($op == 'view') {
      if (!user_access('access chado_stock content', $account)) {
        return NODE_ACCESS_DENY;
      }
    }
    return NODE_ACCESS_IGNORE;
  }
}

/**
 * Implements hook_views_api().
 *
 * Purpose: Essentially this hook tells drupal that there is views support for
 *  for this module which then includes tripal_stock.views.inc where all the
 *  views integration code is
 *
 * @return
 *   An array with fields important for views integration
 *
 * @ingroup tripal_stock
 */
function tripal_stock_views_api() {
  return array(
    'api' => 3.0,
  );
}

/**
 * Implements hook_theme().
 * Register themeing functions for this module
 *
 * @return
 *   An array of themeing functions to register
 *
 * @ingroup tripal_stock
 */
function tripal_stock_theme($existing, $type, $theme, $path) {
  $core_path = drupal_get_path('module', 'tripal_core');

  $items = array(

    // tripal_stock templates
    'node__chado_stock' => array(
      'template' => 'node--chado-generic',
      'render element' => 'node',
      'base hook' => 'node',
      'path' => "$core_path/theme/templates",
    ),
    'tripal_stock_base' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_base',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_properties' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_properties',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_publications' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_publications',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_references' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_references',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_relationships' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_relationships',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_synonyms' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_synonyms',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_collections' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_collections',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_collections' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_collections',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_phenotypes' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_phenotypes',
      'path' => "$path/theme/templates",
    ),
    'tripal_stock_locations' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_locations',
      'path' => "$path/theme/templates",
    ),
    // tripal_organism templates
    'tripal_organism_stocks' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_organism_stocks',
      'path' => "$path/theme/templates",
    ),
    // help template
    'tripal_stock_help' => array(
      'template' => 'tripal_stock_help',
      'variables' =>  array(NULL),
      'path' => "$path/theme/templates",
    ),
    // themed teaser
    'tripal_stock_teaser' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_stock_teaser',
      'path' => "$path/theme/templates",
    ),
  );
  return $items;
}

/**
 * Implements hook_help().
 * Adds a help page to the module list
 *
 * @ingroup tripal_stock
 */
function tripal_stock_help ($path, $arg) {
  if ($path == 'admin/help#tripal_stock') {
    return theme('tripal_stock_help', array());
  }
}
/*
 * Uses the value provided in the $id argument to find all stocks that match
 * that ID by name, stockname or synonym.  If it matches uniquenly to a single
 * stock it will redirect to that stock page, otherwise, a list of matching
 * stocks is shown.
 *
 * @ingroup tripal_stock
 */
function tripal_stock_match_stocks_page($id) {

  // if the URL alias configuration is set such that the URL
  // always begins with 'stock' then we want to use the ID as it is and
  // forward it on. Otherwise, try to find the matching stock.
  $url_alias = variable_get('chado_stock_url_string', '/stock/[genus]/[species]/[type]/[uniquename]');
  if (!$url_alias) {
    $url_alias = '/stock/[genus]/[species]/[type]/[uniquename]';
  }
  $url_alias = preg_replace('/^\//', '', $url_alias); // remove any preceeding forward slash
  if (preg_match('/^stock\//', $url_alias)) {
    drupal_goto($id);
  }

  $sql = "
    SELECT
      S.name, S.uniquename, S.stock_id,
      O.genus, O.species, O.organism_id,
      CVT.cvterm_id, CVT.name as type_name,
      CS.nid
    FROM {stock} S
      INNER JOIN {organism} O on S.organism_id = O.organism_id
      INNER JOIN {cvterm} CVT on CVT.cvterm_id = S.type_id
      INNER JOIN public.chado_stock CS on CS.stock_id = S.stock_id
    WHERE
      S.uniquename = :uname or S.name = :name
  ";
  $results = chado_query($sql, array(':uname' => $id, ':name' => $id));

  $num_matches = 0;

  // iterate through the matches and build the table for showing matches
  $header = array('Uniquename', 'Name', 'Type', 'Species');
  $rows = array();
  $curr_match;
  while ($match = $results->fetchObject()) {
    $curr_match = $match;
    $rows[] = array(
       $match->uniquename,
       "<a href=\"" . url("node/". $match->nid) ."\">" . $match->name . "</a>",
       $match->type_name,
       '<i>' . $match->genus . ' ' . $match->species . '</i>',
    );
    $num_matches++;
  }

  // if we have more than one match then generate the table, otherwise, redirect
  // to the matched stock
  if ($num_matches == 1) {
    drupal_goto("node/" . $curr_match->nid);
  }
  if ($num_matches == 0) {
    return "<p>No stocks matched the given name '$id'</p>";
  }

  $table_attrs = array(
    'class' => 'tripal-table tripal-table-horz'
  );
  $output = "<p>The following stocks match the name '$id'.</p>";
  $output .= theme_table($header, $rows, $table_attrs, $caption);
  return $output;
}

/**
 * Implementation of hook_form_alter().
 *
 * @param $form
 * @param $form_state
 * @param $form_id
 *
 * @ingroup tripal_stock
 */
function tripal_stock_form_alter(&$form, &$form_state, $form_id) {
  // turn of preview button for insert/updates
  if ($form_id == "chado_stock_node_form") {
    $form['actions']['preview']['#access'] = FALSE;

    //remove the body field
    unset($form['body']);
  }
}

/**
 * Load the arguments for the organism stock counts browser
 *
 * @param $organism
 *  The organism of interest
 *
 * @ingroup tripal_stock
 */
function tripal_stock_load_organism_stock_counts($organism) {

  $args = array();
  $order = array();
  $names = array();

  // build the where clause for the SQL statement if we have a custom term list
  // we'll also keep track of the names the admin provided (if any) and the
  // order that the terms should appear.
  $is_custom = 0;
  $temp = rtrim(variable_get('tripal_stock_summary_report_mapping', ''));
  $where = '';
  if ($temp) {
    $is_custom = 1;
    $temp = explode("\n", $temp);
    $i = 0;
    foreach ($temp as $value) {
      // separate the key value pairs
      $temp2 = explode("=", $value);
      $stock_type = rtrim($temp2[0]);
      $order[] = $stock_type;  // save the order of the these terms
      $where .= " OFC.stock_type = :name$i OR ";
      $args[":name$i"] = rtrim($temp2[0]);

      // if the admin specified a new name then store that otherwise use the
      // the default sequence ontology term name
      if(count($temp2) == 2) {
        $names[] = rtrim($temp2[1]);
      }
      else {
        $names[] = $stock_type;
      }
      $i++;
    }
    if ($where) {
      $where = drupal_substr($where, 0, -4);  # remove OR from the end
      $where = "($where) AND";
    }
  }

  // get the stock counts.  This is dependent on a materialized view
  // installed with the organism module
  $sql = "
    SELECT OFC.num_stocks,OFC.stock_type,CVT.definition
    FROM {organism_stock_count} OFC
      INNER JOIN {cvterm} CVT on OFC.cvterm_id = CVT.cvterm_id
    WHERE $where organism_id = :organism_id
    ORDER BY num_stocks desc
  ";
  $args[':organism_id'] = $organism->organism_id;
  $org_stocks = chado_query($sql, $args);

  // iterate through the types
  $types = array();
  while ($type = $org_stocks->fetchObject()) {
    $types[$type->stock_type] = $type;
    // if we don't have an order this means we didn't go through the loop
    // above to set the names, so do that now
    if (!$is_custom) {
      $names[] = $type->stock_type;
      $order[] = $type->stock_type;
    }
  }

  // now reorder the types
  $ordered_types = array();
  foreach ($order as $type) {
    $ordered_types[] = $types[$type];
  }
  return array(
    'types' => $ordered_types,
    'names' => $names
  );
}
