<?php

/**
 * @file
 * Integrates the Chado Phylotree module with Drupal Nodes & Views
 */

/**
 * @defgroup tripal_phylogeny Phylotree Module
 * @ingroup tripal_modules
 * @{
 * Integrates the Chado Phylotree module with Drupal Nodes
 * @}
 */
require_once 'api/tripal_phylogeny.api.inc';
require_once 'theme/tripal_phylogeny.theme.inc';
require_once 'includes/tripal_phylogeny.admin.inc';
require_once 'includes/tripal_phylogeny.chado_node.inc';
require_once 'includes/tripal_phylogeny.import_tree.inc';
require_once 'includes/tripal_phylogeny.taxonomy.inc';

/**
 * Implements hook_permission().
 *
 * Set the permission types that the chado module uses.  Essentially we
 * want permissionis that protect creation, editing and deleting of chado
 * data objects
 *
 * @ingroup tripal_phylogeny
 */
function tripal_phylogeny_permission() {
  return array(
    'access chado_phylotree content' => array(
      'title' => t('View Phylotrees'),
      'description' => t('Allow users to view phylotree pages.'),
    ),
    'administer tripal phylotree' => array(
      'title' => t('Administer Phylotrees'),
      'description' => t('Allow users to administer all phylotrees.'),
    ),
  );
}

/**
 * Implements hook_menu().
 *
 * Menu items are automatically added for the new node types created
 * by this module to the 'Create Content' Navigation menu item.  This function
 * adds more menu items needed for this module.
 *
 * @ingroup tripal_phylogeny
 */
