#!/usr/bin/perl
use strict;

use Carp;

use File::Basename;

use FindBin;

use lib $FindBin::Bin;

use Getopt::Long;

use Pod::Usage;

use ColorHandler::DefaultColorHandler;
use ColorHandler::FileColorHandler;
use FeatureWidget;
use PaintDevice;
use PreferencesHandler;
use PhysicalMapWidget;


# Default range parameters for map display.
my ($first,$last,$step)=(-1,-1,-1);
my @accessnumbers=();
my @gbkfiles=();
my $outputformat='PNG';
my ($width,$height)=(undef,undef);
my $media='a4';
my $urlprefix='http://localhost/';
my $prefsfile="$ENV{'HOME'}/.mugenrc";
my @companalresfiles=();
my @refpos=();
my $colorscheme=undef;

my $help= 0;

GetOptions('help|h' => \$help,
	   'accessnumber|a=s' => \@accessnumbers,
	   'gbkfile|g=s' => \@gbkfiles,
	   'first|f=i' => \$first,
	   'last|l=i' => \$last,
	   'step|s=i' => \$step,
	   'outputformat|o=s' => \$outputformat,
	   'companalresfile|c=s' => \@companalresfiles,
	   'width|w=i' => \$width,
	   'media|m=s' => \$media,
	   'urlprefix|u=s' => \$urlprefix,
           'prefsfile|p=s' => \$prefsfile,
	   'refpos|r=i'=>\@refpos,
	   'colorscheme|e=s' => \$colorscheme); 

pod2usage(1) if $help;
die "$0 : Missing argument(s)."
    if (@ARGV<1);
die "$0 : one and only one of --accessnumber or --gbkfile must be specified"
    if ((@accessnumbers && @gbkfiles) ||
	(@accessnumbers==0 && @gbkfiles==0));

my $mapfilename=shift;


if (defined $prefsfile) {
  PreferencesHandler::set_preferences_file($prefsfile);
  PreferencesHandler::load_preferences();
}

my $device=undef;


if (uc $outputformat eq 'PNG' || uc $outputformat eq 'IMAP') {
    $height=1;
    $width=640 unless
	($width>0);

    if (uc $outputformat eq 'PNG') {
	eval { require PaintDevice::PNGPaintDevice; };
	$device=new PaintDevice::PNGPaintDevice($mapfilename,$width,$height);
    }

    if (uc $outputformat eq 'IMAP') {
	eval { require PaintDevice::ImageMapPaintDevice; };
	$device=new PaintDevice::ImageMapPaintDevice($mapfilename,$width,$height,$urlprefix);
    }
}

if (uc $outputformat eq 'PS' || uc $outputformat eq 'EPS') {
    eval { require PaintDevice::PSPaintDevice; };
    $media=lc $media;
    $media='a4'
	unless (defined $PaintDevice::PAGE_WIDTHS_CM{$media});
    $width=$PaintDevice::PAGE_WIDTHS_CM{$media};
    $height=$PaintDevice::PAGE_HEIGHTS_CM{$media};
    $device=new PaintDevice::PSPaintDevice($mapfilename,
					   $width,$height,
					   type=>lc $outputformat,
					   media=>$media);
}

if (uc $outputformat eq 'XFIG') {
    eval { require PaintDevice::XFigPaintDevice; };
    $media=lc $media;
    $media='a4'
	unless (defined $PaintDevice::PAGE_WIDTHS_CM{$media});
    $width=$PaintDevice::PAGE_WIDTHS_CM{$media};
    $height=$PaintDevice::PAGE_HEIGHTS_CM{$media};
    $device=new PaintDevice::XFigPaintDevice($mapfilename,$width,$height);
}


die "$0: unknown output format $outputformat\n" unless defined $device;


my $mapwidget=new PhysicalMapWidget($device);

my $datasource=undef;
my $bounds_ok=0;

do {

    $datasource=undef;
    my $direction='fw';

    my $accessnumber=shift @accessnumbers;
    if (defined $accessnumber) {
	if ($accessnumber =~ /^!/) {
	    $direction='rev';
	    $accessnumber=~ s/^!//;
	}
	eval { require FeatureDataSource::MicadoFeatureDataSource; 
	     FeatureDataSource::MicadoFeatureDataSource::init(); };
	my %args=(accessnumber=>$accessnumber);
	if ($first>0 && $last>$first) {
	    $args{start}=$first;
	    $args{end}=$last;
	}
	$datasource=new FeatureDataSource::MicadoFeatureDataSource(%args);
    }

    my $gbkfile=shift @gbkfiles; 
    if (defined $gbkfile) {
	if ($gbkfile =~ /^!/) {
	    $direction='rev';
	    $gbkfile=~ s/^!//;
	}
	eval { require FeatureDataSource::FileFeatureDataSource; };
	$datasource=new FeatureDataSource::FileFeatureDataSource($gbkfile,'GenBank');
    }
    
    if (defined $datasource) {

	my $map=new PhysicalMap($datasource);
	
	if (!$bounds_ok) {
	    $first=1
		if ($first<=0);
	    
	    if ($last<=$first) {
		(my $dummy,$last)=$map->get_bounds();
	    }
	    
	    $step=($last-$first)+1
		if ($step<=0);
	    
	    if ($step>($last-$first+1)) {
		$step=$last-$first+1;
	    }
	    
	    $last=$last+$step
		unless (($last-$first+1)%$step==0);
	

	    if ($first<0 && $last<0) {
		($first,$last)=$map->get_bounds();
	    }

	    $bounds_ok=1;
	}
	
	my $anchorpos=shift @refpos;
	$anchorpos=1
	    if (!defined($anchorpos));
	
	my $realfirst=$first+$anchorpos-1;
	my $reallast=$last+$anchorpos-1;

	 if ($direction eq 'rev') {	
	     ($realfirst,$reallast)=($reallast,$realfirst);
	     $realfirst-=$step;
	     $reallast-=$step;
	 }

	$mapwidget->append_map($map,$realfirst,$reallast,$step);
	
	my $companalresfile=shift @companalresfiles;
	if (defined $companalresfile) {
	    $map->load_companal_results($companalresfile);
	}
    }
} while (defined $datasource);


