#!/usr/bin/perl
package Feature_base;
#####################################################################
# Author : Shuai Weng
# Date   : July 2001
#
# Usage: 
#     
#   use Feature;
#
#   ### You may use one of the following syntaxes to 
#   ### instantiate a new Feature object.
#
#   our $featObj = Feature->new(dbh=>$dbh,
#                              feature_name=>$featureName);
#       
#   our $featObj = Feature->new(dbh=>$dbh,
#                              feature_no=>$featureNo);
#       
#       
#
#   ### You can use an accessor for any valid column 
#   ### in the Feature table. For example: 
#   our $feature_name = $featObj->feature_name;
#   our $chromosome = $featObj->chromosome;
#   our $start_coord = $featObj->start_coord;
#   .....
#
#   ### The object also provides other accessor methods to 
#   ### access no-feature columns. For example:
#   our $locus_name = $featObj->locus_name;
#   our $featureTypeList = $featObj->featureTypeList;
#   ....
#   See documentation for detail.
#   
#   http:///usr/local/dicty/www_dictybase/db/lib/html/dictyBase/programmer/Feature.html
#
#####################################################################
use strict;
use DBI;
use vars qw (@ISA %allowedConstructors);
use dictyBase_Table;
@ISA = qw (dictyBase_Table); # base class

# Class Globals

# put column names in the hash below, that are able to uniquely
# specify a row in the table

%allowedConstructors = (feature_name=>undef,
	                feature_no=>undef);

####################################################################
sub DESTROY{
####################################################################
# nothing needs to be done 

}

