spficklin 14 anni fa
parent
commit
4c62dd3793

+ 19 - 14
tripal_analysis_blast/tripal_analysis_blast.module

@@ -355,6 +355,7 @@ function parse_NCBI_Blast_XML($xml_string,$db,$max,$feature_id,$ajax, $analysis)
                 '    <th nowrap>Match Name</th>'.
                 '    <th nowrap>E value</th>'.
                 '    <th nowrap>Identity</th>'.
+                '    <th nowrap>Description</th>'.
                 '  </tr>';
 
 
@@ -490,34 +491,38 @@ function parse_NCBI_Blast_XML($xml_string,$db,$max,$feature_id,$ajax, $analysis)
 				}
 			}
 		}
-		$arrowr_url = url("sites/all/themes/theme_tripal/images/arrow_r.png");
+      $arrowr_url = url(drupal_get_path('theme', 'tripal')."/images/arrow_r.png");
 		$html_out .= "<tr>";
 		if($accession && $db->urlprefix){
-			$html_out .= "<td><img src=$arrowr_url align=\"top\" class=\"blast-hit-arrow-icon\"> <a href=\"$db->urlprefix$accession\" ".
-                            "target=\"_blank\">$hit_name</a></td>";
+			$html_out .= "<td><a href=\"$db->urlprefix$accession\" target=\"_blank\">$hit_name</a></td>";
 		} else {
 			// Test if this is another feature in the database
 			$sql = "SELECT feature_id FROM {feature} WHERE uniquename = '%s'";
-			$previous_db = tripal_db_set_active('chado');
+			$previous_db = db_set_active('chado');
 			$hit_feature_id = db_result(db_query($sql, $hit_name));
-			tripal_db_set_active($previous_db);
+			db_set_active($previous_db);
 			// If it is, add link to that feature
 			if ($hit_feature_id) {
 				$hit_url = url("ID$hit_feature_id");
-				$html_out .= "<td><img src=$arrowr_url align=\"top\" class=\"blast-hit-arrow-icon\"> <a href=\"$hit_url\" ".
-                            "target=\"_blank\">$hit_name</a></td>";
+				$html_out .= "<td><a href=\"$hit_url\" target=\"_blank\">$hit_name</a></td>";
 			} else {
-				$html_out .= "<td><img src=$arrowr_url align=\"top\" class=\"blast-hit-arrow-icon\"> $hit_name</td>";
+				$html_out .= "<td>$hit_name</td>";
 			}
 		}
 		$html_out .= "<td nowrap>$best_evalue</td>";
-		$percent_identity = number_format($best_identity/$best_len*100,
-		2);
+		$percent_identity = number_format($best_identity/$best_len*100, 2);
 		$html_out .= "<td nowrap>$percent_identity%</td>";
-		$html_out .= "</tr><tr><td colspan=3><div class=\"tripal_expandableSubBox\">".
-                         "$description</div></td></tr><tr><td colspan=4><div class=".
-                         "\"tripal_expandableSubBoxContent\">".
-                         "$hsp_html_out</div><td></tr>";
+		$html_out .= "<td nowrap>$description</td>";
+		$html_out .= "</tr>
+                              <tr>
+                                <td colspan=4>
+                                   <a class=\"blast-hit-arrow-icon\"><img src=$arrowr_url align=\"top\"> View Alignment</a>
+                                   <div class=\"tripal_expandableSubBox\"></div>
+                               </td>
+                              </tr>
+                              <tr>
+                                 <td colspan=4><div class=\"tripal_expandableSubBoxContent\">$hsp_html_out</div><td>
+                             </tr>";
 		$hsp_html_out = '';
 	}
 

+ 3 - 1
tripal_analysis_interpro/tripal_analysis_interpro.module

@@ -171,7 +171,9 @@ function chado_analysis_interpro_form ($node){
 	);
 	return $form;
 }
