#!PERLPATH
use strict;



use Carp;

use File::Basename;

use lib 'INSTPATH';

#use FindBin;
#
#use lib $FindBin::Bin;

use Getopt::Long;

use Pod::Usage;

use PreferencesHandler;

use ColorHandler::DefaultColorHandler;
use ColorHandler::FileColorHandler;

use FeatureWidget;
use PaintDevice;
use PhysicalMapWidget;



use CompAnalResultSource;
use CompAnalResultSource::FileResultSource;

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

my $help= 0;

my $version=0;

my @maps=();

GetOptions('help|h' => \$help,
	   'datasource|d=s' => \@datasources,
	   '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,
	   'anchortarget|t=s' => \$anchortarget,
           'prefsfile|p=s' => \$prefsfile,
	   'refpos|r=s'=>\@refpos,
	   'colorscheme|e=s'=>\$colorscheme,
	   'version|v'=>\$version);


if ($version) {
    print "This is mugenv release 20040726.\n";
    exit(0);
}

pod2usage(-exitval=>0,
	  -verbose=>2) if $help;

die "$0 : at least one of --datasource, --accessnumber or --gbkfile must be specified"
    if (@accessnumbers==0 && @gbkfiles==0 && @datasources==0);

my $mapfilename=shift;

die "$0 : missing output filename."
    if (!defined $mapfilename);

my $device=undef;


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

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,$anchortarget);
    }
}

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 $bounds_ok=0;

foreach my $filesource (@gbkfiles) {
    push @datasources,"file:$filesource";
}

foreach my $micadosource (@accessnumbers) {
    push @datasources,"micado:$micadosource";
}

foreach my $datasourcename (@datasources) {

    my $datasource=undef;

    my $protocol='file';
    my $resource=$datasourcename;

    if ($datasourcename =~ /:/) {
	($protocol,$resource)=split ':',$datasourcename;
    } 

    my $direction='fw';
    if ($resource =~ /^!/) {
	$direction='rev';
	$resource =~ s/^!//;
    }
    if ($protocol eq 'agmial') {
	#eval {
	require FeatureDataSource::AgmialFeatureDataSource;
	FeatureDataSource::AgmialFeatureDataSource::init();#};
	my %args=(accessnumber=>$resource);
	if ($first>0 && $last>$first && $#refpos==-1) {
	    $args{start}=$first;
	    $args{end}=$last;
	}
	$datasource=new FeatureDataSource::AgmialFeatureDataSource(%args);
    }
    if ($protocol eq 'micado') {
	eval { require FeatureDataSource::MicadoFeatureDataSource; 
	       FeatureDataSource::MicadoFeatureDataSource::init(); };
	my %args=(accessnumber=>$resource);
	if ($first>0 && $last>$first && $#refpos==-1) {
	    $args{start}=$first;
	    $args{end}=$last;
	}
	$datasource=new FeatureDataSource::MicadoFeatureDataSource(%args);
    }

    if ($protocol eq 'seqdb') {
	eval { require FeatureDataSource::SeqDBFeatureDataSource; 
	       FeatureDataSource::SeqDBFeatureDataSource::init(); };
	my %args=(accessnumber=>$resource);
	if ($first>0 && $last>$first && $#refpos==-1) {
	    $args{start}=$first;
	    $args{end}=$last;
	}
	$datasource=new FeatureDataSource::SeqDBFeatureDataSource(%args);
    }
    
    
    #19-05-2004 : ajout de la base petits genes, l'option -r doit contenir la position du dbut de l'affichage (integer)
    my $anchorpos=shift @refpos;

    if ($protocol eq 'smallgen') {
	eval { 
	require FeatureDataSource::SmallgenFeatureDataSource; 
	       FeatureDataSource::SmallgenFeatureDataSource::init(); };
	my %args=(accessnumber=>$resource);
#	if ($first>0 && $last>$first && $#refpos==-1) {
	if ($first>0 && $last>$first) {
	    $args{start}=$anchorpos;
	    $args{end}=$anchorpos + $step;
	}

	$datasource=new FeatureDataSource::SmallgenFeatureDataSource(%args);
    }
    
    if ($protocol eq 'origami') {
	eval { require FeatureDataSource::OrigamiFeatureDataSource; };
	my %args=(accessnumber=>$resource);
	$datasource=new FeatureDataSource::OrigamiFeatureDataSource(%args);
    }

    if ($protocol eq 'file') {
	eval { require FeatureDataSource::FileFeatureDataSource; };
	$datasource=new FeatureDataSource::FileFeatureDataSource($resource);
    }

    if ($protocol eq 'genbank') {
	eval { require FeatureDataSource::GenBankFeatureDataSource; };
	my %args=(accessnumber=>$resource);
	$datasource=new FeatureDataSource::GenBankFeatureDataSource(%args);
    }
    
    if ($protocol eq 'embl') {
	eval { require FeatureDataSource::EMBLFeatureDataSource; };
	my %args=(accessnumber=>$resource);
	$datasource=new FeatureDataSource::EMBLFeatureDataSource(%args);
    }

    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;
	}

	# maj le 19/05/04 par Cr => traitement smallgen