####################################################################
sub locus_name {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    if (!$self->locus_no) { return; } 
    my $sth = $self->dbh->prepare("	
        SELECT locus_name
        FROM   $schema.locus
        WHERE  locus_no = ?
    ");
    $sth->execute($self->locus_no);
    my $locusName = $sth->fetchrow;
    $sth->finish;
    return $locusName;
}

####################################################################
sub dictyBaseid {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("	
        SELECT dictyBaseid
        FROM   $schema.dictyBaseid
        WHERE  primary_key = ?
        AND    tab_name = 'FEATURE'
        AND    dictyBaseid_type = 'Primary'
    ");
    $sth->execute($self->feature_no);
    my $dictyBaseid = $sth->fetchrow;
    $sth->finish;
    return $dictyBaseid;
}


####################################################################
sub aliasNameList {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("	
        SELECT alias_name
        FROM   $schema.alias
        WHERE  feature_no = ? 
    ");
    $sth->execute($self->feature_no);
    my $aliasList;
    while (my ($alias) = $sth->fetchrow()) {
	if ($aliasList) { $aliasList .= "|";}
	$aliasList .= $alias;
    }
    $sth->finish;
    return $aliasList;
}

####################################################################
sub uniformAliasNameList {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT A.alias_name 
        FROM   $schema.alias A, $schema.feature F
        WHERE  A.feature_no = ?
        AND A.feature_no = F.feature_no
        AND    A.alias_type = 'Uniform'
    ");
    $sth->execute($self->feature_no);
    my $aliasList;
    while (my($alias) = $sth->fetchrow()) {
	if ($aliasList) { $aliasList .= "|"; }
	$aliasList .= $alias;
    }
    $sth->finish;
    return $aliasList;
}


####################################################################
sub nonUniformAliasNameList {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT A.alias_name 
        FROM   $schema.alias A, $schema.feature F
        WHERE  A.feature_no = ?
        AND A.feature_no = F.feature_no
        AND    A.alias_type = 'Non-uniform'
    ");
    $sth->execute($self->feature_no);
    my $aliasList;
    while (my($alias) = $sth->fetchrow()) {
	if ($aliasList) { $aliasList .= "|"; }
	$aliasList .= $alias;
    }
    $sth->finish;
    return $aliasList;
}


####################################################################
sub proteinNameAliasNameList {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT A.alias_name 
        FROM   $schema.alias A, $schema.feature F
        WHERE  A.feature_no = ?
        AND A.feature_no = F.feature_no
        AND    A.alias_type = 'Protein name'
    ");
    $sth->execute($self->feature_no);
    my $aliasList;
    while (my($alias) = $sth->fetchrow()) {
	if ($aliasList) { $aliasList .= "|"; }
	$aliasList .= $alias;
    }
    $sth->finish;
    return $aliasList;
}

####################################################################
sub featureAliasArrayRef {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT A.alias_no, A.alias_name
        FROM   $schema.alias A, $schema.feature F
        WHERE  A.feature_no = ?
        AND A.feature_no = F.feature_no
    ");
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub featureTypeList {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("	
        SELECT feature_type
        FROM   $schema.feature_type
        WHERE  feature_no = ?
    "); 
    $sth->execute($self->feature_no);
    my $featureType;
    while(my ($type) = $sth->fetchrow()) {
	if ($featureType) { $featureType .= "|"; }
	$featureType .= $type;
    }
    $sth->finish;
    return $featureType;
}

####################################################################
sub protein_info_no {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT protein_info_no
        FROM   $schema.protein_info
        WHERE  feature_no = ?
    ");
    $sth->execute($self->feature_no);
    
    my $proteinInfoNo = $sth->fetchrow();

    return $proteinInfoNo;

}

####################################################################
# sub sacchdb_phenotype {
####################################################################
#    my ($self) = @_;
#    my $schema = $self->schema;
#    my $sth = $self->dbh->prepare("
#        SELECT sacchdb_phenotype
#        FROM   $schema.sacchdb_phenotype
#        WHERE  feature_no = ?
#    ");
#    $sth->execute($self->feature_no);
#    my $sacchdbPheno;
#    while(my ($pheno) = $sth->fetchrow()) {
#	if ($sacchdbPheno) { $sacchdbPheno .= "; "; }
#	$sacchdbPheno .= $pheno;
#    }
#    $sth->finish;
#    return $sacchdbPheno;

#}

#######################################################################
sub phenotypeInfoArrayRef {
#######################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT P.phenotype_no, P.phenotype, FP.phenotype_type, 
               FP.sentence
        FROM   $schema.phenotype P, $schema.feat_pheno FP
        WHERE  P.phenotype_no = FP.phenotype_no
        AND    FP.feature_no = ?
    ");  
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub goidArrayRef {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT unique goid
        FROM   $schema.go_feat_goev
        WHERE  feature_no = ?
    ");
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub goInfoForTreeArrayRef {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT unique G.goid, go_term, go_aspect, go_definition
        FROM   $schema.go G, $schema.go_feat_goev GFG
        WHERE  GFG.feature_no = ?
        AND    GFG.goid = G.goid
        AND    GFG.is_not = 'N'
    ");
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub goInfoArrayRef {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT unique G.goid, go_term, go_aspect, go_definition
        FROM   $schema.go G, $schema.go_feat_goev GFG
        WHERE  GFG.feature_no = ?
        AND    GFG.goid = G.goid
    ");
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub goFeatGoevArrayRef {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT goid, go_evidence_no, is_not
        FROM   $schema.go_feat_goev
        WHERE  feature_no = ?
    ");
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}


####################################################################
sub subfeatureInfoArrayRef {
####################################################################
    my ($self) = @_;

    my $schema = $self->schema;

    my $sth = $self->dbh->prepare("
        SELECT ST.subfeature_type, S.start_coord, S.stop_coord 
        FROM   $schema.subfeature S, $schema.subfeature_type ST
        WHERE  S.feature_no = ?
        AND    S.subfeature_no = ST.subfeature_no
        ORDER BY S.start_coord
    ");
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef; 

}

####################################################################
sub curatorNoteInfoArrayRef {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT CN.curator_note_no, CN.note, CN.is_public
        FROM   $schema.curator_note CN, $schema.feat_cn FCN
        WHERE  CN.curator_note_no = FCN.curator_note_no
        AND    FCN.feature_no = ?
    ");
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub curatedRefNum {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
         SELECT count(unique reference_no)
         FROM   $schema.feat_gene_info
         WHERE  feature_no = ?
         AND    upper(literature_topic) != 'NOT YET CURATED' 
    ");
    $sth->execute($self->feature_no);
    my $curatedNum = $sth->fetchrow();
    $sth->finish;
    return $curatedNum;
}

####################################################################
sub notYetCuratedRefNum {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
         SELECT count(unique reference_no)
         FROM   $schema.feat_gene_info
         WHERE  feature_no = ?
         AND    upper(literature_topic) = 'NOT YET CURATED' 
    ");
    $sth->execute($self->feature_no);
    my $notYetCuratedNum = $sth->fetchrow();
    $sth->finish;
    return $notYetCuratedNum;
}


####################################################################
sub refSeqGiNo {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
         SELECT external_id
         FROM   $schema.external_id
         WHERE  source = 'RefSeq GI'
         AND    tab_name = 'FEATURE'
         AND    primary_key = ?
    ");
    $sth->execute($self->feature_no);
    my $gi = $sth->fetchrow;
    $sth->finish;
    return $gi;
}

####################################################################
sub updateLogInfoArrayRef {
####################################################################
    my ($self) = @_;
    my $schema = $self->schema;
    my $sth = $self->dbh->prepare("
        SELECT date_created, old_value, new_value, col_name, 
               description, is_public 
	FROM   $schema.update_log 
	WHERE  tab_name = 'FEATURE'
	AND    primary_key = ?
    ");
    $sth->execute($self->feature_no);
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
# sub deleteSacchdbPhenotype {
####################################################################
#    my ($self) = @_;
#    my $schema = $self->schema;
#    my $sth = $self->dbh->prepare("
#        DELETE from $schema.sacchdb_phenotype
#        WHERE  feature_no = ?
#    ");
#    $sth->execute($self->feature_no);
#    $sth->finish;
# }


###################################################################
sub getDisplaySeqNumHash{
###################################################################
    my ($self, %args) = @_;
    my $schema = $self->schema;

    my $selectStmt = "SELECT display_seq_no, display_seq_type
                        FROM $schema.display_seq
                        WHERE feature_no = ?";

    my $sth = $self->dbh->prepare($selectStmt);

    $sth->execute($self->feature_no);

    my %hash;
    while (my ($display_seq_no, $display_seq_type) = $sth->fetchrow_array()){
       $hash{$display_seq_type} = $display_seq_no;
    }

    $sth->finish;
    return %hash;

}

####################################################################
sub GetUniqueFeatureTypeArrayRef {
####################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || $self->_err_report('dbh');

    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT unique feature_type
        FROM   $schema.feature_type 
        WHERE  feature_type != 'Deleted'
        AND    feature_type != 'Merged'
        AND    feature_type != 'Pseudogene'
        ORDER BY feature_type
    ");
    $sth->execute;

    my $arrayRef = $sth->fetchall_arrayref();

    $sth->finish;

    return $arrayRef;

}

####################################################################
sub GetFeatureArrayRefBYname {
####################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $schema = $self->schema;
    my $sth = $dbh->prepare("
        SELECT feature_name
        FROM   $schema.feature 
        WHERE  upper(feature_name) like ?
        ORDER BY feature_name
    ");
    $sth->execute(uc($args{'feature_name'}));
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub GetFeatNmLocusNmBYgiNo {
####################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $schema = $self->schema;
    my $sth = $dbh->prepare("
        SELECT F.feature_name, L.locus_name
        FROM   $schema.feature F, $schema.locus L,
               $schema.external_id EI
        WHERE  EI.external_id = ?
        AND    EI.tab_name = 'FEATURE'
        AND    EI.primary_key = F.feature_no
        AND    F.locus_no = L.locus_no(+)
    ");
    $sth->execute($args{'gi'});
    my ($featNm, $locusNm) = $sth->fetchrow;
    $sth->finish;
    return ($featNm, $locusNm);
}


########################################################################
sub FeatureArrayRef {
########################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT F.feature_name, F.chromosome, F.strand, 
               F.start_coord, F.stop_coord, S.dictyBaseid, L.locus_name, 
               L.genetic_position, FT.feature_type, P.pI,
               P.molecular_weight, P.protein_length, 
               SFT.subfeature_type, SF.start_coord, SF.stop_coord
        FROM   $schema.feature F, 
               $schema.dictyBaseid S,
               $schema.locus L, 
               $schema.feature_type FT, 
               $schema.protein_info P,
               $schema.subfeature SF,
               $schema.subfeature_type SFT
        WHERE  (F.is_on_pmap = 'Y' or 
                FT.feature_type = 'Telomeric Region') 
        AND    F.feature_no = S.primary_key
        AND    S.tab_name = 'FEATURE'
        AND    S.dictyBaseid_type = 'Primary'
        AND    F.locus_no = L.locus_no(+)
        AND    F.feature_no = FT.feature_no(+)
        AND    F.feature_no = P.feature_no(+)
        AND    F.feature_no = SF.feature_no(+)
        AND    SF.subfeature_no = SFT.subfeature_no(+)
        ORDER BY F.feature_name, SF.start_coord  
    ");
 
    $sth->execute;

    my $arrayRef = $sth->fetchall_arrayref();

    $sth->finish;

    return $arrayRef;

}

########################################################################
sub SysDelPhenotype4FeatArrayRef {
########################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT L.locus_name, P.phenotype
        FROM   $schema.locus L, $schema.locus_pheno LP, 
               $schema.phenotype P
        WHERE  L.locus_no = LP.locus_no
        AND    LP.phenotype_no = P.phenotype_no
        AND    LP.phenotype_type = 'Systematic deletion'
          union
        SELECT F.feature_name, P.phenotype
        FROM   $schema.feature F, $schema.feat_pheno FP, 
               $schema.phenotype P
        WHERE  F.feature_no = FP.feature_no
        AND    FP.phenotype_no = P.phenotype_no
        AND    FP.phenotype_type = 'Systematic deletion'
    ");

    $sth->execute;

    my $arrayRef = $sth->fetchall_arrayref();

    $sth->finish;

    return $arrayRef;

}

####################################################################
sub GetFeatureTableArrayRefByChrBegEnd {
####################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
#    my $chr = $args{'chromosome'} || $self->_err_report('chromosome');

    my $schema = $self->schema;
    my $sth = $dbh->prepare("
        SELECT  F.feature_name, F.start_coord, F.stop_coord, 
                F.strand, L.locus_name, F.brief_id, S.dictyBaseid,
                FT.feature_type
        FROM    $schema.feature F, $schema.locus L, 
                $schema.dictyBaseid S, $schema.feature_type FT
	WHERE   F.chromosome = ?
        AND     F.locus_no = L.locus_no(+)
	AND     F.is_on_pmap = 'Y'
        AND    (
                  ( start_coord < stop_coord and 
                    stop_coord > ? and 
                    start_coord < ? )
                    or 
                  ( start_coord > stop_coord and 
                    start_coord > ? and 
                    stop_coord < ? )
        ) 
        AND     F.feature_no = S.primary_key
        AND     S.tab_name = 'FEATURE'
        AND     S.dictyBaseid_type = 'Primary'
        AND     FT.feature_no = F.feature_no
	ORDER BY F.start_coord, F.stop_coord
    ");
    $sth->execute($args{'chromosome'}, 
		  $args{'start_coord'}, $args{'stop_coord'}, 
		  $args{'start_coord'}, $args{'stop_coord'}); 
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub GetFeatureTableArrayRefByChr {
####################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $chr = $args{'chromosome'} || $self->_err_report('chromosome');

    my $schema = $self->schema;
    my $sth = $dbh->prepare("
        SELECT  F.feature_name, F.start_coord, F.stop_coord, 
                F.strand, L.locus_name, F.brief_id, S.dictyBaseid,
                FT.feature_type
        FROM    $schema.feature F, $schema.locus L, 
                $schema.dictyBaseid S, $schema.feature_type FT
	WHERE   F.chromosome = ?
        AND     F.locus_no = L.locus_no(+)
        AND     F.feature_no = S.primary_key
        AND     S.tab_name = 'FEATURE'
        AND     S.dictyBaseid_type = 'Primary'
        AND     FT.feature_no = F.feature_no
	ORDER BY F.start_coord, F.stop_coord
    ");
    $sth->execute($chr); 
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;
}

####################################################################
sub GetSageInfoArrayRefByChrBegEnd {
####################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $chr = $args{'chromosome'} || $self->_err_report('chromosome');
    my $beg = $args{'beg'} || $self->_err_report('beg');
    my $end = $args{'end'} || $self->_err_report('end');
  
    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT STL.tag_seq, STL.class, 
	       STL.chromosome, STL.start_coord,
	       STL.strand, ST.genome_hits
	FROM   $schema.sage_tag_location STL, 
	       $schema.sage_tag ST
	WHERE  STL.tag_seq = ST.tag_seq 
	AND    STL.chromosome = ? 
	AND    STL.start_coord > ? 
	AND    STL.start_coord < ?
	ORDER BY STL.start_coord
    ");
    $sth->execute($chr, $beg, $end); 
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;

}


####################################################################
sub GetSageClass3InfoArrayRefByChrTagnameCrd {
####################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $chr = $args{'chromosome'} || $self->_err_report('chromosome');
    my $tag = $args{'tagname'} || $self->_err_report('tagname');
    my $crd = $args{'crd'} || $self->_err_report('crd');
  
    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT  SP.porf_class, SP.start_coord, SP.stop_coord, 
		ST.genome_hits, SI.strand, SP.cai, SP.pvalue, 
                SP.sequence, SI.start_coord, SI.stop_coord 
	FROM    $schema.sage_porf SP, $schema.sage_interval SI,
		$schema.sage_tag_location STL, $schema.sage_tag ST
	WHERE   STL.tag_seq = ?  
	AND     STL.start_coord = ?  
	AND     STL.chromosome = ?  
	AND     STL.interval_no = SI.interval_no 
	AND     SI.interval_no = SP.interval_no  
	AND     STL.tag_seq = ST.tag_seq
    ");
    $sth->execute($tag, $crd, $chr); 
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;

}

####################################################################
sub GetChrLength {
####################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $chr = $args{'chr'} || $self->_err_report('chr');
    if ($chr =~ /^mit/i) {
	$chr = 17;
    }
    if ($chr !~ /^[0-9]+$/) {

	print "$chr is not a valid chromosome number. A positive integer (1 to 17) is required for the 'chr' argument when you call 'GetChrLength' method in Feature.pm."; 

	return;

    }

    my $schema = $self->schema;
    my $sth = $dbh->prepare("
        SELECT physical_length
        FROM   $schema.chromosome
        WHERE  chromosome = ?
    ");
    $sth->execute($chr);
    my $chrsize = $sth->fetchrow;
    $sth->finish;
    return $chrsize;
}

####################################################################
sub GetAllFeatInfoArrayRef {
####################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    
    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT F.feature_name, F.feature_no, L.locus_name, 
               F.chromosome, F.start_coord, F.stop_coord, 
               F.strand
        FROM   $schema.feature F, $schema.locus L
        WHERE  F.locus_no = L.locus_no (+)
    ");
    $sth->execute; 
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;

}

####################################################################
sub GetFeatureArrayRefForCoord {
####################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $chr = $args{'chr'} || $self->_err_report('chr');
    my $coord = $args{'coord'} || $self->_err_report('coord');
    
    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT feature_name, start_coord, stop_coord
        FROM   $schema.feature
        WHERE  chromosome = ?
        AND    (  (start_coord < stop_coord and 
                   start_coord <= ? and 
                   stop_coord > ? ) 
               or (start_coord > stop_coord and 
                   stop_coord <= ? and 
                   start_coord > ?) )
    ");
    $sth->execute($chr, $coord, $coord, $coord, $coord); 
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;

}

####################################################################
sub GetFeatureArrayRefForCoords {
####################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $chr = $args{'chr'} || $self->_err_report('chr');
    my $coord1 = $args{'coord1'} || $self->_err_report('coord1');
    my $coord2 = $args{'coord2'} || $self->_err_report('coord2');
    
    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT feature_name, start_coord, stop_coord
        FROM   $schema.feature
        WHERE  chromosome = ?
        AND    (  (start_coord < stop_coord and 
                   start_coord <= ? and 
                   stop_coord >= ? ) 
               or (start_coord > stop_coord and 
                   stop_coord <= ? and 
                   start_coord >= ?) )
    ");
    $sth->execute($chr, $coord2, $coord1, $coord2, $coord1); 
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;

}

####################################################################
sub GetDownStreamFeatureArrayRefForCoord {
####################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $chr = $args{'chr'} || $self->_err_report('chr');
    my $coord = $args{'coord'} || $self->_err_report('coord');
    
    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        SELECT feature_name, start_coord, stop_coord
        FROM   $schema.feature
        WHERE  chromosome = ?
        AND    (  (start_coord < stop_coord and 
                   start_coord > ? ) 
               or (start_coord > stop_coord and 
                   stop_coord > ? ) )
    ");
    $sth->execute($chr, $coord, $coord); 
    my $arrayRef = $sth->fetchall_arrayref();
    $sth->finish;
    return $arrayRef;

}

################################################################
sub UpdateDownStreamFeatureCoords {
################################################################
    my ($self, %args) = @_;
    
    my $dbh = $args{'dbh'} || $self->_err_report('dbh');
    my $chr = $args{'chr'} || $self->_err_report('chr');
    my $coord = $args{'coord'} ||$self->_err_report('coord'); 
    my $bpChanged = $args{'bpChanged'} || $self->_err_report('bpChanged');

    my $schema = $self->schema;

    my $sth = $dbh->prepare("
        UPDATE $schema.feature
        SET    start_coord = start_coord + ?,
               stop_coord = stop_coord + ?
        WHERE  chromosome = ?
        AND    (  (start_coord < stop_coord and 
                   start_coord > ? ) or
                  (start_coord > stop_coord and
                   stop_coord > ? ))
    ");
    $sth->execute($bpChanged, $bpChanged, $chr, 
		  $coord, $coord);
    $sth->finish;
  
}

###########################################################
###########################################################

########################################################################
sub GetSysDate { 
########################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} ||  $self->_err_report('dbh');

    my $sth = $dbh->prepare("
        SELECT SYSDATE
        FROM   dual 
    ");
    $sth->execute();
    my $sysDate = $sth->fetchrow;
    $sth->finish;
    return $sysDate;
}


#########################################################

###################################################################
sub GetAllFeatureArray{  ### added by Mira
###################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || "A database handle must be passed into 'GetRawSeqNumHash' method.";


    my $schema = $self->schema;

    my $selectStmt = "SELECT feature.feature_no,  feature_name 
                        FROM $schema.feature, $schema.feature_type
                        WHERE feature.feature_no = feature_type.feature_no 
                        AND (feature_type = 'ORF' OR feature_type = 'Ty ORF')
                        AND feature.feature_no NOT IN 
                              (SELECT feature_no FROM $schema.feature_type
                                  WHERE feature_type = 'Deleted'
                                  OR    feature_type = 'Merged')
                        ORDER BY chromosome, feature_name";

#ORDER BY feature_name";


    my $sth = $dbh->prepare($selectStmt);

    $sth->execute();

    my @array;
    while (my ($feature_no, $feature_name) = $sth->fetchrow_array()){
       push(@array,$feature_no);
    }

    $sth->finish;
    return @array;


}

###################################################################
sub GetYFeatureArray{  ### added by Mira
###################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || "A database handle must be passed into 'GetRawSeqN
umHash' method.";


    my $schema = $self->schema;

    my $selectStmt = "SELECT feature.feature_no,  feature_name, chromosome
                        FROM $schema.feature, $schema.feature_type
                        WHERE feature.feature_no = feature_type.feature_no 
                        AND   feature_name LIKE 'Y%'
                        AND (feature_type = 'ORF' OR feature_type = 'Ty ORF')
                        AND feature.feature_no NOT IN
                              (SELECT feature_no FROM $schema.feature_type
                                  WHERE feature_type = 'Deleted'
                                  OR    feature_type = 'Merged')
                        ORDER BY CHROMOSOME";

                        #ORDER BY feature_name";

    my $sth = $dbh->prepare($selectStmt);

    $sth->execute();

    my @array;
    while (my ($feature_no, $feature_name, $chromosome) = $sth->fetchrow_array()){
       push(@array,$feature_no);
    }


    $sth->finish;

    return @array;


}


####################################################################
sub GetChrBegEndForFeatureArray {  ### added by Mira
####################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || "A database handle must be passed into 'GetChrBegEndForFeatureArray' method.";

    my $schema = $self->schema;

    my $WStmt = "SELECT chromosome, start_coord, stop_coord, feature_no
                        FROM $schema.feature
                        WHERE strand = 'W'
                        AND feature.feature_no NOT IN
                              (SELECT feature_no FROM $schema.feature_type
                                  WHERE feature_type = 'Deleted'
                                  OR    feature_type = 'Merged'
                                  OR    feature_type = 'Dubious')
                        ORDER BY CHROMOSOME, START_COORD, STOP_COORD";
 

    my $Wsth = $dbh->prepare($WStmt);

    $Wsth->execute();


    my $CStmt = "SELECT chromosome, start_coord, stop_coord, feature_no
                        FROM $schema.feature
                        WHERE strand = 'C'
                        AND feature.feature_no NOT IN
                              (SELECT feature_no FROM $schema.feature_type
                                  WHERE feature_type = 'Deleted'
                                  OR    feature_type = 'Merged')
                        ORDER BY CHROMOSOME, STOP_COORD, START_COORD";


    my $Csth = $dbh->prepare($CStmt);

    $Csth->execute();

    my @Warray;
    while (my ($chr, $start, $stop, $feature_no) = $Wsth->fetchrow_array()){
      push(@Warray,"$chr:$start:$stop:$feature_no");  
    }

    $Wsth->finish;

    my @Carray;
    while (my ($chr, $start, $stop, $feature_no) = $Csth->fetchrow_array()){
      #switch start and stop
      push(@Carray,"$chr:$stop:$start:$feature_no");
    }

    $Csth->finish;


    my @chrArray;
    my @startArray;
    my @stopArray;


    #merge two arrays...
    my $i;
    my $j;
    while (($i<=$#Warray) &&($j<=$#Carray)){
      my ($wchr, $wstart, $wstop, $wfeature_no) = split(/:/,@Warray[$i]); 
      my ($cchr, $cstart, $cstop, $cfeature_no) = split(/:/,@Carray[$j]); 


      if ($wchr < $cchr) {
          push(@chrArray, $wchr);
          push(@startArray, $wstart);
          push(@stopArray, $wstop);
          $i++;
      } elsif ($wchr > $cchr) {
          push(@chrArray, $cchr);
          push(@startArray, $cstart);
          push(@stopArray, $cstop);
          $j++;
      } else {
        #we are on the same chromosome, compare start coordinates 
        if ($wstart < $cstart) {
            push(@chrArray, $wchr);
            push(@startArray, $wstart);
            push(@stopArray, $wstop);
            $i++;
        } elsif ($wstart > $cstart) {
            push(@chrArray, $cchr);
            push(@startArray, $cstart);
            push(@stopArray, $cstop);
            $j++;

        } else {
            #same chromosome
            #start coordinates are the same - order by stop coordinates
            if ($wstop <$cstop) {
               push(@chrArray, $wchr);
               push(@startArray, $wstart);
               push(@stopArray, $wstop);
               $i++;
 
            } elsif ($wstop > $cstop) {
               push(@chrArray, $cchr);
               push(@startArray, $cstart);
               push(@stopArray, $cstop);
               $j++;

            } else {

               push(@chrArray, $wchr);
               push(@startArray, $wstart);
               push(@stopArray, $wstop);
               $i++;
               push(@chrArray, $cchr);
               push(@startArray, $cstart);
               push(@stopArray, $cstop);
               $j++;

            }


        }
      }

    }


    while ($i<=$#Warray) {
      my ($wchr, $wstart, $wstop, $wfeature_no) = split(/:/,@Warray[$i]);
      push(@chrArray, $wchr);
      push(@startArray, $wstart);
      push(@stopArray, $wstop);
      $i++;

    }

    while ($j<=$#Carray) {
      my ($cchr, $cstart, $cstop, $cfeature_no) = split(/:/,@Carray[$j]);
      push(@chrArray, $cchr);
      push(@startArray, $cstart);
      push(@stopArray, $cstop);
      $j++;

    }

    return (\@chrArray,\@startArray,\@stopArray);

}

###################################################################
sub GetNumOfFeaturesBetween2StartCoord {  ### added by Mira
###################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || "A database handle must be passed into 'GetNumOfFeaturesBetween2StartCoord' method.";

    my $coord1 = $args{'coord1'} || die "An coord1 must be passed into 'GetNumOfFeaturesBetween2StartCoord' method.";
   
    my $coord2 = $args{'coord2'} || die "An coord1 must be passed into 'GetNumOfFeaturesBetween2StartCoord' method.";
 
    my $chr = $args{'chr'} || die "An chrnum must be passed into 'GetNumOfFeaturesBetween2StartCoord' method.";

   my $strand = $args{'strand'} || die "A strand must be passed into 'GetNumOfFeaturesBetween2StartCoord' method.";

    my $schema = $self->schema;
    my $stm = "SELECT count(*) from $schema.feature 
                WHERE START_COORD > $coord1 AND START_COORD < $coord2 
                AND CHROMOSOME = ? 
                AND STRAND = ?";
    my $sth = $dbh->prepare($stm);
    $sth->execute($chr, $strand);
    my $count = $sth->fetchrow;
    $sth->finish;

    return $count;

}

###################################################################
sub GetAllFeatureArray{ ### added by Mira
###################################################################
    my ($self, %args) = @_;
    my $dbh = $args{'dbh'} || "A database handle must be passed into 'GetRawSeqNumHash' method.";


    my $schema = $self->schema;

    my $selectStmt = "SELECT feature.feature_no,  feature_name
                        FROM $schema.feature, $schema.feature_type
                        WHERE feature.feature_no = feature_type.feature_no
                        AND (feature_type = 'ORF' OR feature_type = 'Ty ORF')
                        AND feature.feature_no NOT IN
                              (SELECT feature_no FROM $schema.feature_type
                                  WHERE feature_type = 'Deleted'
                                  OR    feature_type = 'Merged')
                        ORDER BY chromosome, feature_name";


    my $sth = $dbh->prepare($selectStmt);

    $sth->execute();

    my @array;
    while (my ($feature_no, $feature_name) = $sth->fetchrow_array()){
       push(@array,$feature_no);
    }

    $sth->finish;
    return @array;


}

####################################################################
sub GetChrBegEndForFeatureArray { ## added by Mira
####################################################################
    my ($self, %args) = @_;

    my $dbh = $args{'dbh'} || "A database handle must be passed into 'GetChrBegEndForFeatureArray' method.";

    my $schema = $self->schema;

    my $WStmt = "SELECT chromosome, start_coord, stop_coord, feature_no
                        FROM $schema.feature
                        WHERE strand = 'W'
                        AND feature.feature_no NOT IN
                              (SELECT feature_no FROM $schema.feature_type
                                  WHERE feature_type = 'Deleted'
                                  OR    feature_type = 'Merged')
                        ORDER BY CHROMOSOME, START_COORD, STOP_COORD";


    my $Wsth = $dbh->prepare($WStmt);

    $Wsth->execute();


    my $CStmt = "SELECT chromosome, start_coord, stop_coord, feature_no
                        FROM $schema.feature
                        WHERE strand = 'C'
                        AND feature.feature_no NOT IN
                              (SELECT feature_no FROM $schema.feature_type
                                  WHERE feature_type = 'Deleted'
                                  OR    feature_type = 'Merged')
                        ORDER BY CHROMOSOME, STOP_COORD, START_COORD";


    my $Csth = $dbh->prepare($CStmt);

    $Csth->execute();

    my @Warray;
    while (my ($chr, $start, $stop, $feature_no) = $Wsth->fetchrow_array()){
      push(@Warray,"$chr:$start:$stop:$feature_no");
    }

    $Wsth->finish;


    my @Carray;
    while (my ($chr, $start, $stop, $feature_no) = $Csth->fetchrow_array()){
      #switch start and stop
      push(@Carray,"$chr:$stop:$start:$feature_no");
    }

    $Csth->finish;


    my @chrArray;
    my @startArray;
    my @stopArray;


    #merge two arrays...
    my $i;
    my $j;
    while (($i<=$#Warray) &&($j<=$#Carray)){
      my ($wchr, $wstart, $wstop, $wfeature_no) = split(/:/,@Warray[$i]);
      my ($cchr, $cstart, $cstop, $cfeature_no) = split(/:/,@Carray[$j]);


      if ($wchr < $cchr) {
          push(@chrArray, $wchr);
          push(@startArray, $wstart);
          push(@stopArray, $wstop);
          $i++;
      } elsif ($wchr > $cchr) {
          push(@chrArray, $cchr);
          push(@startArray, $cstart);
          push(@stopArray, $cstop);
          $j++;
      } else {
        #we are on the same chromosome, compare start coordinates
        if ($wstart < $cstart) {
            push(@chrArray, $wchr);
            push(@startArray, $wstart);
            push(@stopArray, $wstop);
            $i++;
        } elsif ($wstart > $cstart) {
            push(@chrArray, $cchr);
            push(@startArray, $cstart);
            push(@stopArray, $cstop);
            $j++;

        } else {
            #same chromosome
            #start coordinates are the same - order by stop coordinates
            if ($wstop <$cstop) {
               push(@chrArray, $wchr);
               push(@startArray, $wstart);
               push(@stopArray, $wstop);
               $i++;

            } elsif ($wstop > $cstop) {
               push(@chrArray, $cchr);
               push(@startArray, $cstart);
               push(@stopArray, $cstop);
               $j++;

            } else {

               push(@chrArray, $wchr);
               push(@startArray, $wstart);
               push(@stopArray, $wstop);
               $i++;
               push(@chrArray, $cchr);
               push(@startArray, $cstart);
               push(@stopArray, $cstop);
               $j++;

            }


        }
      }

    }


    while ($i<=$#Warray) {
      my ($wchr, $wstart, $wstop, $wfeature_no) = split(/:/,@Warray[$i]);
      push(@chrArray, $wchr);
      push(@startArray, $wstart);
      push(@stopArray, $wstop);
      $i++;

    }

    while ($j<=$#Carray) {
      my ($cchr, $cstart, $cstop, $cfeature_no) = split(/:/,@Carray[$j]);
      push(@chrArray, $cchr);
      push(@startArray, $cstart);
      push(@stopArray, $cstop);
      $j++;

    }

    return (\@chrArray,\@startArray,\@stopArray);

}

####################################################################
sub _err_report {
####################################################################
    my ($self, $args) = @_;
    my ($file, $line, $method) = (caller(1))[1..3];
    print "The argument '$args' must be passed to '$method' method.<br>";
    print "Please add this argument to line $line in $file.<br>"; 
    exit;

}


####################################################################
1; #################################################################
####################################################################


=pod

=head1 Name

Feature.pm


=head1 Description

This perl object (Feature.pm) acts as container for feature info associated with a feature_no or feature_name in oracle database. Once an object has been instantiated, several methods are available to retrieve the
attributes of the object. 


=head1 Instantiating a New Feature Object

To instantiate a new Feature object, you may use following syntax: 

my $featureObj = Feature->new(dbh=>$dbh, $colNm=>$value); 

where $colNm is either feature_no, feature_name or dictyBaseid, and $dbh is a valid database handle to either dictyBase or SDEV. $value must be a valid value for the column that was provided, otherwise the script will die, with an appropriate error message.
 

Syntax example :

my $featureObj = Feature->new(dbh=>$dbh, feature_no=>$featureNo); 

my $featureObj = Feature->new(dbh=>$dbh, feature_name=>$featureName);  


=head1 Accessor Methods


All accessor methods take the form of : 


my $column_value = $featureObj->column_name, eg: 


my $featureName = $featureObj->feature_name; 


my $chromsome = $featureObj->chromosome; 

my $start_coord = $featureObj->start_coord;

etc. You can use an accessor for any valid column in the Feature table. 

See valid columns in feature table:

http:///usr/local/dicty/www_dictybase/db/lib/cgi-bin/dictyBase/tableSpecifications?table=FEATURE

In addition, following accessor methods are provided to access non
Feature table columns:

=head2 locus_name

Usage : 

my $locusNm = $featureObj->locus_name;

This accessor returns standard gene_name for a given feature. 


=head2 dictyBaseid

Usage : 

my $dictyBaseid = $featureObj->dictyBaseid;

This accessor returns primary dictyBaseid for a given feature. 


=head2 aliasNameList


Usage:

my $aliasList = $featureObj->aliasNameList;

This method returns pipe ('|') delimited alias list.

=head2 uniformAliasNameList


Usage:

my $uniformAliasList = $featureObj->uniformAliasNameList;

This method returns pipe ('|') delimited uniform alias list.

=head2 nonUniformAliasNameList


Usage:

my $nonUniformAliasList = $featureObj->nonUniformAliasNameList;

This method returns pipe ('|') delimited Non-uniform alias list.

=head2 proteinNameAliasNameList


Usage:

my $proteinNameAliasList = $featureObj->proteinNameAliasNameList;

This method returns pipe ('|') delimited protein name alias list.


=head2 featureTypeList
 
Usage : 

my $featureTypeList = $featureObj->featureTypeList;

This method returns pipe ('|') delimited feature_types 
associated with a given feature.


=head2 phenotypeInfoArrayRef

Usage : 

foreach my $rowRef (@{$featureObj->phenotypeInfoArrayRef}) {
    
    my ($phenotype_no, $phenotype, $phenotype_type, $sentence) 

	= @$rowRef;

    .....
	
}

This method returns an arrayref for the phenotype information 
associated with a given feature.

=head2 goidArrayRef

Usage : 

foreach $rowRef (@{$featureObj->goidArrayRef}) {

    my ($goid) = @$rowRef;

    ....

}

This method returns an arrayref for the goid associated with
a given feature.

=head2 goInfoArrayRef

Usage : 

foreach $rowRef (@{$featureObj->goInfoArrayRef}) {

    my ($goid, $goTerm, $goAspect) = @$rowRef;

    ....

}

This method returns an arrayref to the go information associated with
a given feature.

=head2 curatorNoteInfoArrayRef

Usage :

foreach my $rowRef (@{$featureObj->curatorNoteInfoArrayRef}) {

    my ($noteNo, $note, $isPublic) = @$rowRef;

    ######

}


=head2 curatedRefNum

Usage : 

my $curatedRefNum = $featureObj->curatedRefNum;

This method returns the number of curated references associated with
the given feature.

=head2 notYetCuratedRefNum

Usage : 

my $notYetCuratedRefNum = $featureObj->notYetCuratedRefNum;

This method returns the number of not yet curated references 
associated with the given feature.

=head2 refSeqGiNo

Usage : 

my $gi = $featureObj->refSeqGiNo;

This method returns gi number for the given feature.


=head2 updateLogInfoArrayRef

Usage :

foreach my $rowRef (@{$featObj->updateLogInfoArrayRef}) 

    my ($dateCreated, $oldVal, $newVal, $colNm, $desc, $isPublic) 

    = @$rowRef;


    ####

}


This method returns update_log info for the given feature entry.


=head2 getRow method

Usage:

my $row = $obj->getRow;

This method returns a tab-delimited row from feature table.


=head2 GetFeatureArrayRefBYname

Usage :

my $arrayRef = Feature->GetFeatureArrayRefBYname(dbh=>$Dbh,
						 feature_name=>$featNm);


foreach my $rowRef (@$arrayRef) {

    my ($featureNm) = @$RowRef;

    ####

}


=head2 featureAliasArrayRef

Usage :

my $arrayRef = Feature->featureAliasArrayRef(dbh=>$Dbh,
						 feature_name=>$featNm);


foreach my $rowRef (@$arrayRef) {

    my ($aliasNo, $aliasNm) = @$RowRef;

    ####

}

This method returns alias_no and alias_name of all aliases for the given feature.


=head2 GetFeatNmLocusNmBYgiNo

Usage :

my ($featNm, $locusNm) = Feature->GetFeatNmLocusNmBYgiNo(dbh=>$dbh,
							 gi=>$gi);


This method returns the feature name and locus name for the given ncbi gi number.


=head2 GetFeatureTableArrayRefByChrBegEnd

Usage :

my $arrayRef = Feature->GetFeatureTableArrayRefByChrBegEnd(dbh=>$dbh,
						chromosome=>$chrnum,
						start_coord=>$beg,
						stop_coord=>$end);


foreach my $rowRef (@$arrayRef) {

    my ($featNm, $start_coord, $stop_coord, $strand, $locusNm, 

	$briefId, $dictyBaseid) = @$rowRef;


    ########


}

This method returns all feature info in $chrnum, between $beg and $end range.


=head1 Insert, update and delete Methods

You can also use 'Insert' class method and 'update' and 'delete' 
instance methods for inserting new row into database, updating and 
deleting info for a specified row. 

See dictyBase_Table documentation for usage details :

Update : http:///usr/local/dicty/www_dictybase/db/lib/staff/dictyBase/programmer/dictyBase_Table.html#Update_Method

Insert : http:///usr/local/dicty/www_dictybase/db/lib/staff/dictyBase/programmer/dictyBase_Table.html#Insert_Method

Delete : http:///usr/local/dicty/www_dictybase/db/lib/staff/dictyBase/programmer/dictyBase_Table.html#Delete_Method


=head1 Author

Shuai Weng

shuai@genome.stanford.edu

=cut