-
+/*******************************************************************************
+ *  
+ */
 function chado_analysis_interpro_insert($node){
 	global $user;
 	// Create a timestamp so we can insert it into the chado database

+ 398 - 0
tripal_core/bulk_loader.php

@@ -1,5 +1,403 @@
 <?php
 
+/*************************************************************************
+*
+*/
 function tripal_core_bulk_loader_create (){
+  
+   return drupal_get_form('tripal_core_bulk_loader_create_form');
+}
+/*************************************************************************
+*
+*/
+function tripal_core_bulk_loader_create_form (&$form_state = NULL){
+   $form = array();  
+
+   // get the step used by this multistep form
+   $step = 1;
+   if(isset($form_state['storage'])){
+      $step = (int)$form_state['storage']['step'];
+   }  
+
+   $form = array();
+   if($step == 1){
+      tripal_core_bulk_loader_create_form_step1 ($form,$form_state);
+      $form_state['storage']['step'] = $step + 1;
+   }
+   if($step == 2){
+      tripal_core_bulk_loader_create_form_step2 ($form,$form_state);
+   }
+
+   return $form;
+}
+/*************************************************************************
+*
+*/
+function tripal_core_bulk_loader_create_form_validate ($form,&$form_state) {
+
+
+}
+/*************************************************************************
+*
+*/
+function tripal_core_bulk_loader_create_form_submit ($form,&$form_state) {
+   if($form_State['storage']['step'] < 4){
+      return;
+   }
+}
+
+/*************************************************************************
+*
+*/
+function tripal_core_bulk_loader_create_form_step2 (&$form,$form_state){
+
+   if(isset($form_state['values']['columns'])){
+      $form_state['storage']['columns'] = $form_state['values']['columns'];
+   }
+
+   $form['bulk_loader'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Step 2: Define the columns of the file'),
+   );
+
+   $columns = $form_state['storage']['columns'];
+//   $form['debug']= array(
+//      '#value' => "Columns: $columns",
+//      '#weight'        => -1
+//   );
+
+	$fields = array();
+   $fields[''] = '';
+
+   // these fields correspond with the columns of the feature table and
+   // the foreign key contraints for the feature table.
+   $fields = array(
+        '' => '',
+        'ignore' => 'Ignore this column',
+        'Feature details' => array (
+           'name' => 'Feature Name (human readable)',
+           'uniquename' => 'Unique Feature Name',
+           'type' => 'Feature type (must be a valid SO term)',
+           'alt_type' => 'Additional ontology term',
+           'residues' => 'Residues',
+         ),
+        'Organism specification' => array (
+           'organism_id' => 'Organism ID number',
+           'genus' => 'Genus',
+           'species' => 'Species',
+           'full_name' => 'Scientific Name (genus + species)',
+           'common_name' => 'Common Name',
+         ),
+        'External Database Cross-Reference' => array(
+           'db_id' => 'Database ID number',
+           'db_name' => 'Database name (must exists in the database)',
+           'accession' => 'Accession',
+         ),
+        'Feature Relationship' => array (
+            'rel_type' => 'Relationship Type (must be a valid relationship term)',
+            'parent' => 'Parent unique name',
+            'parent type' => 'Parent Type (must be a valid SO term)',
+         ),
+        'Feature Location' => array (
+           'srcfeature' => 'Reference feature (must already exist in the database)',
+           'srcfeature_type' => 'Reference feature type (must be a valid SO term)',
+           'fmin' => 'Start position',
+           'fmax' => 'Stop position',
+           'strand' => 'Strand (valid values: 0,-1,+1)',
+           'phase' => 'Phase (valid values: (+,-,.)',
+         ),
+         'Feature Property' => array (
+            'property' => 'Feature property value',
+         ),
+         'Feature Synonym' => array (
+            'syn_name' => 'Synonym name',
+         ),
+         'Library specification' => array (
+            'library_id' => 'Library ID number',
+            'library_name' => 'Library name',
+         ),
+         'Analysis specification' => array (
+            'analysis_id' => 'Analysis ID number',
+            'analysis_source' => 'Analysis identifying name (sourcename column in Chado)',
+            'analysis_desc' => 'Analysis description',
+            'analysis_program' => 'Analysis program',
+            'analysis_program_version' => 'Analysis program version'
+         ),
+   );
+
+   // organism foreign key identifies.  These are used to find the organism
+   // for which the feature belongs.
+   $form['columns'] = array(
+      '#type' => 'hidden',
+      '#value' => $columns,
+   );
+
+
+   // get the list of organisms
+   $sql = "SELECT * FROM {organism} ORDER BY genus, species";
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $org_rset = db_query($sql);
+   tripal_db_set_active($previous_db);  // now use drupal database
+   $organisms = array();
+   $genus = array();
+   $species = array();
+   $common_names = array();
+   $genera[''] = '';
+   $species[''] = '';
+   $common_names[''] = '';
+   $full_names[''] = '';
+   while($organism = db_fetch_object($org_rset)){
+      $full_names["$organism->genus $organism->species"] = "$organism->genus $organism->species";
+      $genera[$organism->genus] = "$organism->genus";
+      $species[$organism->species] = "$organism->species";
+      $common_names[$organism->common_name] = "$organism->common_name";
+   }
+
+   for($i = 1; $i <= $columns; $i++){
+      $form['bulk_loader']["col_$i"] = array(
+         '#type' => 'fieldset',
+         '#title' => t("Column $i of the input file"),
+      );
+      $form['bulk_loader']["col_$i"]["col_type_$i"] = array(
+       '#title'         => t('Field Selection'),
+       '#type'          => 'select',
+       '#options'       => $fields,
+       '#weight'        => 0,
+        // this field will use AJAX to populate and information needed
+        // for specific types, such as for feature properties.  It
+        // calls the step2_get_type URL and passes the column ($i).  
+        // the return value is additional form items or text
+       '#ahah'          => array(
+          'event' => 'change',
+          'wrapper' => "type_cols_$i",
+          'path' => "/admin/tripal/bulk_load/step2_get_type/$i",
+          'effect' => 'fade',
+          'method' => 'replace'
+        ),
+ 	   );
+
+     // these next fields are hidden (access = false) and will be shown
+     // if the user selects the feature property type in the drop down
+     // above.  
+
+
+     //-------------------------------------------------------------------------
+     // default text box for allowed values
+     $form['bulk_loader']["col_$i"]["col_prop_valid_$i"] = array(
+       '#title'         => t('Allowed Values'),
+       '#type'          => 'textarea',
+       '#weight'        => 0,
+       '#description'   => 'Please provide a list of allowed values for this field. Separate these values with a space. Leave blank to allow any value',
+       '#access'        => FALSE
+     );
+
+     //-------------------------------------------------------------------------
+     // Organism allowed values
+     $form['bulk_loader']["col_$i"]["col_prop_genera_$i"] = array (
+        '#title'       => t('Allowed Values'),
+        '#type'        => t('select'),
+        '#description' => t("Choose all allowed genera values for this column (ctrl+click to select multiple values). Select none to allow all"),
+        '#required'    => FALSE,
+        '#options'     => $genera,
+        '#weight'      => 2,
+        '#multiple'    => TRUE,
+        '#size'        => 10,
+        '#access'        => FALSE
+      );
+     $form['bulk_loader']["col_$i"]["col_prop_species_$i"] = array (
+        '#title'       => t('Allowed Values'),
+        '#type'        => t('select'),
+        '#description' => t("Choose all allowed species values for this column (ctrl+click to select multiple values). Select none to allow all"),
+        '#required'    => FALSE,
+        '#options'     => $species,
+        '#weight'      => 2,
+        '#multiple'    => TRUE,
+        '#size'        => 10,
+        '#access'        => FALSE
+      );
+     $form['bulk_loader']["col_$i"]["col_prop_common_name_$i"] = array (
+        '#title'       => t('Allowed Values'),
+        '#type'        => t('select'),
+        '#description' => t("Choose all allowed values for this column (ctrl+click to select multiple values). Select none to allow all"),
+        '#required'    => FALSE,
+        '#options'     => $common_names,
+        '#weight'      => 2,
+        '#multiple'    => TRUE,
+        '#size'        => 10,
+        '#access'        => FALSE
+      );
+     $form['bulk_loader']["col_$i"]["col_prop_full_name_$i"] = array (
+        '#title'       => t('Allowed Values'),
+        '#type'        => t('select'),
+        '#description' => t("Choose all allowed values for this column (shift+click to select multiple values). Select none to allow all"),
+        '#required'    => FALSE,
+        '#options'     => $full_names,
+        '#weight'      => 2,
+        '#multiple'    => TRUE,
+        '#size'        => 10,
+        '#access'        => FALSE
+      );
+
+
+     //-------------------------------------------------------------------------
+     // feature property fields
+     $form['bulk_loader']["col_$i"]["col_prop_name_$i"] = array(
+       '#title'         => t('Property Name'),
+       '#type'          => 'textfield',
+       '#weight'        => 1,
+       '#description'   => 'Please provide a name for this property.  It should be a single 
+                            word with only alphanumeric characters and underscores.  If this 
+                            name exists as a CV term in Chado already it will be reused, otherwise
+                            a new CV term with this name will be added.',
+       '#required'      => TRUE,
+       '#access'        => FALSE
+     );
+     $form['bulk_loader']["col_$i"]["col_prop_full_name_$i"] = array(
+       '#title'         => t('Property Full Name'),
+       '#type'          => 'textfield',
+       '#weight'        => 3,
+       '#description'   => 'Please provide a human readable name for this property.  This will be used when
+                            displaying the property title',
+       '#access'        => FALSE
+     );
+     $form['bulk_loader']["col_$i"]["col_prop_desc_$i"] = array(
+       '#title'         => t('Property Description'),
+       '#type'          => 'textarea',
+       '#weight'        => 4,
+       '#description'   => 'Please provide a description of this property.',
+       '#access'        => FALSE
+     );
+
+     // this is an empty div box that gets put on the form.  This is the
+     // box where the hidden form elements will be rendered when the
+     // AJAX call returns
+     $form['bulk_loader']["col_$i"]["type_wrap_$i"] = array(        
+            '#prefix' => "<div class=\"clear-block\" id=\"type_cols_$i\">",
+            '#value' => ' ',             
+            '#suffix' => '</div>',
+        );
+   }
+
+   
+   $form['submit'] = array (
+     '#type'         => 'submit',
+     '#value'        => t('Next'),
+     '#weight'       => 5,
+     '#executes_submit_callback' => TRUE,
+   );   
+}
+/*************************************************************************
+*
+*/
+
+function tripal_core_bulk_loader_ahah_step2_feature_type($column){
+
+
+  // create a form_state array to hold the form variables
+  $form_state = array('storage' => NULL, 'submitted' => FALSE);
+  $form_state['storage']['step'] = 2;
+  
+  // retreive the form from the cache
+  $form_build_id = $_POST['form_build_id'];
+  $form = form_get_cache($form_build_id, $form_state);
+
+  // get the form name
+  $args = $form['#parameters'];
+  $form_id = array_shift($args); 
+
+  // add the post variables to the form and set a few other items
+  $form['#post'] = $_POST;
+  $form['#redirect'] = FALSE;
+  $form['#programmed'] = FALSE;
+  $form_state['post'] = $_POST;
+
+  drupal_process_form($form_id, $form, $form_state);
+  $form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
+
+  // get the column
+  $i = $column;
+
+  // check to see what type of field has been selected and provide the
+  // additional fields as appropriate
+  $type = $form_state["post"]["col_type_$i"];
+  if(strcmp($type,'genus')==0){
+     $propform['bulk_loader']["col_$i"]["col_prop_genera_$i"] = $form['bulk_loader']["col_$i"]["col_prop_genera_$i"];
+     $propform['bulk_loader']["col_$i"]["col_prop_genera_$i"]['#access'] = TRUE;
+
+  }
+  elseif(strcmp($type,'species')==0){
+     $propform['bulk_loader']["col_$i"]["col_prop_species_$i"] = $form['bulk_loader']["col_$i"]["col_prop_species_$i"];
+     $propform['bulk_loader']["col_$i"]["col_prop_species_$i"]['#access'] = TRUE;
+
+  }
+  elseif(strcmp($type,'common_name')==0){
+     $propform['bulk_loader']["col_$i"]["col_prop_common_name_$i"] = $form['bulk_loader']["col_$i"]["col_prop_common_name_$i"];
+     $propform['bulk_loader']["col_$i"]["col_prop_common_name_$i"]['#access'] = TRUE;
+
+  }
+  elseif(strcmp($type,'full_name')==0){
+     $propform['bulk_loader']["col_$i"]["col_prop_full_name_$i"] = $form['bulk_loader']["col_$i"]["col_prop_full_name_$i"];
+     $propform['bulk_loader']["col_$i"]["col_prop_full_name_$i"]['#access'] = TRUE;
+
+  }
+  elseif(strcmp($type,'property')==0){
+     // we just want to render the property fields that were previously not visible
+     $propform['bulk_loader']["col_$i"]["col_prop_name_$i"] = $form['bulk_loader']["col_$i"]["col_prop_name_$i"];
+     $propform['bulk_loader']["col_$i"]["col_prop_full_name_$i"] = $form['bulk_loader']["col_$i"]["col_prop_full_name_$i"];
+     $propform['bulk_loader']["col_$i"]["col_prop_desc_$i"] = $form['bulk_loader']["col_$i"]["col_prop_desc_$i"];
+     $propform['bulk_loader']["col_$i"]["col_prop_name_$i"]['#access'] = TRUE;
+     $propform['bulk_loader']["col_$i"]["col_prop_full_name_$i"]['#access'] = TRUE;
+     $propform['bulk_loader']["col_$i"]["col_prop_desc_$i"]['#access'] = TRUE;
+  } 
+  else {
+     // use a default valid values textbox if we have no special needs for the type
+     $propform['bulk_loader']["col_$i"]["col_prop_valid_$i"] = $form['bulk_loader']["col_$i"]["col_prop_valid_$i"];
+     $propform['bulk_loader']["col_$i"]["col_prop_valid_$i"]['#access'] = TRUE;
+  }
+
+  $output = theme('status_messages') . drupal_render($propform);
+
+  // Final rendering callback.
+  drupal_json(array('status' => TRUE, 'data' => $output));
+}
+/*************************************************************************
+*
+*/
+function tripal_core_bulk_loader_create_form_step1 (&$form,$form_state){
+	$modules = array();
+   $modules['feature'] = 'Feature';
+   $modules['organism'] = 'Organism';
+   $modules['library'] = 'Library';
+   $modules['analysis'] = 'Analysis';
+
+
+   // set the fieldset title to indicate the step
+   $form['bulk_loader'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Step 1: Select the Chado module'),
+   );
+
+	$form['bulk_loader']['chado_module'] = array(
+      '#title'         => t('Chado Module'),
+      '#description'   => t('Please select the module for which you would like to create an importer'),
+      '#type'          => 'select',
+      '#options'       => $modules,
+      '#weight'        => 0,
+      '#required'      => TRUE
+	);
+
+   $form['bulk_loader']['columns']= array(
+      '#type'          => 'textfield',
+      '#title'         => t('Number of Columns'),
+      '#description'   => t('Please specify the number of columns in the input file.'),
+      '#weight'        => 2,
+      '#required'      => TRUE
+   );
 
+   $form['submit'] = array (
+     '#type'         => 'submit',
+     '#value'        => t('Next'),
+     '#weight'       => 5,
+     '#executes_submit_callback' => TRUE,
+   );   
 }

+ 273 - 46
tripal_core/gff_loader.php

@@ -1,5 +1,11 @@
 <?php
 
+
+// TODO: The rank column on the feature_relationship table needs to be used to
+//       make sure the ordering of CDS (exons) is correct.
+
+// The entries in the GFF file are not in order so the order of the relationships
+// is not put in correctly.
 /*************************************************************************
 *
 */
@@ -14,25 +20,48 @@ function tripal_core_gff3_load_form (){
       '#required' => TRUE,
       '#weight'        => 1
    );
-   $form['add_only']= array(
+   // get the list of organisms
+   $sql = "SELECT * FROM {organism} ORDER BY genus, species";
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $org_rset = db_query($sql);
+   tripal_db_set_active($previous_db);  // now use drupal database
+   $organisms = array();
+   $organisms[''] = '';
+   while($organism = db_fetch_object($org_rset)){
+      $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
+   }
+   $form['organism_id'] = array (
+     '#title'       => t('Organism'),
+     '#type'        => t('select'),
+     '#description' => t("Choose the organism to which these sequences are associated "),
+     '#required'    => TRUE,
+     '#options'     => $organisms,
+   );
+   $form['import_options'] = array(
+      '#type' => 'fieldset',
+      '#title' => t('Import Options'),
+      '#weight'=> 6,
+      '#collapsed' => TRUE
+   );
+   $form['import_options']['add_only']= array(
       '#type' => 'checkbox',
       '#title' => t('Import only new features'),
       '#required' => FALSE,
-      '#default_value' => 'checked',
       '#description' => t('The job will skip features in the GFF file that already
                            exist in the database and import only new features.'),
       '#weight' => 2
    );
-   $form['update']= array(
+   $form['import_options']['update']= array(
       '#type' => 'checkbox',
       '#title' => t('Import all and update'),
       '#required' => FALSE,
+      '#default_value' => 'checked',
       '#description' => t('Existing features will be updated and new features will be added.  Attributes 
                            for a feature that are not present in the GFF but which are present in the 
                            database will not be altered.'),
       '#weight' => 3
    );
-   $form['refresh']= array(
+   $form['import_options']['refresh']= array(
       '#type' => 'checkbox',
       '#title' => t('Import all and replace'),
       '#required' => FALSE,
@@ -40,7 +69,7 @@ function tripal_core_gff3_load_form (){
                            present in the GFF file will be removed.'),
       '#weight' => 4
    );
-   $form['remove']= array(
+   $form['import_options']['remove']= array(
       '#type' => 'checkbox',
       '#title' => t('Delete features'),
       '#required' => FALSE,
@@ -60,16 +89,47 @@ function tripal_core_gff3_load_form (){
 /*************************************************************************
 *
 */
+function tripal_core_gff3_load_form_validate ($form, &$form_state){
+
+   $gff_file = $form_state['values']['gff_file'];
+   $organism_id = $form_state['values']['organism_id'];
+   $add_only = $form_state['values']['add_only'];
+   $update   = $form_state['values']['update'];
+   $refresh  = $form_state['values']['refresh'];
+   $remove   = $form_state['values']['remove'];
+
+   // check to see if the file is located local to Drupal
+   $dfile = $_SERVER['DOCUMENT_ROOT'] . base_path() . $gff_file; 
+   if(!file_exists($dfile)){
+      // if not local to Drupal, the file must be someplace else, just use
+      // the full path provided
+      $dfile = $gff_file;
+   }
+   if(!file_exists($dfile)){
+      form_set_error('gff_file',t("Cannot find the file on the system. Check that the file exists or that the web server has permissions to read the file."));
+   }
+
+   if (($add_only and ($update or $refresh or $remove)) or 
+       ($update   and ($add_only or $refresh or $remove)) or
+       ($refresh and ($update or $add_only or $remove)) or
+       ($remove and ($update or $refresh or $add_only))){
+       form_set_error('add_only',t("Please select only one checkbox from the import options section"));
+   }
+}
+/*************************************************************************
+*
+*/
 function tripal_core_gff3_load_form_submit ($form, &$form_state){
    global $user;
 
    $gff_file = $form_state['values']['gff_file'];
+   $organism_id = $form_state['values']['organism_id'];
    $add_only = $form_state['values']['add_only'];
    $update   = $form_state['values']['update'];
    $refresh  = $form_state['values']['refresh'];
    $remove   = $form_state['values']['remove'];
 
-   $args = array($gff_file,$add_only,$update,$refresh,$remove);
+   $args = array($gff_file,$organism_id,$add_only,$update,$refresh,$remove);
    $type = '';
    if($add_only){
      $type = 'import only new features';
@@ -83,7 +143,7 @@ function tripal_core_gff3_load_form_submit ($form, &$form_state){
    if($remove){
      $type = 'delete features';
    }
-   tripal_add_job("Import GFF3 file: $type",'tripal_core',
+   tripal_add_job("$type GFF3 file $dfile",'tripal_core',
       'tripal_core_load_gff3',$args,$user->uid);
 
    return '';
@@ -91,8 +151,14 @@ function tripal_core_gff3_load_form_submit ($form, &$form_state){
 /*************************************************************************
 *
 */
-function tripal_core_load_gff3($gff_file, $add_only =0, $update = 0, $refresh = 0, $remove = 0, $job = NULL){
-   
+function tripal_core_load_gff3($gff_file, $organism_id,$add_only =0, 
+   $update = 0, $refresh = 0, $remove = 0, $job = NULL)
+{
+
+   // this array is used to cache all of the features in the GFF file and
+   // used to lookup parent and target relationships
+   $gff_features = array();
+ 
    // check to see if the file is located local to Drupal
    $dfile = $_SERVER['DOCUMENT_ROOT'] . base_path() . $gff_file; 
    if(!file_exists($dfile)){
@@ -113,23 +179,34 @@ function tripal_core_load_gff3($gff_file, $add_only =0, $update = 0, $refresh =
 
    // get the controlled vocaubulary that we'll be using.  The
    // default is the 'sequence' ontology
-   $vocab = 'sequence';
    $sql = "SELECT * FROM cv WHERE name = '%s'";
-   $cv = db_fetch_object(db_query($sql,$vocab));
+   $cv = db_fetch_object(db_query($sql,'sequence'));
    if(!$cv){
-      print "ERROR:  cannot find the '$vocab' ontology\n";
+      print "ERROR:  cannot find the 'sequence' ontology\n";
       return '';
    }
 
    // get the organism for which this GFF3 file belongs
-   $sql = "SELECT * FROM organism WHERE common_name = 'fruitfly'";
-   $organism = db_fetch_object(db_query($sql));
+   $sql = "SELECT * FROM organism WHERE organism_id = %d";
+   $organism = db_fetch_object(db_query($sql,$organism_id));
+
 
+   $num_lines = sizeof($lines);
+   $interval = intval($num_lines * 0.01);
    foreach ($lines as $line_num => $line) {
       $i++;  // update the line count
+      // update the job status every 1% features
+      if($job and $i % $interval == 0){
+         tripal_job_set_progress($job,intval(($i/$num_lines)*100));
+      }
 
+      // skip comments
       if(preg_match('/^#/',$line)){
-         continue; // skip comments
+         continue; 
+      }
+      // skip empty lines
+      if(preg_match('/^\s*$/',$line)){
+         continue; 
       }
       
 
@@ -173,8 +250,13 @@ function tripal_core_load_gff3($gff_file, $add_only =0, $update = 0, $refresh =
       }
 
       // get the type record
-      $sql = "SELECT * from cvterm CVT WHERE name = '%s' and cv_id = %d";
-      $cvterm = db_fetch_object(db_query($sql,$type,$cv->cv_id));
+      $cvtermsql = "SELECT CVT.cvterm_id, CVT.cv_id, CVT.name, CVT.definition,
+                       CVT.dbxref_id, CVT.is_obsolete, CVT.is_relationshiptype
+                    FROM {cvterm} CVT
+                       INNER JOIN {cv} CV on CVT.cv_id = CV.cv_id
+                       LEFT JOIN {cvtermsynonym} CVTS on CVTS.cvterm_id = CVT.cvterm_id
+                    WHERE CV.cv_id = %d and (CVT.name = '%s' or CVTS.synonym = '%s')";
+      $cvterm = db_fetch_object(db_query($cvtermsql,$cv->cv_id,$type,$type));
       if(!$cvterm){
          print "ERROR: cannot find ontology term '$type' on line $i.\n";
          return '';
@@ -190,7 +272,9 @@ function tripal_core_load_gff3($gff_file, $add_only =0, $update = 0, $refresh =
       $attr_fmax_partial = 'f';
       $attr_is_obsolete = 'f';
       $attr_is_analysis = 'f';
+      $attr_others = '';
       $residues = '';
+      $generate_name = 0;
       foreach($attrs as $attr){
          $attr = rtrim($attr);
          $attr = ltrim($attr);
@@ -209,22 +293,63 @@ function tripal_core_load_gff3($gff_file, $add_only =0, $update = 0, $refresh =
          if(strcmp($tag[0],'ID')==0){
             $attr_uniquename = $tag[1];
          }
-         if(strcmp($tag[0],'Name')==0){
+         elseif(strcmp($tag[0],'Name')==0){
             $attr_name = $tag[1];
          }
+         // get the list of other attributes other than those reserved ones.
+         elseif(strcmp($tag[0],'Alias')!=0        and strcmp($tag[0],'Parent')!=0 and 
+                strcmp($tag[0],'Target')!=0       and strcmp($tag[0],'Gap')!=0 and
+                strcmp($tag[0],'Derives_from')!=0 and strcmp($tag[0],'Note')!=0 and
+                strcmp($tag[0],'Dbxref')!=0       and strcmp($tag[0],'Ontology_term')!=0 and
+                strcmp($tag[0],'Is_circular')!=0){
+            $attr_others[$tag[0]] = $tag[1];
+         }
       }
+
+      // if neither name nor uniquename are provided then generate one
+      if(!$attr_uniquename and !$attr_name){
+         $generate_name = 1;
+      }
+
+      // if a name is not specified then use the unique name
       if(strcmp($attr_name,'')==0){
          $attr_name = $attr_uniquename;
       }
 
-      // skip features that have no ID attribute
+      // if an ID attribute is not specified then use the attribute name and
+      // hope for the best
       if(!$attr_uniquename){
-         continue;
+         $attr_uniquename = $attr_name;
       }
+
+      // make sure the landmark sequence exists in the database.  We don't
+      // know the type of the landmark so we'll hope that it's unique across
+      // all types. If not we'll error out.  This test is only necessary if
+      // if the landmark and the uniquename are different.  If they are the same
+      // then this is the information for the landmark
+      if(strcmp($landmark,$attr_uniquename)!=0){
+         $feature_sql = "SELECT count(*) as num_landmarks
+                         FROM {feature} 
+                         WHERE organism_id = %d and uniquename = '%s'";
+         $count = db_fetch_object(db_query($feature_sql,$organism_id,$landmark));
+         if(!$count or $count->num_landmarks == 0){
+            print "ERROR: the landmark '$landmark' cannot be found for this organism. ". 
+                  "Please add the landmark and then retry the import of this GFF3 ".
+                  "file.\n";
+            return '';
+
+         }
+         if($count->num_landmarks > 1){
+            print "ERROR: the landmark '$landmark' is not unique for this organism. ".
+                  "The features cannot be associated.\n";
+            return '';
+         }
+      }
+
       
       // if the option is to remove or refresh then we want to remove
       // the feature from the database.
-      if($remove or $refresh){
+      if(!$generate_name and ($remove or $refresh)){
          print "Removing feature '$attr_uniquename'\n";
          $sql = "DELETE FROM {feature}
                  WHERE organism_id = %d and uniquename = '%s' and type_id = %d";
@@ -237,12 +362,23 @@ function tripal_core_load_gff3($gff_file, $add_only =0, $update = 0, $refresh =
 
       // add or update the feature and all properties
       if($update or $refresh or $add_only){
+    
+
          // add/update the feature
          $feature = tripal_core_load_gff3_feature($organism,$cvterm,
-            $attr_uniquename,$attr_name,$residues,$attr_is_analysis,$attr_is_obsolete,
-            $add_only);
+            $attr_uniquename,$attr_name,$residues,$attr_is_analysis,
+            $attr_is_obsolete, $add_only,$generate_name);
+
+         // store all of the features so far use later by parent and target
+         // relationships
+         $gff_features[$feature->uniquename]['type'] = $type;
+
          if($feature){
-            // add/update the featureloc if the landmark and the feature ID are not the same
+            if($generate_name){
+               $attr_uniquename = $feature->uniquename;
+            }
+ 
+            // add/update the featureloc if the landmark and the ID are not the same
             // if they are the same then this entry in the GFF is probably a landmark identifier
             if(strcmp($landmark,$attr_uniquename)!=0){
                tripal_core_load_gff3_featureloc($feature,$organism,
@@ -257,6 +393,10 @@ function tripal_core_load_gff3($gff_file, $add_only =0, $update = 0, $refresh =
             if(array_key_exists('Dbxref',$tags)){
                tripal_core_load_gff3_dbxref($feature,$tags['Dbxref']);
             }
+            // add parent relationships
+            if(array_key_exists('Parent',$tags)){
+               tripal_core_load_gff3_parents($feature,$cvterm,$tags['Parent'],$gff_features,$organism_id);
+            }
          }
       }
    }
@@ -266,9 +406,70 @@ function tripal_core_load_gff3($gff_file, $add_only =0, $update = 0, $refresh =
 /*************************************************************************
 *
 */
+function tripal_core_load_gff3_parents($feature,$cvterm,$parents,$gff_features,$organism_id){
+
+   $uname = $feature->uniquename;
+   $type = $cvterm->name;
+   $rel_type = 'part_of';
+
+
+   // create these SQL statements that will be used repeatedly below.
+   $cvtermsql = "SELECT CVT.cvterm_id
+                 FROM {cvterm} CVT
+                    INNER JOIN {cv} CV on CVT.cv_id = CV.cv_id
+                    LEFT JOIN {cvtermsynonym} CVTS on CVTS.cvterm_id = CVT.cvterm_id
+                 WHERE cv.name = '%s' and (CVT.name = '%s' or CVTS.synonym = '%s')";
+
+   $feature_sql = "SELECT * FROM {feature} 
+                   WHERE organism_id = %d and uniquename = '%s' and type_id = %d";
+
+   // iterate through the parents in the list
+   foreach($parents as $parent){  
+      $parent_type = $gff_features[$parent]['type'];
+
+      $parentcvterm = db_fetch_object(db_query($cvtermsql,'sequence',$parent_type,$parent_type));
+      $relcvterm = db_fetch_object(db_query($cvtermsql,'relationship',$rel_type,$rel_type));
+      $parent_feature = db_fetch_object(db_query($feature_sql,$organism_id,$parent,$parentcvterm->cvterm_id));
+
+      if($parent_feature){
+
+         // check to see if the relationship already exists
+         $sql = "SELECT * FROM {feature_relationship} WHERE subject_id = %d and object_id = %d and type_id = %d";
+         $rel = db_fetch_object(db_query($sql,$feature->feature_id,$parent_feature->feature_id,$relcvterm->cvterm_id));
+         if($rel){
+            print "   Relationship already exists, skipping '$uname' ($type) $rel_type '$parent' ($parent_type)\n";
+         } else {      
+            $sql = "INSERT INTO {feature_relationship} (subject_id,object_id,type_id)
+                    VALUES (%d,%d,%d)";
+            $result = db_query($sql,$feature->feature_id,$parent_feature->feature_id,$relcvterm->cvterm_id);
+            if(!$result){
+               print "WARNING: failed to insert feature relationship '$uname' ($type) $rel_type '$parent' ($parent_type)\n";
+            } else {
+               print "   Inserted relationship relationship: '$uname' ($type) $rel_type '$parent' ($parent_type)\n";
+            }
+         } 
+      }
+      else {
+         print "WARNING: cannot establish relationship '$uname' ($type) $rel_type '$parent' ($parent_type): Cannot find the parent\n";
+      }
+   }
+}
+/*************************************************************************
+*
+*/
 function tripal_core_load_gff3_dbxref($feature,$dbxrefs){
    foreach($dbxrefs as $dbxref){
-      print "Adding: $dbxref\n";
+      // check to see if this accession reference exists, if not add it
+//      $dbxrefsql = "SELECT * FROM {dbxref} WHERE db_id = %s and accession = '%s'";
+//      $dbxref = db_fetch_object(db_query($dbxrefsql,$db_id,$accession));
+//      if(!$dbxref){
+//         $sql = "INSERT INTO {dbxref} (db_id,accession) VALUES (%d,'%s')";
+//         $result = db_query($sql,$db_id,$accession);
+//         if(!$result){
+//           print "WARNING: could not add external database acession: '$name accession: $accession'\n";
+//         }
+//         $dbxref = db_fetch_object(db_query($dbxrefsql,$db_id,$accession));
+//      }
    }
 }
 
@@ -372,7 +573,11 @@ function tripal_core_load_gff3_alias($feature,$aliases){
 *
 */
 function tripal_core_load_gff3_feature($organism,$cvterm,$uniquename,$name,
-   $residues,$is_analysis='f',$is_obsolete='f',$add_only)  {
+   $residues,$is_analysis='f',$is_obsolete='f',$add_only,$generate_name)  {
+
+   if($generate_name){
+      $uniquename = 'tripal_temp_loading_name' . rand(1,99999999);
+   }
 
    // check to see if the feature already exists
    $feature_sql = "SELECT * FROM {feature} 
@@ -386,53 +591,73 @@ function tripal_core_load_gff3_feature($organism,$cvterm,$uniquename,$name,
       $is_analysis = 'false';
    }
 
+
    // insert the feature if it does not exist otherwise perform an update
    if(!$feature){
-      print "Adding feature '$uniquename'\n";
-      $sql = "INSERT INTO {feature} (organism_id, name, uniquename, residues, seqlen,
-                 md5checksum, type_id,is_analysis,is_obsolete)
-              VALUES(%d,'%s','%s','%s',%d, '%s', %d, %s, %s)";
-      $result = db_query($sql,$organism->organism_id,$name,$uniquename,$residues,strlen($residues),
+      print "Adding feature '$uniquename' ($cvterm->name)\n";
+      $isql = "INSERT INTO {feature} (organism_id, name, uniquename, residues, seqlen,
+                  md5checksum, type_id,is_analysis,is_obsolete)
+               VALUES(%d,'%s','%s','%s',%d, '%s', %d, %s, %s)";
+      $result = db_query($isql,$organism->organism_id,$name,$uniquename,$residues,strlen($residues),
                md5($residues),$cvterm->cvterm_id,$is_analysis,$is_obsolete);
       if(!$result){
-         print "ERROR: failed to insert feature '$uniquename'\n";
+         print "ERROR: failed to insert feature '$uniquename' ($cvterm->name)\n";
          return 0;
       }
    } 
    elseif(!$add_only) {
-      print "Updating feature '$uniquename'\n";
-      $sql = "UPDATE {feature} 
-              SET name = '%s', residues = '%s', seqlen = '%s', md5checksum = '%s',
-                 is_analysis = %s, is_obsolete = %s
-              WHERE organism_id = %d and uniquename = '%s' and type_id = %d";
-      $result = db_query($sql,$name,$residues,strlen($residues),md5($residues),$is_analysis,$is_obsolete);
+      print "Updating feature '$uniquename' ($cvterm->name)\n";
+      $usql = "UPDATE {feature} 
+               SET name = '%s', residues = '%s', seqlen = '%s', md5checksum = '%s',
+                  is_analysis = %s, is_obsolete = %s
+               WHERE organism_id = %d and uniquename = '%s' and type_id = %d";
+      $result = db_query($usql,$name,$residues,strlen($residues),md5($residues),$is_analysis,$is_obsolete,
+                   $organism_id,$uniquename,$cvterm->cvterm_id);
       if(!$result){
-         print "ERROR: failed to update feature '$uniquename'\n";
+         print "ERROR: failed to update feature '$uniquename' ($cvterm->name)\n";
          return 0;
       }
    }
    else {
       // the feature exists and we don't want to update it so return
       // a value of 0.  This will stop all downstream property additions
-      print "Skipping existing feature: '$uniquename'.\n";
+      print "Skipping existing feature: '$uniquename' ($cvterm->name).\n";
       return 0;
    }
-
    $feature = db_fetch_object(db_query($feature_sql,$organism->organism_id,$uniquename,$cvterm->cvterm_id));
+   // now that we've added the feature let's reset it's uniquename to be
+   // the feature id
+   if($generate_name){
+      $usql = "UPDATE {feature} 
+               SET name = '%s', uniquename = '%s'
+               WHERE feature_id = %d";
+      print "   Renaming feature '$uniquename' => ";
+      $uniquename = "$feature->feature_id";
+      print "$uniquename\n";
+      $result = db_query($usql,$uniquename,$uniquename,$feature_id);
+      if(!$result){
+         print "ERROR: failed to update unnamed feature '$uniquename' with generic name\n";
+         return 0;
+      }
+      $feature->name = $uniquename;
+      $feature->uniquename = $uniquename;
+   }
+
    return $feature;
 }
 /*************************************************************************
 *
 */
-function tripal_core_load_gff3_featureloc($feature,$organism,$landmark,$fmin,$fmax,$strand,$phase,
-   $is_fmin_partial,$is_fmax_partial,$residue_info,$locgroup)  {
+function tripal_core_load_gff3_featureloc($feature,$organism,$landmark,$fmin,
+   $fmax,$strand,$phase,$is_fmin_partial,$is_fmax_partial,$residue_info,$locgroup)
+{
  
    // get the source feature
    $sql = "SELECT * FROM {feature} 
            WHERE organism_id = %d and uniquename = '%s'";
    $srcfeature = db_fetch_object(db_query($sql,$organism->organism_id,$landmark));
    if(!$srcfeature){
-      print "ERROR: cannot find source feature $landmark.\n";
+      print "ERROR: cannot find landmark feature $landmark.  Cannot add the feature location record\n";
       return 0;
    }
 
@@ -443,7 +668,7 @@ function tripal_core_load_gff3_featureloc($feature,$organism,$landmark,$fmin,$fm
 
    // check to see if this featureloc already exists, but also keep track of the
    // last rank value
-   $rank = 0;  
+   $rank = -1;  
    $exists = 0;  
    $featureloc_sql = "SELECT FL.featureloc_id,FL.fmin,FL.fmax, FL.is_fmin_partial,
                          FL.is_fmax_partial, FL.strand, FL.phase, FL.residue_info,
@@ -468,7 +693,8 @@ function tripal_core_load_gff3_featureloc($feature,$organism,$landmark,$fmin,$fm
       $rank = $featureloc->rank;
    }
    if(!$exists){
-      // this feature does not have a feature loc so add it
+      $rank++;
+      // this feature location is new so add it
       if(!$phase){
           $phase = 'NULL';
       }
@@ -493,6 +719,7 @@ function tripal_core_load_gff3_featureloc($feature,$organism,$landmark,$fmin,$fm
                $strand,$phase,$residue_info,$locgroup,$rank);
       if(!$result){
          print "ERROR: failed to insert featureloc\n";
+exit;
          return 0;
       }
    }

+ 58 - 1
tripal_core/tripal_core.module

@@ -159,6 +159,15 @@ function tripal_core_menu() {
      'type' => MENU_NORMAL_ITEM,
    );
 
+   $items['admin/tripal/bulk_load/step2_get_type/%'] = array(
+     'title' => 'Create Bulk Loader',
+     'description' => 'Create a bulk loader template for loading data into Chado',
+     'page callback' => 'tripal_core_bulk_loader_ahah_step2_feature_type',
+     'page arguments' => array(4),
+     'access arguments' => array('access administration pages'),
+     'type' => MENU_CALLBACK,
+   );
+
   return $items;
 }
 /************************************************************************
@@ -253,4 +262,52 @@ function tripal_core_views_api() {
    return array(
       'api' => 2.0,
    );
-}
+}
+
+/*************************************************************************
+ * Purpose: Get max rank for a given set of criteria
+ *   This function was developed with the many property tables in chado in mind
+ *
+ * @params tablename: the name of the chado table you want to select the max rank from
+ *    this table must contain a rank column of type integer
+ * @params where_options: array(
+ *													<column_name> => array(
+ *														'type' => <type of column: INT/STRING>,
+ *														'value' => <the value you want to filter on>,
+ *														'exact' => <if TRUE use =; if FALSE use ~>,
+ *													)
+ *				)
+ *     where options should include the id and type for that table to correctly
+ *     group a set of records together where the only difference are the value and rank
+ * @return the maximum rank
+ *
+ */
+function tripal_get_max_chado_rank ($tablename, $where_options) {
+
+	$where= array();
+	//generate the where clause from supplied options
+	// the key is the column name
+	foreach ($where_options as $key => $val_array) {
+		if (preg_match('/INT/', $val_array['type'])) {
+			$where[] = $key."=".$val_array['value'];
+		} else {
+			if ($val_array['exact']) { $operator='='; }
+			else { $operator='~'; }
+			$where[] = $key.$operator."'".$val_array['value']."'";
+		}
+	}
+	
+  $previous_db = tripal_db_set_active('chado');
+  $result = db_fetch_object(db_query(
+    "SELECT max(rank) as max_rank, count(rank) as count FROM %s WHERE %s",
+    $tablename,
+    implode(' AND ',$where)
+  ));
+  tripal_db_set_active($previous_db);
+	//drupal_set_message("Max Rank Query=SELECT max(rank) as max_rank, count(rank) as count FROM ".$tablename." WHERE ".implode(' AND ',$where));
+	if ($result->count > 0) {
+	  return $result->max_rank;
+	} else {
+		return -1;
+	}
+}

+ 1 - 0
tripal_cv/obo_loader.php

@@ -454,6 +454,7 @@ function tripal_cv_obo_add_synonyms($term,$cvterm){
       if(!db_query($sql)){
          tripal_cv_obo_quiterror("Failed to add the synonyms type vocabulary");
       }
+      $syncv = db_fetch_object(db_query($sql));
    }
 
    // now add the synonyms

+ 2 - 3
tripal_cv/tripal_cv.module

@@ -4,9 +4,8 @@ require_once "charts.php";
 require_once "trees.php";
 require_once "obo_loader.php";
 
-//
-// Copyright 2009 Clemson University
-//
+require_once "tripal_cv.api.inc";
+
 /*************************************************************************
 *
 */

+ 3 - 3
tripal_db/tripal_db.module

@@ -1,7 +1,7 @@
 <?php
-//
-// Copyright 2009 Clemson University
-//
+
+require_once "tripal_db.api.inc";
+
 /*************************************************************************
 *
 */

+ 9 - 2
tripal_feature/fasta_loader.php

@@ -208,7 +208,7 @@ function tripal_feature_fasta_load_form_validate($form, &$form_state){
       $dfile = $fasta_file;
    }
    if(!file_exists($dfile)){
-      form_set_error('fasta_file',t("Cannot find the file on the system"));
+      form_set_error('fasta_file',t("Cannot find the file on the system. Check that the file exists or that the web server has permissions to read the file."));
    }
 
    // make sure if a relationship is specified that all fields are provided.
@@ -294,6 +294,10 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type,
    $residues = '';
    $num_lines = sizeof($lines);
    $interval = intval($num_lines * 0.01);
+   if($interval == 0){
+      $interval = 1;
+   }
+
    foreach ($lines as $line_num => $line) {
       $i++;  // update the line count     
 
@@ -342,7 +346,10 @@ function tripal_feature_load_fasta($dfile, $organism_id, $type,
          $residues .= trim($line);
       }
    }
-
+   // now load the last sequence in the file
+   tripal_feature_fasta_loader_insert_feature($name,$uname,$db_id,
+      $accession,$subject,$rel_type,$parent_type,$library_id,$organism_id,$type,
+      $source,$residues,$update);
    return '';
 }
 /*************************************************************************

+ 1 - 1
tripal_feature/syncFeatures.php

@@ -203,7 +203,7 @@ function tripal_feature_sync_feature ($feature_id){
       $new_node = new stdClass();
       $new_node->type = 'chado_feature';
       $new_node->uid = $user->uid;
-      $new_node->title = "$feature->uniquename ($feature->cvname) $organism->genus $organism->species";
+      $new_node->title = "$feature->name, $feature->uniquename ($feature->cvname) $organism->genus $organism->species";
       $new_node->name = "$feature->name";
       $new_node->uniquename = "$feature->uniquename";
       $new_node->feature_id = $feature->feature_id;

+ 132 - 144
tripal_feature/tripal_feature.module

@@ -5,6 +5,14 @@ require_once "syncFeatures.php";
 require_once "indexFeatures.php";
 require_once "fasta_loader.php";
 
+require_once "tripal_feature.api.inc";
+
+require_once "tripal_feature-secondary_tables.inc";
+require_once "tripal_feature-properties.inc";
+require_once "tripal_feature-relationships.inc";
+require_once "tripal_feature-db_references.inc";
+
+
 /*************************************************************************
 *
 */
@@ -128,13 +136,63 @@ function tripal_feature_menu() {
      'type' => MENU_NORMAL_ITEM,
    );
 
-   $items['admin/settings/tripal/tripal_feature/load'] = array(
-     'title' => 'Bulk Load',
-     'description' => 'Upload Data into Chado & Drupal',
-     'page callback' => 'tripal_feature_bulkload',
-     'access arguments' => array('administer site configuration'),
-     'type' => MENU_NORMAL_ITEM,
-   );
+ // Adding Secondary Properties-----------------
+  $items['node/%/properties'] = array(       
+    'title' => t('Add Properties & Synonyms'),                         
+    'description' => t('Settings for Features'),
+    'page callback' => 'tripal_feature_add_ALL_property_page',           
+    'page arguments' => array(1), 
+    'access arguments' => array('create chado_feature content'),
+    'type' => MENU_CALLBACK
+  ); 
+
+  $items['node/%/db_references'] = array(                        
+    'title' => t('Add Database References'),                   
+    'description' => t('Settings for Features'),              
+    'page callback' => 'tripal_feature_add_ALL_dbreferences_page',                         
+    'page arguments' => array(1),
+    'access arguments' => array('create chado_feature content'),
+    'type' => MENU_CALLBACK
+  ); 
+
+  $items['node/%/relationships'] = array(                      
+    'title' => t('Add Relationships'),                      
+    'description' => t('Settings for Features'),               
+    'page callback' => 'tripal_feature_add_ALL_relationships_page',                          
+    'page arguments' => array(1),
+    'access arguments' => array('create chado_feature content'),
+    'type' => MENU_CALLBACK
+  );
+  //Edit/Deleting Secondary Properties-------------
+  $items['node/%/edit_properties'] = array(
+    'title' => t('Edit Properties'),
+    'description' => t('Settings for Features'),
+    'page callback' => 'tripal_feature_edit_ALL_properties_page',
+    'page arguments' => array(1),
+    'access arguments' => array('edit chado_feature content'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 8,
+  );
+
+    $items['node/%/edit_relationships'] = array(
+    'title' => t('Edit Relationships'),
+    'description' => t('Settings for Feature'), 
+    'page callback' => 'tripal_feature_edit_ALL_relationships_page',
+    'page arguments' => array(1),
+    'access arguments' => array('edit chado_feature content'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 9,
+  );
+
+  $items['node/%/edit_db_references'] = array(
+    'title' => t('Edit DB References'),
+    'description' => t('Settings for Feature'),
+    'page callback' => 'tripal_feature_edit_ALL_dbreferences_page',
+    'page arguments' => array(1),
+    'access arguments' => array('edit chado_feature content'),
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 10,
+  );
 
    return $items;
 }
@@ -618,7 +676,7 @@ function chado_feature_load($node){
    $map = db_fetch_object(db_query($sql, $node->vid));
 
 
-   // get information about this organism and add it to the items in this node
+   // get information about this feature and add it to the items in this node
    $sql = "SELECT F.feature_id, F.name as featurename, F.uniquename, ".
           "F.residues, F.seqlen, O.genus, O.species, O.common_name, ".
           "  CVT.name as cvname, O.organism_id, F.type_id, F.is_obsolete  ".
@@ -631,11 +689,19 @@ function chado_feature_load($node){
    tripal_db_set_active($previous_db);  // now use drupal database
    $additions->feature = $feature;
    $additions->seqlen = $feature->seqlen;
+
    // add organism node nid
    $sql = "SELECT nid FROM {chado_organism} WHERE organism_id = %d";
    $org_nid = db_result(db_query($sql, $additions->feature->organism_id));
    $additions->org_nid = $org_nid;
    $additions->accession =  variable_get('chado_feature_accession_prefix','ID') . $feature->feature_id;
+
+   // add organism details
+   $sql = "SELECT * FROM {organism} WHERE organism_id = %d";
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $organism = db_fetch_object(db_query($sql, $additions->feature->organism_id));
+   tripal_db_set_active($previous_db);  // now use drupal database
+   $additions->organism = $organism;
    
    // add the feature synonyms
    $sql = "SELECT S.name ".
@@ -685,15 +751,30 @@ function chado_feature_load($node){
              FO.uniquename as object_uniquename, 
              CVTO.name as object_type,
              FO.residues as object_residues,
-             FR.object_id
+             FR.object_id,
+             FLS.name as src_name,
+             FLS.feature_id as src_featureid,
+             CVTR.name as src_cvname, 
+             CVTR.cvterm_id as src_type_id,
+             FL.fmin, 
+             FL.fmax, 
+             FL.is_fmin_partial, 
+             FL.is_fmax_partial,
+             FL.strand, 
+             FL.phase, 
+             FL.residue_info
            FROM {feature_relationship} FR
              INNER JOIN {cvterm} CVT ON FR.type_id = CVT.cvterm_id
              INNER JOIN {feature} FS ON FS.feature_id = FR.subject_id
              INNER JOIN {feature} FO ON FO.feature_id = FR.object_id
              INNER JOIN {cvterm} CVTO ON FO.type_id = CVTO.cvterm_id
-             INNER JOIN {cvterm} CVTS ON FS.type_id = CVTS.cvterm_id ";
-   $osql = "$sql  WHERE FR.object_id = %d";
-   $ssql = "$sql  WHERE FR.subject_id = %d";
+             INNER JOIN {cvterm} CVTS ON FS.type_id = CVTS.cvterm_id
+             LEFT JOIN {featureloc} FL on FL.feature_id = FS.feature_id 
+             LEFT JOIN {feature} FLS on FLS.feature_id = FL.srcfeature_id
+             LEFT JOIN {cvterm} CVTR on FLS.type_id = CVTR.cvterm_id
+   ";
+   $osql = "$sql  WHERE FR.object_id = %d ORDER BY FLS.name, FL.fmin ASC";
+   $ssql = "$sql  WHERE FR.subject_id = %d ORDER BY FLS.name, FL.fmin ASC";
 
    // first get the relationships where this feature is the object
    // then where it is the subject 
@@ -731,10 +812,45 @@ function chado_feature_load($node){
      }  
      $srelationships[$i++] = $rel;      
    }
-   $additions->orelationships = $orelationships;
-   $additions->srelationships = $srelationships;
-   // add the feature properties
-   
+   $additions->object_relationships = $orelationships;
+   $additions->subject_relationships = $srelationships;
+
+
+  // get the locations for this feature
+   $sql = "SELECT F.name,F.feature_id, F.uniquename,CVT.name as cvname, CVT.cvterm_id,
+             FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, 
+             FL.phase, FL.residue_info
+           FROM featureloc FL
+              INNER JOIN feature F on FL.srcfeature_id = F.feature_id
+              INNER JOIN cvterm CVT on F.type_id = CVT.cvterm_id
+           WHERE FL.feature_id = %d";
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $flresults = db_query($sql, $map->feature_id);
+   tripal_db_set_active($previous_db);  // now use drupal database 
+   $i=0;
+   $featurelocs = array();
+   while($loc = db_fetch_object($flresults)){
+      $featurelocs[$i++] = $loc;
+   }
+   $additions->featurelocs = $featurelocs;
+
+   // get features that are aligned to this feature
+   $sql = "SELECT F.name,F.feature_id, F.uniquename,CVT.name as cvname, CVT.cvterm_id,
+             FL.fmin, FL.fmax, FL.is_fmin_partial, FL.is_fmax_partial,FL.strand, 
+             FL.phase, FL.residue_info
+           FROM featureloc FL
+              INNER JOIN feature F on FL.feature_id = F.feature_id
+              INNER JOIN cvterm CVT on F.type_id = CVT.cvterm_id
+           WHERE FL.srcfeature_id = %d";
+   $previous_db = tripal_db_set_active('chado');  // use chado database
+   $flresults = db_query($sql, $map->feature_id);
+   tripal_db_set_active($previous_db);  // now use drupal database 
+   $i=0;
+   $myfeaturelocs = array();
+   while($loc = db_fetch_object($flresults)){
+      $myfeaturelocs[$i++] = $loc;
+   }
+   $additions->myfeaturelocs = $myfeaturelocs;   
 
    return $additions;
 }
@@ -1415,134 +1531,6 @@ function tripal_features_cleanup($dummy = NULL, $job_id = NULL) {
    }
    return '';
 }
-
-/************************************************************************
- *
- */
-function tripal_feature_bulkload(){
-   return drupal_get_form('tripal_feature_load_fasta_form');
-}
-/************************************************************************
- *
- */
-function tripal_feature_load_fasta_form (&$form_state = NULL){
-
-   // get the list of organisms
-   $sql = "SELECT * FROM {Organism} ORDER BY genus,species";
-   $previous_db = tripal_db_set_active('chado');  // use chado database
-   $org_rset = db_query($sql);
-   tripal_db_set_active($previous_db);  // now use drupal database
-   $organisms = array();
-   $organisms[''] = '';
-   while($organism = db_fetch_object($org_rset)){
-      $organisms[$organism->organism_id] = "$organism->genus $organism->species ($organism->common_name)";
-   }
-
-   // get the list of supported feature types
-   $ftypes = array();
-   $ftypes[''] = '';
-   $supported_ftypes = split("[ \n]",variable_get('chado_feature_feature_types','EST contig'));
-   foreach($supported_ftypes as $ftype){
-      $ftypes["$ftype"] = $ftype;
-   }
-
-   // get the list of libraries
-   // TODO !!!! Use Ajax to filter this automatically based on the organism
-   // selected by the user. This will prevent mistakes from user input.
-   $sql = "SELECT * FROM {Library} L ".
-          "  INNER JOIN Organism O ON L.organism_id = O.organism_id ".
-          "ORDER BY L.name";
-   $previous_db = tripal_db_set_active('chado');  // use chado database
-   $lib_rset = db_query($sql);
-   tripal_db_set_active($previous_db);  // now use drupal database
-   $libraries = array();
-   $libraries[''] = '';
-   while($library = db_fetch_object($lib_rset)){
-      $libraries[$library->library_id] = "$library->name ($library->genus $library->species)";
-   }
-
-   $form['#attributes']['enctype'] = 'multipart/form-data';
-
-   $form['organism'] = array (
-      '#title'       => t('Organism'),
-      '#type'        => t('select'),
-      '#description' => t("Choose the organism with which these sequences are associated "),
-      '#required'    => TRUE,
-      '#default_vaule' => '',
-      '#options'     => $organisms,
-      '#weight'      => 1,
-   );
-   $form['library'] = array (
-      '#title'       => t('Library'),
-      '#type'        => t('select'),
-      '#description' => t("Choose the library with from which these sequences are derived. Leave blank if not applicable."),
-      '#required'    => FALSE,
-      '#default_vaule' => '',
-      '#options'     => $libraries,
-      '#weight'      => 2,
-   );
-   $form['ftype'] = array (
-      '#title'       => t('Feature Type'),
-      '#type'        => t('select'),
-      '#description' => t("Choose the category of sequences you are uploading.  All sequences in the FASTA file will be imported as this type"),
-      '#required'    => TRUE,
-      '#default_vaule' => '',
-      '#options'     => $ftypes,
-      '#weight'      => 3,
-   );
-   $form['fasta_file'] = array(
-      '#type'       => t('file'),
-      '#title'      => t('Fasta File'),
-      '#description'   => t('Upload a FASTA file of sequences. The definition line should contain only the feature name. All other annotations should be removed. The file must not be larger than ' . file_upload_max_size() . ' bytes'),
-      '#weight'        => 4,
-   );
-   $form['upload'] = array(
-      '#type' => 'submit',
-      '#value' => t('Upload File'),
-      '#weight' => 2,
-      '#executes_submit_callback' => TRUE,
-      '#weight'      => 5,
-   );
-
-   return $form;
-}
-/************************************************************************
- *
- */
-function tripal_feature_load_fasta_form_validate($form, &$form_state){
-
-   // TODO !!! check that the fasta file is valid
-
-   global $user;
-
-   // we need a path within the drupal installation to temporarily use as the destination
-   // after we upload, we'll move the file to analysis directory
-   $upload_url = file_directory_path() . "/chado_feature_bulk_upload/$user->uid";
-
-   // create the download directory. We do it this way rather than the
-   // file_check_directory because we don't want a drupal message presented
-   // the user when the directory is created.
-   if (!is_dir($upload_url)) {
-      mkdir($upload_url,0775,TRUE);
-   }
-
-   // upload the file and copy it to the proper location
-   $validators = array();  // we don't have any validators
-   if($file = file_save_upload('fasta_file',$validators,$upload_url)){
-      drupal_set_message("File $file->name uploaded succesfully");
-   } else {
-      form_set_error('fasta_file',t('Upload Failed'));
-   }
-}
-/************************************************************************
- *
- */
-function tripal_feature_load_fasta_form_submit($form, &$form_state){
-   global $user;
-
-   // add a job to be executed
-   tripal_add_job ($job_name,$type,$callback,$uid);
-}
 /************************************************************************
  *
  */

+ 3 - 1
tripal_organism/tripal_organism.module

@@ -1,5 +1,7 @@
 <?php
 
+require_once "tripal_organism.api.inc";
+
 /*******************************************************************************
  *  Provide information to drupal about the node types that we're creating
  *  in this module
@@ -932,7 +934,7 @@ function tripal_organism_taxonify_features ($organism_id = NULL, $job_id = NULL)
    $interval = intval($count * 0.01);
    foreach($ids as $feature_id){
       // update the job status every 1% features
-      if($job_id and $i % interval == 0){
+      if($job_id and $i % $interval == 0){
 	     tripal_job_set_progress($job_id,intval(($i/$count)*100));
 	   }
       $node = db_fetch_object(db_query($nsql,$feature_id));