#!/usr/bin/env perl
############################################################
#
# $Id: Genbank_classes.pl,v 1.13 2009/05/14 11:04:44 jvanheld Exp $
#
# Time-stamp: <2003-08-09 00:37:11 jvanheld>
#
############################################################

################################################################
#### Genbank_classes.pl
#### definition of object classes used for parsing Genbank flat files

if ($0 =~ /([^(\/)]+)$/) {
    push (@INC, "$`"); ### add the program's directory to the lib path
}
require "lib/util.pl";


################################################################
#### organism
package Genbank::Organism; ### for parsing genbank files
{
  @ISA = qw ( classes::DatabaseObject );
  ### class attributes
  $_count = 0;
  $_prefix = "org_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     names=>"ARRAY",
			     taxonomy=>"SCALAR",
			     source=>"SCALAR"
			     );
}


################################################################
#### Contig
#### One Genbank flat fiels contains one or several contigs
package Genbank::Contig; ### for parsing genbank files
{
  @ISA = qw ( classes::DatabaseObject );
  ### class attributes
  $_count = 0;
  $_prefix = "ctg_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     names=>"ARRAY",
			     organism=>"SCALAR",
			     type=>"SCALAR",
			     date=>"SCALAR",
			     xrefs=>"EXPANDED",
			     comment=>"ARRAY",

			     taxid=>"SCALAR",
			     );
}


################################################################
#### a generic class for all features in the flat file
package Genbank::Feature;
{
  @ISA = qw ( classes::DatabaseObject );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (
      id=>"SCALAR",
      
      ### Additional attributes generated by the parser
      names=>"ARRAY",
      organism=>"SCALAR",
      description=>"SCALAR",
      chromosome=>"SCALAR",
      strand=>"SCALAR",
      start_pos=>"SCALAR",
      end_pos=>"SCALAR",
      source=>"SCALAR",
      type=>"SCALAR",
      locus_tag=>"SCALAR",
      GeneID=>"SCALAR",
  );
  
      
  ################################################################
  #### use Genbank GI as identifier
  sub UseGenbankGIasID {
      my ($self) = @_;

      #### cross-references
      my @xrefs = $self->get_attribute("db_xref");
      my $gi = "";
      foreach my $xref (@xrefs) {
	  #### extract GI from cross-references
	  if ($xref =~ /GI:/) {
	      $gi = "$'";
	      last;
	  } 
      }
      warn join ("\t", "ID", $self->get_attribute("id"), "GI", $gi), "\n" if ($verbose >= 4);
      if ($gi) {
	  $self->force_attribute("id",$gi); #### use GI as dientifier
      } else {
	  &main::ErrorMessage("; Error\tfeature ".$self->get_attribute("id")." has no GI.\n"); 
      }
  }

  ################################################################
  #### use GeneID as identifier
  sub UseGeneIDasID {
      my ($self) = @_;
      
      #### cross-references
      my @xrefs = $self->get_attribute("db_xref");
      my $gi = "";
      foreach my $xref (@xrefs) {
	  #### extract GI from cross-references
	  if ($xref =~ /^geneid:/i) {
	      $GeneID = "$'";
	      last;
	  } 
      }
      &RSAT::message::Info(join("\t", "Replacing ID", $self->get_attribute("id"), 
				"by GeneID", $GeneID,
				"feature type", $self->get_attribute("type"))) if ($verbose >= 5);
      if ($GeneID) {
	  $self->force_attribute("id",$GeneID); #### use GI as dientifier
      } else {
	  &main::ErrorMessage("; Error\tfeature ".$self->get_attribute("id")." has no GeneID.\n"); 
      }
  }

  ################################################################
  ## Replace ID by the value of a single-value attribute
  sub ReplaceID {
      my ($self, $field) = @_;

      my ($value) = $self->get_attribute($field);

      if ($value) {
	  &RSAT::message::Info("Replacing ID", $self->get_attribute("id"), "by attribute", $field, $value, "feature type", $self->get_attribute("type")) 
	      if ($verbose >= 5);
	  $self->force_attribute("id",$value);
      } else {
	&RSAT::message::Warning("There is no value in the field",$field,"for feature", $self->get_attribute("id"),"feature type", $self->get_attribute("type"));
      }
  }

  ################################################################
  ## Use arbitrary cross-reference as IDentifier
  sub UseAttributesAsID {
    my ($self, @attributes) = @_;
    &RSAT::message::Debug("Use attribute as ID", $self->get_attribute("id"), join(",", @attributes)) if ($main::verbose >= 4);
    my $i = 0;
    my $attr;
    my $id;
    do {
      $attr = $attributes[$i];
      my @values = $self->get_attribute($attr);
      $id = shift(@values);
      $i++;
      if ($id eq $main::null) {
	$id = "";
	&RSAT::message::Debug("&Genbank::Feature::UseAttributeAsID()",
			      "Skipping attribute", $attr, "because has a null value", $main::null) if ($main::verbose >= 5);
      }
    } until (($id) || ($i > $#attributes));
    if ($id) {
      $self->force_attribute("id", $id);
      &RSAT::message::Info("feature", $self->get_attribute("id"), "Using attribute", $attr, "as ID", $id) if ($main::verbose >= 4);
    } else {
      &RSAT::message::Warning("Feature", $self->get_attribute("id"), "has no suitable attribute to reset ID", join (";", @attributes)) if ($main::verbose >= 3);
    }
  }

}




################################################################
#### source
package Genbank::Source;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "src_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     
			     #### single value attributes from Genbank flat files
			     organism=>"SCALAR",
			     isolate=>"SCALAR",
			     serotype=>"SCALAR",
			     chromosome=>"SCALAR",
			     strain=>"SCALAR",
			     sub_strain=>"SCALAR",
			     plasmid=>"SCALAR",
			     
			     ### multivalued attributes from Genabk flat files
			     transl_except=>"ARRAY",
			     note=>"ARRAY",
			     db_xref=>"ARRAY",
			     
			     #### additional attributes generated by the parser
			     taxid=>"SCALAR"
			     );


  #### extract taxid from db_xref
  sub get_taxid {
      my ($self) = @_;
      my @xrefs = $self->get_attribute("db_xref");
      my $taxid = "";

      #### search taxid in cross-references
      foreach my $xref (@xrefs) {
	  if ($xref =~ /taxon:(\d+)/) {
	      $taxid = $1;
	      last;
	  }
      }

      #### check if taxid was found
      if ($taxid) {
	  $self->set_attribute("taxid", $taxid);
      } else {
	  warn ("; Error\tSource ", $self->get_attribute("id"), "has no taxon identifier", "\n");
      }
  }

}