if (defined $colorscheme) {
    $FeatureWidget::ColorHandler=new ColorHandler::FileColorHandler;
    $FeatureWidget::ColorHandler->load_colors($colorscheme);
} else {
    $FeatureWidget::ColorHandler=new ColorHandler::DefaultColorHandler;
}

$mapwidget->render();

__END__

=head1 NAME

MuGeN - Multi-Genome Navigator


=head1 DESCRIPTION

MuGeN is a for exploring multiple annotated genomes
simultaneously.  It provides two commands: B<mugenv> an interactive
navigation tool and B<mugenb> a batch mode multi-genome map generator.
Extensive documentation for MuGen is available at :

http://www-mig.versailles.inra.fr/bdsi/MuGeN

=head1 SYNOPSIS

mugenv [options]

mugenb [options] mapfile

=head1 USAGE

B<mugenv> and B<mugenb> share a large set of options. B<mugenb> provides some extra options to control map generation and needs an additionnal argument, B<mapfile>, specifying the filename of the resulting image.

=over

=item Options common to B<mugenv> and B<mugenb>:

=over

=item B<--help or -h or -?>

Display help message.

=item B<--gbkfile or -g filename>

Display the annotated sequence stored in F<filename> (GenBank format).

=item B<--accessnumber or -a an>

Display the annotated sequence having access number B<an> stored in the Micado database (the preferences file has to be configured with a Micado username/password to use this feature).

=item B<--companalresfile or -c filename>

Defines a computational analysis results file to be drawn on the map.

=item B<--first or -f n>

Map display will start at base position B<n> (default value 1)

=item B<--last or -l m>

Map display will end at base position B<m> (default value 20000).

=item B<--step or -s k>

Map display will have B<k> bases per display line (default value 5000).

=item B<--width or -w p>

Width of map drawing area (in pixels). This option works for B<mugenv> and for B<mugenb> with 'PNG' or 'IMAP' output formats.

=item B<--prefsfile or -p filename>

Load preferences from F<filename> (default is F<$HOME/.mugenrc>).

=back

=item B<--refpos> or B<-r n>

Anchor positions for loaded maps. When loading multiple maps, their
relative positioning is obtained through the repeated use of the B<-r>
option.

=back

=item B<mugenb> specific options:

=over

=item B<-o> or B<--outputformat>

Graphics format for output file. One of 'PNG', 'IMAP', 'PS', 'EPS' or 'XFIG'.

=item B<-u> or B<--urlprefix>

URL prefix used for image maps. Image maps are client side maps where each feature determines a clickable area. The URL pointed by each feature is composed of the URL prefix followed by 3 additionnal parameters : the primary tag of the feature, as value of the tag parameter, the start and end positions of the feature (in base positions) as values of the start and end parameters. Ex, a 'CDS' feature positioned between bases 100 and 200 will give rise to the following map area :
    
    <area shape="rect" coords="<image coordinates>" 
    qhref="<urlprefix>tag=CDS&start=100&end=200">

=item B<-m> or B<--media>

Media specification for XFig and PostScript or encapsulated PostScript maps ('XFIF', 'PS' and 'EPS' output formats). Values can be a4, a3, a2, a1 and a0.

=item B<--colorscheme> or <-e filename>

Uses the color scheme defined in  file F<filename> to draw the maps.

=back

=back

=head1 EXAMPLES

=over

=item Viewing a map stored in the GenBank formatted file F<myfile.map.gbk>.

C<mugenv -g map.gbk>

=item Viewing a map stored in the Micado database with accession number AB021978.

C<mugenv -a AB021978>

=item Viewing a portion of 20kb starting at position 100001 on 4 lines of 5kb each.

C<mugenv -g myfile.gbk -f 100001 -l 120000 -s 5000>

=item Viewing a map using the display preferences stored in the F<myprefs.xml> file

C<mugenv -g myfile.gbk -p myprefs.xml>

=item Generating a PNG image of the GenBank entry contained in file F<myfile.gbk>

C<mugenb -g myfile.gbk -o PNG myfile.png>

=item Generating an image map image of the GenBank entry contained in file F<myfile.gbk>, the HTML description of the map components will be stored in F<myfile.html>, and the image map will be found in F<myfile.map>.

C<mugenb -g myfile.gbk -o IMAP -u http://localhost/Maps/map.html? myfile.map E<gt> myfile.html>

=item Generating an encapsulated PostScript file of the complete genome stored at accession number CG0031, 100 Kbp per line and a3-sized. Output will be stored in file F<myfile.eps>.

C<mugenb -a CG0031 -o EPS -s 100000 -m a3 myfile.eps>


=item Generating an XFig file of two maps. The second map will be
positioned 2Mb downstream of the first map.

C<mugenb -a CG0031 -a CG0057 -r 1 -r 2000000 -o XFIG multimap.fig>

=back

=head1 CONTACT

Comments, contributions, bug-reports can be sent to:

hoebeke@versailles.inra.fr

=cut
