my $self = shift;
my $casm_mapper = shift;
my $from = shift;
my $seq_region_id = shift;
my $ranges = shift;
my $to_slice = shift;
my $to_seq_region_id;
if(defined($to_slice)){
if($casm_mapper->first_CoordSystem()->equals($casm_mapper->last_CoordSystem())){
return $self->_register_chained_special($casm_mapper, $from, $seq_region_id, $ranges, $to_slice);
}
$to_seq_region_id = $to_slice->get_seq_region_id();
if(!defined($to_seq_region_id)){
die "Could not get seq_region_id for to_slice".$to_slice->seq_region_name."\n";
}
}
my ($start_name, $start_mid_mapper, $start_cs, $start_registry,
$end_name, $end_mid_mapper, $end_cs, $end_registry);
if($from eq 'first') {
$start_name = 'first';
$start_mid_mapper = $casm_mapper->first_middle_mapper();
$start_cs = $casm_mapper->first_CoordSystem();
$start_registry = $casm_mapper->first_registry();
$end_mid_mapper = $casm_mapper->last_middle_mapper();
$end_cs = $casm_mapper->last_CoordSystem();
$end_registry = $casm_mapper->last_registry();
$end_name = 'last';
} elsif($from eq 'last') {
$start_name = 'last';
$start_mid_mapper = $casm_mapper->last_middle_mapper();
$start_cs = $casm_mapper->last_CoordSystem();
$start_registry = $casm_mapper->last_registry();
$end_mid_mapper = $casm_mapper->first_middle_mapper();
$end_cs = $casm_mapper->first_CoordSystem();
$end_registry = $casm_mapper->first_registry();
$end_name = 'first';
} else {
throw("Invalid from argument: [$from], must be 'first' or 'last'");
}
my $combined_mapper = $casm_mapper->first_last_mapper();
my $mid_cs = $casm_mapper->middle_CoordSystem();
my $mid_name = 'middle';
my $csa = $self->db->get_CoordSystemAdaptor();
# Check for the simple case where the ChainedMapper is short
if( ! defined $mid_cs ) {
$start_mid_mapper = $combined_mapper;
}
##############
# obtain the first half of the mappings and load them into the start mapper
#
#ascertain which is component and which is actually assembled coord system
my @path;
# check for the simple case, where the ChainedMapper is short
if( defined $mid_cs ) {
@path = @{$csa->get_mapping_path($start_cs, $mid_cs)};
} else {
@path = @{$csa->get_mapping_path( $start_cs, $end_cs )};
}
if(@path != 2 && defined( $path[1] )) {
my $path = join(
',',
map({$_->name .
' '. $_->version} @path));
my $len = scalar(@path) - 1;
throw("Unexpected mapping path between start and intermediate " .
"coord systems (". $start_cs->name . " " . $start_cs->version .
" and " . $mid_cs->name . " " . $mid_cs->version . ")." .
"\nExpected path length 1, got $len. " .
"(path=$path)");
}
my $sth;
my ($asm_cs,$cmp_cs);
$asm_cs = $path[0];
$cmp_cs = $path[-1];
#the SQL varies depending on whether we are coming from assembled or
#component coordinate system
my $asm2cmp = (<<ASMCMP);
SELECT
asm.cmp_start,
asm.cmp_end,
asm.cmp_seq_region_id,
sr.name,
sr.length,
asm.ori,
asm.asm_start,
asm.asm_end
FROM
assembly asm, seq_region sr
WHERE
asm.asm_seq_region_id = ? AND
? <= asm.asm_end AND
? >= asm.asm_start AND
asm.cmp_seq_region_id = sr.seq_region_id AND
sr.coord_system_id = ?
ASMCMP
my $cmp2asm = (<<CMPASM);
SELECT
asm.asm_start,
asm.asm_end,
asm.asm_seq_region_id,
sr.name,
sr.length,
asm.ori,
asm.cmp_start,
asm.cmp_end
FROM
assembly asm, seq_region sr
WHERE
asm.cmp_seq_region_id = ? AND
? <= asm.cmp_end AND
? >= asm.cmp_start AND
asm.asm_seq_region_id = sr.seq_region_id AND
sr.coord_system_id = ?
CMPASM
my $asm2cmp_sth;
my $cmp2asm_sth;
if(defined($to_slice)){
my $to_cs = $to_slice->coord_system;
if($asm_cs->equals($to_cs)){
$asm2cmp_sth = $self->prepare($asm2cmp);
$cmp2asm_sth = $self->prepare($cmp2asm." AND asm.asm_seq_region_id = $to_seq_region_id");
}
elsif($cmp_cs->equals($to_cs)){
$asm2cmp_sth = $self->prepare($asm2cmp." AND asm.cmp_seq_region_id = $to_seq_region_id");
$cmp2asm_sth = $self->prepare($cmp2asm);
}
else{
$asm2cmp_sth = $self->prepare($asm2cmp);
$cmp2asm_sth = $self->prepare($cmp2asm);
}
}
else{
$asm2cmp_sth = $self->prepare($asm2cmp);
$cmp2asm_sth = $self->prepare($cmp2asm);
}
$sth = ($asm_cs->equals($start_cs)) ? $asm2cmp_sth : $cmp2asm_sth;
my $mid_cs_id;
# check for the simple case where the ChainedMapper is short
if( defined $mid_cs ) {
$mid_cs_id = $mid_cs->dbID();
} else {
$mid_cs_id = $end_cs->dbID();
}
my @mid_ranges;
my @start_ranges;
#need to perform the query for each unregistered range
foreach my $range (@$ranges) {
my ($start, $end) = @$range;
$sth->bind_param(1,$seq_region_id,SQL_INTEGER);
$sth->bind_param(2,$start,SQL_INTEGER);
$sth->bind_param(3,$end,SQL_INTEGER);
$sth->bind_param(4,$mid_cs_id,SQL_INTEGER);
$sth->execute();
#load the start <-> mid mapper with the results and record the mid cs
#ranges we just added to the mapper
my ($mid_start, $mid_end, $mid_seq_region_id, $mid_seq_region, $mid_length,
$ori, $start_start, $start_end);
$sth->bind_columns(\$mid_start, \$mid_end, \$mid_seq_region_id,
\$mid_seq_region, \$mid_length, \$ori, \$start_start,
\$start_end);
while($sth->fetch()) {
if( defined $mid_cs ) {
$start_mid_mapper->add_map_coordinates
(
$seq_region_id,$start_start, $start_end, $ori,
$mid_seq_region_id, $mid_start, $mid_end
);
} else {
if( $from eq "first" ) {
$combined_mapper->add_map_coordinates
(
$seq_region_id,$start_start, $start_end, $ori,
$mid_seq_region_id, $mid_start, $mid_end
);
} else {
$combined_mapper->add_map_coordinates
(
$mid_seq_region_id, $mid_start, $mid_end, $ori,
$seq_region_id,$start_start, $start_end
);
}
}
#update sr_name cache
my $arr = [ $mid_seq_region_id, $mid_seq_region,
$mid_cs_id, $mid_length ];
$self->{'sr_name_cache'}->{"$mid_seq_region:$mid_cs_id"} = $arr;
$self->{'sr_id_cache'}->{"$mid_seq_region_id"} = $arr;
push @mid_ranges,[$mid_seq_region_id,$mid_seq_region,
$mid_start,$mid_end];
push @start_ranges, [ $seq_region_id, $start_start, $start_end ];
#the region that we actually register may actually be larger or smaller
#than the region that we wanted to register.
#register the intersection of the region so we do not end up doing
#extra work later
if($start_start < $start || $start_end > $end) {
$start_registry->check_and_register($seq_region_id,$start_start,
$start_end);
}
}
$sth->finish();
}
# in the one step case, we load the mid ranges in the
# last_registry and we are done
if( ! defined $mid_cs ) {
for my $range ( @mid_ranges ) {
$end_registry->check_and_register( $range->[0], $range->[2],
$range->[3] );
}
# and thats it for the simple case ...
return;
}
###########
# now the second half of the mapping
# perform another query and load the mid <-> end mapper using the mid cs
# ranges
#
#ascertain which is component and which is actually assembled coord system
@path = @{$csa->get_mapping_path($mid_cs, $end_cs)};
if(@path == 2 || ( @path == 3 && !defined $path[1])) {
$asm_cs = $path[0];
$cmp_cs = $path[-1];
} else {
my $path = join(
',',
map({$_->name .
' '. $_->version} @path));
my $len = scalar(@path)-1;
throw("Unexpected mapping path between intermediate and last" .
"coord systems (". $mid_cs->name . " " . $mid_cs->version .
" and " . $end_cs->name . " " . $end_cs->version . ")." .
"\nExpected path length 1, got $len. " .
"(path=$path)");
}
if(defined($to_slice)){
my $to_cs = $to_slice->coord_system;
if($asm_cs->equals($to_cs)){
$asm2cmp_sth = $self->prepare($asm2cmp);
$cmp2asm_sth = $self->prepare($cmp2asm." AND asm.asm_seq_region_id = $to_seq_region_id");
}
elsif($cmp_cs->equals($to_cs)){
$asm2cmp_sth = $self->prepare($asm2cmp." AND asm.cmp_seq_region_id = $to_seq_region_id");
$cmp2asm_sth = $self->prepare($cmp2asm);
}
else{
$asm2cmp_sth = $self->prepare($asm2cmp);
$cmp2asm_sth = $self->prepare($cmp2asm);
}
}
$sth = ($asm_cs->equals($mid_cs)) ? $asm2cmp_sth : $cmp2asm_sth;
my $end_cs_id = $end_cs->dbID();
foreach my $mid_range (@mid_ranges) {
my ($mid_seq_region_id, $mid_seq_region,$start, $end) = @$mid_range;
$sth->bind_param(1,$mid_seq_region_id,SQL_INTEGER);
$sth->bind_param(2,$start,SQL_INTEGER);
$sth->bind_param(3,$end,SQL_INTEGER);
$sth->bind_param(4,$end_cs_id,SQL_INTEGER);
$sth->execute();
#load the end <-> mid mapper with the results and record the mid cs
#ranges we just added to the mapper
my ($end_start, $end_end, $end_seq_region_id, $end_seq_region, $end_length,
$ori, $mid_start, $mid_end);
$sth->bind_columns(\$end_start, \$end_end, \$end_seq_region_id,
\$end_seq_region, \$end_length, \$ori, \$mid_start,
\$mid_end);
while($sth->fetch()) {
$end_mid_mapper->add_map_coordinates
(
$end_seq_region_id, $end_start, $end_end, $ori,
$mid_seq_region_id, $mid_start, $mid_end
);
#update sr_name cache
my $arr = [ $end_seq_region_id,$end_seq_region,$end_cs_id,$end_length ];
$self->{'sr_name_cache'}->{"$end_seq_region:$end_cs_id"} = $arr;
$self->{'sr_id_cache'}->{"$end_seq_region_id"} = $arr;
#register this region on the end coord system
$end_registry->check_and_register($end_seq_region_id, $end_start, $end_end);
}
$sth->finish();
}
#########
# Now that both halves are loaded
# Do stepwise mapping using both of the loaded mappers to load
# the final start <-> end mapper
#
$combined_mapper, $start_name);
#all done!
return;
}