function tripal_phylogeny_menu() {
  $items = array();

  // administration landing page. currently has no content but is
  // apparently required for the Sync and Help links to work.
  $items['admin/tripal/legacy/tripal_phylogeny'] = array(
    'title' => 'Phylogeny and Taxonomy',
    'description' => 'Phylogenetic and taxonomic trees.',
    'page callback' => 'tripal_phylogeny_admin_phylotrees_listing',
    'access arguments' => array('administer tripal phylotree'),
    'type' => MENU_NORMAL_ITEM,
  );

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

  // configuration menu item
  $items['admin/tripal/legacy/tripal_phylogeny/configuration'] = array(
    'title' => 'Settings',
    'description' => 'Configure the Tripal Phylotree module',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('tripal_phylogeny_admin'),
    'access arguments' => array('administer tripal phylotree'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 1
  );

  $items['admin/tripal/legacy/tripal_phylogeny/plots'] = array(
    'title' => 'Plot Defaults',
    'description' => 'Set defaults for the trees',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('tripal_phylogeny_default_plots_form'),
    'access arguments' => array('administer tripal phylotree'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 2
  );

  // sync menu item (will be rendered as a tab by tripal)
  $items['admin/tripal/legacy/tripal_phylogeny/sync'] = array(
    'title' => ' Sync',
    'description' => 'Create pages on this site for phylotrees stored in Chado',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('chado_node_sync_form', 'tripal_phylogeny', 'chado_phylotree'),
    'access arguments' => array('administer tripal phylotree'),
    'type' => MENU_LOCAL_TASK,
    'weight' => 3
  );

  // Enable admin view
  $items['admin/tripal/legacy/tripal_phylogeny/views/phylotree/enable'] = array(
    'title' => 'Enable Phylotree Administrative View',
    'page callback' => 'tripal_enable_view',
    'page arguments' => array('tripal_phylogeny_admin_phylotree', 'admin/tripal/legacy/tripal_phylogeny'),
    'access arguments' => array('administer tripal phylotree'),
    'type' => MENU_CALLBACK,
  );

   $items['taxonomy_view'] = array(
     'title' => 'Taxonomy',
     'description' => 'Taxonomic view of the species available on this site.',
     'page callback' => 'tripal_phylogeny_taxonomy_view',
     'access arguments' => array('access taxonomy content'),
     'file' => '/includes/tripal_phylogeny.taxonomy.inc',
     'type' => MENU_NORMAL_ITEM,
   );

   // create a route for viewing json of all phylonodes having this phylotree_id
   $items['ajax/chado_phylotree/%/json'] = array(
     'page callback' => 'tripal_phylogeny_ajax_get_tree_json',
     'page arguments' => array(2),
     // allow all anonymous http clients
     'access callback' => TRUE
   );

  return $items;
}

/**
 * Implements hook_search_biological_data_views().
 *
 * Adds the described views to the "Search Data" Page created by Tripal Views
 */
function tripal_phylogeny_search_biological_data_views() {
  return array(
      'tripal_phylogeny_user_phylotree' => array(
          'machine_name' => 'tripal_phylogeny_user_phylotree',
          'human_name' => 'Phylogenetic Trees',
          'description' => 'Gene trees, species trees, etc.',
          'link' => 'chado/phylotree'
      ),
  );
}

/**
 * Implements hook_views_api().
 *
 * Essentially this hook tells drupal that there is views support for
 *  for this module which then includes tripal_db.views.inc where all the
 *  views integration code is
 *
 * @ingroup tripal_phylogeny
 */
function tripal_phylogeny_views_api() {
  return array(
    'api' => 3.0,
  );
}

/**
 *  Implements hook_theme().
 *
 * We need to let drupal know about our theme functions and their arguments.
 *  We create theme functions to allow users of the module to customize the
 *  look and feel of the output generated in this module
 *
 * @ingroup tripal_phylogeny
 */
function tripal_phylogeny_theme($existing, $type, $theme, $path) {
  $core_path = drupal_get_path('module', 'tripal_core');
  $items = array(
    // built-in theme
    'node__chado_phylotree' => array(
      'template' => 'node--chado-generic',
      'render element' => 'node',
      'base hook' => 'node',
      'path' => "$core_path/theme/templates",
    ),
    // base template for this page (default tab) includes the phylogram
    'tripal_phylogeny_base' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_phylogeny_base',
      'path' => "$path/theme/templates",
    ),
    // Template for the phylogram.
    'tripal_phylogeny_phylogram' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_phylogeny_phylogram',
      'path' => "$path/theme/templates",
    ),
    // Template for the taxonomic tree.
    'tripal_phylogeny_taxonomic_tree' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_phylogeny_taxonomic_tree',
      'path' => "$path/theme/templates",
    ),
    // partial for organisms block
    'tripal_phylogeny_organisms' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_phylogeny_organisms',
      'path' => "$path/theme/templates",
    ),
    // partial for cross references block
    'tripal_phylogeny_references' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_phylogeny_references',
      'path' => "$path/theme/templates",
    ),
    // partial for cross references block
    'tripal_phylogeny_analysis' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_phylogeny_analysis',
      'path' => "$path/theme/templates",
    ),
    // partial for teaser view
    'tripal_phylogeny_teaser' => array(
      'variables' => array('node' => NULL),
      'template' => 'tripal_phylogeny_teaser',
      'path' => "$path/theme/templates",
    ),

    // FORM THEMES
    // Theme function for the project table in admin projects form
    'tripal_phylogeny_admin_org_color_tables' => array(
      'render element' => 'element',
    )
  );
  return $items;
}

/**
 * Implements hook_help().
 * Adds a help page to the module list
 *
 * @ingroup tripal_phylogeny
 */
function tripal_phylogeny_help ($path, $arg) {
  if ($path == 'admin/help#tripal_phylogeny') {
    return theme('tripal_phylogeny_help', array());
  }
}

/**
 * Get json representation of a phylotree id.
 *
 * This function is meant to be called via AJAX.
 *
 * @param int $phylotree_id
 *   the ID of the phylotree node.
 *
 * @return string json
 *
 * @ingroup tripal_phylogeny
 */
