package Sequence::Locus;
use Carp;
use warnings;
use strict;


###################################################
# Global variables
my $validStrands = ['+', '-', '.'];


###################################################
sub new {
    my $pkg = shift;
    bless {
	seqID  => undef, 
	start  => undef, 
	end    => undef, 
	strand => undef
    }, $pkg;
}


###################################################
sub setSeqID {
    my $self = shift;
    my $seqID = shift or croak "Sequence ID is not defined.";
    $self->{seqID} = $seqID;
}


###################################################
sub setStart {
    my $self = shift;
    my $start = shift;
    if( !defined($start) ){ croak "Start coordinate is not defined." };
    $self->{start} = $start;
}


###################################################
sub setEnd {
    my $self = shift;
    my $end = shift;
    if( !defined($end) ){ croak "End coordinate is not defined." };
    $self->{end} = $end;
}


###################################################
sub setStrand {
    my $self = shift;
    my $strand = shift or croak "Strand is not defined.";
    if( isValidStrand( $strand ) ){
	$self->{strand} = $strand;
    } else {
	croak "Invalid strand:$strand.";
    }
}


###################################################
sub isValidStrand {
    my $strand = shift;
    my $validFlag = 0;
    foreach my $validStrand (@$validStrands){
	if( $strand eq $validStrand ){
	    $validFlag = 1; last;
	}
    }
    return $validFlag;
}


###################################################
sub getSeqID {
    my $self = shift;
    return $self->{seqID};
}

###################################################
sub getShortSeqID {
    my $self = shift;
    my $seqID = $self->getSeqID();
    $seqID =~ s/\s.+//;
    return $seqID;
}

###################################################
sub getStart {
    my $self = shift;
    return $self->{start};
}


###################################################
sub getEnd {
    my $self = shift;
    return $self->{end};
}


###################################################
sub getStrand {
    my $self = shift;
    return $self->{strand};
}

###################################################
sub getLength {
    my $self = shift;
    return $self->getEnd() - $self->getStart() + 1;
}

###################################################
sub isOverlap {
    my $self = shift;
    my $locus = shift;
    if( $self->getSeqID() eq $locus->getSeqID() ){
	if( ( $self->getStart() <= $locus->getStart()
	      and $locus->getStart() <= $self->getEnd() ) 
	    or
	    ( $locus->getStart() <= $self->getStart() 
	      and $self->getStart() <= $locus->getEnd() ) ){
	    return 1;
	}
    }
    return 0;
}

###################################################
sub merge {
    my $self = shift;
    my $locus = shift;
    if( $self->getSeqID() ne $locus->getSeqID() ){
	die "Cannot merge because of inconsistent sequence IDs";
    }
    if( $locus->getStart() < $self->getStart() ){
	$self->setStart( $locus->getStart() );
    }
    if( $locus->getEnd() > $self->getEnd() ){
	$self->setEnd( $locus->getEnd() );
    }
}

###################################################
sub extend5 {
    my $self = shift;
    my $bps  = shift;
    if( $self->getStrand() eq '+' ){
	$self->setStart( $self->getStart() - $bps );
    } else {
	$self->setEnd( $self->getEnd() + $bps );
    }
}

###################################################
sub extend3 {
    my $self = shift;
    my $bps  = shift;
    if( $self->getStrand() eq '+' ){
	$self->setEnd( $self->getEnd() + $bps );
    } else {
	$self->setStart( $self->getStart() - $bps );
    }
}

###################################################
sub getString {
    my $self = shift;
    return $self->getSeqID() . "_" . $self->getStart()  . "_" . $self->getEnd() . "_" . $self->getStrand();
}

###################################################
sub show {
    my $self = shift;
    print $self->getString() . "\n";
}


1;
