package Chip;
require Exporter;

use strict;
use GenomicsUtils;
use Experiment;
use DBI;

our (@ISA, @EXPORT);

@ISA = qw(Exporter);
@EXPORT = qw();

{
sub new;
sub columns();
sub chipId($);
sub taxonomyId($);
sub source($);			# may be NULL (undef)
sub chipType($);		# may be NULL
sub description($);		# may be NULL
sub experiments($);		# list of objects - note they may be different taxa
sub getSpotInfo($$$$);		# pass in the list of attributes to fetch, etc.
sub getSpotORFs($$);		# pass in additional where clause
sub getUniqueSpotsForORFs($@);	# pass in optional list of Locuses
sub getSpotPos($$);		# pass in additional where clause
sub getSpotAttrs($$$);		# pass in the list of attributes to fetch, and additional where clause

sub new{
    my %params = @_;
    my $self = {};
    bless $self;
    if (!exists $params{'taxonomyId'}) {
	die if !exists $params{'chipId'};
	my @columns = columns();
	GenomicsUtils::queryAttrs("ChipInfo", "chipId", $params{'chipId'}, \@columns, $self, "_");
    } else {
	foreach my $attr (keys %params) {
	    $self->{$attr."_"} = $params{$attr};
	}
    }
    return($self);
}

sub columns() {
    return qw(chipId taxonomyId source chipType description);
}

sub chipId($) {
    return shift->{'chipId_'};
}

sub taxonomyId($) {
    return shift->{'taxonomyId_'};
}

sub source($) {
    return shift->{'source_'};
}

sub chipType($) {
    return shift->{'chipType_'};
}

sub description($) {
    return shift->{'description_'};
}

sub experiments($) {
    return ( map { Experiment::new('expId'=>$_) }
	     queryList("SELECT expId from ExpInfo where chipId=" . shift->chipId()) );
}

# returns a hash spotId->list, with one list member for each attribute passed in
# $failedOK and $where allow you to restrict the results
sub getSpotInfo($$$$) {
    my ($self,$attrRef,$failedOK,$where) = @_;
    my $query = "SELECT " . join(",", "spotId", @$attrRef) . " FROM SpotInfo "
	. " WHERE chipId=" . $self->chipId();
    if (!$failedOK) {
	# also see similar code in SubExperiment::getSpotData
	$query .= " AND (mismatch IS NULL OR mismatch=0)"
	    . " AND (verificationCode IS NULL OR verificationCode=0)"
	    . " AND (contaminated IS NULL OR contaminated=0)";
    }
    if ($where ne "") {
	$query .= " AND ($where)";
    }
    my $result = GenomicsUtils::query($query);
    my $hash = {};
    foreach my $row (@$result) {
	my $spotId = shift @$row;
	$hash->{$spotId} = $row;
    }
    return($hash);
}

### Underimplemented
sub getSpotPos($$) {
    my ($self, $where) = @_;
    die "getSpotPos not implemented yet";
}

# returns spotId -> list of matching Locuses
sub getSpotORFs($$) {
    my ($self, $where) = @_;
    my $query = "SELECT SpotPos.spotId,SpotPos.locusId FROM SpotInfo,SpotPos WHERE SpotInfo.spotId=SpotPos.spotId";
    $query .= " AND SpotInfo.chipId=" . $self->chipId();
    $query .= " AND ($where)" if $where ne "";
    return GenomicsUtils::queryHashList($query);
}

# returns locus -> list of spots which match uniquely
sub getUniqueSpotsForORFs($@) {
    my $self = shift;
    my @locuss = @_;

    my $query = "SELECT SpotInfo.spotID,MIN(SpotPos.locusId) o1,MAX(SpotPos.locusId) o2 FROM SpotPos,SpotInfo"
	. " WHERE SpotInfo.spotId=SpotPos.spotID AND SpotInfo.chipId=" . $self->chipId()
	. " GROUP BY SpotInfo.spotID HAVING o1=o2";
    $query .= " AND o1 IN (" . join(",", @locuss) . ")" if scalar @locuss > 0;
    my $hash = {};
    map { addToHashList($hash, $_->[1], $_->[0]) } @{ &query($query) };
    return($hash);
}

# returns a reference to a hash of attr->spotId->value
# empty attribute set means all
sub getSpotAttrs($$$) {
    my ($self,$attrRef, $where) = @_;
    my $query = "SELECT a.spotId,a.attr,a.value FROM SpotInfo s,SpotAttrs a WHERE "
	. "s.chipId=" . $self->chipId() . " AND s.spotId=a.spotId";
    if (scalar @$attrRef > 0) {
	my @quoted = map {"'" . $_ . "'"} @$attrRef;
	$query .= " AND attr IN (" . join("," , @quoted) . ")";
    }
    if ($where) {
	$query .= " AND ($where)";
    }
    my $result = GenomicsUtils::query($query);
    my $hash = {};
    foreach my $row (@$result) {
	my ($spotId,$attr,$value) = @$row;
	$hash->{$attr} = {} if !exists $hash->{$attr};
	$hash->{$attr}{$spotId} = $value;
    }
    return($hash);
}
    
}
return 1;