function tripal_phylogeny_ajax_get_tree_json($phylotree_id) {

  $phylotree = chado_generate_var('phylotree', array('phylotree_id' => $phylotree_id));

  // This SQL gets all of the phylonodes for a given tree as well as the
  // features and organisms with which it is assocaited.  Each phylonode
  // can be associated with an orgnaism in one of two ways: 1) via a
  // feature linked by the phylonode.feature_id field or 2) via a
  // a record in the phylonde_organsim table.  Therefore both types of
  // organism records are returned in the query below, but those
  // retrieved via a FK link on features are prefixed with 'fo_'.
  $sql = "
    SELECT
      n.phylonode_id, n.parent_phylonode_id, n.label AS name, n.distance AS length,
      f.feature_id, f.name AS feature_name,
      cvt.name AS cvterm_name,
      o.organism_id, o.common_name, o.abbreviation, o.genus, o.species,
      fo.organism_id AS fo_organism_id, fo.common_name AS fo_common_name,
      fo.abbreviation AS fo_abbreviation, fo.genus as fo_genus, fo.species AS fo_species,
      cf.nid AS feature_node_id,
      fco.nid AS fo_organism_node_id,
      co.nid AS organism_node_id
    FROM {phylonode} n
      LEFT OUTER JOIN {cvterm} cvt              ON n.type_id = cvt.cvterm_id
      LEFT OUTER JOIN {feature} f               ON n.feature_id = f.feature_id
      LEFT OUTER JOIN [chado_feature] cf        ON cf.feature_id = f.feature_id
      LEFT OUTER JOIN {organism} fo             ON f.organism_id = fo.organism_id
      LEFT OUTER JOIN [chado_organism] fco      ON fco.organism_id = fo.organism_id
      LEFT OUTER JOIN {phylonode_organism} po   ON po.phylonode_id = n.phylonode_id
      LEFT OUTER JOIN {organism} o              ON PO.organism_id = o.organism_id
      LEFT OUTER JOIN [chado_organism] co       ON co.organism_id = o.organism_id
    WHERE n.phylotree_id = :phylotree_id
  ";
  $args = array(':phylotree_id' => $phylotree_id);
  $result = chado_query($sql, $args);

  // Fetch all the phylonodes into an assoc array indexed by phylonode_id.
  // Convert from resultset record to array, fixing datatypes. chado_query
  // returns numeric as string and fun stuff like that.
  $phylonodes = array();
  $root_phylonode_ref = null;

  foreach ($result as $r) {
    $phylonode_id = (int) $r->phylonode_id;

    // expect all nodes to have these properties
    $node = array(
      'phylonode_id' => $phylonode_id,
      'parent_phylonode_id' => (int) $r->parent_phylonode_id,
      'length' => (double) $r->length,
      'cvterm_name' => $r->cvterm_name
    );

    // If the nodes are taxonomic then set an equal distance
    if ($phylotree->type_id->name == 'taxonomy') {
      $node['length'] = 0.001;
    }

    // Other props may exist only for leaf nodes
    if ($r->name) {
      $node['name'] = $r->name;
    }
    // If this node is associated with a feature then add in the details
    if ($r->feature_id) {
      $node['feature_id'] = (int) $r->feature_id;
      $node['feature_name'] = $r->feature_name;
      $node['feature_node_id'] = (int) $r->feature_node_id;
    }
    // Add in the organism fields when they are available via the
    // phylonode_organism table.
    if ($r->organism_id) {
      $node['organism_id'] = (int) $r->organism_id;
      $node['common_name'] = $r->common_name;
      $node['abbreviation'] = $r->abbreviation;
      $node['genus'] = $r->genus;
      $node['species'] = $r->species;
      $node['organism_node_id'] = (int) $r->organism_node_id;
      // If the node does not have a name but is linked to an organism
      // then set the name to be that of the genus and species.
      if (!$r->name) {
        $node['name'] = $r->genus . ' ' . $r->species;
      }
    }
    // Add in the organism fields when they are available via the
    // the phylonode.feature_id FK relationship.
    if ($r->fo_organism_id) {
      $node['fo_organism_id'] = (int) $r->fo_organism_id;
      $node['fo_common_name'] = $r->fo_common_name;
      $node['fo_abbreviation'] = $r->fo_abbreviation;
      $node['fo_genus'] = $r->fo_genus;
      $node['fo_species'] = $r->fo_species;
      $node['fo_organism_node_id'] = (int) $r->fo_organism_node_id;
    }

    // Add this node to the list, organized by ID.
    $phylonodes[$phylonode_id] = $node;
  }

  // Populate the children[] arrays for each node.
  foreach ($phylonodes as $key => &$node) {
    if ($node['parent_phylonode_id'] !== 0) {
      $parent_ref = &$phylonodes[ $node['parent_phylonode_id']];
      // Append node refernce to children.
      $parent_ref['children'][] = &$node;
    }
    else {
      $root_phylonode_ref = &$node;
    }
  }

  // dump datastructure as json to browser. drupal sets the mime-type correctly.
  drupal_json_output($root_phylonode_ref);
}



