Tripal 0.3b
tripal_feature/tripal_feature.module
Go to the documentation of this file.
00001 <?php
00002 
00003 /**
00004  * @defgroup tripal_feature Feature
00005  * @{
00006  * Provides functions for managing chado features including creating details pages for each feature
00007  * @}
00008  * @ingroup tripal_modules
00009  */
00010  
00011 require_once "tripal_feature.admin.inc";
00012 require_once "syncFeatures.php";
00013 require_once "indexFeatures.php";
00014 require_once "fasta_loader.php";
00015 require_once "gff_loader.php";
00016 
00017 require_once "tripal_feature.api.inc";
00018 
00019 require_once "tripal_feature-secondary_tables.inc";
00020 require_once "tripal_feature-properties.inc";
00021 require_once "tripal_feature-relationships.inc";
00022 require_once "tripal_feature-db_references.inc";
00023 
00024 
00025 /**
00026  *
00027  * @ingroup tripal_feature
00028  */
00029 function tripal_feature_init(){
00030 
00031    // add the jGCharts JS and CSS
00032    drupal_add_js (drupal_get_path('theme', 'tripal').'/js/tripal_feature.js'); 
00033    drupal_add_js (drupal_get_path('theme', 'tripal').'/js/jgcharts/jgcharts.js'); 
00034 
00035    drupal_add_css(drupal_get_path('theme', 'tripal').
00036                                   '/css/tripal_feature.css');
00037 }
00038 
00039 /**
00040  * Implements hook_views_api()
00041  *
00042  * Purpose: Essentially this hook tells drupal that there is views support for
00043  *  for this module which then includes tripal_db.views.inc where all the
00044  *  views integration code is
00045  *
00046  * @ingroup tripal_feature
00047  */ 
00048 function tripal_feature_views_api() {
00049    return array(
00050       'api' => 2.0,
00051    );
00052 }
00053 
00054 /**
00055  * Display help and module information
00056  *
00057  * @param 
00058  *   path which path of the site we're displaying help
00059  * @param 
00060  *   arg array that holds the current path as would be returned from arg() function
00061  *
00062  * @return 
00063  *   help text for the path
00064  *
00065  * @ingroup tripal_feature
00066  */
00067 function tripal_feature_help($path, $arg) {
00068    $output = '';
00069    switch ($path) {
00070       case "admin/help#tripal_feature":
00071          $output='<p>'.t("Displays links to nodes created on this date").'</p>';
00072          break;
00073    }
00074    return $output;
00075 }
00076 
00077 /**
00078  *  Provide information to drupal about the node types that we're creating
00079  *  in this module
00080  *
00081  * @ingroup tripal_feature
00082  */
00083 function tripal_feature_node_info() {
00084    $nodes = array();
00085 
00086    $nodes['chado_feature'] = array(
00087       'name' => t('Feature'),
00088       'module' => 'chado_feature',
00089       'description' => t('A feature from the chado database'),
00090       'has_title' => FALSE,
00091       'title_label' => t('Feature'),
00092       'has_body' => FALSE,
00093       'body_label' => t('Feature Description'),
00094       'locked' => TRUE
00095    );
00096    return $nodes;
00097 }
00098 
00099 /**
00100  *  Set the permission types that the chado module uses.  Essentially we
00101  *  want permissionis that protect creation, editing and deleting of chado
00102  *  data objects
00103  *
00104  * @ingroup tripal_feature
00105  */
00106 function tripal_feature_perm(){
00107    return array(
00108       'access chado_feature content',
00109       'create chado_feature content',
00110       'delete chado_feature content',
00111       'edit chado_feature content',
00112       'manage chado_feature aggregator',
00113    );
00114 }
00115 
00116 /**
00117  *  Set the permission types that the module uses.
00118  *
00119  * @ingroup tripal_feature
00120  */
00121 function chado_feature_access($op, $node, $account) {
00122    if ($op == 'create') {
00123       return user_access('create chado_feature content', $account);
00124    }
00125 
00126    if ($op == 'update') {
00127       if (user_access('edit chado_feature content', $account)) {
00128          return TRUE;
00129       }
00130    }
00131    if ($op == 'delete') {
00132       if (user_access('delete chado_feature content', $account)) {
00133          return TRUE;
00134       }
00135    }
00136    if ($op == 'view') {
00137       if (user_access('access chado_feature content', $account)) {
00138          return TRUE;
00139       }
00140    }
00141    return FALSE;
00142 }
00143 /**
00144  *  Menu items are automatically added for the new node types created
00145  *  by this module to the 'Create Content' Navigation menu item.  This function
00146  *  adds more menu items needed for this module.
00147  *
00148  * @ingroup tripal_feature
00149  */
00150 function tripal_feature_menu() {
00151    $items = array();
00152 
00153    // the administative settings menu
00154    $items['admin/tripal/tripal_feature'] = array(
00155      'title' => 'Features',
00156      'description' => 'Basic Description of Tripal Organism Module Functionality',
00157      'page callback' => 'tripal_feature_module_description_page',
00158      'access arguments' => array('administer site configuration'),
00159      'type' => MENU_NORMAL_ITEM,
00160    );
00161    $items['admin/tripal/tripal_feature/configuration'] = array(
00162      'title' => 'Feature Configuration',
00163      'description' => 'Settings for Chado Features',
00164      'page callback' => 'drupal_get_form',
00165      'page arguments' => array('tripal_feature_admin'),
00166      'access arguments' => array('administer site configuration'),
00167      'type' => MENU_NORMAL_ITEM,
00168    );
00169    $items['admin/tripal/tripal_feature/fasta_loader'] = array(
00170      'title' => 'Import a multi-FASTA file',
00171      'description' => 'Load sequences from a multi-FASTA file into Chado',
00172      'page callback' => 'drupal_get_form',
00173      'page arguments' => array('tripal_feature_fasta_load_form'),
00174      'access arguments' => array('administer site configuration'),
00175      'type' => MENU_NORMAL_ITEM,
00176    );
00177    $items['admin/tripal/tripal_feature/gff3_load'] = array(
00178      'title' => 'Import a GFF3 file',
00179      'description' => 'Import a GFF3 file into Chado',
00180      'page callback' => 'drupal_get_form',
00181      'page arguments' => array('tripal_core_gff3_load_form'),
00182      'access arguments' => array('access administration pages'),
00183      'type' => MENU_NORMAL_ITEM,
00184    );  
00185 
00186   // Adding Secondary Properties
00187 
00188 
00189   $items['node/%tf_node/tf_properties'] = array(       
00190     'title' => t('Add Properties & Synonyms'),                         
00191     'description' => t('Settings for Features'),
00192     'page callback' => 'tripal_feature_add_ALL_property_page',           
00193     'page arguments' => array(1), 
00194     'access arguments' => array('create chado_feature content'),
00195     'type' => MENU_CALLBACK
00196   ); 
00197 
00198   $items['node/%tf_node/tf_db_references'] = array(                        
00199     'title' => t('Add Database References'),                   
00200     'description' => t('Settings for Features'),              
00201     'page callback' => 'tripal_feature_add_ALL_dbreferences_page',                         
00202     'page arguments' => array(1),
00203     'access arguments' => array('create chado_feature content'),
00204     'type' => MENU_CALLBACK
00205   ); 
00206 
00207   $items['node/%tf_node/tf_relationships'] = array(                      
00208     'title' => t('Add Relationships'),                      
00209     'description' => t('Settings for Features'),               
00210     'page callback' => 'tripal_feature_add_ALL_relationships_page',                          
00211     'page arguments' => array(1),
00212     'access arguments' => array('create chado_feature content'),
00213     'type' => MENU_CALLBACK
00214   );
00215   //Edit/Deleting Secondary Properties-------------
00216 /**
00217   $items['node/%tf_node/tf_edit_properties'] = array(
00218     'title' => t('Edit Properties'),
00219     'description' => t('Settings for Features'),
00220     'page callback' => 'tripal_feature_edit_ALL_properties_page',
00221     'page arguments' => array(1),
00222     'access arguments' => array('edit chado_feature content'),
00223     'type' => MENU_LOCAL_TASK,
00224     'weight' => 8,
00225   );
00226 
00227     $items['node/%tf_node/tf_edit_relationships'] = array(
00228     'title' => t('Edit Relationships'),
00229     'description' => t('Settings for Feature'), 
00230     'page callback' => 'tripal_feature_edit_ALL_relationships_page',
00231     'page arguments' => array(1),
00232     'access arguments' => array('edit chado_feature content'),
00233     'type' => MENU_LOCAL_TASK,
00234     'weight' => 9,
00235   );
00236 */
00237   $items['node/%tf_node/tf_edit_db_references'] = array(
00238     'title' => t('Edit References'),
00239     'description' => t('Settings for Feature'),
00240     'page callback' => 'tripal_feature_edit_ALL_dbreferences_page',
00241     'page arguments' => array(1),
00242     'access arguments' => array('edit chado_feature content'),
00243     'type' => MENU_LOCAL_TASK,
00244     'weight' => 10,
00245   );
00246 
00247  // managing relationship aggregates
00248    $items['admin/tripal/tripal_feature/aggregate'] = array(
00249      'title' => 'Feature Relationship Aggegators',
00250      'description' => t('Features have relationships with other features and it may be desirable to aggregate the content from one ore more child or parent feature.'),
00251      'page callback' => 'tripal_feature_aggregator_page',
00252      'access arguments' => array('manage chado_feature aggregator'),
00253      'type' => MENU_NORMAL_ITEM,
00254    );
00255 
00256    $items['admin/tripal/tripal_feature/aggregate/new'] = array(
00257      'title' => 'Add an Aggregator',
00258      'page callback' => 'drupal_get_form',
00259      'page arguments' => array('tripal_feature_aggregator_form'),
00260      'access arguments' => array('manage chado_feature aggregator'),
00261      'type' => MENU_NORMAL_ITEM,
00262    );
00263    $items['admin/tripal/tripal_feature/aggregate/edit/js'] = array(
00264      'title' => 'Edit an Aggegator',
00265      'page callback' => 'tripal_feature_aggregator_ajax_edit',
00266      'access arguments' => array('manage chado_feature aggregator'),
00267      'type' => MENU_CALLBACK,
00268    );
00269 
00270    return $items;
00271 }
00272 
00273 /**
00274  * Implements Menu wildcard_load hook
00275  * Purpose: Allows the node ID of a chado feature to be dynamically 
00276  *   pulled from the path. The node is loaded from this node ID
00277  *   and supplied to the page as an arguement
00278  *
00279  * @ingroup tripal_feature
00280  */
00281 function tf_node_load($nid) {
00282   if (is_numeric($nid)) {
00283     $node = node_load($nid);
00284     if ($node->type == 'chado_feature') {
00285       return $node;
00286     }
00287   }
00288   return FALSE;
00289 }
00290 /**
00291  *
00292  *
00293  * @ingroup tripal_feature
00294  */
00295 function tripal_feature_block($op = 'list', $delta = 0, $edit=array()){
00296    switch($op) {
00297       case 'list':
00298          $blocks['references']['info'] = t('Tripal Feature References');
00299          $blocks['references']['cache'] = BLOCK_NO_CACHE;
00300 
00301          $blocks['base']['info'] = t('Tripal Feature Details');
00302          $blocks['base']['cache'] = BLOCK_NO_CACHE;
00303 
00304          $blocks['sequence']['info'] = t('Tripal Feature Sequence');
00305          $blocks['sequence']['cache'] = BLOCK_NO_CACHE;
00306 
00307          $blocks['synonyms']['info'] = t('Tripal Feature Synonyms');
00308          $blocks['synonyms']['cache'] = BLOCK_NO_CACHE;
00309 
00310          $blocks['properties']['info'] = t('Tripal Feature Properties');
00311          $blocks['properties']['cache'] = BLOCK_NO_CACHE;;
00312 
00313          $blocks['featureloc_sequences']['info'] = t('Tripal Formatted Sequence');
00314          $blocks['featureloc_sequences']['cache'] = BLOCK_NO_CACHE;
00315 
00316          $blocks['alignments']['info'] = t('Tripal Feature Alignments');
00317          $blocks['alignments']['cache'] = BLOCK_NO_CACHE;
00318 
00319          $blocks['relationships']['info'] = t('Tripal Feature Relationships');
00320          $blocks['relationships']['cache'] = BLOCK_NO_CACHE;
00321 
00322          $blocks['org_feature_counts']['info'] = t('Tripal Organism Feature Counts');
00323          $blocks['org_feature_counts']['cache'] = BLOCK_NO_CACHE;
00324 
00325          $blocks['org_feature_browser']['info'] = t('Tripal Organism Feature Browser');
00326          $blocks['org_feature_browser']['cache'] = BLOCK_NO_CACHE;
00327          return $blocks;
00328 
00329 
00330       case 'view':
00331          if(user_access('access chado_feature content') and arg(0) == 'node' and is_numeric(arg(1))) {
00332             $nid = arg(1);
00333             $node = node_load($nid);
00334  
00335             $block = array();
00336             switch($delta){
00337                case 'references':
00338                   $block['subject'] = t('References');
00339                   $block['content'] = theme('tripal_feature_references',$node);
00340                   break;
00341                case 'base':
00342                   $block['subject'] = t('Feature Details');
00343                   $block['content'] = theme('tripal_feature_base',$node);
00344                   break;
00345                case 'synonyms':
00346                   $block['subject'] = t('Synonyms');
00347                   $block['content'] = theme('tripal_feature_synonyms',$node);
00348                   break;
00349                case 'properties':
00350                   $block['subject'] = t('Properties');
00351                   $block['content'] = theme('tripal_feature_properties',$node);
00352                   break;;
00353                case 'sequence':
00354                   $block['subject'] = t('Sequence');
00355                   $block['content'] = theme('tripal_feature_sequence',$node);
00356                   break;
00357                case 'featureloc_sequences':
00358                   $block['subject'] = t('Formatted Sequences');
00359                   $block['content'] = theme('tripal_feature_featureloc_sequences',$node);
00360                   break;
00361                case 'alignments':
00362                   $block['subject'] = t('Alignments');
00363                   $block['content'] = theme('tripal_feature_featurelocs',$node);
00364                   break;
00365                case 'relationships':
00366                   $block['subject'] = t('Relationships');
00367                   $block['content'] = theme('tripal_feature_relationships',$node);
00368                   break;
00369                case 'org_feature_counts':
00370                   $block['subject'] = t('Feature Type Summary');
00371                   $block['content'] = theme('tripal_organism_feature_counts', $node);
00372                   break;
00373                case 'org_feature_browser':
00374                   $block['subject'] = t('Feature Browser');
00375                   $block['content'] = theme('tripal_organism_feature_browser', $node);
00376                   break;
00377                default :
00378             }
00379             return $block;
00380          }
00381 
00382    }
00383 }
00384 /**
00385  *  When a new chado_feature node is created we also need to add information
00386  *  to our chado_feature table.  This function is called on insert of a new node
00387  *  of type 'chado_feature' and inserts the necessary information.
00388  *
00389  * @ingroup tripal_feature
00390  */
00391 function chado_feature_insert($node){
00392    // remove spaces, newlines from residues
00393    $residues = preg_replace("/[\n\r\s]/","",$node->residues);
00394    $obsolete = 'FALSE';
00395    if($node->is_obsolete){
00396       $obsolete = 'TRUE';
00397    }
00398    $values = array(
00399       'cv_id' => array(
00400          'name' => 'sequence'
00401       ),
00402       'name' => $node->feature_type
00403    );
00404    $type = tripal_core_chado_select('cvterm',array('cvterm_id'),$values);
00405    $values = array(
00406       'organism_id' => $node->organism_id,
00407       'name' => $node->fname,
00408       'uniquename' => $node->uniquename,
00409       'residues' => $residues,
00410       'seqlen' => strlen($residues),
00411       'is_obsolete' => $obsolete,
00412       'type_id' => $type[0]->cvterm_id,
00413       'md5checksum' => md5($residues)
00414    );
00415 
00416    $istatus = tripal_core_chado_insert('feature', $values);
00417    if (!$istatus) {
00418     drupal_set_message('Unable to add feature.', 'warning');
00419     watchdog('tripal_organism', 
00420       'Insert feature: Unable to create feature where values: %values', 
00421       array('%values' => print_r($values, TRUE)),
00422       WATCHDOG_WARNING
00423     );
00424   }  
00425    $values = array(
00426       'organism_id' => $node->organism_id,
00427       'uniquename' => $node->uniquename,
00428       'type_id' => $type[0]->cvterm_id,
00429    );
00430    $feature = tripal_core_chado_select('feature',array('feature_id'),$values);   
00431    // add the genbank accession and synonyms
00432    chado_feature_add_synonyms($node->synonyms,$feature[0]->feature_id);
00433 
00434    // make sure the entry for this feature doesn't already exist in the chado_feature table
00435    // if it doesn't exist then we want to add it.
00436    $node_check_sql = "SELECT * FROM {chado_feature} ".
00437                      "WHERE feature_id = '%s'";
00438    $node_check = db_fetch_object(db_query($node_check_sql,$feature[0]->feature_id));
00439    if(!$node_check){
00440       // next add the item to the drupal table
00441       $sql = "INSERT INTO {chado_feature} (nid, vid, feature_id, sync_date) ".
00442              "VALUES (%d, %d, %d, " . time() . ")";
00443       db_query($sql,$node->nid,$node->vid,$feature[0]->feature_id);
00444    }
00445 }
00446 /**
00447  *
00448  *
00449  * @ingroup tripal_feature
00450  */
00451 function chado_feature_update($node){
00452    if($node->revision){
00453       // TODO -- decide what to do about revisions
00454    } else {
00455       $residues = preg_replace("/[\n\r\s]/","",$node->residues);
00456       $obsolete = 'FALSE';
00457       if($node->is_obsolete){
00458          $obsolete = 'TRUE';
00459       }
00460 
00461       // get the feature type id
00462       $values = array(
00463          'cv_id' => array(
00464             'name' => 'sequence'
00465          ),
00466          'name' => $node->feature_type
00467       );
00468       $type = tripal_core_chado_select('cvterm',array('cvterm_id'),$values);
00469 
00470       $feature_id = chado_get_id_for_node('feature',$node) ;
00471 
00472       if(sizeof($type) > 0){
00473          $match = array(
00474             'feature_id' => $feature_id,
00475          );     
00476          $values = array(
00477             'organism_id' => $node->organism_id,
00478             'name' => $node->fname,
00479             'uniquename' => $node->uniquename,
00480             'residues' => $residues,
00481             'seqlen' => strlen($residues),
00482             'is_obsolete' => $obsolete,
00483             'type_id' => $type[0]->cvterm_id,
00484             'md5checksum' => md5($residues)
00485          );
00486          $status = tripal_core_chado_update('feature', $match,$values); 
00487 
00488          // add the genbank synonyms
00489          chado_feature_add_synonyms($node->synonyms,$feature_id);
00490       }    
00491       else {
00492        drupal_set_message('Unable to update feature.', 'warning');
00493        watchdog('tripal_organism', 
00494          'Update feature: Unable to update feature where values: %values', 
00495          array('%values' => print_r($values, TRUE)),
00496          WATCHDOG_WARNING
00497        );
00498       }
00499    }
00500 }
00501 /**
00502  *
00503  *
00504  * @ingroup tripal_feature
00505  */
00506 function chado_feature_delete($node){
00507 
00508    $feature_id  = chado_get_id_for_node('feature',$node);
00509 
00510    // remove the drupal content  
00511    $sql_del = "DELETE FROM {chado_feature} ".
00512               "WHERE nid = %d ".
00513               "AND vid = %d";
00514    db_query($sql_del, $node->nid, $node->vid);
00515    $sql_del = "DELETE FROM {node} ".
00516               "WHERE nid = %d ".
00517               "AND vid = %d";
00518    db_query($sql_del, $node->nid, $node->vid);
00519    $sql_del = "DELETE FROM {node_revisions} ".
00520               "WHERE nid = %d ".
00521               "AND vid = %d";
00522    db_query($sql_del, $node->nid, $node->vid);
00523 
00524 
00525    // Remove data from feature tables of chado database.  This will
00526    // cause a cascade delete and remove all data in referencing tables
00527    // for this feature
00528    $previous_db = tripal_db_set_active('chado');
00529    db_query("DELETE FROM {feature} WHERE feature_id = %d", $feature_id);
00530    tripal_db_set_active($previous_db);
00531    
00532    drupal_set_message("The feature and all associated data were removed from ".
00533       "chado");
00534 
00535 }
00536 /**
00537  *
00538  *
00539  * @ingroup tripal_feature
00540  */
00541 function chado_feature_add_synonyms($synonyms,$feature_id){
00542 
00543    // make sure we only have a single space between each synonym
00544    $synonyms = preg_replace("/[\s\n\r]+/"," ",$synonyms);
00545    // split the synonyms into an array based on a space as the delimieter
00546    $syn_array = array();
00547    $syn_array = explode(" ",$synonyms);
00548 
00549    // use the chado database
00550    $previous_db = tripal_db_set_active('chado');
00551 
00552    // remove any old synonyms
00553    $feature_syn_dsql = "DELETE FROM {feature_synonym} WHERE feature_id = %d";
00554    if(!db_query($feature_syn_dsql,$feature_id)){
00555       $error .= "Could not remove synonyms from feature. ";
00556    }
00557 
00558    // return if we don't have any synonmys to add
00559    if(!$synonyms){
00560       tripal_db_set_active($previous_db);
00561       return;
00562    }
00563    // iterate through each synonym and add it to the database
00564    foreach($syn_array as $syn){
00565       // skip this item if it's empty
00566       if(!$syn){ break; }
00567 
00568       // check to see if we have this accession number already in the database
00569       // if so then don't add it again. it messes up drupal if the insert fails.
00570       // It is possible for the accession number to be present and not the feature
00571       $synonym_sql = "SELECT synonym_id FROM {synonym} ".
00572                      "WHERE name = '%s'";
00573       $synonym = db_fetch_object(db_query($synonym_sql,$syn));
00574       if(!$synonym){
00575          $synonym_isql = "INSERT INTO {synonym} (name,synonym_sgml,type_id) ".
00576                          "VALUES ('%s','%s', ".
00577                          "   (SELECT cvterm_id ".
00578                          "    FROM {CVTerm} CVT ".
00579                          "    INNER JOIN CV ON CVT.cv_id = CV.cv_id ".
00580                          "    WHERE CV.name = 'feature_property' and CVT.name = 'synonym'))";
00581          if(!db_query($synonym_isql,$syn,$syn)){
00582             $error .= "Could not add synonym. ";
00583          }
00584          // now get the synonym we just added
00585          $synonym_sql = "SELECT synonym_id FROM {synonym} ".
00586                         "WHERE name = '%s'";
00587          $synonym = db_fetch_object(db_query($synonym_sql,$syn));
00588       }
00589 
00590       // now add in our new sysnonym
00591       $feature_syn_isql = "INSERT INTO {feature_synonym} (synonym_id,feature_id,pub_id) ".
00592                           "VALUES (%d,%d,1)";
00593       if(!db_query($feature_syn_isql,$synonym->synonym_id,$feature_id)){
00594          $error .= "Could not add synonyms to feature. ";
00595       }
00596    }
00597 
00598    // return to the drupal database
00599    tripal_db_set_active($previous_db);
00600    return $error;
00601 
00602 }
00603 /**
00604  *
00605  *
00606  * @ingroup tripal_feature
00607  */
00608 function chado_feature_add_gbaccession($accession,$feature_id){
00609 
00610    // use chado database
00611    $previous_db = tripal_db_set_active('chado');
00612 
00613    // remove any old accession from genbank dbEST
00614    $fdbxref_dsql = "DELETE FROM {feature_dbxref} ".
00615                    "WHERE feature_id = %d and dbxref_id IN ".
00616                    "   (SELECT DBX.dbxref_id FROM {dbxref} DBX ".
00617                    "    INNER JOIN DB  ON DB.db_id = DBX.db_id ".
00618                    "    INNER JOIN feature_dbxref FDBX ON DBX.dbxref_id = FDBX.dbxref_id ".
00619                    "    WHERE DB.name = 'DB:Genbank' and FDBX.feature_id = %d)";
00620    if(!db_query($fdbxref_dsql,$feature_id,$feature_id)){
00621       $error .= "Could not remove accession from feature. ";
00622    }
00623 
00624    // if we don't have an accession number to add then just return
00625    if(!$accession){
00626       tripal_db_set_active($previous_db);
00627       return;
00628    }
00629    // get the db_id
00630    $db_sql = "SELECT db_id FROM {DB} ".
00631              "WHERE name = 'DB:Genbank_est'";
00632    $db = db_fetch_object(db_query($db_sql));
00633 
00634    // check to see if we have this accession number already in the database
00635    // if so then don't add it again. it messes up drupal if the insert fails.
00636    // It is possible for the accession number to be present and not the feature
00637    $dbxref_sql = "SELECT dbxref_id FROM {dbxref} ".
00638                  "WHERE db_id = %d and accession = '%s'";
00639    $dbxref = db_fetch_object(db_query($dbxref_sql,$db->db_id,$accession));
00640    if(!$dbxref){
00641       // add the accession number
00642       $dbxref_isql = "INSERT INTO {dbxref} (db_id,accession) ".
00643                      "  VALUES (%d, '%s') ";
00644       if(!db_query($dbxref_isql,$db->db_id,$accession)){
00645          $error .= 'Could not add accession as a database reference ';
00646       }
00647       // get the dbxref_id for the just added accession number
00648       $dbxref_sql = "SELECT dbxref_id FROM {dbxref} ".
00649                     "WHERE db_id = %d and accession = '%s'";
00650       $dbxref = db_fetch_object(db_query($dbxref_sql,$db->db_id,$accession));
00651    }
00652 
00653 
00654    // associate the accession number with the feature
00655    $feature_dbxref_isql = "INSERT INTO {feature_dbxref} (feature_id,dbxref_id) ".
00656                           "  VALUES (%d, %d) ";
00657    if(!db_query($feature_dbxref_isql,$feature_id,$dbxref->dbxref_id)){
00658       $error .= 'Could not add feature database reference. ';
00659    }
00660 
00661    tripal_db_set_active($previous_db);
00662    return $error;
00663 }
00664 
00665 /**
00666  *
00667  *
00668  * @ingroup tripal_feature
00669  */
00670 function chado_feature_form ($node,$param){
00671 
00672    $type = node_get_types('type', $node);
00673    $form = array();
00674 
00675    $feature = $node->feature;
00676 
00677    // add the residues to the feature object
00678    $feature = tripal_core_expand_chado_vars($feature,'field','feature.residues');
00679 
00680    // if the node has synonyms then use that as the form may be returning
00681    // from an error.  Otherwise try to find synonyms from the database
00682    $synonyms = $node->synonyms;
00683    $feature = tripal_core_expand_chado_vars($feature,'table','feature_synonym');
00684    $feature_synonyms = $feature->feature_synonym;
00685    if(!$synonyms){
00686       if (!is_array($feature_synonyms)) {
00687          $synonyms = $feature_synonyms->synonym_id->name;
00688       } 
00689       elseif(is_array($feature_synonyms)) { 
00690          foreach($feature_synonyms as $index => $synonym){
00691             $synonyms .= $synonym->synonym_id->name ."\n";
00692          }
00693       }
00694    }
00695 
00696    $analyses = $node->analyses;
00697    $references = $node->references;
00698 
00699    // We need to pass above variables for preview to show
00700    $form['feature'] = array(
00701       '#type' => 'value',
00702       '#value' => $feature
00703    );
00704    // This field is read when previewing a node
00705    $form['synonyms'] = array(
00706       '#type' => 'value',
00707       '#value' => $synonyms
00708    );
00709    // This field is read when previewing a node
00710    $form['analyses'] = array(
00711       '#type' => 'value',
00712       '#value' => $analyses
00713    );
00714    // This field is read when previewing a node
00715    $form['references'] = array(
00716       '#type' => 'value',
00717       '#value' => $references
00718    );
00719 
00720    // keep track of the feature id if we have one.  If we do have one then
00721    // this would indicate an update as opposed to an insert.
00722    $form['feature_id'] = array(
00723       '#type' => 'value',
00724       '#value' => $feature->feature_id,
00725    );
00726 
00727    $form['title']= array(
00728       '#type' => 'textfield',
00729       '#title' => t('Title'),
00730       '#required' => TRUE,
00731       '#default_value' => $node->title,
00732       '#description' => t('The title must be a unique identifier for this feature.  It is recommended to use a combination of uniquename, organism and feature type in the title as this is guranteed to be unique.'),
00733       '#weight' => 1,
00734       '#maxlength' => 255
00735    );
00736 
00737    $form['uniquename']= array(
00738       '#type' => 'textfield',
00739       '#title' => t('Unique Feature Name'),
00740       '#required' => TRUE,
00741       '#default_value' => $feature->uniquename,
00742       '#description' => t('Enter a unique name for this feature.  This name must be unique for the organism and feature type.'),
00743       '#weight' => 1,
00744       '#maxlength' => 255
00745    );
00746 
00747    $form['fname']= array(
00748       '#type' => 'textfield',
00749       '#title' => t('Feature Name'),
00750       '#required' => TRUE,
00751       '#default_value' => $feature->name,
00752       '#description' => t('Enter the name used by humans to refer to this feature.'),
00753       '#weight' => 1,
00754       '#maxlength' => 255
00755    );
00756 
00757    // get the list of supported feature types
00758    $ftypes = array();
00759    $ftypes[''] = '';
00760    $supported_ftypes = split("[ \n]",variable_get('chado_feature_types','EST contig'));
00761    foreach($supported_ftypes as $ftype){
00762       $ftypes["$ftype"] = $ftype;
00763    }
00764 
00765    $form['feature_type'] = array (
00766      '#title'       => t('Feature Type'),
00767      '#type'        => t('select'),
00768      '#description' => t("Choose the feature type."),
00769      '#required'    => TRUE,
00770      '#default_value' => $feature->type_id->name,
00771      '#options'     => $ftypes,
00772      '#weight'      => 2
00773    );
00774    // get the list of organisms
00775    $sql = "SELECT * FROM {Organism} ORDER BY genus, species";
00776    $previous_db = tripal_db_set_active('chado');  // use chado database
00777    $org_rset = db_query($sql);
00778    tripal_db_set_active($previous_db);  // now use drupal database
00779 
00780    //
00781    $organisms = array();
00782    $organisms[''] = '';
00783    while($organism = db_fetch_object($org_rset)){
00784       $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
00785    }
00786 
00787    $form['organism_id'] = array (
00788      '#title'       => t('Organism'),
00789      '#type'        => t('select'),
00790      '#description' => t("Choose the organism with which this feature is associated "),
00791      '#required'    => TRUE,
00792      '#default_value' => $feature->organism_id->organism_id,
00793      '#options'     => $organisms,
00794      '#weight'      => 3,
00795    );
00796 
00797    // Get synonyms
00798    if ($synonyms) {
00799       if (is_array($synonyms)) {
00800          foreach ($synonyms as $synonym){
00801             $syn_text .= "$synonym->name\n";
00802          }
00803       } else {
00804          $syn_text = $synonyms;
00805       }
00806    }
00807    $form['synonyms']= array(
00808       '#type' => 'textarea',
00809       '#title' => t('Synonyms'),
00810       '#required' => FALSE,
00811       '#default_value' => $syn_text,
00812       '#description' => t('Enter alternate names (synonmys) for this feature to help in searching and identification. You may enter as many alternate names as needed separated by spaces or on different lines.'),
00813       '#weight' => 5,
00814    );
00815 
00816    $form['residues']= array(
00817       '#type' => 'textarea',
00818       '#title' => t('Residues'),
00819       '#required' => FALSE,
00820       '#default_value' => $feature->residues,
00821       '#description' => t('Enter the nucelotide sequences for this feature'),
00822       '#weight' => 6
00823    );
00824 
00825    $checked = '';
00826    if($feature->is_obsolete == 't'){
00827       $checked = '1';
00828    }
00829    $form['is_obsolete']= array(
00830       '#type' => 'checkbox',
00831       '#title' => t('Is Obsolete'),
00832       '#required' => FALSE,
00833       '#default_value' => $checked,
00834       '#description' => t('Check this box if this sequence should be retired and no longer included in further analysis.'),
00835       '#weight' => 8
00836    );
00837    return $form;
00838 }
00839 /**
00840  *
00841  *
00842  * @ingroup tripal_feature
00843  */
00844 function chado_feature_validate($node){
00845    $result = 0;
00846 
00847    // if this is an update, we want to make sure that a different feature for
00848    // the organism doesn't already have this uniquename. We don't want to give
00849    // two sequences the same uniquename
00850    if($node->feature_id){
00851       $sql = "SELECT * 
00852               FROM {Feature} F
00853                 INNER JOIN {cvterm} CVT ON F.type_id = CVT.cvterm_id
00854               WHERE uniquename = '%s' 
00855                AND organism_id = %d AND CVT.name = '%s' AND NOT feature_id = %d";
00856       $previous_db = tripal_db_set_active('chado');
00857       $result = db_fetch_object(db_query($sql, $node->uniquename,$node->organism_id,$node->feature_type,$node->feature_id));
00858       tripal_db_set_active($previous_db);
00859       if($result){
00860          form_set_error('uniquename',t("Feature update cannot proceed. The feature name '$node->uniquename' is not unique for this organism. Please provide a unique name for this feature. "));
00861       }
00862    }
00863 
00864    // if this is an insert then we just need to make sure this name doesn't
00865    // already exist for this organism if it does then we need to throw an error
00866    else {
00867       $sql = "SELECT * 
00868               FROM {Feature} F
00869                 INNER JOIN {cvterm} CVT ON F.type_id = CVT.cvterm_id
00870               WHERE uniquename = '%s' 
00871                AND organism_id = %d AND CVT.name = '%s'";
00872       $previous_db = tripal_db_set_active('chado');
00873       $result = db_fetch_object(db_query($sql, $node->uniquename,$node->organism_id,$node->feature_type));
00874       tripal_db_set_active($previous_db);
00875       if($result){
00876          form_set_error('uniquename',t("Feature insert cannot proceed. The feature name '$node->uniquename' already exists for this organism. Please provide a unique name for this feature. "));
00877       }
00878    }
00879 
00880    // we want to remove all characters except IUPAC nucleotide characters from the
00881    // the residues. however, residues are not required so if blank then we'll skip
00882    // this step
00883    if($node->residues){
00884       $residues = preg_replace("/[^\w]/",'',$node->residues);
00885       if(!preg_match("/^[ACTGURYMKSWBDHVN]+$/i",$residues)){
00886          form_set_error('residues',t("The residues in feature $node->name contains more than the nucleotide IUPAC characters. Only the following characters are allowed: A,C,T,G,U,R,Y,M,K,S,W,B,D,H,V,N: '" . $residues ."'"));
00887       }
00888    }
00889 
00890    // we don't allow a genbank accession number for a contig
00891    if($node->feature_type == 'contig' and $node->gbaccession){
00892       form_set_error('gbaccession',t("Contigs cannot have a genbank accession number.  Please change the feature type or remove the accession number"));
00893    }
00894 
00895 }
00896 /**
00897  *  When a node is requested by the user this function is called to allow us
00898  *  to add auxiliary data to the node object.
00899  *
00900  * @ingroup tripal_feature
00901  */
00902 function chado_feature_load($node){
00903    // get the feature details from chado
00904    $feature_id = chado_get_id_for_node('feature',$node);
00905 
00906    $values = array('feature_id' => $feature_id);
00907    $feature = tripal_core_generate_chado_var('feature',$values);
00908 
00909    $additions->feature = $feature;
00910    return $additions;
00911 }
00912 /**
00913  *  
00914  *
00915  * @ingroup tripal_feature
00916  */
00917 function tripal_feature_load_organism ($organism_id){
00918    // add organism details
00919    $sql = "SELECT * FROM {organism} WHERE organism_id = %d";
00920    $previous_db = tripal_db_set_active('chado');  // use chado database
00921    $organism = db_fetch_object(db_query($sql,$organism_id));
00922    tripal_db_set_active($previous_db);  // now use drupal database
00923    return $organism;
00924 }
00925 /**
00926  *  
00927  *
00928  * @ingroup tripal_feature
00929  */
00930 function tripal_feature_load_synonyms ($feature_id){
00931 
00932    $sql = "SELECT S.name ".
00933           "FROM {Feature_Synonym} FS ".
00934           "  INNER JOIN {Synonym} S ".
00935           "    ON FS.synonym_id = S.Synonym_id ".
00936           "WHERE FS.feature_id = %d ".
00937           "ORDER BY S.name ";
00938    $previous_db = tripal_db_set_active('chado');  // use chado database
00939    $results = db_query($sql,$feature_id);
00940    tripal_db_set_active($previous_db);  // now use drupal database
00941    $synonyms = array();
00942    $i=0;
00943    while($synonym = db_fetch_object($results)){
00944       $synonyms[$i++] = $synonym;
00945    }
00946    return $synonyms;
00947 }
00948 /**
00949  * 
00950  *
00951  * @ingroup tripal_feature
00952  */
00953 function tripal_feature_load_properties ($feature_id){
00954 
00955    $sql = "SELECT CVT.name as cvname, FS.type_id, FS.value, FS.rank,
00956              CVT.definition, CVT.is_obsolete, 
00957              DBX.dbxref_id,DBX.accession,DB.name as dbname, 
00958              DB.urlprefix, DB.description as db_description, DB.url
00959            FROM {featureprop} FS 
00960              INNER JOIN {cvterm} CVT ON FS.type_id = CVT.cvterm_id
00961              INNER JOIN {dbxref} DBX ON CVT.dbxref_id = DBX.dbxref_id
00962              INNER JOIN {db} DB      ON DB.db_id = DBX.db_id
00963            WHERE FS.feature_id = %d
00964            ORDER BY FS.rank ASC";
00965    $previous_db = tripal_db_set_active('chado');  // use chado database
00966    $results = db_query($sql,$feature_id);
00967    tripal_db_set_active($previous_db);  // now use drupal database
00968    $i=0;
00969    $properties = array();
00970    while($property = db_fetch_object($results)){
00971       $properties[$i++] = $property;
00972    }
00973    return $properties;
00974 }
00975 /**
00976  *  
00977  *
00978  * @ingroup tripal_feature
00979  */
00980 function tripal_feature_load_references ($feature_id){
00981 
00982    $sql = "SELECT F.uniquename,F.Feature_id,DBX.accession,DB.description as dbdesc, ".
00983           "   DB.db_id, DB.name as db_name, DB.urlprefix,DBX.dbxref_id ".
00984           "FROM {feature} F ".
00985           "  INNER JOIN {feature_dbxref} FDBX on F.feature_id = FDBX.feature_id ".
00986           "  INNER JOIN {dbxref} DBX on DBX.dbxref_id = FDBX.dbxref_id ".
00987           "  INNER JOIN {db} on DB.db_id = DBX.db_id ".
00988           "WHERE F.feature_id = %d ".
00989           "ORDER BY DB.name ";
00990    $previous_db = tripal_db_set_active('chado');  // use chado database
00991    $results = db_query($sql,$feature_id);
00992    tripal_db_set_active($previous_db);  // now use drupal database
00993    $references = array();
00994    $i=0;
00995    while($accession = db_fetch_object($results)){
00996       $references[$i++] = $accession;
00997    }
00998    return $references;
00999 }
01000 /**
01001  *  
01002  *
01003  * @ingroup tripal_feature
01004  */
01005 function tripal_feature_load_featurelocs ($feature_id,$side = 'as_parent',$aggregate = 1){
01006 
01007    $sql = "SELECT 
01008              F.name, F.feature_id, F.uniquename,
01009              FS.name as src_name, 
01010              FS.feature_id as src_feature_id, 
01011              FS.uniquename as src_uniquename,
01012              CVT.name as cvname, CVT.cvterm_id,
01013              CVTS.name as src_cvname, CVTS.cvterm_id as src_cvterm_id,
01014              FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, 
01015              FL.phase
01016            FROM {featureloc} FL
01017               INNER JOIN {feature} F on FL.feature_id = F.feature_id
01018               INNER JOIN {feature} FS on FS.feature_id = FL.srcfeature_id
01019               INNER JOIN {cvterm} CVT on F.type_id = CVT.cvterm_id
01020               INNER JOIN {cvterm} CVTS on FS.type_id = CVTS.cvterm_id
01021            ";
01022    if(strcmp($side,'as_parent')==0){
01023       $sql .= "WHERE FL.srcfeature_id = %d ";
01024    }
01025    if(strcmp($side,'as_child')==0){
01026       $sql .= "WHERE FL.feature_id = %d ";
01027    }
01028 
01029    $previous_db = tripal_db_set_active('chado');  // use chado database
01030    $flresults = db_query($sql, $feature_id);
01031    tripal_db_set_active($previous_db);  // now use drupal database 
01032 
01033    // copy the results into an array
01034    $i=0;
01035    $featurelocs = array();
01036    while($loc = db_fetch_object($flresults)){
01037       // if a drupal node exists for this feature then add the nid to the
01038       // results object
01039       $sql = 'SELECT nid FROM {chado_feature} WHERE feature_id = %d';
01040 
01041       $ffeature = db_fetch_object(db_query($sql, $loc->feature_id));
01042       $sfeature = db_fetch_object(db_query($sql, $loc->src_feature_id));
01043       $loc->fnid = $ffeature->nid;
01044       $loc->snid = $sfeature->nid;
01045       // add the result to the array
01046       $featurelocs[$i++] = $loc;
01047    }
01048 
01049    // Add the relationship feature locs if aggregate is turned on
01050    if($aggregate and strcmp($side,'as_parent')==0){ 
01051       // get the relationships for this feature without substituting any children
01052       // for the parent. We want all relationships
01053       $relationships = tripal_feature_get_aggregate_relationships($feature_id,0);
01054       foreach($relationships as $rindex => $rel){ 
01055          // get the featurelocs for each of the relationship features
01056          $rel_featurelocs = tripal_feature_load_featurelocs ($rel->subject_id,'as_child',0);
01057          foreach($rel_featurelocs as $findex => $rfloc){
01058             $featurelocs[$i++] = $rfloc;
01059          }
01060       }
01061    } 
01062    
01063    usort($featurelocs,'tripal_feature_sort_locations');
01064    return $featurelocs;
01065 }
01066 /**
01067  *  used to sort the feature locs by start position
01068  *
01069  * @ingroup tripal_feature
01070  */
01071 function tripal_feature_sort_locations($a,$b){
01072    return strnatcmp($a->fmin, $b->fmin); 
01073 }
01074 /**
01075  *  
01076  *
01077  * @ingroup tripal_feature
01078  */
01079 function tripal_feature_load_relationships ($feature_id,$side = 'as_subject'){
01080    // get the relationships for this feature.  The query below is used for both
01081    // querying the object and subject relationships
01082    $sql = "SELECT 
01083              FS.name as subject_name, 
01084              FS.uniquename as subject_uniquename, 
01085              CVTS.name as subject_type,
01086              CVTS.cvterm_id as subject_type_id,
01087              FR.subject_id,          
01088              FR.type_id as relationship_type_id,
01089              CVT.name as rel_type,     
01090              FO.name as object_name, 
01091              FO.uniquename as object_uniquename, 
01092              CVTO.name as object_type,
01093              CVTO.cvterm_id as object_type_id,
01094              FR.object_id, 
01095              FR.rank
01096            FROM {feature_relationship} FR
01097              INNER JOIN {cvterm} CVT ON FR.type_id = CVT.cvterm_id
01098              INNER JOIN {feature} FS ON FS.feature_id = FR.subject_id
01099              INNER JOIN {feature} FO ON FO.feature_id = FR.object_id
01100              INNER JOIN {cvterm} CVTO ON FO.type_id = CVTO.cvterm_id
01101              INNER JOIN {cvterm} CVTS ON FS.type_id = CVTS.cvterm_id
01102    ";
01103    if(strcmp($side,'as_object')==0){
01104       $sql .= " WHERE FR.object_id = %d";
01105    }
01106    if(strcmp($side,'as_subject')==0){
01107       $sql .= " WHERE FR.subject_id = %d";
01108    }
01109    $sql .= " ORDER BY FR.rank";
01110 
01111    // get the relationships 
01112    $previous_db = tripal_db_set_active('chado');  // use chado database
01113    $results = db_query($sql, $feature_id);
01114    tripal_db_set_active($previous_db);  // now use drupal database
01115 
01116 
01117    // iterate through the relationships, put these in an array and add
01118    // in the Drupal node id if one exists
01119    $i=0;
01120    $nodesql = "SELECT nid FROM {chado_feature} WHERE feature_id = %d";
01121    $relationships = array();
01122    while($rel = db_fetch_object($results)){
01123      $node = db_fetch_object(db_query($nodesql,$rel->subject_id));
01124      if($node){
01125         $rel->subject_nid = $node->nid;
01126      }  
01127      $node = db_fetch_object(db_query($nodesql,$rel->object_id));
01128      if($node){
01129         $rel->object_nid = $node->nid;
01130      }  
01131      $relationships[$i++] = $rel;      
01132    }
01133    return $relationships;
01134 }
01135 /**
01136  *  
01137  *
01138  * @ingroup tripal_feature
01139  */
01140 function tripal_feature_get_aggregate_types($feature_id){
01141    // get the feature details
01142    $sql = 'SELECT type_id FROM {feature} WHERE feature_id = %d';
01143    $previous_db = tripal_db_set_active('chado');  // use chado database
01144    $feature = db_fetch_object(db_query($sql, $feature_id));
01145    tripal_db_set_active($previous_db);  // now use drupal database
01146 
01147    // check to see if this feature is of a type with an aggregate
01148    $sql = "SELECT * FROM {tripal_feature_relagg} WHERE type_id = %d";
01149    $types = array();
01150    $results = db_query($sql,$feature->type_id);
01151    while($agg = db_fetch_object($results)){
01152       $types[] = $agg->rel_type_id;
01153    }
01154    
01155    return $types;
01156 }
01157 /**
01158  *  
01159  *
01160  * @ingroup tripal_feature
01161  */
01162 function tripal_feature_get_aggregate_relationships($feature_id, $substitute=1,
01163   $levels=0, $base_type_id=NULL, $depth=0)
01164 {
01165 
01166    // we only want to recurse to as many levels deep as indicated by the 
01167    // $levels variable, but only if this variable is > 0. If 0 then we 
01168    // recurse until we reach the end of the relationships tree.
01169    if($levels > 0 and $levels == $depth){
01170       return NULL;
01171    }
01172 
01173    // first get the relationships for this feature
01174    $relationships = tripal_feature_load_relationships($feature_id,'as_object');
01175 
01176    // next, iterate through these relationships and descend, adding in those
01177    // that are specified by the aggregator.
01178    $i=0;
01179    $new_relationships = array();
01180    foreach($relationships as $rindex => $rel){
01181 
01182       // set the base type id 
01183       if(!$base_type_id){
01184          $base_type_id = $rel->object_type_id;
01185       } 
01186       // check to see if we have an aggregator for this base type
01187       $sql = "SELECT * FROM {tripal_feature_relagg} WHERE type_id = %d and rel_type_id = %d";
01188       $agg = db_fetch_object(db_query($sql,$base_type_id,$rel->subject_type_id));
01189       if($agg){
01190          // if we're not going to substitute the resulting relationships for the
01191          // parent then we need to add the parent to our list
01192          if(!$substitute){
01193             $new_relationships[$i++] = $rel;
01194          }
01195          // recurse all relationships 
01196          $agg_relationships = tripal_feature_get_aggregate_relationships(
01197             $rel->subject_id,$levels,$base_type_id,$depth++);
01198          // if we have an aggregate defined but we have no relationships beyond
01199          // this point then there's nothing we can substitute 
01200          if(!$agg_relationships and $substitute){
01201             $new_relationships[$i++] = $rel;
01202          }
01203 
01204          // merge all relationships into one array
01205          foreach($agg_relationships as $aindex => $arel){
01206             $new_relationships[$i++] = $arel;
01207          }  
01208       }  
01209       else {
01210          // if we don't have an aggregate then keep the current relationship
01211          $new_relationships[$i++] = $rel;
01212       }    
01213    } 
01214    return $new_relationships;
01215 }
01216 /**
01217  *  
01218  *
01219  * @ingroup tripal_feature
01220  */
01221 function tripal_feature_load_featureloc_sequences($feature_id,$featurelocs){
01222 
01223    // if we don't have any featurelocs then no point in continuing
01224    if(!$featurelocs){
01225       return array();
01226    }
01227 
01228    // get the list of relationships (including any aggregators) and iterate
01229    // through each one to find information needed to color-code the reference sequence
01230    $relationships = tripal_feature_get_aggregate_relationships($feature_id);
01231    if(!$relationships){
01232       return array();
01233    }
01234 
01235 
01236    // iterate through each of the realtionships features and get their 
01237    // locations
01238    foreach($relationships as $rindex => $rel){
01239       // get the featurelocs for each of the relationship features
01240       $rel_featurelocs = tripal_feature_load_featurelocs ($rel->subject_id,'as_child',0);   
01241       foreach($rel_featurelocs as $rfindex => $rel_featureloc){
01242          // keep track of this unique source feature
01243          $src = $rel_featureloc->src_feature_id ."-". $rel_featureloc->src_cvterm_id;
01244 
01245          // copy over the results to the relationship object.  Since there can
01246          // be more than one feature location for each relationship feature we 
01247          // use the '$src' variable to keep track of these.
01248          $rel->featurelocs->$src->src_uniquename = $rel_featureloc->src_uniquename;
01249          $rel->featurelocs->$src->src_cvterm_id  = $rel_featureloc->src_cvterm_id;
01250          $rel->featurelocs->$src->src_cvname     = $rel_featureloc->src_cvname;
01251          $rel->featurelocs->$src->fmin           = $rel_featureloc->fmin;
01252          $rel->featurelocs->$src->fmax           = $rel_featureloc->fmax;
01253          $rel->featurelocs->$src->src_name       = $rel_featureloc->src_name;
01254 
01255          // keep track of the individual parts for each relationship 
01256          $start = $rel->featurelocs->$src->fmin;
01257          $end   = $rel->featurelocs->$src->fmax;
01258          $rel_locs[$src]['parts'][$start]['type']  = $rel->subject_type;
01259          $rel_locs[$src]['parts'][$start]['start'] = $start;
01260          $rel_locs[$src]['parts'][$start]['end']   = $end;
01261       }
01262    }
01263 
01264    // the featurelocs array provided to the function contains the locations
01265    // where this feature is found.   We want to get the sequence for each 
01266    // location and then annotate it with the parts found from the relationships
01267    // locations determiend above. 
01268    $sql = "SELECT residues FROM {feature} WHERE feature_id = %d";
01269    $floc_sequences = array();
01270    foreach ($featurelocs as $featureloc){
01271       // get the residues for this feature
01272       $previous_db = tripal_db_set_active('chado');  // use chado database
01273       $feature = db_fetch_object(db_query($sql,$featureloc->srcfeature_id->feature_id));
01274       tripal_db_set_active($previous_db);  // now use drupal database
01275 
01276       $src = $featureloc->srcfeature_id->feature_id ."-". $featureloc->srcfeature_id->type_id->cvterm_id;
01277 
01278       // orient the parts to the beginning of the feature sequence
01279       $parts = $rel_locs[$src]['parts'];
01280       usort($parts, 'tripal_feature_sort_rel_parts');
01281       foreach ($parts as $start => $attrs){
01282          $parts[$start]['start'] = $parts[$start]['start'] - $featureloc->fmin;
01283          $parts[$start]['end']   = $parts[$start]['end'] - $featureloc->fmin;
01284       }      
01285       $floc_sequences[$src]['src'] = $src;
01286       $floc_sequences[$src]['type'] = $featureloc->feature_id->type_id->name;
01287       $sequence = substr($feature->residues,$featureloc->fmin-1,($featureloc->fmax - $featureloc->fmin)+1);
01288       $floc_sequences[$src]['formatted_seq'] =  tripal_feature_color_sequence (
01289           $sequence,$parts);
01290    }
01291    return $floc_sequences;
01292 }
01293 /**
01294  *  
01295  *
01296  * @ingroup tripal_feature
01297  */
01298 function tripal_feature_load_organism_feature_counts($organism){
01299 
01300    // don't show the browser if the settings in the admin page is turned off
01301    // instead return the array indicating the status of the browser
01302    $show_counts = variable_get('tripal_feature_summary_setting','show_feature_summary');
01303    if(strcmp($show_counts,'show_feature_summary')!=0){
01304       return array ('enabled' => false );
01305    }
01306 
01307    // get the feature counts.  This is dependent on a materialized view
01308    // installed with the organism module
01309    $sql = "
01310       SELECT OFC.num_features,OFC.feature_type,CVT.definition
01311       FROM {organism_feature_count} OFC
01312         INNER JOIN {cvterm} CVT on OFC.cvterm_id = CVT.cvterm_id
01313       WHERE organism_id = %d 
01314       ORDER BY num_features desc
01315    ";
01316    $previous_db = tripal_db_set_active('chado');  // use chado database
01317    $org_features = db_query($sql,$organism->organism_id);
01318    tripal_db_set_active($previous_db);  // now use drupal database
01319 
01320    $i=0;
01321    $types = array();
01322    while($type = db_fetch_object($org_features)){
01323       $types[$i++] = $type;
01324    }
01325    return array ( 'types' => $types, 'enabled' => true );
01326 }
01327 /**
01328  * 
01329  *
01330  * @ingroup tripal_feature
01331  */
01332 function tripal_feature_load_organism_feature_browser($organism){
01333 
01334    // don't show the browser if the settings in the admin page is turned off
01335    // instead return the array indicating the status of the browser
01336    $show_browser = variable_get('tripal_feature_browse_setting','show_feature_browser');
01337    if(strcmp($show_browser,'show_feature_browser')!=0){
01338       return array ('enabled' => false);
01339    }
01340 
01341    # get the list of available sequence ontology terms for which
01342    # we will build drupal pages from features in chado.  If a feature
01343    # is not one of the specified typse we won't build a node for it.
01344    $allowed_types = variable_get('chado_feature_types','EST contig');
01345    $allowed_types = preg_replace("/[\s\n\r]+/"," ",$allowed_types);
01346    $so_terms = split(' ',$allowed_types);
01347    $where_cvt = "";
01348    foreach ($so_terms as $term){
01349       $where_cvt .= "CVT.name = '$term' OR ";
01350    }
01351    $where_cvt = substr($where_cvt,0,strlen($where_cvt)-3);  # strip trailing 'OR'
01352 
01353    // get the features for this organism
01354    $sql  = "SELECT F.name,F.feature_id,F.uniquename,CVT.name as cvname ".
01355            "FROM {feature} F ".
01356               "  INNER JOIN {cvterm} CVT on F.type_id = CVT.cvterm_id ".
01357             "WHERE organism_id = %s and ($where_cvt) ".
01358             "ORDER BY feature_id ASC";
01359 
01360    // the counting SQL
01361    $csql  = "SELECT count(*) ".
01362             "FROM {feature} F".
01363             "  INNER JOIN {cvterm} CVT on F.type_id = CVT.cvterm_id ".
01364             "WHERE organism_id = %s and ($where_cvt) ".
01365             "GROUP BY organism_id ";
01366 
01367    $previous_db = tripal_db_set_active('chado');  // use chado database
01368    $org_features = pager_query($sql,10,0,$csql,$organism->organism_id);
01369    tripal_db_set_active($previous_db);  // now use drupal database
01370    $pager = theme('pager');
01371 
01372    // prepare the query that will lookup node ids
01373    $sql = "SELECT nid FROM {chado_feature} ".
01374            "WHERE feature_id = %d";
01375    $i=0;
01376    $features = array();
01377    while($feature = db_fetch_object($org_features)){
01378       $node = db_fetch_object(db_query($sql,$feature->feature_id));
01379       $feature->nid = $node->nid;
01380       $features[$i++] = $feature;
01381    }
01382 
01383    return array ( 'features' => $features, 'pager' => $pager, 'enabled' => true );
01384 }
01385 
01386 /**
01387  *  used to sort the list of relationship objects by start position
01388  *
01389  * @ingroup tripal_feature
01390  */
01391 function tripal_feature_sort_rel_objects($a,$b){
01392    return strnatcmp($a->fmin, $b->fmin);
01393 }
01394 
01395 /**
01396  *  used to sort the list of relationship parts by start position
01397  *
01398  * @ingroup tripal_feature
01399  */
01400 function tripal_feature_sort_rel_parts($a,$b){
01401    return strnatcmp($a['start'], $b['start']); 
01402 }
01403 
01404 /**
01405  * 
01406  *
01407  * @ingroup tripal_feature
01408  */
01409 function tripal_feature_color_sequence ($sequence,$parts){
01410 
01411    $types = array();
01412 
01413    // first get the list of types so we can create a color legend
01414    foreach ($parts as $index => $child){ 
01415       $type = $child['type'];
01416       if(!in_array($type,$types)){
01417          $types[] = $type;
01418       }
01419    }
01420  
01421    $newseq .= "<div id=\"tripal_feature-featureloc_sequence-legend\">Legend: ";
01422    foreach($types as $type){
01423       $newseq .= "<span class=\"tripal_feature-featureloc_sequence-$type\">$type</span>";
01424    }
01425    $newseq .= "</div>";
01426    
01427 
01428    // set the background color of the rows based on the type
01429    $pos = 0;
01430    $newseq .= "<pre id=\"tripal_feature-featureloc_sequence\">";
01431    foreach ($parts as $index => $child){
01432       $type = $child['type'];
01433       $start = $child['start'];
01434       $end = $child['end']+1;
01435       
01436       $class = "class=\"tripal_feature-featureloc_sequence-$type\"";
01437 
01438       // iterate through the sequence up to the end of the child
01439       for ($i = $pos; $i < $end; $i++){ 
01440     
01441          // if we're at the beginning of the child sequence then set the
01442          // appropriate text color
01443          if($pos == $start){
01444             $newseq .= "<span $class>";
01445             $func = 'uc';  // nucleotides within the child should be uppercase
01446          }
01447          $newseq .= $sequence{$pos};
01448          $seqcount++;
01449 
01450          if($seqcount % 60 == 0){
01451             $newseq .= "\n";
01452          } 
01453          $pos++;  
01454          if($pos == $end){
01455             $newseq .= "</span>";
01456             $func = 'lc';
01457          }
01458       }
01459    }
01460 
01461    $newseq .= "</pre>";
01462    return $newseq;
01463 }
01464 
01465 /**
01466  *  This function customizes the view of the chado_feature node.  It allows
01467  *  us to generate the markup.
01468  *
01469  * @ingroup tripal_feature
01470  */
01471 function chado_feature_view ($node, $teaser = FALSE, $page = FALSE) {
01472 
01473    if (!$teaser) {
01474       // use drupal's default node view:
01475       $node = node_prepare($node, $teaser);           
01476 
01477       // if we're building the node for searching then
01478       // we want to handle this within the module and
01479       // not allow theme customization.  We don't want to
01480       // index all items (such as DNA sequence).
01481       if($node->build_mode == NODE_BUILD_SEARCH_INDEX){
01482          $node->content['index_version'] = array(
01483             '#value' => theme('tripal_feature_search_index',$node),
01484             '#weight' => 1,
01485          );
01486       }
01487       elseif($node->build_mode == NODE_BUILD_SEARCH_RESULT){
01488          $node->content['index_version'] = array(
01489             '#value' => theme('tripal_feature_search_results',$node),
01490             '#weight' => 1,
01491          );
01492       }
01493       else {
01494          // do nothing here, let the theme derived template handle display
01495       }
01496    }
01497 
01498    return $node;
01499 }
01500 
01501 /**
01502  * Display feature information for associated organisms. This function also
01503  * provides contents for indexing
01504  *
01505  * @ingroup tripal_feature
01506  */
01507 function tripal_feature_nodeapi(&$node, $op, $teaser, $page) {
01508 
01509    switch ($op) {
01510       // Note that this function only adds feature view to an organism node.
01511       // The view of a feature node is controled by the theme *.tpl file
01512       case 'view':
01513          switch($node->type){
01514             case 'chado_organism':
01515                // Show feature browser
01516                $types_to_show = array('chado_organism', 'chado_library');
01517                if (in_array($node->type, $types_to_show, TRUE)) {
01518                   $node->content['tripal_organism_feature_counts'] = array(
01519                     '#value' => theme('tripal_organism_feature_counts', $node),
01520                   );
01521                   $node->content['tripal_organism_feature_browser'] = array(
01522                     '#value' => theme('tripal_organism_feature_browser', $node),
01523                   );
01524                }
01525                break;
01526             case 'chado_library':
01527                break;
01528             default:           
01529          }
01530          break;
01531    }
01532 }
01533 
01534 /**
01535  *  We need to let drupal know about our theme functions and their arguments.
01536  *  We create theme functions to allow users of the module to customize the
01537  *  look and feel of the output generated in this module
01538  *
01539  * @ingroup tripal_feature
01540  */
01541 function tripal_feature_theme () {
01542    return array(
01543       'tripal_feature_search_index' => array (
01544          'arguments' => array('node'),
01545       ),
01546       'tripal_feature_search_results' => array (
01547          'arguments' => array('node'),
01548       ),
01549       'tripal_organism_feature_browser' => array (
01550          'arguments' => array('node'=> null),
01551          'template' => 'tripal_organism_feature_browser',
01552       ),
01553       'tripal_organism_feature_counts' => array (
01554          'arguments' => array('node'=> null),
01555          'template' => 'tripal_organism_feature_counts',
01556       ),
01557       'tripal_feature_base' => array (
01558          'arguments' => array('node'=> null),
01559          'template' => 'tripal_feature_base',
01560       ),
01561       'tripal_feature_sequence' => array (
01562          'arguments' => array('node'=> null),
01563          'template' => 'tripal_feature_sequence',
01564       ),
01565       'tripal_feature_synonyms' => array (
01566          'arguments' => array('node'=> null),
01567          'template' => 'tripal_feature_synonyms',
01568       ),
01569       'tripal_feature_featureloc_sequences' => array (
01570          'arguments' => array('node'=> null),
01571          'template' => 'tripal_feature_featureloc_sequences',
01572       ),
01573       'tripal_feature_references' => array (
01574          'arguments' => array('node'=> null),
01575          'template' => 'tripal_feature_references',
01576       ),
01577       'tripal_feature_properties' => array (
01578          'arguments' => array('node'=> null),
01579          'template' => 'tripal_feature_properties',
01580       ),
01581       'tripal_feature_featurelocs' => array (
01582          'arguments' => array('node'=> null),
01583          'template' => 'tripal_feature_featurelocs',
01584       ),
01585       'tripal_feature_relationships' => array (
01586          'arguments' => array('node'=> null),
01587          'template' => 'tripal_feature_relationships',
01588       ),
01589    );
01590 }
01591 
01592 
01593 /**
01594  *
01595  *
01596  * @ingroup tripal_feature
01597  */
01598 function tripal_feature_preprocess_tripal_organism_feature_counts(&$variables){
01599    $organism = $variables['node']->organism;
01600    $organism->feature_counts = tripal_feature_load_organism_feature_counts($organism);
01601 }
01602 
01603 /**
01604  *  
01605  *
01606  * @ingroup tripal_feature
01607  */
01608 function tripal_feature_preprocess_tripal_organism_feature_browser(&$variables){
01609    $organism = $variables['node']->organism;
01610    $organism->feature_browser = tripal_feature_load_organism_feature_browser($organism);
01611 }
01612 
01613 
01614 /**
01615  *
01616  *
01617  * @ingroup tripal_feature
01618  */
01619 function tripal_feature_cv_chart($chart_id){
01620 
01621   // The CV module will create the JSON array necessary for buillding a
01622   // pie chart using jgChart and Google Charts.  We have to pass to it
01623   // a table that contains count information, tell it which column 
01624   // contains the cvterm_id and provide a filter for getting the
01625   // results we want from the table.
01626   $organism_id = preg_replace("/^tripal_feature_cv_chart_(\d+)$/","$1",$chart_id);
01627   $options = array(
01628      count_mview      => 'organism_feature_count',
01629      cvterm_id_column => 'cvterm_id',
01630      count_column     => 'num_features',
01631      size             => '550x200',
01632      filter           => "CNT.organism_id = $organism_id",
01633   );
01634   return $options;
01635 }
01636 
01637 /**
01638  *
01639  *
01640  * @ingroup tripal_feature
01641  */
01642 function tripal_feature_cv_tree($tree_id){
01643 
01644   // The CV module will create the JSON array necessary for buillding a
01645   // pie chart using jgChart and Google Charts.  We have to pass to it
01646   // a table that contains count information, tell it which column 
01647   // contains the cvterm_id and provide a filter for getting the
01648   // results we want from the table.
01649   $organism_id = preg_replace("/^tripal_feature_cv_tree_(\d+)$/","$1",$tree_id);
01650   $options = array(
01651      cv_id            => tripal_cv_get_cv_id('sequence'),
01652      count_mview      => 'organism_feature_count',
01653      cvterm_id_column => 'cvterm_id',
01654      count_column     => 'num_features',
01655      filter           => "CNT.organism_id = $organism_id",
01656      label            => 'Features',
01657   );
01658   return $options;
01659 }
01660 
01661 /**
01662  *  This function is an extension of the chado_feature_view by providing
01663  *  the markup for the feature object THAT WILL BE INDEXED.
01664  *
01665  * @ingroup tripal_feature
01666  */
01667 function theme_tripal_feature_search_index ($node) {
01668    $feature = $node->feature;
01669    $content = '';
01670 
01671    // get the accession prefix
01672    $aprefix = variable_get('chado_feature_accession_prefix','ID');
01673 
01674    $content .= "<h1>$feature->uniquename</h1>. ";
01675    $content .= "<strong>$aprefix$feature->feature_id.</strong> ";
01676    $content .= "$feature->cvname ";
01677    $content .= "$feature->common_name ";
01678 
01679    // add the synonyms of this feature to the text for searching
01680    $synonyms = $node->synonyms;
01681    if(count($synonyms) > 0){
01682       foreach ($synonyms as $result){
01683          $content .= "$result->name ";
01684       }
01685    }
01686 
01687    return $content;
01688 }
01689 
01690 /**
01691  *  This function is an extension of the chado_feature_view by providing
01692  *  the markup for the feature object THAT WILL BE INDEXED.
01693  *
01694  * @ingroup tripal_feature
01695  */
01696 function theme_tripal_feature_search_results ($node) {
01697    $feature = $node->feature;
01698    $content = '';
01699 
01700    // get the accession prefix
01701    $aprefix = variable_get('chado_feature_accession_prefix','ID');
01702 
01703    $content .= "Feature Name: <h1>$feature->uniquename</h1>. ";
01704    $content .= "<strong>Accession: $aprefix$feature->feature_id.</strong>";
01705    $content .= "Type: $feature->cvname. ";
01706    $content .= "Organism: $feature->common_name. ";
01707 
01708    // add the synonyms of this feature to the text for searching
01709    $synonyms = $node->synonyms;
01710    if(count($synonyms) > 0){
01711       $content .= "Synonyms: ";
01712       foreach ($synonyms as $result){
01713          $content .= "$result->name, ";
01714       }
01715    }
01716 
01717    return $content;
01718 }
01719 
01720 /**
01721  *
01722  *
01723  * @ingroup tripal_feature
01724  */
01725 function tripal_feature_set_vocabulary (){
01726 
01727    //include the file containing the required functions for adding taxonomy vocabs
01728    module_load_include('inc', 'taxonomy', 'taxonomy.admin');
01729 
01730    // get the vocabularies so that we make sure we don't recreate
01731    // the vocabs that already exist
01732    $vocabularies = taxonomy_get_vocabularies();
01733    $ft_vid = NULL;
01734    $op_vid = NULL;
01735    $lb_vid = NULL;
01736    $an_vid = NULL;
01737 
01738    // These taxonomic terms are hard coded because we
01739    // konw we have these relationships in the chado tables
01740    // through foreign key relationships.  The tripal
01741    // modules that correspond to these chado "modules" don't
01742    // need to be installed for the taxonomy to work.
01743    foreach($vocabularies as $vocab){
01744       if($vocab->name == 'Feature Type'){
01745          $ft_vid = $vocab->vid;
01746       }
01747       if($vocab->name == 'Organism'){
01748          $op_vid = $vocab->vid;
01749       }
01750       if($vocab->name == 'Library'){
01751          $lb_vid = $vocab->vid;
01752       }
01753       if($vocab->name == 'Analysis'){
01754          $an_vid = $vocab->vid;
01755       }
01756    }
01757 
01758    if(!$ft_vid){
01759       $form_state = array();
01760       $values = array(
01761          'name' => t('Feature Type'),
01762          'nodes' => array('chado_feature' => 'chado_feature'),
01763          'description' => t('The feature type (or SO cvterm for this feature).'),
01764          'help' => t('Select the term that matches the feature '),
01765          'tags' => 0,
01766          'hierarchy' => 1,
01767          'relations' => 1,
01768          'multiple' => 0,
01769          'required' => 0,
01770          'weight' => 1,
01771       );
01772       drupal_execute('taxonomy_form_vocabulary', $form_state,$values);
01773       drupal_execute('taxonomy_form_vocabulary', $form_state);
01774    }
01775 
01776    if(!$op_vid){
01777       $form_state = array();
01778       $values = array(
01779          'name' => t('Organism'),
01780          'nodes' => array('chado_feature' => 'chado_feature'),
01781          'description' => t('The organism to which this feature belongs.'),
01782          'help' => t('Select the term that matches the feature '),
01783          'tags' => 0,
01784          'hierarchy' => 1,
01785          'relations' => 1,
01786          'multiple' => 0,
01787          'required' => 0,
01788          'weight' => 2,
01789       );
01790       drupal_execute('taxonomy_form_vocabulary', $form_state,$values);
01791       drupal_execute('taxonomy_form_vocabulary', $form_state);
01792    }
01793 
01794    if(!$lb_vid){
01795       $form_state = array();
01796       $values = array(
01797          'name' => t('Library'),
01798          'nodes' => array('chado_feature' => 'chado_feature'),
01799          'description' => t('Chado features associated with a library are assigned the term associated with the library'),
01800          'help' => t('Select the term that matches the feature '),
01801          'tags' => 0,
01802          'hierarchy' => 1,
01803          'relations' => 1,
01804          'multiple' => 0,
01805          'required' => 0,
01806          'weight' => 3,
01807       );
01808       drupal_execute('taxonomy_form_vocabulary', $form_state, $values);
01809       drupal_execute('taxonomy_form_vocabulary', $form_state);
01810    }
01811 
01812    if(!$an_vid){
01813       $form_state = array();
01814       $values = array(
01815          'name' => t('Analysis'),
01816          'nodes' => array('chado_feature' => 'chado_feature'),
01817          'description' => t('Any analysis to which this feature belongs.'),
01818          'help' => t('Select the term that matches the feature '),
01819          'tags' => 0,
01820          'hierarchy' => 1,
01821          'relations' => 1,
01822          'multiple' => 1,
01823          'required' => 0,
01824          'weight' => 4,
01825       );
01826       drupal_execute('taxonomy_form_vocabulary', $form_state,$values);
01827       drupal_execute('taxonomy_form_vocabulary', $form_state);
01828    }
01829 }
01830 
01831 /**
01832  *
01833  *
01834  * @ingroup tripal_feature
01835  */
01836 function tripal_feature_del_vocabulary(){
01837    //include the file containing the required functions for adding taxonomy vocabs
01838    module_load_include('inc', 'taxonomy', 'taxonomy.admin');
01839 
01840    // get the vocabularies
01841    $vocabularies = taxonomy_get_vocabularies();
01842 
01843    // These taxonomic terms are hard coded because we
01844    // know we have these relationships in the chado tables
01845    // through foreign key relationships.  The tripal
01846    // modules that correspond to these chado "modules" don't
01847    // need to be installed for the taxonomy to work.
01848    foreach($vocabularies as $vocab){
01849       if($vocab->name == 'Feature Type'){
01850          taxonomy_del_vocabulary($vocab->vid);
01851       }
01852       if($vocab->name == 'Organism'){
01853          taxonomy_del_vocabulary($vocab->vid);
01854       }
01855       if($vocab->name == 'Library'){
01856          taxonomy_del_vocabulary($vocab->vid);
01857       }
01858       if($vocab->name == 'Analysis'){
01859          taxonomy_del_vocabulary($vocab->vid);
01860       }
01861    }
01862 
01863 }
01864 
01865 /**
01866  *
01867  *
01868  * @ingroup tripal_feature
01869  */
01870 function tripal_features_set_taxonomy($max_sync = 0,$job_id = NULL){
01871 
01872    // make sure our vocabularies are cleaned and reset before proceeding
01873    tripal_feature_del_vocabulary();
01874    tripal_feature_set_vocabulary();
01875 
01876    // iterate through all drupal feature nodes and set the taxonomy
01877    $results = db_query("SELECT * FROM {chado_feature}");
01878    $nsql =  "SELECT * FROM {node} ".
01879             "WHERE nid = %d";
01880    $i = 0;
01881 
01882    // load into ids array
01883    $count = 0;
01884    $chado_features = array();
01885    while($chado_feature = db_fetch_object($results)){
01886       $chado_features[$count] = $chado_feature;
01887       $count++;
01888    }
01889 
01890    // Iterate through features that need to be synced
01891    $interval = intval($count * 0.01);
01892    foreach($chado_features as $chado_feature){
01893 
01894       // update the job status every 1% features
01895       if($job_id and $i % $interval == 0){
01896          tripal_job_set_progress($job_id,intval(($i/$count)*100));
01897       }
01898       print "$i of $count: ";
01899       $node = db_fetch_object(db_query($nsql,$chado_feature->nid));
01900       tripal_feature_set_taxonomy($node,$chado_feature->feature_id);
01901 
01902       $i++;
01903    }
01904 }
01905 
01906 /**
01907  *
01908  *
01909  * @ingroup tripal_feature
01910  */
01911 function tripal_feature_set_taxonomy ($node,$feature_id){
01912 
01913    // iterate through the taxonomy classes that have been
01914    // selected by the admin user and make sure we only set those
01915    $tax_classes = variable_get('tax_classes', '');
01916    $do_ft = 0;
01917    $do_op = 0;
01918    $do_lb = 0;
01919    $do_an = 0;
01920    foreach($tax_classes as $class){
01921       if(strcmp($class ,'organism')==0){
01922          $do_op = 1;
01923       }
01924       if(strcmp($class,'feature_type')==0){
01925          $do_ft = 1;
01926       }
01927       if(strcmp($class,'library')==0){
01928          $do_lb = 1;
01929       }
01930       if(strcmp($class,'analysis')==0){
01931          $do_an = 1;
01932       }
01933    }
01934 
01935 
01936    // get the list of vocabularies and find our two vocabularies of interest
01937    $vocabularies = taxonomy_get_vocabularies();
01938    $ft_vid = NULL;
01939    $op_vid = NULL;
01940    $lb_vid = NULL;
01941    $an_vid = NULL;
01942    foreach($vocabularies as $vocab){
01943       if($vocab->name == 'Feature Type'){
01944          $ft_vid = $vocab->vid;
01945       }
01946       if($vocab->name == 'Organism'){
01947          $op_vid = $vocab->vid;
01948       }
01949       if($vocab->name == 'Library'){
01950          $lb_vid = $vocab->vid;
01951       }
01952       if($vocab->name == 'Analysis'){
01953          $an_vid = $vocab->vid;
01954       }
01955    }
01956 
01957    // get the cvterm and the organism for this feature
01958    $sql = "SELECT CVT.name AS cvname, O.genus, O.species ".
01959           "FROM {CVTerm} CVT ".
01960           "  INNER JOIN Feature F on F.type_id = CVT.cvterm_id ".
01961           "  INNER JOIN Organism O ON F.organism_id = O.organism_id ".
01962           "WHERE F.feature_id = $feature_id";
01963    $previous_db = tripal_db_set_active('chado');  // use chado database
01964    $feature = db_fetch_object(db_query($sql));
01965    tripal_db_set_active($previous_db);  // now use drupal database
01966 
01967    // Set the feature type for this feature
01968    if($do_ft && $ft_vid){
01969       $tags["$ft_vid"] = "$feature->cvname";
01970    }
01971    // Set the organism for this feature type
01972    if($do_op && $op_vid){
01973       $tags["$op_vid"] = "$feature->genus $feature->species";
01974    }
01975 
01976    // get the library that this feature may belong to and add it as taxonomy
01977    if($do_lb && $lb_vid){
01978       $sql = "SELECT L.name ".
01979              "FROM {Library} L ".
01980              "  INNER JOIN Library_feature LF ON LF.library_id = L.library_id ".
01981              "WHERE LF.feature_id = %d ";
01982       $previous_db = tripal_db_set_active('chado');  // use chado database
01983       $library = db_fetch_object(db_query($sql,$feature_id));
01984       tripal_db_set_active($previous_db);  // now use drupal database
01985       $tags["$lb_vid"] = "$library->name";
01986    }
01987 
01988    // now add the taxonomy to the node
01989    $terms['tags'] = $tags;
01990    taxonomy_node_save($node,$terms);
01991    //   print "Setting $node->name: " . implode(", ",$tags) . "\n";
01992 
01993    // get the analysis that this feature may belong to and add it as taxonomy
01994    // We'll add each one individually since there may be more than one analysis
01995    if($do_an && $an_vid){
01996       $sql = "SELECT A.name ".
01997              "FROM {Analysis} A ".
01998              "  INNER JOIN Analysisfeature AF ON AF.analysis_id = A.analysis_id ".
01999              "WHERE AF.feature_id = $feature_id ";
02000       $results = db_query($sql);
02001       $previous_db = tripal_db_set_active('chado');  // use chado database
02002       $analysis_terms = array();
02003       while($analysis=db_fetch_object($results)){
02004          $tags2["$an_vid"] = "$analysis->name";
02005          $terms['tags'] = $tags2;
02006          taxonomy_node_save($node,$terms);
02007       }
02008       tripal_db_set_active($previous_db);  // now use drupal database
02009    }
02010 
02011 }
02012 
02013 /**
02014  *
02015  *
02016  * @ingroup tripal_feature
02017  */
02018 function tripal_features_cleanup($dummy = NULL, $job_id = NULL) {
02019 
02020    // build the SQL statments needed to check if nodes point to valid features
02021    $dsql = "SELECT * FROM {node} WHERE type = 'chado_feature' order by nid";
02022    $nsql = "SELECT * FROM {node} WHERE nid = %d";
02023    $csql = "SELECT * FROM {chado_feature} where nid = %d ";
02024    $cfsql= "SELECT * FROM {chado_feature}";
02025    $tsql = "SELECT * FROM {feature} F ".
02026           "  INNER JOIN CVTerm CVT ON F.type_id = CVT.cvterm_id ".
02027           "WHERE feature_id = %d  AND (";
02028    $supported_ftypes = split("[ \n]",variable_get('chado_feature_types','EST contig'));
02029    foreach($supported_ftypes as $ftype){
02030       $tsql .= " CVT.name = '$ftype' OR ";
02031    }
02032    $tsql .= " 0=1) ";  // add a 0=1 just as a filler so we don't have to remove a trailing 'OR'
02033 
02034    // load into nodes array
02035    $results = db_query($dsql);
02036    $count = 0;
02037    $nodes = array();
02038    while($node = db_fetch_object($results)){
02039       $nodes[$count] = $node;
02040       $count++;
02041    }
02042 
02043    // load the chado_features into an array
02044    $results = db_query($cfsql);
02045    $cnodes = array();
02046    while($node = db_fetch_object($results)){
02047       $cnodes[$count] = $node;
02048       $count++;
02049    }
02050    $interval = intval($count * 0.01);
02051 
02052    // iterate through all of the chado_feature nodes and delete those  that aren't valid
02053    foreach($nodes as $nid){
02054 
02055       // update the job status every 1% features
02056       if($job_id and $i % $interval == 0){
02057          tripal_job_set_progress($job_id,intval(($i/$count)*100));
02058       }
02059 
02060       // first check to see if the node has a corresponding entry
02061       // in the chado_feature table. If not then delete the node.
02062       $feature = db_fetch_object(db_query($csql,$nid->nid));
02063       if(!$feature){
02064          node_delete($nid->nid);
02065          $message = "Missing in chado_feature table.... DELETING: $nid->nid\n";
02066          watchdog('tripal_feature',$message,array(),WATCHDOG_WARNING);
02067          continue;
02068       }
02069 
02070       // second check to see if the node is for a feature of an allowed type.
02071       // if not, then delete the node.  This check will also take care of the
02072       // case when a node exists and an entry in the chado_feature table exists
02073       // but no feature with a matching feature_id exists
02074       $previous_db = tripal_db_set_active('chado');  // use chado database
02075       $ftype = db_fetch_object(db_query($tsql,$feature->feature_id));
02076       tripal_db_set_active($previous_db);  // now use drupal database
02077 
02078       if(!$ftype){
02079          node_delete($nid->nid);
02080          db_query("DELETE FROM {chado_feature} WHERE feature_id = $feature->feature_id");
02081          $message = "Node of the wrong feature type.... DELETING: $nid->nid\n";
02082          watchdog('tripal_feature',$message,array(),WATCHDOG_WARNING);
02083       }
02084       $i++;
02085    }
02086 
02087    // iterate through all of the chado_feature nodes and delete those  that aren't valid
02088    foreach($cnodes as $nid){
02089       // update the job status every 1% features
02090       if($job_id and $i % $interval == 0){
02091          tripal_job_set_progress($job_id,intval(($i/$count)*100));
02092       }
02093       $node = db_fetch_object(db_query($nsql,$nid->nid));
02094       if(!$node){
02095          db_query("DELETE FROM {chado_feature} WHERE nid = $nid->nid");
02096          $message = "chado_feature missing node.... DELETING: $nid->nid\n";
02097          watchdog('tripal_feature',$message,array(),WATCHDOG_WARNING);
02098       }
02099 
02100       $i++;
02101    }
02102    return '';
02103 }
02104 
02105 /**
02106  *
02107  *
02108  * @ingroup tripal_feature
02109  */
02110 function tripal_feature_return_fasta($feature,$desc){   
02111    $fasta  = ">" . variable_get('chado_feature_accession_prefix','ID') . "$feature->feature_id|$feature->name";
02112    $fasta .= " $desc\n";
02113    $fasta .= wordwrap($feature->residues, 50, "\n", true);
02114    $fasta .= "\n\n";
02115    return $fasta;
02116 }
02117 /**
02118  *
02119  *
02120  * @ingroup tripal_feature
02121  */
02122 function tripal_feature_job_describe_args($callback,$args){
02123 
02124    $new_args = array();
02125    if($callback == 'tripal_feature_load_fasta'){
02126       $new_args['FASTA file'] = $args[0];
02127       $organism = tripal_core_chado_select('organism',array('genus','species'),array('organism_id' => $args[1]));
02128       $new_args['Organism'] = $organism[0]->genus." ". $organism[0]->species;
02129       $new_args['Sequence Type'] = $args[2];
02130       $new_args['Name RE'] = $args[4];
02131       $new_args['Unique Name RE'] = $args[5];
02132 
02133       // add in the relationship arguments
02134       $new_args['Relationship Type'] = $args[8];
02135       $new_args['Relationship Parent RE'] = $args[9];
02136       $new_args['Relationship Parent Type'] = $args[10];
02137 
02138       // add in the database reference arguments
02139       if($args[7]){
02140          $db = tripal_core_chado_select('db',array('name'),array('db_id' => $args[7]));
02141       }
02142       $new_args['Database Reference'] = $db[0]->name;
02143       $new_args['Accession RE'] = $args[6];
02144       if($args[11]){
02145          $new_args['Update and Insert'] = 'Yes';
02146       }
02147       else {
02148          $new_args['Insert Only New Features'] = 'Yes';
02149       }
02150 
02151       // add in the analysis 
02152       if($args[13]){
02153          $analysis = tripal_core_chado_select('analysis',array('name'),array('analysis_id' => $args[13]));
02154       }
02155       $new_args['Analysis'] = $analysis[0]->name;
02156    }
02157    return $new_args;
02158 }
02159 
 All Classes Files Functions Variables