################################################################
#### Gene. Note that the gene annotation contains almost no
#### information. The information is distributed between the
#### corresponding mRNA(s) and CDS(s)
package Genbank::Gene;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",

			     ### raw info found in Genbank flat files
			     chrom_position=>"SCALAR",
			     gene=>"SCALAR",

			     note=>"ARRAY",
			     exons=>"ARRAY",
			     introns=>"ARRAY",

			     ### info resulting from parsing
#			     mRNAs=>"ARRAY",
#			     CDSs=>"ARRAY"
			     );
}


################################################################
#### Messenger RNA
#### one gene can be associated to one or several mRNAs
package Genbank::mRNA;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     gene_id=>"SCALAR",

			     ### raw info found in Genbank flat files
			     chrom_position=>"SCALAR",
			     note=>"ARRAY",
			     gene=>"SCALAR",
			     product=>"SCALAR",
			     transcript_id=>"SCALAR",
			     db_xref=>"ARRAY"
			     );
}


################################################################
#### Micro RNA
#### one gene can be associated to one or several scRNAs
package Genbank::scRNA;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     gene_id=>"SCALAR",

			     ### raw info found in Genbank flat files
			     chrom_position=>"SCALAR",
			     note=>"ARRAY",
			     gene=>"SCALAR",
			     product=>"SCALAR",
			     transcript_id=>"SCALAR",
			     db_xref=>"ARRAY"
			     );
}

################################################################
#### Transfer RNA
package Genbank::tRNA;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     gene_id=>"SCALAR",
			     names=>"ARRAY",

			     ### raw info found in Genbank flat files
			     chrom_position=>"SCALAR",
			     gene=>"SCALAR",
			     product=>"SCALAR",

			     #### multi-value attributes
			     note=>"ARRAY",
			     function=>"ARRAY",
			     );
}

################################################################
#### Ribosomial RNA
package Genbank::rRNA;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     gene_id=>"SCALAR",
			     names=>"ARRAY",

			     ### raw info found in Genbank flat files
			     chrom_position=>"SCALAR",
			     gene=>"SCALAR",
			     product=>"SCALAR",

			     #### multi-value attributes
			     note=>"ARRAY",
			     function=>"ARRAY",
			     );
}

################################################################
#### Miscellaneous RNA
package Genbank::misc_RNA;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     gene_id=>"SCALAR",
			     names=>"ARRAY",

			     ### raw info found in Genbank flat files
			     chrom_position=>"SCALAR",
			     gene=>"SCALAR",
			     product=>"SCALAR",

			     #### multi-value attributes
			     note=>"ARRAY",
			     function=>"ARRAY",
			     );
}

################################################################
## repeat region
package Genbank::repeat_region;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",

			     ### raw info found in Genbank flat files
			     chrom_position=>"SCALAR",

			     );
}


################################################################
#### Ribosomial RNA
package Genbank::misc_feature;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     gene_id=>"SCALAR",
			     names=>"ARRAY",

			     ### raw info found in Genbank flat files
			     chrom_position=>"SCALAR",
			     gene=>"SCALAR",
			     product=>"SCALAR",

			     #### multi-value attributes
			     note=>"ARRAY",
			     function=>"ARRAY",
			     );
}



################################################################
#### CDS (coding sequence)
#### One gene can be associated to one or several CDSs
package Genbank::CDS;
{
  @ISA = qw ( Genbank::Feature );
  ### class attributes
  $_count = 0;
  $_prefix = "ft_";
  @_objects = ();
  %_name_index = ();
  %_id_index = ();
  %_attribute_count = ();
  %_attribute_cardinality = (id=>"SCALAR",
			     gene_id=>"SCALAR",


			     #### Single-value attributes found in Genbank files
			     chrom_position=>"SCALAR",
			     gene=>"SCALAR",
			     product=>"SCALAR",
			     codon_start=>"SCALAR",
			     protein_id=>"SCALAR",
			     translation=>"ARRAY", ## This is a trick: translation is a single-value attribute, not an array, it is a single-valued attribute but I prefer to store it in a separate table

			     #### Multivaluted attributes found in Genbank files
			     EC_number=>"ARRAY",
			     note=>"ARRAY",
			     db_xref=>"ARRAY",
			     transl_except=>"ARRAY",
			     function=>"ARRAY",

			     );
}


#### end of class definitions
return 1;