#	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;
	}
	
	if ($anchorpos<=0) {
	    my $range=$last-$first+1;
	    my ($gstart,$gend,$strand)=(-1,-1,-1);
	    ($gstart,$gend,$strand)=$map->get_feature_location('CDS','gene',
							       $anchorpos);
	    if ($gstart>0) {
		$realfirst=$gstart+$first-1;
		$reallast=$realfirst+$range;
		if ($strand==-1) {
		    $realfirst=$gend-$first-1;
		    $reallast=$realfirst-$range;
		} 
	    }
	}

	$mapwidget->append_map($map,$realfirst,$reallast,$step);

	push @maps,$map;

    }
}

foreach my $companalresfile (@companalresfiles) {
    my $mapindex=0;
    if ($companalresfile =~ /,(\d+)$/) {
	$mapindex=$1-1;
	$companalresfile =~ s/,\d+$//;
    }
    
    if (defined $maps[$mapindex]) {
	my $resultsource=new CompAnalResultSource::FileResultSource($companalresfile);
	$maps[$mapindex]->add_comp_anal_results($resultsource->get_results());
    }   

}

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

=head1 SYNOPSIS


The Multi-Genome Navigator, or MuGeN, is a bioinformatics software package providing tools for exploring multiple annotated genomes along with in silico analysis results. It offers two distinct programs, one for interactive vizualization and navigation and another for the generation of images in various formats. Both programs can load annotated sequence data from a local file or retrieve it from databases across the network. Most of the parameters governing the way annotations and analysis results are displayed are customizable, either through the graphical user interface or with command-line parameters. The following sections show how to install and to use MuGeN before describing how to format home-made analysis results in order to integrate them in MuGeN.


=head1 USAGE

B<Options common to mugenb and mugenv>

=over

=item B<-d source:id>

Specifies a resource from which to load annotated genome maps. Each resource consists of two parts, a source and an id. The source can be one of file, genbank, embl, xembl or origami (for publicly accessible sources) or micado, seqdb, mosaic or agmial (for sources needing a valid login and password). When no source is specified, file is taken as default. The id points to the specific map in the source. When the latter is a file, the id is simply the filename (in GenBank, EMBL, BSML or fasta format). When the source is a database (genbank, embl, xembl, origami, micado, seqdb, mosaic, agmial) the id is the access number of the database entry. Maps will be displayed from top to bottom in the order they are entered on the command line. If the id start with a "!" the map will be flipped.


=item B<-f firstbase>

Specifies the starting point of the image to build. In the absence of any reference points, this is the first base of the map that will be located in the upper left corner of the image. If a reference point is given, the upper left corner will be the reference point offset by the amount specified by this option.


=item B<-l lastbase>

Specifies the ending point of the image to build. In the absence of any reference points, this is the last base of the map that will be located in the upper lower right corner of the image. If a reference point is given, the lower right corner will be the reference point offset by the amount specified by this option.


=item B<-s step>

Specifies the number of bases per display line.


=item B<-r refpos>

Specifies a reference position or anchor for a genome map. If the reference position is an integer, the start of the displayed image will be computed by adding the value of the -f option to the integer. If the reference position is a string, MuGeN will look for a CDS feature having a gene qualifier whose value equals the given string. If such a CDS is found, it's start base will be used to compute the start of de displayed image as explained above. Moreover, if the gene is on the reverse strand, the map will be flipped. The genome map for which the reference position is defined is determined by the index of the -r option wrt. the -d option (i.e. the first -r option will be applied to the map defined by the first -doption, the second -r applies to the second -d and so on).


=item B<-c filename[,index]>

Specifies a computational analysis results file to display with a genome map. If a comma and an index are appended to the filename, the result will be applied to the genome map of the corresponding index. Index 1 is the genome map loaded by the first -d option, index 2 the map corresponding to the second -d and so on.


=item B<-e filename>

Specifes a file containing a color scheme to apply to displayed features.


=item B<-w n>

Specifes the width in pixels of the drawing area


=item B<-p filename>

Specifes the preferences file to load. If no -p option is given, the preferenes file will be set to ${HOME}/.mugenrc.


=back


B<Options specific to mugenb>

=over

=item B<-o format>

Specifies the output format of the image file to be generated. Valid formats are : PNG, IMAP, PS, EPS, XFIG.


=item B<-m mediatype>

Specifies the media type, for PS or EPS output files. Valid types are : a7, a6, a5, a4, a3, a2, a1, a0, b7, b6, b7, b4, b3, b2, b1, b0, lettern legal, executive, ledger.


=item B<-u urlprefix>

Specifies the root URL for client-side image maps in IMAP format. Parameters relative to dislayed features will be appended to this root URL. For instance, given a root URL of http://www.somewhere.org/cgi-bin/myscript.pl?myid=xyz&, and an image containing a CDS feature, whose name is abcX positioned from base 1234 to base 5678, the URL generated for it's clickable area will be http://www.somewhere.org/cgi-bin/myscript.pl?myid=xyz&tag=CDS&name=abcX&start=1234&end=5678.


=item B<-t anchortarget>

Sets the target frame of map links in IMAP format. Default is: _self.


=back



=head1 CONTACT

Mark Hoebeke (mhoebeke{at}genopole{dot}cnrs{dot}fr)
