#!/usr/local/bin/perl
#BEGIN:{
    #warn("#######0 BEGIN BLOCK MARTVIEW $$".localtime(time));
#}

package martview;

use strict;
use HTML::Template;
use Spreadsheet::WriteExcel;
use CGI qw(standard escape escapeHTML unescape unescapeHTML );
use Storable qw(nfreeze freeze thaw);
use Data::Dumper;     # Used for debug
use File::Temp qw( tempfile );
use Carp;
use Mail::Mailer;

use SiteDefs;
use EnsEMBL::HTML::Page;
#use EnsEMBL::DB::Mart;
use GZipper;

use MartView::Meta;
use MartView::MetaStage;
use MartView::MetaBlock;
use MartView::MetaForm; 
use MartView::MetaFormEntry;
use MartView::MetaHyperlink;


use MartView::Panel;
use MartView::PanelMain;
use MartView::PanelTop;
use MartView::PanelStatus;


use BioMart::Initializer;
use BioMart::Query;
use BioMart::QueryPlanner;
use BioMart::ResultTable;
use BioMart::AttributeTable;

use FmtPrinter::HTML;
use FmtPrinter::TXT;
use FmtPrinter::CSV;
use FmtPrinter::TSV;
use FmtPrinter::FASTA;
use FmtPrinter::XLS;
use FmtPrinter::GFF;
use FmtPrinter::ADF;
use FmtPrinter::MAF; ## New
use FmtPrinter::AXT; ## New

#warn("#######1 $$ ENTERING MARTVIEW AT ".localtime(time));

require EBI::HtmlHelper if ($SiteDefs::ENSEMBL_SITETYPE eq 'EBI');

our $failed_modules;
our $SPECIES_DEFS;
sub dynamic_use {
  my( $classname ) = @_;
  unless( $classname ) {
    my @caller = caller(0);
    my $error_message = "Dynamic use called from $caller[1] (line $caller[2]) with no classname parameter\n";
    warn $error_message;
    $failed_modules->{$classname} = $error_message;
    return 0;
  }
  if( exists( $failed_modules->{$classname} ) ) {
  #  warn "EnsEMBL::Web::Root: tried to use $classname again - this has already failed $failed_modules->{$classname}";
    return 0;
  }
  my( $parent_namespace, $module ) = $classname =~/^(.*::)(.*)$/ ? ($1,$2) : ('::',$classname);
  no strict 'refs';
  return 1 if $parent_namespace->{$module.'::'}; # return if already used
  eval "require $classname";
  if($@) {
    warn "EnsEMBL::Web::Root: failed to use $classname\nEnsEMBL::Web::Root: $@" unless $@ =~/^Can't locate /;
    delete( $parent_namespace->{$module.'::'} );
    $failed_modules->{$classname} = $@;
    return 0;
  }
  $classname->import();
  return 1;
}

if( $SiteDefs::ENSEMBL_SITETYPE eq 'EnsEMBL' ) {
  dynamic_use('EnsEMBL::Web::SpeciesDefs');
  dynamic_use('EnsEMBL::Web::Document::Renderer::Apache');
  dynamic_use('EnsEMBL::Web::Document::Dynamic');
  dynamic_use('EnsEMBL::Web::Document::Static');
  dynamic_use('EnsEMBL::Web::Document::Panel');
  $SPECIES_DEFS ||= EnsEMBL::Web::SpeciesDefs->new();
}
# Path to HTML templates (used by HTML::Template)
$ENV{HTML_TEMPLATE_ROOT} = $SiteDefs::ENSEMBL_TEMPLATE_ROOT;

#print STDERR "TMPL ROOT: ",$ENV{HTML_TEMPLATE_ROOT},"\n";


# Package globals
use vars qw( $CGI $REGISTRY);
use vars qw( @JSCRIPT_EXTRA @ON_LOAD_EXTRA %CACHE_ON_LOAD_EXTRA); # Jscript 
use vars qw( %ERRORS ); # Errors per-stage

#my $initializer;
my $martRegistryFile = $SiteDefs::ENSEMBL_SERVERROOT."/conf/martRegistry.xml";
my $initializer = BioMart::Initializer->new('registryFile' => $martRegistryFile);
$REGISTRY = $initializer->getRegistry;

#use MartView::RegistryCache;
#MartView::RegistryCache->init();
#$REGISTRY    = $MartView::RegistryCache::REGISTRY;
#$initializer = $MartView::RegistryCache::initializer;
#$initializer->getRegistry;
#my $confForest = $REGISTRY->getConfigurationTrees();# don't use - really slooooow



my @stages = qw(start filter output);

MAIN:{
  if( is_script_suspended() ){ # Check for manual suspend. See sub for detail
    print( get_suspend_page() );
    exit;
  } 

  # Populate package globals for each request.
  @JSCRIPT_EXTRA = ();
  @ON_LOAD_EXTRA = ();
  %ERRORS     = ();

  $CGI       = CGI->new();

  # Process the REQUEST_URI. This may contain:
  # 1. the MART_STATE_ID
  # 2. A result file
  #if( $ENV{REQUEST_URI} =~ /martview\/([^\/]+)\?/ ){# for GET requests
  if( $ENV{REQUEST_URI} =~ /martview\/([^\/]+)/ ){
    # Got the MART_STATE_ID
    $CGI->param('id',$1);
    
    if( $ENV{REQUEST_URI} =~ /martview\/.+?\/(.+)/ ){
      # Got a result file
      $CGI->param('_export',1);      # Want to export
      $CGI->param('outtarget',0);
      $CGI->param('stage_parent',0); # Don't expect any POST data
      #warn( "SAVE FILE: $1" );
    }
  }
  elsif($ENV{REQUEST_URI} =~ /martview\?species=(.+)/){# do ensembl URL linking processing hack
      #warn("#######7 $$ DOING ENSEMBL SPECIES HACK AT ".localtime(time));
      my @species_url = split(/\&/,$1);
      my @species = split(/_/,$species_url[0]); 
      my $dataset = lc(substr($species[0],0,1)).$species[1].'_gene_ensembl';
      $CGI->param('database','Ensembl');
      $CGI->param('dataset',$dataset);
  }

  # Look for a BlastView ticket
  if( $CGI->param('_blast_ticket') ){ 
    &import_blast_data() 
  }

  # Process name/value pairs from image submits
  process_image_submits();

  # Process genome type - must be done before retrieving state
  process_genome_type();

  # Reset UI by deleting all params from $CGI
  if( defined $CGI->param('_new') ){
    map{ $CGI->Delete($_) } $CGI->param();
  }

  # Recover state
  my $id = restore_state();

  recover_state();

  # A bit of defensive porgramming - pid file is unlinked on exit, or if one
  # of the signals is caught. Note - SIGPIPE may not be available behind
  # mod_proxy :(
  my $pid_file = ( $SiteDefs::ENSEMBL_TMP_DIR . "/" .
                   join( '.',  $id, Sys::Hostname::hostname , $$ ) );
  open( PID, ">$pid_file" );
  print PID Dumper( $CGI );
  close PID;
  local $SIG{INT}     = sub{ unlink( $pid_file ); Apache::exit };
  local $SIG{TERM}    = sub{ unlink( $pid_file ); Apache::exit };
  local $SIG{PIPE}    = sub{ unlink( $pid_file ); Apache::exit };
  local $SIG{__DIE__} = sub{ unlink( $pid_file ); die(@_) };
  

  # More cgi param processing - after retrieving state
  process_stage();


  #process_outformat();
  #process_defaults();#form->default processing from MetaData - move to get_main_panel
  validate_params();#add_cgi_processing and add_error aspects from MetaData

  my $print_page = 1;

  
  if( $CGI->param('_export') && ! %ERRORS ){
    if( $CGI->param('GALAXY_URL') ){

	my $datasetName = $CGI->param('dataset');
	my $dataset = $REGISTRY->getDatasetByName($CGI->param('schema'),$datasetName);
	my $displayName = $dataset->displayName();
	$CGI->param('outformat','txt');
	my $port = $ENSEMBL_PROXY_PORT || $ENSEMBL_PORT;
      print qq(Content-Type: text/html

<head>
<meta http-equiv="refresh" content="0;url=).$CGI->param('GALAXY_URL').qq(?name=$displayName&type=text&URL=http://).$ENSEMBL_SERVER.':'.$port.qq(/biomart/martview?id=$1&GALAXY_URL=0&_export=1">
</head>
);
      save_state();
      exit;
      #$print_page = 0; # Don't print the page
    }


    if( $CGI->param('outtarget') ){
	push( @ON_LOAD_EXTRA, 'viewResults()' );
    }
    else{
	print_results();
	$print_page = 0; # Don't print the page
    }
  }  

  if( $print_page ){
    # Build/retrieve panel HTML
    my $status_box  = get_status_panel(); # Run first: errors affect top panel
    my $top_panel   = get_top_panel();
    my $page_tmpl   = get_page_tmpl();

    # All CGI processing complete; now save state

    save_state();
    # Print page
    my %header_opts;

    set_jscript_onload();

    if( @JSCRIPT_EXTRA ){
      $header_opts{additional_functions} = \@JSCRIPT_EXTRA;
    }
    if( @ON_LOAD_EXTRA ){
      $header_opts{onload} = \@ON_LOAD_EXTRA;
    }
    print $CGI->header;
    $header_opts{ensembl_species}     = 'BioMart';
    $header_opts{species_common_name} = 'BioMart';
    $header_opts{ensembl_link}        = '/Multi/martview';
    my $page;
    if( $SiteDefs::ENSEMBL_SITETYPE eq 'EnsEMBL' ) {
      my $renderer = new EnsEMBL::Web::Document::Renderer::Apache;
      $page     = new EnsEMBL::Web::Document::Dynamic( $renderer,undef,$SPECIES_DEFS );
      $page->_initialize_HTML;
      #$page->set_doc_type( 'HTML', '4.01 Trans' );
      $page->masthead->sp_bio    ||= 'BioMart';
      $page->masthead->sp_common ||= 'BioMart';
      foreach( @{$header_opts{additional_functions}||[]} ) {
        $page->javascript->add_script( $_ );
      }
      foreach( @{$header_opts{onload}||[]} ) {
        $page->add_body_attr( 'onload', "$_;" );
      }
      $page->stylesheet->add_sheet( 'all', '/css/martview.css' );
    } else {
      print ensembl_page_header(%header_opts);
    }

    # EBI HEADER - uncomment for BioMart site header
    if ($SiteDefs::ENSEMBL_SITETYPE eq 'EBI'){
	my $load_methods;
	if( $CGI->param( '_export' ) && ! %ERRORS ){
	    $load_methods = "viewResults(); LOADED=1";
	}
	#else{
	#    $load_methods = "initialiseSeqType(); changeImage(seqType); validatedSeqType(seqType)";
	#}
	EBI::HtmlHelper::printTop(0, "databases", "", 
				  "BioMart", "http://www.ebi.ac.uk/biomart", 
				  "", "", $load_methods, 0, 0);
    }

    my $content = update_selection( $page_tmpl, $top_panel, $status_box );
    if( $CGI->param( '_export' ) && ! %ERRORS ){
      $content .= view_results_js();
    }

    if( $SiteDefs::ENSEMBL_SITETYPE eq 'EnsEMBL' ) {
      $page->content->add_panel( new EnsEMBL::Web::Document::Panel( 'raw' => $content ) );
      $page->render;
    } else {
      print $content;
      print ensembl_page_footer;
    }
  }
  $CGI = undef();       # Clean CGI object
  unlink( $pid_file );  # Remove PID file
  Apache::exit;
}

#----------------------------------------------------------------------
# Check whether page has been manually suspended
sub is_script_suspended{
  my $script = $ENV{ENSEMBL_SCRIPT};
  my $suspend_file = ( $SiteDefs::ENSEMBL_SERVERROOT.
		       '/perl/multi/'.
		       $script.'.suspend' );
  return -e $suspend_file;
}

#----------------------------------------------------------------------
# 
sub get_suspend_page{
  my $msg = shift;
  my $script = $ENV{ENSEMBL_SCRIPT};
  if( $SiteDefs::ENSEMBL_SITETYPE eq 'EnsEMBL' ) {
    my $renderer = new EnsEMBL::Web::Document::Renderer::Apache( );
    my $page     = new EnsEMBL::Web::Document::Static( $renderer );
    my $page->content->add_panel( new EnsEMBL::Web::Document::Panel( 'caption' => 'Ensembl Web site message',
      content => "<p>Sorry, MartView is unavailable at the moment due to essential maintenance work.</p><p>$msg</p><p>Normal service will be resumed shortly</p>"
    ));
    CGI::header;
    $page->render();
  } else {
    my $page = EnsEMBL::HTML::Page->new();
    print $page->http_header;
    print $page->start_html;
    print ensembl_navigation_table(
      ensembl_link        => "/BioMart/$script",
      species_common_name => $page->script_pretty_name
    );
    $msg  ||= ( "Sorry, ". $page->script_pretty_name.
              " is unavailable due to essential maintenance work.".
              " Normal service will be resumed shortly" );
    return qq( <h1>Ensembl Web Site Message</h1><P>$msg</P> );
  }
}

#----------------------------------------------------------------------
# TODO: Document
sub get_page_tmpl{

  # What do we cache on?
  my @cache_params = ( 'schema','database','dataset','stage','second_dataset','outtype','adf' );

  # Build the cache location
  my @cache_location = ('onload');
  foreach( @cache_params ){
    if( my @vals = sort( $CGI->param( $_ ) ) ){
      my $cgi_value = join( '_', $CGI->param( $_ ) );
      if( $CGI->param('stage') eq 'filter' && $_ eq 'outtype' ){ push @cache_location, 'none'  }
      else {push @cache_location, ( $cgi_value || 'none' ) }
      # 'Stage' eq 'start' does not depend on species, focus
      if( $_ eq 'stage' && $cgi_value eq 'start' ){ last }
    }
    else{ push @cache_location, 'none' }
  }

  # Build the cache file
  my $tmp_dir = $SiteDefs::ENSEMBL_TMP_DIR;
  my $cache_file = ( "$tmp_dir/martview-" . 
		     join( '_', @cache_location ) . 
		     '.html.tmpl' );

  # Do we have this location cached in memory?
  if(my $cached = $MartView::Panel::CACHE->get_cached( \@cache_location ) ){
#    warn( 'Got from cache: ', join( ', ', @cache_location ) );
    return $cached;
  }

  # Do we have this location cached on file?
  if( -e $cache_file ){
    local $\="";
    if( open( CACHE, $cache_file ) ){
      #warn( 'Got from cache file: ', join( ', ', @cache_location ) );
      my $contents = '';
      while( <CACHE> ){
	$contents .= $_;
      }
      close CACHE;
      $MartView::Panel::CACHE->update_cache( \@cache_location, $contents );
      return $contents;
    }
    else{ warn( "Could not open file $cache_file" ) }
  }
  
  # Still here? need to build the main table and update the cache


  my $t = HTML::Template->new( filename => 'martview.page.html.tmpl',
			       cache    => 0,
                                die_on_bad_params => 0,
                                strict => 0 );

  my( $main_box, $suffix_html ) = get_main_panel();
  my %params;
  map{ $params{$_}="<TMPL_VAR $_>" } $t->query;
  $t->param(%params); 
  $t->param(
	    MAIN_BOX      => $main_box,
	    SUFFIX_HTML   => $suffix_html,
	    BORDER_COLOR  => $MartView::Panel::BORDER_COLOR,
	    #MAIN_BG_COLOR => $EnsMart::Panel::MAIN_BG_COLOR,
	    #DARK_BG_COLOR => $EnsMart::Panel::DARK_BG_COLOR,
	    #VDARK_BG_COLOR=> $EnsMart::Panel::VDARK_BG_COLOR,
	    IMG_BLANK     => MartView::Panel::IMG_BLANK,
	   );

  my $output = $t->output();
  
  # Update memory and file caches
  $MartView::Panel::CACHE->update_cache( \@cache_location, $output );
  open( CACHE, ">$cache_file" ) 
    or die( "Could not open file $cache_file for write" );
  print CACHE $output;
  close CACHE;

 # reading from a cached file rather than returing directly makes
 # it work with perl 5.8.0 and HTML::Template 2.6
 # awaiting better fix

  if( -e $cache_file ){
    local $\="";
    if( open( CACHE, $cache_file ) ){
      my $contents = '';
      while( <CACHE> ){
        $contents .= $_;
      }
      close CACHE;
      $MartView::Panel::CACHE->update_cache( \@cache_location, $contents );
      return $contents;
    }
    else{ warn( "Could not open file $cache_file" ) }
  }

  #return $output;

}

#----------------------------------------------------------------------
# Uses MartView::PanelTop to generate a top panel.
sub get_top_panel{
  my $src_tmpl = join( '',
		       MartView::Panel::IMG_ROOT_ROVER,
		       '/',
		       '%s',
		       '-%s.gif' );

  my $top_panel = MartView::PanelTop->new($CGI);
  $top_panel->add_block();
  $top_panel->add_entry();

  my @stage_names = @stages;
  my @arrows;
  my %input_names;
  my %input_values;
  my %srcs;
  my $error = 0; # Grey out all stages after error

  for( my $i=0; $i<@stage_names; $i++ ){
    my $suffix;
    my $this_name = $stage_names[$i];
    my $next_name = $stage_names[$i+1];
    if( $this_name eq $CGI->param('stage') ){ 
      if( $ERRORS{$this_name} ){ $error ++ };
      $suffix = 'sel';
      $input_values{$this_name} = $this_name;
      $input_names{$this_name} = 'stage';
    }
    elsif( is_stage_initialised( $this_name ) and ! $error ){ 
      $suffix = 'on';
      $input_values{$this_name} = $this_name;
      $input_names{$this_name} = 'stage';
    }
    else{ $suffix = 'off' }
    $srcs{$this_name} = sprintf( $src_tmpl, 
				 uc($this_name),
				 $suffix );
    # Arrows:
    if( ( $this_name eq $CGI->param('stage')   ||
	  is_stage_initialised( $this_name   ) ) &&
	( $next_name eq $CGI->param('stage') ||
	  is_stage_initialised( $next_name ) ) && $next_name ) {
      push @arrows, join( '/', 
			  MartView::Panel::IMG_ROOT_ROVER, 
			  'arrow-on.gif' );
    }
    elsif( $next_name ){
      push @arrows, join( '/', 
			  MartView::Panel::IMG_ROOT_ROVER, 
			  'arrow-off.gif' );
    }
  }

  # NEW and EXPORT buttons
  unshift @stage_names, 'new';
  unshift @arrows, MartView::Panel::IMG_BLANK;
  $input_names{new}  = '_new';
  $input_values{new} = 'new';
  $srcs{new} = sprintf( $src_tmpl, 
			'new',
			'on' );

  push @stage_names, 'export';
  push @arrows, MartView::Panel::IMG_BLANK;
  my $export_suffix = 'off';#'off' - hacked 1/11/04

  if( $CGI->param('outtype') and ! %ERRORS ){ # Should export be live?
    $export_suffix = 'on';
    $input_names{export}  = '_export';
    $input_values{export} = 1;    
  }

  $srcs{export} = sprintf( $src_tmpl, 
			   'export',
			   $export_suffix );
  

  # Add the button row
  $top_panel->add_top_form({ -keys    => \@stage_names,
			     -divs    => \@arrows,
			     -names   => \%input_names,
			     -srcs    => \%srcs,
			     -vals    => \%input_values, });

  return $top_panel->output();
}

#----------------------------------------------------------------------
# Generates HTML for main panel
sub get_main_panel{
  # --- MainPanel --
  my $main_panel = MartView::PanelMain->new($CGI);
  my $panel_tmpl = '';
  my $this_stage = $CGI->param( 'stage' );  

  my @javascript_code = ();

  my $visible_only = 1;
  my $dataSetNames = $REGISTRY->getAllDatasetNames($CGI->param('schema'),$visible_only);
  my $displayNames = $REGISTRY->getAllDisplayNames($CGI->param('schema'),$visible_only);

  my $stage = $CGI->param('stage') || return 'No stage';

  my $dataset = $CGI->param('dataset');
  return 'No datasets' if (!$dataset && $stage ne 'start');
  
  my @config_trees;
  
  my $datasetConfig = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset) if ($dataset);
  return "No dataset for $dataset" if (!$datasetConfig && $stage ne 'start');
  
  my $datasetConfigTree = $datasetConfig->getConfigurationTree if ($datasetConfig);
  return "No config for $dataset" if (!$datasetConfigTree && $stage ne 'start');

  push @config_trees, $datasetConfigTree if ($datasetConfigTree);

  

  my @possibleLinks;
  my $dataset_obj;
  foreach my $dataSet($REGISTRY->getAllDatasetNames($CGI->param('schema'))){
    if ($dataset eq $dataSet){
      $dataset_obj = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataSet);
      next;
    }
    if (($REGISTRY->getDatasetByName($CGI->param('schema'),$dataSet)->visible) || 
        ($REGISTRY->getDatasetByName($CGI->param('schema'),$dataSet)
	      ->getConfigurationTree->visibleFilterPage)){
	if ($REGISTRY->getPath($CGI->param('schema'),$dataSet,$dataset)){# make unidirectional for now
	   push @possibleLinks, $dataSet;
	}
    }
  }

#  warn("$dataset POSSIBLE LINKS ". $possibleLinks[0]. " SEC ".$CGI->param('second_dataset')); 
  #$CGI->param('second_dataset',$possibleLinks[0]) if (!$CGI->param('second_dataset'));
  my $chosenDataset = $REGISTRY->getDatasetByName($CGI->param('schema'),$CGI->param('second_dataset'))
      if (@possibleLinks > 0);# stops leftover second dataset setting being used
  my $chosen_ct = $chosenDataset->getConfigurationTree if ($chosenDataset);
  push @config_trees, $chosen_ct if ($chosen_ct);
  set_main_panel_nav_buttons( $main_panel, 1 );

  # START MAIN PANEL
  if ($stage eq 'start'){
      # prepare page with a drop down menu of all public datasets
      $main_panel->add_block;
      $main_panel->add_block_header(1, { LABEL => qq(
           Select the <B>dataset</B> for this query) });
      
      my $form = MartView::MetaForm->new();
      my $schemas = $REGISTRY->getAllVirtualSchemaNames($visible_only);
      
      set_jscript_setStartOptions($form,$REGISTRY->getAllVirtualSchemaNames(),\@javascript_code);
      $form->set_name('dataset');

      my %schemaHash;
      foreach my $schema(@{$REGISTRY->getAllVirtualSchemas()}){
	  $schemaHash{$schema->name} = $schema->displayName || $schema->name;
      }
      my @schema_options;
      foreach (keys %schemaHash){
	  push @schema_options,[$_,$schemaHash{$_}];
      } 


      # Schema
      if (@$schemas > 1){
	  my $entry = MartView::MetaFormEntry->new();
	  $entry->set_cgi_name('schema');
          my $schema_label = $SiteDefs::MART_SCHEMA_LABEL;
	  $entry->set_label($schema_label);
	  $entry->set_cgi_onchange('javascript:setStartOptions()');
	  #$entry->set_options($schemas);
	  $entry->set_options(\@schema_options);
	  push my @entry_objs, $entry;
	  my $entry2 = MartView::MetaFormEntry->new();
	  $entry2->set_cgi_name('schema_last');
	  push @entry_objs, $entry2;
	  my $warn_placeholder = $main_panel->add_entry();      
	  $main_panel->add_form
	      ( $main_panel->gen_start_select( @entry_objs ).
		$main_panel->gen_warn_placeholder('dataset') );
      }

      # Create a unique list of Databases for all schemas
      # ...and a count of num databases per schema
      my @databases;
      my %databases_by_schema;
      foreach my $schema(@{$REGISTRY->getAllVirtualSchemaNames()}){
        $databases_by_schema{$schema} = 0;
        foreach my $database(@{$REGISTRY->getAllDatabaseNames($schema,$visible_only)}){
          #$databases{$database}++;
	  #push @databases,$database.'__'.$schema;
          #push @databases,$database;
	    push @databases,[$database.'__'.$schema,$database];
	    $databases_by_schema{$schema}++;
        }
      }
      #my @databases = keys %databases;
      my( $max_databases_per_schema ) = ( sort{ $b <=> $a } values %databases_by_schema );

      # Display database select list only if there is a choice of DBs!
      if ( scalar( @databases > 1 ) and $max_databases_per_schema > 1 ){
	  my $entry = MartView::MetaFormEntry->new();
	  $entry->set_cgi_name('database');
          my $database_label = $SiteDefs::MART_DATABASE_LABEL;
	  $entry->set_label($database_label);
	  $entry->set_cgi_onchange('javascript:setStartOptions()');
	  #$entry->set_options([@databases]);
          $entry->set_options(\@databases);

	  my $warn_placeholder = $main_panel->add_entry();      
	  $main_panel->add_form
	      ( $main_panel->gen_start_select( $entry ).
		$main_panel->gen_warn_placeholder('dataset') );
      }
      
      # datasets
      my $entry2 = MartView::MetaFormEntry->new();
      $entry2->set_cgi_name('dataset');
      my $dataset_label = $SiteDefs::MART_DATASET_LABEL;
      $entry2->set_label($dataset_label);

      my %datasets;
      foreach my $schema(@{$REGISTRY->getAllVirtualSchemaNames()}){
	  foreach my $dataset_name(@{$REGISTRY->getAllDatasetNames($schema,$visible_only)}){
	      my $dataset = $REGISTRY->getDatasetByName($schema,$dataset_name);
	      next if (!$dataset);
	      my $version = '';
	      $version = ' ('.$dataset->version.')' if ($dataset->version);
	      #$datasets{$dataset->name} = $dataset->displayName.$version || $dataset->name;
	      $datasets{$dataset->name} = $dataset->displayName || $dataset->name;
	  }
      }
      my @options;
      foreach (sort{$datasets{$a} cmp $datasets{$b}} keys %datasets){
	  push @options,[$_,$datasets{$_}];
      } 
      $entry2->set_options(\@options);


      my $warn_placeholder = $main_panel->add_entry();      
      $main_panel->add_form
	  ( $main_panel->gen_start_select( $entry2 ).
	   $main_panel->gen_warn_placeholder('dataset') );

      $main_panel->add_panel_header({ LABEL=>qq( Using MartView)});
      $main_panel->add_panel_text({ LABEL=>qq(After choosing a DATASET above, select
some FILTERS on the next page and then which data you want to EXPORT from the OUTPUT 
page. At any stage the COUNT button will calculate the number of entries you can expect 
in the final output.)});
      $main_panel->add_panel_text({ LABEL=>qq(MartView can generate a number of 
different types of output, including sequence and tabulated list data. Multiple output 
formats, including HTML, text and Microsoft Excel, are also supported.)});      
    }

  # FILTER MAIN PANEL
  elsif ($stage eq 'filter'){
      # Build the page description
      my ($ref, $subRef, $secondRef);
      my $added = 1;
      my $datasetCounter = 1;
      foreach my $ct(@config_trees){
	  my $dataSetName = $ct->dataSetName;
	  #my $displayName = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataSetName)->displayName;	  
	  $main_panel->add_panel_header({LABEL=>'DATASET '.$datasetCounter});
	  $datasetCounter++;

	  # Add the blocks/forms
	  foreach my $fpage (@{$ct->getAllFilterTrees}){
	      next if ($fpage->hideDisplay eq 'true'); 
		  foreach my $fgroup (@{$fpage->getAllFilterGroups}){#fgroup = block
		      $main_panel->add_block;
		      $main_panel->add_block_header($added,{ LABEL => $fgroup->displayName})
			  if ($fgroup->displayName);
		      # Examine block/group for additional Java Script functions
		      FC:foreach my $fcollection(@{$fgroup->getAllCollections}){#= form
		          #create the new form object
			  my $form = MartView::MetaForm->new();
			  $form->set_name('collection_'.$fcollection->name);
			  my $j = 0;
			  # below stops ref problem
			  my $filters = [ @{$fcollection->getAllFilters} ];
			  next if (!$$filters[0]);
			  # deal with placeholders and any push actions
			  foreach my $filter(@$filters){#$filter = entry
			      #deal with filters from other datasets
			      my $name = $filter->name;
			      my ($options,$push_actions);
                              
         		      if ($name =~ /\./){
				  my @names = split(/\./,$name);
				  next FC if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
				  $filter = $REGISTRY->getDatasetByName($CGI->param('schema'),
				    $names[0])->getConfigurationTree->getFilterByName(
				      $names[1]);
				  next if (!$filter);
				  $$filters[$j] = $filter;
			      }
			      # add java script if filter has push actions
			      $options = $filter->getAllOptions;
			      $push_actions = $$options[0]->getAllPushActions
				  if ($$options[0]);

			      set_jscript_setOptions($form,$filters,$dataSetName, 
				  \@javascript_code) if ($$push_actions[0]);
			      $j++;
			  }
			  
			  my ($sub,$filter,$entry);
			  my $entry_objs;
			  $j = 0;
			  
			  # DEFINE THE CHECKBOX
			  $entry = MartView::MetaFormEntry->new();
			  $entry->set_cgi_name($dataSetName.'_'.'collection_'.$fcollection->name);
			  $entry->set_label($fcollection->displayName);
			  $entry->set_value(1);
			  $entry_objs->[0]->[0] = 'check';
			  $entry_objs->[0]->[1] = $entry;
			  
			  foreach my $filter(@$filters){#$filter = entry
			       $j++;
			       ###########################################################
			       # Deprecate the $filter->isa and $$options[0] tests
			       # and just use filter->types and option-types eventually
			       ###########################################################
			       
			       # FILTERLIST
			       if ($filter->isa("BioMart::Configuration::FilterList")){
				   my $options = $filter->getAllOptions;
				   if ($$options[0]){# DEFINE AS A CHECKBOX GROUP
				       my $check_counter = 0;
				       my @entry_objs;
				       foreach my $option(@$options){
					   #$entry_objs->[$check_counter]->[0] = 'check';
					   $entry = MartView::MetaFormEntry->new();
					   $entry->set_cgi_name($dataSetName.'_'.$filter->name);
					   $entry->set_label($option->displayName);
					   my $value = $option->value;
					   $value =~ s/ /\_/g;
					   $entry->set_value($value);
					   #$entry_objs->[$check_counter]->[1] = $entry;
					   push @entry_objs, $entry;
					   $check_counter++;
				       }
				       my $warn_placeholder = $main_panel->add_entry();
				       $main_panel->add_form
					   ( $main_panel->gen_checkbox_group( @entry_objs ).
					     $main_panel->gen_warn_placeholder('collection_'.$fcollection->name) );
				       next FC;

				   }
				   else{
                                        #DEFINE A ID LIST FILTER
				        $entry_objs->[$j]->[0] = 'textarea_and_file';
		  
					$entry = MartView::MetaFormEntry->new();
					my $list_param = $dataSetName.'_'.$filter->name;
					$entry->set_cgi_name($list_param);
					$entry->set_cgi_cols( 25 );
					$entry->set_cgi_rows( 4 );
					
					my($comma, $label);
					my $list_filters = $filter->getAllFilters;
					foreach (@$list_filters){
					    $label = $label.$comma.$_->displayName();
					    $comma = ',';
					}
					$entry->set_label($fcollection->displayName.'('.$label.')');

					$entry_objs->[$j]->[1] = $entry;
				       
					$entry = MartView::MetaFormEntry->new();
					$entry->set_cgi_name($dataSetName.'_'.$filter->name.
							     '_file');
					$entry->set_cgi_size( 16 );
					$entry_objs->[$j]->[2] = $entry;
				    }
			       }


			       # CHECKBOX WITH RADIO BUTTONS
			       if ($filter->isa("BioMart::Configuration::BooleanFilter")){
				   $entry_objs->[$j]->[0] = 'radio';
				   $entry = MartView::MetaFormEntry->new();
				   $entry->set_cgi_name($dataSetName.'_'.$filter->name);
				   $entry->set_label('Only');
				   $entry->set_value('Only');
				   $entry_objs->[$j]->[1] = $entry;
				   $entry = MartView::MetaFormEntry->new();
				   $entry->set_cgi_name($dataSetName.'_'.$filter->name);
				   $entry->set_label('Excluded');
				   $entry->set_value('Excluded');
				   $entry_objs->[$j]->[2] = $entry;
			       }
			       elsif ($filter->isa("BioMart::Configuration::ValueFilter")){
				   my $options = $filter->getAllOptions;
				   # test if has nested options
				   my $nested_option_flag;
				   foreach my $op (@$options){
				       if (${$op->getAllOptions}[0]){
				           $nested_option_flag++;
				           last;
				       }
			           }
				   

                                   # Create a MetaFormEntry obj representing the buttonURL
                                   my $button_url_entry;
                                   if ($filter->buttonURL){
                                     $button_url_entry = MartView::MetaFormEntry->new();
                                     $button_url_entry->set_cgi_name($filter->name);
                                     $button_url_entry->set_value('<browse>');
                                     $button_url_entry->set_type('buttonURL');
                                     my $category = $filter->displayName ;
                                     my $url = $filter->buttonURL;
                                     if ($SiteDefs::ENSEMBL_SITETYPE eq 'EBI' && 
                                         $fcollection->name =~ /.+expression_collection/){ #hack for ebi website
                                       my @url = split(/\//,$url);    
                                       $url = '/BioMart/ontology/'.$url[-1];
                                     }
                                     $button_url_entry->set_cgi_onclick( 
                                          qq|javascript:
                                          var nW = window.open("$url", "$category",
                                                               "menubar=no,scrollbars=yes,width=800,height=800");
                                          if( nW.opener == null ){
                                          nW.opener = window;
                                         }|);
                                   }

  
				   # CHECKBOX WITH SELECT AND RADIO BUTTONS
				   if (($$options[0] && $$options[0]->filter && 
				       $$options[0]->filter->isa
				       ("BioMart::Configuration::BooleanFilter"))){
				  
				       $entry_objs->[$j]->[0] = 'select_and_radio';
				       $entry = MartView::MetaFormEntry->new();
				       $entry->set_cgi_name($dataSetName.'_'.$filter->name.
							'_filter');
				       $entry->set_label($filter->displayName);
				       $entry->set_options( sub {
					   my @ops;
					   foreach (@$options){
					       push @ops, [$_->name,$_->displayName]; 
					   }
					   return @ops;
				       });
				       $entry_objs->[$j]->[1] = $entry;
				       $entry = MartView::MetaFormEntry->new();
				       $entry->set_cgi_name($dataSetName.'_'.$filter->name);
				       $entry->set_label('Only');
				       $entry->set_value('Only');
				       $entry_objs->[$j]->[2] = $entry;
				       $entry = MartView::MetaFormEntry->new();
				       $entry->set_cgi_name($dataSetName.'_'.$filter->name);
				       $entry->set_label('Excluded');
				       $entry->set_value('Excluded');
				       $entry_objs->[$j]->[3] = $entry;
				   }
				   # ID UPLOAD FILTER
				   elsif ($$options[0] && $$options[0]->filter && 
					  $$options[0]->filter->isa
					  ("BioMart::Configuration::ValueFilter")){
				       $entry_objs->[$j]->[0] = 'select_textarea_and_file';
				       my $entry = MartView::MetaFormEntry->new();
				       $entry->set_cgi_name($dataSetName.'_'.$filter->name);
				       my $options = $filter->getAllOptions;
				       my $push_actions = $$options[0]->getAllPushActions
					   if ($$options[0]);
				       if ($$push_actions[0]){
					   $ref = $$push_actions[0]->ref;
				           if ($ref =~ /\./){
					       my @ref = split(/\./,$ref);
					       $ref = $ref[1];
					   }
					   $entry->set_cgi_onchange('javascript:set'.uc($dataSetName).uc($ref).
								     'Options()');
				       }
				       if ($filter->name eq $ref){
					   $entry->set_options();
				       }
				       else{
					   $entry->set_options( sub {
					       my @ops;
					       foreach (@$options){
						   push @ops, [$_->name,$_->displayName]; 
					       }
					       return @ops;
					   });
				       }
				       $entry_objs->[$j]->[1] = $entry;
				   
				       ENTRY_TEXTAREA:{
					   # The user pastes a list of identifiers
					   $entry = MartView::MetaFormEntry->new();
					   my $list_param = $dataSetName.'_'.$filter->name.'_list';
					   $entry->set_cgi_name($list_param);
					   $entry->set_cgi_cols( 25 );
					   $entry->set_cgi_rows( 4 );
					   $entry_objs->[$j]->[2] = $entry;
				       }
				       ENTRY_FILE:{
					   # The user uploads a file of identifiers. 
					   # Values are copied from the file param into a
					   # new CGI param, prepresented as a hidden form to
					   # allow state to be maintained.
					   $entry = MartView::MetaFormEntry->new();
					   $entry->set_cgi_name($dataSetName.'_'.$filter->name.
							      '_file');
					   $entry->set_cgi_size( 16 );
					   $entry_objs->[$j]->[3] = $entry;
				       }

                                       # ButtonURL
                                       if( $button_url_entry ){
                                         push @{$entry_objs->[$j]}, $button_url_entry;
                                       }
				   }

				   # CHECKBOX WITH SELECT (UNLESS NESTED OPTIONS)
				   elsif ((($$options[0] && !$nested_option_flag) 
					  || $filter->name eq $ref || 
					  $filter->name eq $subRef || 
					  $filter->name eq $secondRef)){				       
				      $entry_objs->[$j]->[0] = 'select';
				      $entry = MartView::MetaFormEntry->new();
				      $entry->set_cgi_name($dataSetName.'_'.
								$filter->name);
				      $entry->set_label($filter->displayName);
				      my $options = $filter->getAllOptions;
				      my $push_actions = $$options[0]->getAllPushActions 
					  if ($$options[0]);
				      $ref = $$push_actions[0]->ref
					  if ($$push_actions[0]);
				      $secondRef = $$push_actions[1]->ref
					  if ($$push_actions[1]);
				      if ($ref =~ /\./){
					  my @ref = split(/\./,$ref);
					  $ref = $ref[1];
				      }
				      if ($secondRef =~ /\./){
					   my @secondRef = split(/\./,$secondRef);
					   $secondRef = $secondRef[1];
				      }
				      if ($$push_actions[0]){
					  my $jscommand;
					  foreach (@$push_actions){
					      my $tempRef = $_->ref;
					      if ($tempRef =~ /\./){
						  my @tempRef = split(/\./,$tempRef);
						  $tempRef = $tempRef[1];
					      }
					      if ($jscommand){
						  $jscommand = $jscommand.';set'.
						      uc($dataSetName).uc($tempRef).'Options()';
					      }
					      else{
						  $jscommand = 'javascript:set'.
						      uc($dataSetName).uc($tempRef).'Options()';
					      }
					  }
					  $entry->set_cgi_onchange($jscommand);
					  $subRef = '';
					  my $subOptions = $$push_actions[0]->
					      getAllOptions;
					  my $subPushActions = $$subOptions[0]->
					      getAllPushActions if ($$subOptions[0]);
					  $subRef = $$subPushActions[0]->ref 
					      if ($$subPushActions[0]);
					  if ($subRef =~ /\./){
					      my @subRef = split(/\./,$subRef);
					      $subRef = $subRef[1];
					  }
				      }

				      if ($filter->name eq $ref && $subRef ne ''){
					  $entry->set_cgi_onchange('javascript:set'.
								    uc($dataSetName).uc($subRef).'Options()');
				      }
				      if ($filter->name eq $ref || $filter->name eq 
					  $subRef || $filter->name eq $secondRef){
					  $entry->set_options();
				      }
				      else{
					  $entry->set_options( sub {
					      my @ops;
					      foreach (@$options){
						  #my $value = $_->value;
						  my $value = $_->name;
                                                  # as spaces get lost in html
						  $value =~ s/ /\*/g;
						  my $displayName = $_->displayName;
						  push @ops, [$value,substr($displayName,0,30)];
					      }
					      return @ops;
					  });
				      }
		      
				      $entry_objs->[$j]->[1] = $entry;
				      # hidden entry for jscript handling
				      $entry = MartView::MetaFormEntry->new();
				      my $filter_name = $filter->name;
				      $entry->set_cgi_name($dataSetName.'_'.
							    $filter_name.'_last');
				      $entry_objs->[$j]->[2] = $entry;
				  }
				  else{# CHECKBOX WITH TEXTFIELD

				      if ($$options[0] && $nested_option_flag){
					  # if reached this stage must have nested ontology type options
					  # therefore generate the ontology_picker_tool
				          generate_ontology_picker_tool($filter,$dataSetName);
					  #create button url entry automatically
					  $button_url_entry = MartView::MetaFormEntry->new();
					  $button_url_entry->set_cgi_name($filter->name);
					  $button_url_entry->set_value('<browse>');
					  $button_url_entry->set_type('buttonURL');
					  my $category = $filter->displayName ;
					  my $url = '/tmp/_ontology/_'.$filter->name.'.html';
					  $button_url_entry->set_cgi_onclick( 
									      qq|javascript:
									  var nW = window.open("$url", "$category",
                                                               "menubar=no,scrollbars=yes,width=800,height=800");
									      if( nW.opener == null ){
                                          nW.opener = window;
                                         }|);
					  

				      }	   
				      $entry_objs->[$j]->[0] = 'text';				   
				     
				      $entry = MartView::MetaFormEntry->new();
				      $entry->set_label($filter->displayName);
				      $entry->set_cgi_name($dataSetName.'_'.
							$filter->name);
				      

				      $entry_objs->[$j]->[1] = $entry;
				       
                                      if( $button_url_entry ){
                                        $entry_objs->[$j]->[2] = $button_url_entry;
                                        $entry_objs->[$j]->[0] = 'text_and_button';
                                      }
                                    }
                                 }
			   }
			  my $warn_placeholder = $main_panel->add_entry();
			  
			  $main_panel->add_form
			      ( $main_panel->gen_form( $added, $entry_objs ).
				$main_panel->gen_warn_placeholder('collection_'.$fcollection->name) );
		      }
		  }
	  }
      
	  if ($added && @possibleLinks > 0){
	      $added = 0;
	      $main_panel->add_block;
	      $main_panel->add_block_header($added, { LABEL => qq(
		 Select the second dataset) });
              $main_panel->add_block_header($added, { LABEL => qq((NB) Summary counts are unavailable once you add a second dataset to the query. Data export is still possible from the next stage) });
	      my $sub  = 'gen_second_dataset';
      
	      my $form = MartView::MetaForm->new();
	      $form->set_name('dataset');

	      set_jscript_setLinks($form, $dataset, @possibleLinks);
	      # Examine form/collection for additional Java Script functions
	      my $jscript = $form->get_jscript;
	      push @javascript_code, $jscript;

	      my $entry = MartView::MetaFormEntry->new();
	      $entry->set_cgi_name('second_dataset');
	      $entry->set_label('Second Dataset:');
	      $entry->set_cgi_onchange(
		      'javascript:setLinkOptions();document.settings.submit()');

              my %link_dataset_options = ('0' => '--NONE--');
              my %link_options;
              my $schema = $CGI->param('schema');
              foreach my $ldataset_name( @possibleLinks ){
                my $ldataset = $REGISTRY->getDatasetByName($schema,$ldataset_name);
                my $ldataset_display = $ldataset->displayName || $ldataset_name;
		$ldataset_display = '['.$ldataset->locationDisplayName.'] '.$ldataset_display;

                $link_dataset_options{$ldataset_name} = $ldataset_display;

                my @paths = @{$REGISTRY->getPath($schema,$ldataset_name,$dataset)};

                my $fr_dataset = $paths[0];
                my $to_dataset = $paths[1];
                #my $fr_dataset_obj = $REGISTRY->getDatasetByName($schema,$fr_dataset);
                my $to_dataset_obj = $REGISTRY->getDatasetByName($schema,$to_dataset); 
                my $link_obj       = $REGISTRY->getLinkBetween($schema,$fr_dataset,$to_dataset);
                foreach my $link_name( $link_obj->getAllLinks ){
                  my $label = $link_name;
                  my $importable =  $to_dataset_obj->getImportables($link_name) || next;
                  if( my $l = $importable->displayName ){ $label = $l }
                  $link_options{$link_name} = $label;

                  for( my $i=1; $i<@paths; $i++ ){
                    my $next_dataset = $paths[$i+1] || last;
                    my $next_dataset_obj = $REGISTRY->getDatasetByName($schema,$next_dataset); 
                    my $next_link_obj  = $REGISTRY->getLinkBetween($schema,$paths[$i],$paths[$i+1]);
                    my $next_link_name = $next_link_obj->defaultLink;
                    my $next_label = $next_link_name;
                    
                    my $next_importable =  $next_dataset_obj->getImportables($next_link_name) 
                        || next;
                    my $next_label;
                    if( my $l = $next_importable->displayName ){ $next_label = $l }
                    $link_options{$link_name} .= " -> $next_label";
                  }
                }
              }

	      $entry->set_options([map{[$_,$link_dataset_options{$_}]} 
                                   sort keys %link_dataset_options]);

	      push my @entry_objs, $entry;
      
	      my $warn_placeholder = $main_panel->add_entry();      
	      $main_panel->add_form
		  ( $main_panel->$sub( @entry_objs ).
		    $main_panel->gen_warn_placeholder('second_dataset') );

	      my $form = MartView::MetaForm->new();
	      $form->set_name('defaultLink');
	      my $entry = MartView::MetaFormEntry->new();
	      $entry->set_cgi_name('default_link');
	      $entry->set_label('Link Dataset Via:');
	      $entry->set_options([map{[$_,$link_options{$_}]}
                                   sort keys %link_options]);

	      @entry_objs = ();
	      push my @entry_objs, $entry;

	      my $entry2 = MartView::MetaFormEntry->new();
	      $entry2->set_cgi_name('default_link_last');
	      push @entry_objs, $entry2;

	      my $warn_placeholder = $main_panel->add_entry();      
	      $main_panel->add_form
		  ( $main_panel->$sub( @entry_objs ).
		    $main_panel->gen_warn_placeholder('default_link') );
	     
	      
	  }
      }
      set_main_panel_nav_buttons( $main_panel, 0 );
  }
  # OUTPUT PANEL
  elsif ($stage eq 'output'){
     $main_panel->add_block;
     $main_panel->add_block_header(1,{ LABEL => qq(Select output type)});
     my $form = MartView::MetaForm->new();
     $form->set_name('outtype');
     my @entry_objs;
     my $no_image = 0;
     foreach (@{$datasetConfigTree->getAllAttributeTrees()}){
	 next if ($_->hideDisplay eq 'true'); 
	 my $entry = MartView::MetaFormEntry->new();
	 $entry->set_value($_->name);
	 
	 # If you want a tab-like GIF for each attribute page as for the core BioMart
	 # datasets then make sure a GIF exists in htdocs/gfx/EnsMart called
         # outttype_<name>.gif and outttype_<name>SELECTED.gif where <name> is the
         # attribute page name
	 
	 my $potential_gif = 'outtype_'.$_->name.'.gif';	 
	 $no_image = 1 if !(-e "${SiteDefs::ENSEMBL_SERVERROOT}/htdocs/gfx/EnsMart/$potential_gif");
	 $entry->set_cgi_name('outtype');
	 $entry->set_label($_->displayName);
	 $entry->set_label_summary($_->displayName);
	 push @entry_objs, $entry;
     }
     
     my $warn_placeholder = $main_panel->add_entry();
     if (@entry_objs > 1 && $no_image == 0){
	 $main_panel->add_form
	     ( $main_panel->gen_tab_group( @entry_objs ).
	       $main_panel->gen_warn_placeholder('outtype') );
     }

     elsif (@entry_objs > 1 && $no_image == 1){# no images available
						   
              $main_panel->add_block;
	      $main_panel->add_block_header(1, { LABEL => qq(
		   Select the <B>Attribute Page</B>) });
	      my $sub  = 'gen_start_select';
	      my $entry = MartView::MetaFormEntry->new();
	      $entry->set_cgi_name('outtype');
	      #$entry->set_label('Attribute Page:');
	      $entry->set_cgi_onchange(
		      'javascript:document.settings.submit()');
	      $entry->set_options(sub{
		  my @options;
		  foreach (@{$datasetConfigTree->getAllAttributeTrees()}){
		      next if ($_->hideDisplay eq 'true' || $_->name eq '');
		      push @options, [$_->name,$_->displayName];
		  }
		  return @options});
		  
	      push my @entry_objs, $entry;
      
	      my $warn_placeholder = $main_panel->add_entry();      
	      $main_panel->add_form
		  ( $main_panel->gen_second_dataset( @entry_objs ).
		    $main_panel->gen_warn_placeholder('second_dataset') );
	      
     }

    foreach my $ct(@config_trees){
	 next if ($ct->dataSetName ne $dataset);# just show main dataset atts for now 
	     foreach my $apage (@{$ct->getAllAttributeTrees}){
		 my $outtype = $CGI->param('outtype');
		 next if ($outtype ne $apage->name);
		 foreach my $agroup (@{$apage->getAllAttributeGroups}){#agroup = block
		     $main_panel->add_block;
		     $main_panel->add_block_header(1,{ LABEL => $agroup->displayName })
			 if ($agroup->displayName); 
		     
		     ACOLLECTION:foreach my $acollection(@{$agroup->getAllCollections}){
			  # create the new form object
			  my $form = MartView::MetaForm->new();
			  $form->set_name('collection_'.$acollection->name);
			  
			  my @entry_objs;
			  my $entry_label = MartView::MetaFormEntry->new();
			  $entry_label->set_label($acollection->displayName);
			  push @entry_objs, $entry_label;
			  #my $attributes = $acollection->getAllAttributes;
			  my $attributes = [ @{$acollection->getAllAttributes} ];#fix ref problem
		          
                          # SEQUENCE LAYOUT
			  if ($acollection->name eq 'seq_scope_type'){
			      $main_panel->add_block_header(1,{ LABEL => qq(Type of Sequence to Export (all in 5'-3' direction): )});
			      my @entry_objs;
			    
			    ENTRY_SEQUENCE_GENE_SCHEMATIC:{
				my $entry = MartView::MetaFormEntry->new();
				$entry->set_cgi_name('seq_scope_img');
				$entry->set_src('gene_schematic.gif');
				push @entry_objs, $entry;
			    }
                            # LOOP THRO SEQ ATTS FROM HERE
			      my ($seq_conversion, $comma);
			      foreach my $attribute(@$attributes){
                                  #next if ($attribute->name =~ /gene\_/);# ignore the gene specific atts
				  my $entry = MartView::MetaFormEntry->new();
				  $entry->set_cgi_name('collection_seq_scope_type');
				  # get the sequence dataset attribute
				  my @placeholder = split(/\./,$attribute->name);
				  next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$placeholder[0]));
				  my $seq_attribute = $REGISTRY->getDatasetByName($CGI->param('schema'),$placeholder[0])->getConfigurationTree->getAttributeByName($placeholder[1]);
				  next if (!$seq_attribute);
				  $entry->set_value($seq_attribute->name);
				  $entry->set_label($seq_attribute->displayName);
				  $entry->set_cgi_onclick('javascript:changeImage(this.value)');
				  push @entry_objs, $entry;
				  $seq_conversion = $seq_conversion.$comma.'"'.$seq_attribute->name.'"';
				  $comma = ',';
			      }
			      my $warn_placeholder = $main_panel->add_entry();
			      $main_panel->add_form($main_panel->gen_seq_type_group( @entry_objs ).
						    $main_panel->gen_warn_placeholder('seq_scope'));
			      my $gene_disables = '"cdna", "coding", "peptide", "5utr", "3utr"';
			      my $jscript = sequence_jscript($gene_disables,$seq_conversion);
			      push @javascript_code, $jscript;
			      next ACOLLECTION;
			  }# end of sequence layout
			  			  
			  my ($sub,$att_cgi_name);
			  if ($acollection->maxSelect == 1){
			      $sub = 'gen_check_with_radio_group';
			      # add checkbox
			      my $entry = MartView::MetaFormEntry->new();
			      $entry->set_cgi_name('collection_'.$acollection->name);
			      $entry->set_label('Include');
			      $entry->set_value('1');
			      push @entry_objs, $entry;

			      $att_cgi_name = 'collection_'.$acollection->name.'_this';
			  }
			  else{
			      $sub = 'gen_checkbox_group';
			      $att_cgi_name = 'collection_'.$acollection->name;
			  }
			 			  
			    my $j = 0;
			    foreach my $attribute(@$attributes){
			        my $name = $attribute->name;
                              
                                #deal with filters from other datasets  
			        if ($name =~ /\./){
				  my @names = split(/\./,$name);
				  if ($names[1] eq 'filter'){# for filters in an att page
				      # add a filter form
				      @entry_objs = ();
				      next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
				      my $filter = $REGISTRY->getDatasetByName($CGI->param('schema'),$names[0])->
					  getConfigurationTree->getFilterByName($names[2]);
				      next if (!$filter);
				      $sub = 'gen_check_with_text';
				      my $entry1 = MartView::MetaFormEntry->new();
				      $entry1->set_cgi_name('collection_'.$acollection->name);
				      $entry1->set_label($acollection->displayName);
				      $entry1->set_value(1);
				      push @entry_objs, $entry1;

				      my $entry2 = MartView::MetaFormEntry->new();
				      $entry2->set_label($filter->displayName);
				      $entry2->set_cgi_name($filter->name);
				      push @entry_objs, $entry2;	
				       
				      my $warn_placeholder = $main_panel->add_entry();      
				      $main_panel->add_form
					  ( $main_panel->$sub( '',@entry_objs ).
					    $main_panel->gen_warn_placeholder($acollection->
							 name) );
				      next ACOLLECTION;
				  }
				  else{
				      next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
				      $attribute = $REGISTRY->getDatasetByName($CGI->param('schema'),$names[0])->
					getConfigurationTree->getAttributeByName($names[1]);
				      if (!$attribute){
					  next;
				      }
				      $$attributes[$j] = $attribute;
				  }
			        }
			     			      
			        $CGI->param( -name=>'collection_'.$acollection->name, 
					   -value=>[$CGI->param( -name=>'collection_'.$acollection->name),
						    $attribute->name] ) 
				  if ($attribute->default eq 'true');

			        my $entry = MartView::MetaFormEntry->new();
			        $entry->set_cgi_name($att_cgi_name);
			        $entry->set_label($attribute->displayName);
			        $entry->set_value($attribute->name);
			        push @entry_objs, $entry;
			         $j++;
			  }
			  my $warn_placeholder = $main_panel->add_entry();      
			  $main_panel->add_form
			      ( $main_panel->$sub( @entry_objs ).
				$main_panel->gen_warn_placeholder('collection_'.$acollection->name) );
		      }
		 }

	       BLOCK_OUTFORMAT:{
		   $main_panel->add_block;
		   $main_panel->add_block_header(1,{ LABEL => qq(Select the output format:)});
		 FORM_OUTFORMAT:{
		     my $form = MartView::MetaForm->new();
		     $form->set_name('outformat');
		     my @entry_objs;

		       my $outformat = $apage->outFormats;
		       my @outformats = split(/\,/,$outformat);
		       foreach (@outformats){
			   my $entry = MartView::MetaFormEntry->new();
			   $entry->set_cgi_name('outformat');
			   $entry->set_value($_);
			   my $formatter = 'FmtPrinter::'.uc($_);
			   $entry->set_label($formatter->displayLabel());
			   push @entry_objs, $entry;
		       }
		       
		       

		   #}
       		     my $warn_placeholder = $main_panel->add_entry();      
		     $main_panel->add_form( $main_panel->gen_radio_group( @entry_objs ).
					    $main_panel->gen_warn_placeholder('outformat') );
		 }
	       }


	       BLOCK_OUTCOMPRESS:{
		   $main_panel->add_block;
		   $main_panel->add_block_header(1,{ LABEL => qq(File compression:)});

		 FORM_OUTCOMPRESS:{
		     my $form = MartView::MetaForm->new();
		     $form->set_name('outcompress');
		     $CGI->param( -name=>'outcompress', -value=>'none' );
		     my @entry_objs;
		   ENTRY_NONE:{
		       my $entry = MartView::MetaFormEntry->new();
		       $entry->set_value('none');
		       $entry->set_cgi_name('outcompress');
		       $entry->set_label('None');
		       push @entry_objs, $entry;
		   }
		   ENTRY_GZIP:{
		       my $entry = $form->addobj_form_entry();
		       $entry->set_value('gz');
		       $entry->set_cgi_name('outcompress');
		       $entry->set_label('gzip (.gz)');
		       push @entry_objs, $entry;
		   }
		     my $warn_placeholder = $main_panel->add_entry();      
		     $main_panel->add_form($main_panel->gen_radio_group( @entry_objs ).
					   $main_panel->gen_warn_placeholder('outcompress'));
		 }
	       }

	       BLOCK_OUTTARGET:{
		   $main_panel->add_block;
		   $main_panel->add_block_header(1,{ LABEL => qq(Enter a name for this 
							       result set:)});
		   
		 FORM_OUTTARGET:{
		     my $form = MartView::MetaForm->new();
		     $form->set_name('outtarget');
		     $form->add_cgi_processing
			 ( sub{
			     my $val = $martview::CGI->param('outtarget' );
			     if( $val =~ s/\W/_/g ){ # Replace all non-word chars with '_'
				 $martview::CGI->param('outtarget', $val );
			     }
			     return();
			 } );

		     my @entry_objs;
		   ENTRY1:{
		       my $entry = $form->addobj_form_entry();
		       $entry->set_default('');
		       $entry->set_cgi_name('outtarget');
		       $entry->set_label('Name:');
		       push @entry_objs, $entry;
		   }
		   ENTRY2:{
		       my $entry = $form->addobj_form_entry();
		       $entry->set_label('Enter a value to open results in new window 
                           (REQUIRES POP-UP UNBLOCKING), or to provide a name for file 
                            download.');	
		       push @entry_objs, $entry;
		   }
		     my $warn_placeholder = $main_panel->add_entry();      
		     $main_panel->add_form( $main_panel->gen_text_box_with_info(@entry_objs).
					    $main_panel->gen_warn_placeholder('outtarget'));
		 }
	       }
		 # Last and next links
		 set_main_panel_nav_buttons( $main_panel, 0 );
		 
            }
       }
 }
  $main_panel->add_panel_text({LABEL=>qq( <TMPL_VAR BOOKMARK> ) } );

  # Generate and return the output
  my $suffix_html = join("\n", @javascript_code);
  return ( $main_panel->output(),
  	   $suffix_html );
}

#----------------------------------------------------------------------
#
sub set_main_panel_nav_buttons{
  my $main_panel = shift;
  my $islabel    = shift;

  # Use the stages to build the panel image header
  my %label_meta = ( LABEL=>uc($CGI->param( 'stage' ) ) );

  # 'back' button
  my %last_meta;
  if( my $last_stage = $CGI->param( '_stage_back' ) ){
    %last_meta = ( -name =>'stage',
		   -value=>$last_stage,
		   -src  =>gen_button_src('back', 'on' ) );
  }
  else{
    %last_meta = ( -name=>'_new',
		   -value=>'new',
		   -src=>gen_button_src('new', 'on') );
  }

  # 'next' button
  my %next_meta;
  if( my $next_stage = $CGI->param( '_stage_next' ) ){
    %next_meta = ( -name=>'stage',
		   -value=>$next_stage,
		   -src=>gen_button_src('next', 'on' ) );    
  }
  else{
    #my $suffix = 'off';
    #if( $CGI->param('outtype') ){ $suffix = '<TMPL_VAR EXPORT_STATUS>' }
    %next_meta = ( -name=>'_export',
		   -value=>1,
		   -src=>gen_button_src('export', 'on' ) );      
  }

  # Add the buttons to the panel, including page header if required
  $main_panel->add_panel_image( $islabel ? \%label_meta : {}, 
				\%last_meta, 
#				\%this_meta, 
				\%next_meta );  
}

#----------------------------------------------------------------------
#
sub get_status_panel{
  my $already_reset = 0; # Have we reset the stage at any point?
  my $error_found = 0;   # Have we found an error at any stage?
  my $change_count = 0;  # Have we changed the status count at any point?
  my $panel = MartView::PanelStatus->new( $CGI );
  $panel->add_panel_button(
                           {
			    SRC   => '/gfx/EnsMart/blank.gif',
			    HEIGHT=> 35,
			    WIDTH => 1,
			   },
                           {
                            SRC   => $SiteDefs::MART_LOGO || 
                                     '/gfx/EnsMart/biomart-logo.gif',
			    #HEIGHT=> 35,
			    #WIDTH => 110,
                            HREF  => $SiteDefs::MART_LOGO_HREF ||
                                     'http://www.biomart.org'
                           },
                           {
			    SRC   => '/gfx/EnsMart/blank.gif',
			    HEIGHT=> 10,
			    WIDTH => 75,
			   },
                           {
			    SRC   => '/gfx/EnsMart/blank.gif',
			    HEIGHT=> 10,
			    WIDTH => 75,
			   },
                           { 
			    LABEL => 'Summary',
			    NAME  => 'stage',
			    VALUE => $CGI->param( 'stage' ),
			    SRC   => gen_button_src('refresh', 'on'),
			    HEIGHT => 20,
			    WIDTH  =>60 
			   },
			   { 
                            #HREF  => $SiteDefs::MART_HELP_DESK || qq(javascript:void(window.open('http://www.ebi.ac.uk/support/index.php?query=Biomart','martview','width=400,height=500,resizable,scrollbars'));),
			    HREF  => qq(javascript:void(window.open('/db/feedback/send_feedback?refer_from=/Multi/martview','martview','width=800,height=500,resizable,scrollbars'));),
			    SRC   => gen_button_src('helpdesk', 'on'),
			    HEIGHT=>20,
			    #WIDTH=>60 
			   },
                           {
                            HREF  => '',
                            SRC   => '/gfx/EnsMart/blank.gif',
                            HEIGHT=>1,
                            WIDTH=>60,
                           },
                           { 
                             HREF  => qq(javascript:void(window.open(\'/tutorials/GrameneMart.html\',\'mart_tutorial\',\'width=800,height=500,resizable,scrollbars\'));),
                             SRC   => '/gfx/EnsMart/tutorial-on.gif'
                           },

                           {},
                           
			  );


  

  $panel->add_panel_header({ LABEL => 'Summary' });

  # Loop da loops (each stage -> each form -> each from entry)
  foreach my $stage( @stages ){

      $panel->add_block();
      $panel->add_block_header(1,{ LABEL => $stage });

      # Don't reset the stage any later than the CGI stage 
      if( $stage eq $CGI->param('stage') ){ 
	  $already_reset++ 
       }
      if( ! is_stage_initialised( $stage ) ){
	  $panel->add_entry_footer({ LABEL => 'Not yet initialised' });
	  next;
      }

      my $any   = 0; # Any filters set?
      my $warn  = 0; # Any warnings detected?
      my $entry;

      my $dataset = $CGI->param('dataset');
      return 'No dataset set' if (!$dataset && $stage ne 'start');
      my @config_trees;

      my $datasetConfig = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset) if ($dataset);
      return "No dataset for $dataset" if (!$datasetConfig && $stage ne 'start');
  
      my $datasetConfigTree = $datasetConfig->getConfigurationTree if ($datasetConfig);
      return "No config for $dataset" if (!$datasetConfigTree && $stage ne 'start');

      push @config_trees, $datasetConfigTree if ($datasetConfigTree);




      #my $chosen_ct = $confForest->{$CGI->param('second_dataset')};
      my $chosen_ct = $REGISTRY->getDatasetByName($CGI->param('schema'),$CGI->param('second_dataset'))->getConfigurationTree
	  if ($CGI->param('second_dataset'));
      push @config_trees, $chosen_ct if ($chosen_ct);


      my $dataset_obj = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset) if ($dataset);
      #my $database_obj = $REGISTRY->getAllDatabaseNames($SCGI->param('schema'));
      my $dataset_label = $dataset_obj->displayName.
	                  '('.$CGI->param('database').')' if ($dataset_obj);

      

      my $query = BioMart::Query->new('registry' => $REGISTRY,'virtualSchemaName' =>$CGI->param('schema'));
      $query->addDatasetName($CGI->param('dataset'));#incase no filters set yet

      my @otherPotentialFilters;

      my $atts_to_set;

      if ($stage eq 'start'){
	  $any = 1;
	  #$panel->add_entry_header({ LABEL => 'Dataset: '.$dataset_label  });
	  my $vSchema_obj = $REGISTRY->getVirtualSchemaByName($CGI->param('schema'));
	  my $vSchemaDisplay = $vSchema_obj->displayName || $vSchema_obj->name;
	  $panel->add_entry_header({ LABEL => 'Schema: '.$vSchemaDisplay }) if (@{$REGISTRY->getAllVirtualSchemaNames(1)} > 1);
	  #$panel->add_entry_header({ LABEL => 'Database: '.$CGI->param('database')  });
	  $panel->add_entry_header({ LABEL => 'Dataset: '.$dataset_obj->displayName  });

	  #if( is_changed('dataset') ){# if leave in breaks for when you have duplicated datasets across schemas
	      $change_count = $dataset;
	  #}
      }
      else{
	  foreach my $ct (@config_trees){
	      my $dataSetName = $ct->dataSetName;
	      my $displayName;
	      $displayName = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataSetName)->displayName
		  if ($dataSetName ne $dataset);
	      foreach my $fpage (@{$ct->getAllFilterTrees}){
		  foreach my $fgroup (@{$fpage->getAllFilterGroups}){#fgroup = block
		       foreach my $fcollection (@{$fgroup->getAllCollections}){#
	                    # Do we need to recalculate summary?
				if( is_changed( $dataSetName.'_'.'collection_'.$fcollection->name ) ){
				    $change_count = 'collection_'.$fcollection->name;
				}

				# Are there CGI params for this form?
				if( ! $CGI->param( $dataSetName.'_'.'collection_'.$fcollection->name ) ){ 
				    next unless (${$fcollection->getAllFilters}[0] && ${$fcollection->getAllFilters}[0]->isa("BioMart::Configuration::FilterList")); 
				}

				# Loop for each form entries
				
				my $fcolls = $fcollection->getAllFilters;

				foreach my $fd( @{$fcolls} ){
				    $entry = $fd;#stop reference problem
				    my $name = $entry->name;
				    if ($name =~ /\./){#entries from other datasets
                                        my @names = split(/\./,$name);
					# GO ANY EVIDENCE CODE
					next if (($name =~ /evidence_code/) && 
						 ($CGI->param($dataSetName.'_'.$names[1]) eq 'any'));


					next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
					$entry = $REGISTRY->getDatasetByName($CGI->param('schema'),$names[0])->
					  getConfigurationTree->getFilterByName($names[1]);
					next if (!$entry);
					# skip adding link if no values set
					my @values = $CGI->param( $dataSetName.'_'.
							      $entry->name );
					#my $value  = $values[0] || next;
					my $value  = $values[0];
					if (!$value && $value ne "0"){next;}
					
					my @path = $REGISTRY->getPath($CGI->param('schema'),$names[0],$dataSetName);
					foreach (my $j = 1; $j < @path; $j++){
					    my $link = $REGISTRY->getLinkBetween($CGI->param('schema'),$path[$j-1], $path[$j]);
					    $query->addLinks($link);
				        }			

					# add 2nd to 1st link if appropiate incase no 2nd dset filters set
					if ($dataSetName eq $CGI->param('second_dataset')){
					    my @path = $REGISTRY->getPath($CGI->param('schema'),$CGI->param('second_dataset'), 
					    $CGI->param('dataset'));
					    foreach (my $j = 1; $j < @path; $j++){
						my $link = $REGISTRY->getLinkBetween($CGI->param('schema'),$path[$j-1], $path[$j]);
						# below is bug - 11/03/2005
						#warn("DEFAULT IS ".$CGI->param('default_link'));
						#warn("LINK BETWEEN ".$path[$j-1]." AND ".$path[$j]);
						#warn("IS ".$link);
						#$link->defaultLink($CGI->param('default_link')) if ($j == 1 && 
						#						$CGI->param('default_link'));
						$query->addLinks($link);
					    }
					}
				    }
				    
				    if( is_changed( $dataSetName.'_'.$entry->name ) ){
					# recalculate status count
					$change_count = $dataSetName.'_'.$entry->name;
				    }
				    elsif(is_changed( $dataSetName.'_'.$entry->name.
						      '_list')){
                                        #recalculate status count for textarea id filters
					$change_count = $dataSetName.'_'.$entry->name.
					    '_list';
				    }
				    elsif( is_changed( $dataSetName.'_'.$entry->name.
						       '_filter' ) ){
                                        # recalculate status count for boolean id filters
					$change_count = $dataSetName.'_'.$entry->name.
					    '_filter';
				    }
				    # Are there CGI values for this entry?
				    my @values = $CGI->param( $dataSetName.'_'.
							      $entry->name );
				    #my $value  = $values[0] || next;
					my $value  = $values[0];
					if (!$value && $value ne "0"){next;}
				    $value = unescapeHTML( $value );

				


			      # handle attribute-on setting
			      if ($entry->setAttribute ne ''){
				$atts_to_set .= '|'.$entry->setAttribute;  
			      }
			      my $options = $entry->getAllOptions();
			      if ($$options[0] && $$options[0]->filter ){
				  foreach my $option (@$options){
				      if ($option->filter->setAttribute ne ''){
					    $atts_to_set .= '|'.$option->filter->setAttribute; 
				      }
				  }
			      }
				



				    # FILTERLIST
				    if ($entry->isa("BioMart::Configuration::FilterList")){				    
					my $att_table = BioMart::AttributeTable->new();
				    
					if ($entry->getAllOptions->[0]){
					    foreach (@values){
						$_ =~ s/\_/ /g;
						$att_table->addRow([$_]);
					    }
					    $value = join ',',@values;# so label is not weird for ID lists
					 }
				     				
					 else{# ID LIST FILTER
					    my $filter_number = @{$entry->getAllFilters};
					    my @values = split('\,',$value);
					    for (my $a = 0; $a < @values; $a += $filter_number){
						my $b = 0;
						my @row;
						while ($b < $filter_number){
						    push @row, $values[$a+$b];
						    $b++;
						}
						$att_table->addRow(\@row);
					    }
					    $value = 'Uploaded';# so label is not weird for ID lists
					 }
				
				         $entry->setTable($att_table); 
				    }
				    


				    if ($entry->isa("BioMart::Configuration::ValueFilter")){
					
					if ($entry->otherFilters){
                                            # if meant to set other filters
					    my $otherFilters = $entry->otherFilters;
					    my @otherFilts = split(/;/,$otherFilters);
					    foreach (@otherFilts){
						my @names = split(/\./,$_);
						next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
						my $otherFilter = $REGISTRY->
						    getDatasetByName($CGI->param('schema'),$names[0])->
						    getConfigurationTree->
						    getFilterByName($names[1]);
						next if (!$otherFilter);
						my $att_table = BioMart::AttributeTable->
						    new();
						my @values = split('\,',$value);
						foreach (@values){
						    $att_table->addRow([$_]);
						}
						next if ($otherFilter->isa("BioMart::Configuration::BooleanFilter"));
						$otherFilter->setTable($att_table);
						push @otherPotentialFilters,$otherFilter;
					    }
					}

					# test if a drop down menu of filters
					my $options = $entry->getAllOptions;
					my $nested_option_flag;
					foreach my $op (@$options){
					    if (${$op->getAllOptions}[0]){
					        $nested_option_flag++;
					        last;
					     }
				        }
					


					if ($$options[0] && $$options[0]->filter && 
					    $$options[0]->filter->isa
					    ("BioMart::Configuration::BooleanFilter")){
					    my $option_name = $CGI->param($dataSetName.
					       '_'.$entry->name.'_filter');
					    my $option = $ct->getOptionByName($option_name);
					    next if (!$option);
					    $entry = $option->filter;
					    if ($value ne 'Only'){
						$entry->setExcluded;
					    }
					    else{
						$entry->setIncluded;
					    }
					    $entry->displayName($option->displayName);
					}
					elsif ($$options[0] && $$options[0]->filter
					       && $$options[0]->filter->isa
					       ("BioMart::Configuration::ValueFilter")){
					    my $option_name = $CGI->param($dataSetName.
					       '_'.$entry->name);#.'_filter');
					    my $option = $ct->getOptionByName($option_name);
					    next if (!$option); 
					    $entry = $option->filter;
					    $entry->displayName($option->displayName);
					    my $att_table = BioMart::AttributeTable->new();
					    $value = $CGI->param( $dataSetName.'_'.$name.
								  '_list' );
					    my @values = split('\,',$value);
					    foreach (@values){
						$value = unescapeHTML( $_ );
						$att_table->addRow([$_]);
					    }
					    $value = 'Uploaded';# so label is not weird for ID lists
					    next if ($entry->isa("BioMart::Configuration::BooleanFilter"));
					    $entry->setTable($att_table);
					}
					else{
					    my $option;
					    # check option does not have an operator override
					    foreach (@$options){
						$option = $_;
						if ($option->name eq $value){
						    $value = $option->value;
						    if ($option->operation ne ''){
							$entry->operation($option->operation);
						    }
						    last;
						}
					    }

					    my $att_table = BioMart::AttributeTable->new();
					    my @values = split('\,',$value);
					    foreach (@values){
						$att_table->addRow([$_]);
					    }
					    if ($option && !$nested_option_flag) {
						$value = $option->displayName;# for status panel below
					    }
					    next if ($entry->isa("BioMart::Configuration::BooleanFilter"));
					    $entry->setTable($att_table);
					}
				    }
				    elsif ($entry->isa
					("BioMart::Configuration::BooleanFilter")){
					#$entry->setExcluded if ($value ne 'Only');
					if ($value ne 'Only'){
					    $entry->setExcluded;
					}
					else{
					    $entry->setIncluded;
					}
				    }
				    $query->addFilter($entry);
		    

				    if ($stage eq 'filter'){
					my $lbl;
					if ($displayName){
					    $lbl = $entry->displayName."($displayName): %s" 
						|| next;
					}
					
					elsif ($entry->displayName){
					    $lbl = $entry->displayName.": %s" || next;
					}
					else{
					    $lbl = $fcollection->displayName.": %s" || next;
					}
					#warn("LABEEL".$lbl.":".$value.":".join ',',@values);
					my $dpy = sprintf( $lbl, $value );
					#my $dpy = sprintf( $lbl, join ',', @values );
					$any = 1;
					$panel->add_entry_header({ LABEL => $dpy  })
				    }
				}
    
				# Do we have any warnings for this form?
				if( is_warning( 'collection_'.$fcollection->name ) ){ $warn = 1 }
			    }
		   }
               }
	  }# end of cycling through config trees

#	  if ($CGI->param('stage') eq 'filter'){    
	  my $stage_initialised = join('',$CGI->param('stage_initialised'));
	  if ($stage_initialised eq 'startfilter'){
             # turn on filter-activated attributes
	     foreach my $apage (@{$datasetConfig->getConfigurationTree->getAllAttributeTrees}){
		 foreach my $agroup (@{$apage->getAllAttributeGroups}){#agroup = block
		     foreach my $acollection(@{$agroup->getAllCollections}){
			 foreach my $att(@{$acollection->getAllAttributes}){
			     my $att_name = $att->name;
			     if ($atts_to_set =~ /\|$att_name/){
				 $CGI->param('collection_'.$acollection->name,$att_name);
			     }
			 }
		     }
		 }
	     }
	 }
          

	     
	  # add filters from potential other filters if relevant
	  foreach my $otherFilter(@otherPotentialFilters){
	      # test if dataset associated with otherFilter is already involved in query
	      my $dataSets = $query->getDatasetNames;
	      foreach my $subName (@{$dataSets}) { 
		  if ($otherFilter->dataSetName eq $subName){
		      $query->addFilter($otherFilter);
									
		      last;
		  }
	      }
	  }

	  if ($stage eq 'output'){
	      my ($lbl,$apg);
	      my $outtype = $CGI->param('outtype');
	      $apg = $datasetConfigTree->getAttributeTreeByName($outtype);
	      if ($apg){
		  $lbl = $apg->displayName;
		  $any = 1;
		  $panel->add_entry_header({ LABEL => $lbl  });
	       }
	  }
      }#end of filter and att stage
   
	  if ($CGI->param('second_dataset') && 
	      ${$query->getAllFilters($CGI->param('second_dataset'))}[0]){
              my @path = $REGISTRY->getPath($CGI->param('schema'),$CGI->param('second_dataset'), 
					    $CGI->param('dataset'));
	      foreach (my $j = 1; $j < @path; $j++){
		  my $link = $REGISTRY->getLinkBetween($CGI->param('schema'),$path[$j-1], $path[$j]);
		  # below is bug
		  #warn("DEFAULT IS ".$CGI->param('default_link'));
		  #warn("LINK BETWEEN ".$path[$j-1]." AND ".$path[$j]);
		  #warn("IS ".$link);
		  #$link->defaultLink($CGI->param('default_link')) if ($j == 1 && 
		#		     $CGI->param('default_link'));
		  
		  $query->addLinks($link);
	      }
	  }

  
  if( ! $any ){ $panel->add_entry_header({ LABEL => 'None'  }) }

  # Do we have any warnings at this stage?
  if( $warn ){
 
      # Display a warning
      $panel->add_warning({ LABEL => 'Warning!' });
      $error_found++; # Update the error flag
      
      # reset the stage to the first one for which warns detected
      if( ! $already_reset ){
	  process_stage( $stage );
	  $already_reset++;    # Don't need to reset again
      }
      next;
  }
  
  # SUMMARY COUNT
  my $status_count;

  # Do we have errors from earlier stages
  if( $error_found ){
      $panel->add_entry_footer({ LABEL => 'Count unavailable' });
      next;
  }
    
  $status_count = status_count( $stage );

  my $err = '';

  


  if( ! defined $status_count or $change_count ){
      my $query_planner = BioMart::QueryPlanner->new();
      return 'No datasets set' if (@{$query->getDatasetNames} < 1);
      
      $query->virtualSchema($CGI->param('schema'));
      my $count = $query_planner->getResultTable($query,$CGI->param('dataset'));
      if ($count =~ /^ERROR::/){
         my @err_messages = split(/::/,$count);
          $err = $err_messages[1];
      }

      $err = 'Default link not set' if ($CGI->param('default_link') eq 'default_link' && $count == -1);
     
      if( ! $count ){ $err = 'No entries found!' }

      $status_count = status_count( $stage,
				    $count );
  }
  
  if( ! $status_count ){ $err = 'No entries found!' }
  if( $err ){
      $panel->add_warning({ LABEL => $err });
      $error_found++;
      $ERRORS{$stage} = 1;
      if( ! $already_reset ){
	  process_stage( $stage );
	  $already_reset++;
      }
      next;
  }
  
  # Display the number of results
  my $number_summary;
  if ($stage eq 'start'){$number_summary = '%s Entries Total'}
  elsif ($stage eq 'filter'){$number_summary = '%s Entries pass Filters'}
  elsif ($stage eq 'output'){$number_summary = '%s Results in Output'}
  my $label;
  
    if ($status_count < 0) {# QueryPlanner returns -1 for linked visible dataset counts
      $label = 'count unavailable for this query';
    } else {
      $label = sprintf( $number_summary, $status_count );
    }
    $panel->add_entry_footer( { LABEL => $label } );
   }
  return $panel->output();

}

#----------------------------------------------------------------------
# Writes out the serialised state to a file in ENSEMBL_TMP_DIR.
# Returns the name of the file (without the path).
sub store_state{
  my( $fh, $filename ) = tempfile( DIR => $SiteDefs::ENSEMBL_TMP_DIR );
  my $fileid = '';
  if( $filename =~ m/\/([^\/\\]+)$/o ){ $fileid = $1 }
  else{ die( "Could not parse file name $filename" ) }

  my $state = serialise_state(-all=>1);
  print $fh $state;
  close( $fh );
  return $fileid;
}

#----------------------------------------------------------------------
# Writes out the serialised state to a file in ENSEMBL_TMP_DIR.
# Returns the name of the file (without the path).
sub save_state{

  my $state_id = $CGI->param('id') || die( "Not found: mart state ID" );
  my $tmp_file = $SiteDefs::ENSEMBL_TMP_DIR ."/$state_id";
  open( TMP_STATE, ">$tmp_file" );
  print TMP_STATE serialise_state();
  close( TMP_STATE );
  return $state_id;

}

#----------------------------------------------------------------------
# Sets any jscript onload functions that may be needed
#
sub set_jscript_onload{
  if( $CGI->param('stage') eq 'output' and
      $CGI->param('outtype') =~ 'sequence' ){
    # Need to run the sequence image picker
    push( @ON_LOAD_EXTRA, "initialiseSeqType()" );
  }
  return 1;
}


#----------------------------------------------------------------------
# Serialiser function
#  Saves the state of the current CGI object as a hash of name=>value_arrayref
#  pairs. Returns a stringified, URL-escaped representation of the hash to be 
#  used in an HTML form element.
#
sub serialise_state{
  my %args = @_;

  my $stage = $CGI->param('stage');
  $CGI->param( -name=>'stage_prev', -value=>$stage );
  my $hashref = {};

  # Loop for each parameter of the current CGI object
  foreach( $CGI->param() ){

    # Ignore params starting with '_'
    next if( $_ =~ /^_/ );

    # Force the param value into array context
    my @value = $CGI->param($_);

    # UnescapeHTML - will be using URL escapes
    @value = map{ unescapeHTML($_) } @value;

    # Update the datastructure with the value_arrayref
    $hashref->{ $_ } = \@value;
  }

#  warn Dumper( $hashref );
  # Stringify the data structure
  my $string = nfreeze($hashref);

  # URL-escape the string
  return CGI->escape( $string );

}

#----------------------------------------------------------------------
# CGI Parameter pre-processing routine. 
#   The image submit convention is: name_value.x = name -> value
sub process_image_submits{

  foreach( $CGI->param() ){
    if( $_ =~ /(\w+?)_(\w+)\.x/o ){
      $CGI->param( -name=>$1, -value=>$2 );
      $CGI->Delete($_);
    }
    elsif( $_ =~ /\w+_\w+\.y/o ){ $CGI->Delete($_) }
  }
}

#----------------------------------------------------------------------
# Processes the stage: sets 'stage', 'stage_next' and 'stage_back' 
# Arg 1 - (optional) stage to set to.
#         Defaults to CGI stage, or default stage
sub process_stage{
  my $stage = ( shift || 
		$CGI->param('stage') || 
		'start' );

  $CGI->param( -name =>'stage', -value=>$stage );


  # initialise stage
  my %seen;
  my @init = grep{ $_ && ! $seen{$_} ++ } ( $CGI->param('stage_initialised'),
					    $CGI->param('_stage_parent') );
#  $CGI->Delete('stage_prev');
  $CGI->param( -name=>"stage_initialised", -value=>\@init );

  # Use the default stage if none found, or if there is no species/focus
  

  # 'back' and 'next' stages
  my %stage_order;
  my $i = 0;
  map{ $stage_order{$_} = $i++ } @stages;
  my $this_stage_idx = $stage_order{$CGI->param( 'stage' )};
  my $back_stage = $this_stage_idx > 0        ? 
                   $stages[$this_stage_idx-1] : '';
  my $next_stage = $this_stage_idx < $#stages ? 
                   $stages[$this_stage_idx+1] :'';
  $CGI->param( -name=>'_stage_back', -value=>$back_stage );
  $CGI->param( -name=>'_stage_next', -value=>$next_stage );
  return 1;
}

#----------------------------------------------------------------------
# Process the species
sub process_species{
  if( ! $CGI->param('species') ){
    $CGI->param( -name=>'species', -value=>$ENV{ENSEMBL_SPECIES});
  }
}

#----------------------------------------------------------------------
# Process genome type
sub process_genome_type{
  if( my $genome_type = $CGI->param('genome_type' ) ) {
    $CGI->param( -name=>$genome_type, -value => 1 ); 
#    $CGI->delete( 'genome_type' );
  }
}



#----------------------------------------------------------------------
#
#sub process_defaults{# deprecated - now done in main_panel

  # Don't set defaults if stage already initialised
#  if( is_stage_initialised( $CGI->param('stage') ) ){ return 1 }

  # Loop through each block/form for this stage
#  my ( $stage_obj ) = 
#    grep{ $_->get_name eq $CGI->param('stage') } $META_DATA->get_stages;
  
#  foreach my $block_obj( $stage_obj->get_blocks ){
#    foreach my $form_obj( $block_obj->get_forms ){
#      my %defaults = $form_obj->get_defaults();
#      map{
#	my @defs = grep{$_} @{$defaults{$_}};
#	scalar( @defs ) && $CGI->param( -name=>$_, -value=>[@defs] )
#      } keys %defaults;
#    }
#  }
#}


#----------------------------------------------------------------------
# De-serialiser function. 
#  Recovers the state of the cgi object from the previous page (as stored
#  to the '_state' hidden field by save_state). Copies all params that do
#  not have a new value to the cgi object for this page.
#
sub recover_state{
  my %args = @_;
#  $args{-buttons} ||= []; # Special case; buttons are always recovered as they
#                          # have no value unless clicked
  
  # Get the 'save state' string, and un-url-escape it:
  my $string = $CGI->param('_state') || return undef();
  $string = unescape( $string );

  # 'Thaw' the re-constructed string
  my $hashref = thaw( $string );
  

  # Update parent stage
  my $stage_parent = $hashref->{'stage'}->[0];
  $CGI->param( -name=>'_stage_parent', -value=>$stage_parent );

  if( $args{-parent} eq 'none' ){ $stage_parent = undef() }

  # compile list of param names, either stored or in $CGI. 
  # Ignore names starting with '_' or 'DEFINE_'
  my %seen;
  my @names = grep{ 
    $_ !~ /^_/ && ! $seen{$_} ++ 
  } ( keys( %$hashref ), $CGI->param() );

  # Get a list of params that _must_ be recovered from the previous stage.
  # These are generally checkboxes that may have been turned off.
  foreach( $CGI->param('_RECOVER') ){
    warn( "_RECOVER is deprecated; prefix with _DEF_ instead" );
    if( ! defined( $CGI->param($_) ) ){ $CGI->param( $_, '' ) }
  }

  # Loop for each name
  foreach my $name( @names ){

    # Get the checkbox-off parameters. These start with '_DEF_'
    if( ! defined $CGI->param($name) ){
      my $pseudo = "_DEF_$name";
      if( defined $CGI->param( $pseudo ) ){
	$CGI->param(-name=>$name, -value=>[ $CGI->param( $pseudo ) ] );
      }
    }

    # Escape HTML: security implications!
    my @these = map{ escapeHTML($_) } $CGI->param($name);
    my @those = map{ escapeHTML($_) } @{$hashref->{$name}};
    my $this = join( '|', sort map{ $_ || '' } @these );
    my $that = join( '|', sort map{ $_ || '' } @those );

    # Determine whether the CGI object contains a new value
    if( defined( $CGI->param($name) ) && ( $this ne $that ) ){
      #warn( "CH_CGI: $name : TO $this : FROM $that\n" ); 
      set_changed($name) 
    }

    # No new values - use old
    else{ 
      #warn( "RECOVER: $name : @those\n" );
      @these = @those 
    };
    
    # Update the CGI object with the 'stored' parameter
    $CGI->param( -name=>$name, -value=>\@these );
  }
  return 1;
}

#----------------------------------------------------------------------
# Looks through all params and validates them as required
sub validate_params{# deals with the add_cgi_processing and add_error aspects of MetaData

  if ($CGI->param('database')){
      my @db_schema = split(/__/,$CGI->param('database'));
      $CGI->param('schema',$db_schema[-1]) if (@db_schema > 1);
  }

  if( $CGI->param('stage') eq 'output' and 
      $CGI->param('outtype') =~ /sequence/ ){
    # TODO: Use default from XML
    $CGI->param('upstream_flank')   || $CGI->param('upstream_flank',100);
    $CGI->param('downstream_flank') || $CGI->param('downstream_flank',100);
  }

  # nb if none or both selected code assumes only upstream is wanted - no sense in having both
  if ($CGI->param('collection_seq_scope_type') =~ /_flank/ and
      ( !($CGI->param('collection_upstream') || $CGI->param('collection_downstream')))){
      $CGI->param('collection_upstream',1);
      #$CGI->param('collection_downstream',1);
  }
  if ($CGI->param('collection_upstream') && $CGI->param('collection_downstream') &&
      $CGI->param('dataset') =~ /gene_ensembl/){
      # LEAVE AS IS AS WANT BOTH FLANKS WHEN GENE SELECTED
      #$CGI->param('collection_downstream',0);
  }

  # start page default set ups
  if ($CGI->param('stage') eq 'start' && $CGI->param('dataset') eq ''){
      my $schema = $CGI->param('schema');
      if ($schema eq ''){
          $schema = $REGISTRY->getDefaultVirtualSchema();
	  #( $schema ) = sort{$b cmp $a} @{$REGISTRY->getAllVirtualSchemaNames()}  if $schema eq '';
          ( $schema )  = @{$REGISTRY->getAllVirtualSchemaNames()} if $schema eq '';
          $CGI->param('schema',$schema);
      }
      my $database = $CGI->param('database');
      my $database_for_reg = $database;
      if ($database eq ''){
	  $database = $REGISTRY->getDefaultDatabase($schema);
	  # if no default just use first one
	  $database = ${$REGISTRY->getAllDatabaseNames($CGI->param('schema'))}[0] if $database eq '';
	  #$CGI->param('database',$schema.'_'.$database);
          $database_for_reg = $database;
          $database =~ s/\s//g; # Strip whitespace. Hacky and may break stuff
          $database = $database.'__'.$schema;# fits new javascript format
          $CGI->param('database',$database);
      }
      my $datasets = $REGISTRY->getAllDataSetsByDatabaseName($CGI->param('schema'),$database_for_reg);

      for my $dataset_name( @$datasets ){
        my $dataset = $REGISTRY->getDatasetByName( $CGI->param('schema'), 
                                                   $dataset_name );
        if( $dataset->getConfigurationTree->defaultDataset eq 'true' ){
          $CGI->param('dataset',$dataset_name);
          last;
        }
      }
      $CGI->param('dataset',$$datasets[0]) if  ($CGI->param('dataset') eq '');
  }

  $CGI->param('outcompress', 'none' )
      if (!$martview::CGI->param('outcompress'));
  $CGI->param('seq_scope', 'tscr' )
      if (!$martview::CGI->param('seq_scope'));
  $CGI->param('collection_seq_scope_type', 'transcript_exon_intron' )
      if (!$martview::CGI->param('collection_seq_scope_type'));

  $CGI->param('default_link_last', $CGI->param('default_link')) 
          if ($CGI->param('default_link'));
 
  $CGI->param('schema_last', $CGI->param('schema')) 
          if ($CGI->param('schema'));
  $CGI->param('database_last', $CGI->param('database')) 
          if ($CGI->param('database'));
  $CGI->param('dataset_last', $CGI->param('dataset')) 
          if ($CGI->param('dataset'));

  my $dataset = $CGI->param('dataset');
  return if (!$dataset);#no dataset selected yet

  #my $ct = $confForest->{$dataset};
  my $datasetObj = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset);
  return if (!$datasetObj);
  my $ct = $datasetObj->getConfigurationTree;

  if( $CGI->param('stage') eq 'output' ){
    # Test that outtype is valid for this dataset. Else def is first in XML
    my @attrib_pages = @{$ct->getAllAttributeTrees};
    my $outtype = $CGI->param('outtype');
    my $attrib_page;
    if( $outtype ){ ($attrib_page) = grep{$_->name eq $outtype} @attrib_pages }
    $attrib_page ||= $attrib_pages[0];
    $CGI->param('outtype',$attrib_page->name);

    # Test that outformat is valid dataset. Else def is first in XML
    my @formats = split( /\s*,\s*/, $attrib_page->outFormats );
    my $format = $CGI->param('outformat');
    if( $format ){ ($format) =  grep{$_ eq $format } @formats }
    $format ||= $formats[0] || 'html';
    $CGI->param('outformat',$format);
  }
    
  # make sure default atts are set
  if (!$martview::CGI->param('outformat')){
      my $apage = $ct->getAttributeTreeByName($CGI->param('outtype')) if ($CGI->param('outtype')); 
      if ($apage && $apage->outFormats =~ /fasta/){
	  $CGI->param('outformat', 'fasta');
      }
      else{
	  $CGI->param('outformat', 'html');
      }
  }



  my @configTrees;
  push @configTrees, $ct if ($ct);
  
#  # second dataset validation for start page
  if ($CGI->param('stage') eq 'start'){
    unless( $CGI->param('second_dataset') ){
      $CGI->param('second_dataset','0'); # Turn off by default
    }
  }

  # now sort the default link
  unless( $CGI->param('default_link' ) ){
      my $link = $REGISTRY->getLinkBetween($CGI->param('schema'), 
                                         $CGI->param('second_dataset'),
                                         $CGI->param('dataset'));
      $CGI->param('default_link',$link->defaultLink) if ($link);
  }

  my $second_ct = $REGISTRY->getDatasetByName($CGI->param('schema'),$CGI->param('second_dataset'))->getConfigurationTree
      if ($CGI->param('second_dataset'));
  push @configTrees, $second_ct if ($second_ct);
  
  foreach my $ct(@configTrees){
      # may need to repeat for start and output stages as well
      my $dataset = $ct->dataSetName;

      # Output page validation
      if ($CGI->param('stage') eq 'output'){
	  my $comma;
	  my @default_atts;
	  my $set_defaults = 0;
          my $stage_initialised = join('',$CGI->param('stage_initialised'));
	  if ($stage_initialised ne 'startfilteroutput'){
              $set_defaults = 1;# set defaults on all pages
	  } 

	     foreach my $apage (@{$ct->getAllAttributeTrees}){

               # just validate main dataset atts for now 
               next if ($dataset ne $CGI->param('dataset'));

		 my $outtype = $CGI->param('outtype'); 
		 #next if ($outtype ne $apage->name);# remove as want to set all defaults below
		 foreach my $agroup (@{$apage->getAllAttributeGroups}){#agroup = block
		     foreach my $acollection(@{$agroup->getAllCollections}){
			 if ($acollection->maxSelect == 1){
			     if ($CGI->param('collection_'.$acollection->name.'_this') eq ''){
				 $CGI->param('collection_'.$acollection->name.'_this',
					     ${$acollection->getAllAttributes}[0]->name);
			     }
			 }
		         next unless($set_defaults);
		         my $attributes = [ @{$acollection->getAllAttributes} ];#fix ref problem
			 
                         @default_atts = ();
		         $comma = '';
                         foreach my $att( @$attributes ){
			     my $def_att = $att;
			     if ($att->name =~ /\./ && $att->name !~ /filter/){
				 my @placeholder = split(/\./,$att->name);				 
				 next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$placeholder[0]));
				 $def_att = $REGISTRY->getDatasetByName($CGI->param('schema'),$placeholder[0])
				                               ->getConfigurationTree
							       ->getAttributeByName($placeholder[1]);	
                                 next if (!$def_att);
			     }

			     
			     if ($def_att->default() eq 'true'){
				 push @default_atts, $def_att->name;
				 $comma = ',';
				 $CGI->param('collection_'.$acollection->name,@default_atts);# just get 1st and last
			     }
			 }
		     }
		 }
           }
     }

      foreach my $fpage (@{$ct->getAllFilterTrees}){
          next if ($fpage->name =~ /link/);#ignore link filters 
              foreach my $fgroup( @{$fpage->getAllFilterGroups} ){ #fgroup = block
		   foreach my $fcollection(@{$fgroup->getAllCollections}){#fcollection = form
			  my $filters = $fcollection->getAllFilters;
			  if (!$$filters[0]){
			      next;
			  }
			  foreach my $fd(@$filters){#$filter = entry
			      my $filt = $fd;
			      my $name;
			     
			      # if setAttributePage defined for a filter
                              if ($filt->setAttributePage){
				  #warn("FILTER ".$filt->name. " HAS AP ".$filt->setAttributePage);
				  $CGI->param('outtype',$filt->setAttributePage);
			      }

			      



			      if ($filt->name =~ /\./){
				  my @names = split(/\./,$filt->name);
				  $name = $names[1];
			      }
			      else{
				  $name = $filt->name;
			      }
			      
			      # FILTERLIST
			      if ($filt->isa("BioMart::Configuration::FilterList")){

				  if (${$filt->getAllOptions}[0]){
				      next;
			          }

				  # process file data
				  my $fh = $martview::CGI->param($dataset.'_'.$filt->name.'_file');
				  $/ = undef;
				  my $str = escapeHTML( <$fh> );
				  $str =~ s/\n/,/g;
			          #warn("$str before validation");
				  my @list = split( /\s*,\s*|\s/, $str );
				  if( ! $list[0] )      { shift };
				  if( ! $list[@list-1] ){ pop };
				  $str = join(",", @list );
				  my $num = @list;
				  # Delete file upload param - not used further
				  $martview::CGI->Delete($dataset.'_'.$filt->name.'_file' );
				  # Copy value to hidden form to allow state maintenance
				  $martview::CGI->param($dataset.'_'.$filt->name.'_file', $str);
				  # Put a label in the text box to indicate file upload
				  my $list_param = $dataset.'_'.$filt->name;

				  my @test_cgi = $CGI->param($list_param);
				  next if (!@test_cgi);
			      
				  $martview::CGI->param($list_param, $str) if ($str);
                                  # text area processing
				  my $str = $martview::CGI->param($list_param);
			      
				  if (!$str){
				      $CGI->param($dataset.'_'.$name, '');
				      next;
				  }
			      		   
				  # File upload flagged. No action needed
				  if( $str =~ /^FILE UPLOAD/ ){ next }
						   
				  # New value - remove any old file upload values
				  $martview::CGI->Delete($dataset.'_'.$filt->name.'_file');

				  # Process new value into a neat list
				  $str =~ s/\n/,/g;
				  my @list = split( /\s*,\s*|\s/, $str );
				  if( ! $list[0] )      { shift };
				  if( ! $list[@list-1] ){ pop };
			      
				  $str = join(",", @list );
			      
				  $martview::CGI->param($list_param, $str) if ($str);
			      }
    
			      # do any default value setting
			      if (!$filt->isa("BioMart::Configuration::BooleanFilter") && 
				  !$filt->isa("BioMart::Configuration::FilterList") &&
				  $filt->defaultValue && $CGI->param($dataset.'_'.$name) eq ''){
				  $CGI->param($dataset.'_'.$name,$filt->defaultValue);
			      }

			      # default-on filter handling
			      my $stage_initialised = join('',$CGI->param('stage_initialised'));
			      if (($filt->defaultOn eq 'true') && ($stage_initialised !~ /startfilter/)){
                                       $CGI->param($dataset.'_'.'collection_'.$fcollection->name,1);
			      }
                              
			      my $val = $martview::CGI->param($dataset.'_'.$name);

			      # do any reg expression testing
			      #if ($filt->isa("BioMart::Configuration::ValueFilter")){
				#  my $regexp = $filt->regexp();
				#  if ($regexp){
				#      if ($val !~ /$regexp/){
				#	  $CGI->param($dataset.'_'.$name,'not valid');
				#	  next;
				#      }
				#  }
			      #}
			      if ($val =~ /\*/){
				  # substitute any stars back to spaces
				  $val =~ s/\*/ /g;
			      }
			      $martview::CGI->param($dataset.'_'.$name, $val);
			      $martview::CGI->param($dataset.'_'.$name.'_last', $val);

			      # sort out defaults
			      
			      if ($filt->isa("BioMart::Configuration::BooleanFilter") || 
				      ($filt->isa("BioMart::Configuration::ValueFilter") && 
				       $filt->getAllOptions->[0] &&
                                       $filt->getAllOptions->[0]->filter &&
                                       $filt->getAllOptions->[0]->filter->isa
				       ("BioMart::Configuration::BooleanFilter"))){
				  $martview::CGI->param($dataset.'_'.$name, 'Only' )
				      if ($martview::CGI->param($dataset.'_'.$name)
					  ne 'Excluded');
			      }


			      

			      # process file data
			      my $fh = $martview::CGI->param($dataset.'_'.$filt->name.'_file');
			      $/ = undef;
			      #my $str = escapeHTML( <$fh> );
			      my $str = unescapeHTML( <$fh> );
			      $str =~ s/\n/,/g;
			      #warn("$str before file validation");
			      my @list;
			      if ($str =~ /\"/){
				  @list = split( /\"*,\"*|\"/, $str );
			      }
			      else{
				  @list = split( /\s*,\s*|\s/, $str );
			      }
			      #my @list = split( /\s*,\s*|\s/, $str );

			      if( ! $list[0] )      { shift @list};
			      if( ! $list[@list-1] ){ pop @list};
			      $str = join(",", @list );
			      #warn("$str after file validation");
			      my $num = @list;
                              # Delete file upload param - not used further
			      $martview::CGI->Delete($dataset.'_'.$filt->name.'_file' );
                              # Copy value to hidden form to allow state maintenance
			      $martview::CGI->param($dataset.'_'.$filt->name.'_file', $str);
                              # Put a label in the text box to indicate file upload
                              my $list_param = $dataset.'_'.$filt->name.'_list';

			      my @test_cgi = $CGI->param($list_param);
			      next if (!@test_cgi);
			      
			      $martview::CGI->param($list_param, $str) if ($str);

			      # text area processing
			      #my $str = $martview::CGI->param($list_param);
			      my $str = unescapeHTML ($martview::CGI->param($list_param));
			      
			      if (!$str){
				  $CGI->param($dataset.'_'.$name, '');
				  next;
			      }
			      
			      # No change. No action needed. - ? IF NEEDED
			      #if( ! martview::is_changed( $list_param ) ){ next }
						   
			      # File upload flagged. No action needed
			      if( $str =~ /^FILE UPLOAD/ ){ next }
						   
			      # New value - remove any old file upload values
			      $martview::CGI->Delete($dataset.'_'.$filt->name.'_file');

			      # Process new value into a neat list
			      $str =~ s/\n/,/g;
			     
			      #warn("$str before text validation");
			      my @list;
			      if ($str =~ /\"/){
				  @list = split( /\"*,\"*|\"/, $str );
			      }
			      else{
				  @list = split( /\s*,\s*|\s/, $str );
			      }
			      
			      if( ! $list[0] )      {
				  #warn("GET RID OF FIRST");
				  shift @list;
			      }
			      if( ! $list[@list-1] ){ pop @list };
			      
			      $str = join(",", @list );
			      $martview::CGI->param($list_param, $str) if ($str);
			      
			  }
		      }
	       }
     } 
  }

}

#----------------------------------------------------------------------
# Adds a warning flag associated with a form name to the CGI object.
# Requires the stage, form name, and the warning text.
sub add_warning{
  my $stage     = shift || die( "Warning needs a stage" );
  my $form_name = shift || die( "Warning needs a form"  );
  my $err_str   = shift || die( "Warning needs some text" );
  warn( "MartView User Error: $err_str" );
  $ERRORS{$stage} = 1;
  warn join( ', ', caller(0) );
  my $param_name = '_'.$form_name.'!!warning';
  my @warns = ( $CGI->param( $param_name ), $err_str );
  $CGI->param( -name => $param_name,
	       -value=> \@warns );
}

#----------------------------------------------------------------------
# Returns the number of warnings stored in the CGI object associated with 
# a form name.
sub is_warning{
  my $form_name = shift;
  my $param_name = '_'.$form_name.'!!warning';
  my @warns = $CGI->param( $param_name );
  return scalar( @warns );
}

#----------------------------------------------------------------------
# Flags a CGI param as changed on last submit
#
sub set_changed{
  my $param = shift || return;
#  warn( "CHANGED: $param" );
  my $prefix = '_changed_';
  $CGI->param( -name=>"$prefix$param", -value => 1 );
  return 1;
}

#----------------------------------------------------------------------
# Reports whether a CGI param was changed on last submit
sub is_changed{
  my $param = shift || return;
  my $prefix = '_changed_';
  return $CGI->param( "$prefix$param" ) ? 1 : 0;
}

#----------------------------------------------------------------------
# gets/sets the status_count for a given stage
sub status_count{
  my $stage = shift || return;
  my $count = shift;
  my $param = "status_count_$stage";
  if( defined( $count ) ){ $CGI->param(-name=>$param, -value=>$count) }
  return $CGI->param($param);
}

#----------------------------------------------------------------------
#
sub update_selection{
  my $tmpl    = shift;
  my $top     = shift;
  my $status  = shift;
  
  # Create a template
  # Strict set to 0 to help rendering xml on linux/perl 5.8.0 (to be fixed properly)
  my $t = HTML::Template->new( scalarref => \$tmpl,
			       die_on_bad_params => 0,
			       strict => 0);
  
  my %params = (
		TOP_BOX       => $top, 
		STATUS_BOX    => $status,
		SPECIES_URL   => $SiteDefs::BIOMART_URL || 'biomart',#'Multi' or 'BioMart' 
		SCRIPT_NAME   => 'martview',
		MART_STATE_ID => $CGI->param('id'),
		EXPORT_STATUS => %ERRORS ? 'off' : 'on'
	       );

  # Build a bookmarkable link for this page
  my @key_values;
  foreach my $p( $CGI->param() ){
    next if $p =~ /^_/; # Skip starting with '_'
    next if $p eq 'id'; # Skip the token
    foreach my $v( $CGI->param($p) ){
      next if ! $v;
      push @key_values, join( '=', map{escape($_)} ($p,$v) );
    }
  }
  $params{BOOKMARK} = sprintf( 'For a bookmarkable version of this page, '.
                               'click <a href="martview?%s"><b>[here]</b></a>',
                               join( '&', @key_values ) );

  foreach my $p( $t->query() ){
    my( $name, $value, $action ) = split( '!!', $p );
    $action=$value if ! $action;
    $action = uc($action);
    if( $action eq 'SELECTED' or $action eq 'CHECKED'  ){
      
      $value =~ s/\*/ /g; # Remove the * for the whitespace hack
      if( grep{ uc($value) eq uc($_)} $CGI->param($name) ){
	$params{$p} = uc( $action );
      }
    }
    elsif( uc( $action  ) eq 'VALUE' ){
      my @vals = grep{ $_ ne 'on' } $CGI->param($name);
      my $length = length( $vals[0] );
#      if( $length > 5000 ){ $vals[0] = "$length bytes.\nToo long to display!" } 
      $params{$p} = shift( @vals );
    }
    elsif( uc( $action ) eq 'WARNING' && $CGI->param('_'.$p) ){
      my @warns;
      foreach( $CGI->param('_'.$p) ){
	push @warns, get_panel_warning( $_ );
      }
      $params{$p} = join '<BR>', @warns;
    }
  }
  #warn("UPDATE SELECTION 4 $$");
  $t->param( %params );
  #warn("UPDATE SELECTION 5 $$");
#  require Data::Dumper; warn(Data::Dumper->Dump([\%params]));
  #warn("UPDATE SELECTION FINISHED $$ \n");
  return $t->output();

}

#----------------------------------------------------------------------
# Tests whether a given stage has been viewed before for this user 'session'
# Flag is reset when the user clicks the 'new' button.
sub is_stage_initialised{
  my $stage = shift || $CGI->param('stage'); # Defaults to the current stage
  foreach( $CGI->param('stage_initialised') ){
    if( $stage eq $_ ){ return 1 }
  }
  return 0;
}

#----------------------------------------------------------------------
#
=head2 form_belongs_to_stage

  Arg [1]   : hash
  Function  : 
  Returntype: boolean
  Exceptions: 
  Caller    : 
  Example   : if( form_belongs_to_stage(-form=>'my_form', -stage=>'my_stage')

=cut

#sub form_belongs_to_stage{# deprecated - to be removed
#  my %args = @_;
#  if( ! $args{-stage} ){ die( "Need a stage name" ) };
#  if( ! $args{-form}  ){ die( "Need a form name"  ) };

#  return 1 if $args{-form} eq 'stage';
#  return 0 if $args{-stage} eq 'output';

  # TODO: imporve efficiency of META 
#  if( 
#     grep{ $_->get_name eq $args{-form} }
#     map { $_->get_forms  }
#     map { $_->get_blocks }
#     grep{ $_->get_name eq $args{-stage} }
#     $META_DATA->get_stages
#    ){ return 1 }
#  if( 
#     grep{ $_->get_cgi_name eq $args{-form} }
#     map { $_->get_form_entries }
#     map { $_->get_forms  }
#     map { $_->get_blocks }
#     grep{ $_->get_name eq $args{-stage} }
#     $META_DATA->get_stages
#    ){ return 1 }
#
#  return 0;
#}


#----------------------------------------------------------------------
#
sub gen_button_src{
  my $src_tmpl = join( '',
		       MartView::Panel::IMG_ROOT_ROVER,
		       '/',
		       '%s',
		       '-%s.gif' );
  return sprintf( $src_tmpl, $_[0], $_[1] );
}

#----------------------------------------------------------------------
# Main result handler method. 
#
# Results are one of 2 types ( $CGI->param('outtype') ):
#   attribute
#   sequence
#
sub print_results{
  #warn("START PRINT RESULTS $$".localtime(time));
  my $fmt_printer;
  my %header;

  my %fmt_printer_args; # Additional args for format printer
  $fmt_printer_args{-outtarget} = $CGI->param('outtarget');
  $fmt_printer_args{-outformat} = $CGI->param('outformat');
  $fmt_printer_args{-gzip}      = $CGI->param('outcompress') eq 'gz' ? 1 : 0;

  my $formatter = 'FmtPrinter::'.uc($CGI->param('outformat'));
  $fmt_printer = $formatter->new( %fmt_printer_args );

  $fmt_printer->print_http_header();
  #warn("START INITIALISE RESULTS $$".localtime(time));
  # Generate the result set
  my ( $query, $fields_ref, $display_ref, $widths ) = initialise_results();
  #warn("END INITIALISE RESULTS $$".localtime(time));
  # Has the result set thrown an error?
  my $error = ( ref($query) eq 'BioMart::Query' ? 
		'' : $query );
  
  $error = "No attributes set" if ($error eq '' && !$query->getAllAttributes);
  
  if( $error ){ 
    print($error);
    if ($CGI->param('outformat') eq 'html'){
	$fmt_printer->print_error($error);
	$fmt_printer->flush;
	return undef;
    }
    else{
	return undef;
    }
  }

  # Print the results
  # set the batch size
  my $batch_size = 100;

  my $query_planner = BioMart::QueryPlanner->new();  
  return 'No datasets set' if (@{$query->getDatasetNames} < 1);
  $query->virtualSchema($CGI->param('schema'));
  
  my $rtable;
  eval{
      $rtable = $query_planner->getResultTable($query);
  };
  unless ($rtable){
      print "SQL FAILED - LIKELY XML MISCONFIGURATION ERROR".$@;
      return;
  }
  #if ($rtable == -1){
    #print "SQL FAILED - LIKELY XML MISCONFIGURATION ERROR Grrrrrrr !!! |-[ ";
    #return;
  #}
  # query validation errors
  if ($rtable =~ /^ERROR::/){
      my @err_messages = split(/::/,$rtable);
      my $err = $err_messages[1];
      print $err;
      return;
  }
  # some CGI data needed for certain formatters
  my $dataset = $CGI->param('dataset');
  my $id_filter_list = $CGI->param($dataset.'_id_list_limit_filters_list');
  my @id_filter_list = split(/\,/,$id_filter_list);
  $fmt_printer->print_data($rtable,$fields_ref, $display_ref, $widths, $batch_size, $dataset, \@id_filter_list);

  #warn("## FINISHED PRINT RESULTS $$".localtime(time)); ##
  return 1;
}

#----------------------------------------------------------------------
#
sub view_results_js{
  
  my $JS_TMPL = qq(
<SCRIPT LANGUAGE="JavaScript" >
var resultWindow; 
var resultTarget = "%s";
var resultURL = "/%s/martview/%s/%s";

function viewResults()
{
  resultWindow = window.open( resultURL,resultTarget);
  resultWindow.focus;
}

</SCRIPT>
);

  my $file_ext = $CGI->param('outformat');
  my $outtarget = $CGI->param('outtarget');
  if( $CGI->param('outcompress') eq 'gz' ){ 
    $file_ext .= ".gz";
    $outtarget = '_self';  
  }

  my $state_file_id = $CGI->param('id');
  my $target_file   = $CGI->param('outtarget').".$file_ext";

   my $url_type = $SiteDefs::BIOMART_URL || 'biomart';

  return sprintf( 
		 $JS_TMPL, 
		 $outtarget,
                 $url_type,
	         $state_file_id,
		 $target_file
	        );
}


#----------------------------------------------------------------------
sub restore_state{

  my $file = $CGI->param('id');
  my $tmp_file = $SiteDefs::ENSEMBL_TMP_DIR ."/$file";

  # Create new tmp file
  if( ( ! $file ) or ( ! -e $tmp_file ) ){

    #map{ $CGI->Delete($_) } $CGI->param(); # Clear $CGI

    my $fh;
    ( $fh, $tmp_file ) = tempfile( 'XXXXXXXXXX',
				   DIR    => $SiteDefs::ENSEMBL_TMP_DIR,
				   SUFFIX => '.mart',
				   UNLINK => 0 );

    #if( $tmp_file =~ m/\/([^\/\\]+)$/o ){ $CGI->param('id', $1 ) }
    if( $tmp_file =~ m/[\/\\]([^\/\\]+)$/o ){ $CGI->param('id', $1 ) }
    else{ die( "Could not parse file name $tmp_file" ) }
    close( $fh );
  }

  open( TMP_STATE, $tmp_file ) or die( "Could not open file $tmp_file: $!" );
  my $state = <TMP_STATE>;
  close( TMP_STATE );
  $CGI->param(-name=>'_state', -value=>$state);
  return $CGI->param('id');
}

#----------------------------------------------------------------------
sub initialise_results{

  my %fields;
  my @display_fields;
  my @widths;
  my $i = 0;
  my $error;
  my $outtype = $CGI->param('outtype');
  my $dataset = $CGI->param('dataset');
  $error = "No dataset set" if (!$dataset);
  #my $datasetConfigTree = $confForest->{$dataset};
  my $datasetObj = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset) if ($dataset);
  $error = "Unknown dataset" if (!$datasetObj);
  my $datasetConfigTree = $datasetObj->getConfigurationTree if ($datasetObj);
  my @config_trees;
  push @config_trees, $datasetConfigTree if ($datasetConfigTree);

  #my $chosen_ct = $confForest->{$CGI->param('second_dataset')};
  my $second_datasetObj = $REGISTRY->getDatasetByName($CGI->param('schema'),$CGI->param('second_dataset')) if ($CGI->param('second_dataset'));
  $error = "Unknown second dataset" if ($CGI->param('second_dataset') && !$second_datasetObj);
  my $chosen_ct = $second_datasetObj->getConfigurationTree
      if ($second_datasetObj);
  push @config_trees, $chosen_ct if ($chosen_ct);


  my $query = BioMart::Query->new('registry' => $REGISTRY,'virtualSchemaName' =>$CGI->param('schema'));
  $query->addDatasetName($dataset) if ($datasetObj);#incase no filters or atts set yet

  my @otherPotentialFilters;

  foreach my $stage( @stages ){
      if ($stage eq 'filter'){
	foreach my $ct(@config_trees){
	 my $dataSetName = $ct->dataSetName;
	  foreach my $fpage (@{$ct->getAllFilterTrees}){
	      foreach my $fgroup (@{$fpage->getAllFilterGroups}){#fgroup = block
		foreach my $fcollection (@{$fgroup->getAllCollections}){#fcollection = form
		   if(  $CGI->param($dataSetName.'_'.'collection_'.$fcollection->name) ||
			(${$fcollection->getAllFilters}[0] && 
			 ${$fcollection->getAllFilters}[0]->isa("BioMart::Configuration::FilterList"))){
		       # Loop for each form entries
		       foreach my $fd( @{$fcollection->getAllFilters} ){
			   my $entry = $fd;#stop reference problem
			   my $name = $entry->name;
			   
			   if ($name =~ /\./){#deal with filters from other datasets
			       my @names = split(/\./,$name);
			       next if (($name =~ /evidence_code/) && 
						 ($CGI->param($dataSetName.'_'.$names[1]) eq 'any'));

			       next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
			       $entry = $REGISTRY->getDatasetByName($CGI->param('schema'),$names[0])->
				   getConfigurationTree->getFilterByName($names[1]);
			       
			       # skip adding link if no values set
			       my @values = $CGI->param( $dataSetName.'_'.
							 $entry->name );
			       #my $value  = $values[0] || next;
					my $value  = $values[0];
					if (!$value && $value ne "0"){next;}

			       my @path = $REGISTRY->getPath($CGI->param('schema'),$names[0],$dataSetName);
			       foreach (my $j = 1; $j < @path; $j++){
				   my $link = $REGISTRY->getLinkBetween($CGI->param('schema'),$path[$j-1], $path[$j]);
				   $query->addLinks($link);
			       }

			       # add 2nd to 1st link if appropiate incase no 2nd dset filters set
			       if ($dataSetName eq $CGI->param('second_dataset')){
				   my @path = $REGISTRY->getPath($CGI->param('schema'),$CGI->param('second_dataset'), 
								 $CGI->param('dataset'));
				   foreach (my $j = 1; $j < @path; $j++){
				       my $link = $REGISTRY->getLinkBetween($CGI->param('schema'),$path[$j-1], $path[$j]);
				       $link->defaultLink($CGI->param('default_link')) if ($j == 1 && 
					       $CGI->param('default_link') && $CGI->param('default_link') ne 'default_link');
				       $query->addLinks($link);
				   }
			       }
			   }
			   

			   # Are there CGI values for this entry?
			   my @values = $CGI->param( $dataSetName.'_'.$entry->name );
							
			   my $value  = $values[0];
				if (!$value && $value ne "0"){next;}
			
			 
			   $value = unescapeHTML( $value );

				

				# FILTERLIST
			   if ($entry->isa("BioMart::Configuration::FilterList")){
			       my $att_table = BioMart::AttributeTable->new();
			       if (${$entry->getAllOptions}[0]){
			           foreach (@values){
				       $_ =~ s/\_/ /g;
				       $att_table->addRow([$_]);
				   }
			       }
			       else{# ID LIST FILTER
				    my $filter_number = @{$entry->getAllFilters};
				    my @values = split('\,',$value);
				    for (my $a = 0; $a < @values; $a += $filter_number){
					my $b = 0;
					my @row;
					while ($b < $filter_number){
					    push @row, $values[$a+$b];
					    $b++;
					}
					$att_table->addRow(\@row);
				    }
				}
			        $entry->setTable($att_table); 
		           }

			   if ($entry->isa("BioMart::Configuration::ValueFilter")){
			
				if ($entry->otherFilters){# if meant to set other filters
				   my $otherFilters = $entry->otherFilters;
				   my @otherFilts = split(/;/,$otherFilters);
				   foreach (@otherFilts){
				       my @names = split(/\./,$_);
				       next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
				       my $otherFilter = $REGISTRY->getDatasetByName
					   ($CGI->param('schema'),$names[0])->getConfigurationTree->
					                getFilterByName($names[1]);
				       next if (!$otherFilter);
				       my $att_table = BioMart::AttributeTable->new();
				       my @values = split('\,',$value);
				       foreach (@values){
					   $att_table->addRow([$_]);
				       }
				       next if ($otherFilter->isa("BioMart::Configuration::BooleanFilter"));
				       $otherFilter->setTable($att_table);
				       push @otherPotentialFilters, $otherFilter;
				   }
			       }

       
			       # test if a drop down menu of filters
			       my $options = $entry->getAllOptions;
			       if ($$options[0] && $$options[0]->filter && 
				   $$options[0]->filter->isa
				   ("BioMart::Configuration::BooleanFilter")){
				   
				   my $option_name = $CGI->param($dataSetName.'_'.
								 $entry->name.'_filter');
				   my $option = $ct->getOptionByName($option_name);
				   next if (!$option);
				   $entry = $option->filter;
				   $entry->displayName($option->displayName);
				   if ($entry->isa("BioMart::Configuration::ValueFilter")){
				       
				       my $att_table = BioMart::AttributeTable->new();
				       my @values = split('\,',$value);
				       foreach (@values){
					   $att_table->addRow([$_]);
				       }
				       next if ($entry->isa("BioMart::Configuration::BooleanFilter"));
				       $entry->setTable($att_table);
				   }
				   else{
				       if ($value ne 'Only'){
					   $entry->setExcluded;
				       }
				       else{
					   $entry->setIncluded;
				       }
				   }
			       }

			       elsif ($$options[0] && $$options[0]->filter &&
				      $$options[0]->filter->isa
				      ("BioMart::Configuration::ValueFilter")){
				  
				   my $option_name = $CGI->param($dataSetName.'_'.
								 $entry->name);
				   my $option = $ct->getOptionByName($option_name);
				   $entry = $option->filter;
				   $entry->displayName($option->displayName);
				   
				   my $att_table = BioMart::AttributeTable->new();
				   # may be a comma separated list
				   $value = $CGI->param( $dataSetName.'_'.$name.'_list' );
				   
				   my @values = split('\,',$value);
				   foreach (@values){
				       $att_table->addRow([$_]);
				   }
				   next if ($entry->isa("BioMart::Configuration::BooleanFilter"));
				   $entry->setTable($att_table);

			       }

			       else{
				   
				   # check option does not have an operator override
				   foreach my $option(@$options){
					if ($option->name eq $value){
						$value = $option->value;
						if ($option->operation ne ''){
						    $entry->operation($option->operation);
						}
						last;
					}
				   }

				   my $att_table = BioMart::AttributeTable->new();
				   
				   my @values = split('\,',$value);
				   foreach (@values){    
				       $att_table->addRow([$_]);
				   }
				   next if ($entry->isa("BioMart::Configuration::BooleanFilter"));
				   $entry->setTable($att_table);
			       }
			   }
			   elsif ($entry->isa("BioMart::Configuration::BooleanFilter")){
			       if ($value ne 'Only'){
				   $entry->setExcluded;
			       }
			       else{
				   $entry->setIncluded;
			       }
			   }
			   $query->addFilter($entry);
			
		       } # End entry attribute	  }
		   }# End form entry
		}
	    }
	  }
        }

        # add filters from potential other filters if relevant
	foreach my $otherFilter(@otherPotentialFilters){
	    # test if dataset associated with otherFilter is already involved in query
	    my $dataSets = $query->getDatasetNames;
	    foreach my $subName (@{$dataSets}) { 
		if ($otherFilter->dataSetName eq $subName){
		    $query->addFilter($otherFilter);
		    last;
		}
	    }
	}

      }# end of filter

      elsif ($stage eq 'output'){

	if($CGI->param('outformat') eq 'gff'){

	    my @data = qw(str_chrom_name exon_chrom_start exon_chrom_end transcript_chrom_strand gtf_cds_chrom_start gtf_cds_chrom_end gtf_start_codon_start gtf_stop_codon_start gtf_frame gene_stable_id_v transcript_stable_id_v exon_stable_id_v  );

	    foreach (@data){
		my $entry = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset.'_structure')->
		    getConfigurationTree->getAttributeByName($_);
		$query->addAttribute($entry) if ($entry);
	    }	   
	    my $link = $REGISTRY->getLinkBetween($CGI->param('schema'),$dataset, $dataset.'_structure');
	    $query->addLinks($link);
	    
	    my @order_atts;
	    push @order_atts, $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset.'_structure')->
		    getConfigurationTree->getAttributeByName('str_gene_id');
	    push @order_atts, $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset.'_structure')->
		    getConfigurationTree->getAttributeByName('str_transcript_id');
	    push @order_atts, $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset.'_structure')->
		    getConfigurationTree->getAttributeByName('rank');
	    
	    $query->orderBy(\@order_atts);

	}
	
	elsif($CGI->param('outformat') eq 'adf'){
	    my @data;
	    if ($dataset eq 'hsapiens_gene_ensembl'){
		@data = qw(ensembl_gene_id ensembl_transcript_id adf_embl adf_refseq adf_entrezgene
			   adf_swall adf_swissprot adf_pdb interpro family adf_go adf_omim);
	    }
	    elsif ($dataset eq 'mmusculus_gene_ensembl'){
		@data = qw(ensembl_gene_id ensembl_transcript_id adf_embl adf_refseq adf_entrezgene
			   adf_swall adf_swissprot adf_pdb interpro family  adf_omim);
	    }
	    elsif ($dataset eq 'dmelanogaster_gene_ensembl'){
		@data = qw(ensembl_gene_id ensembl_transcript_id adf_embl 
			   adf_swall adf_swissprot adf_pdb interpro family adf_go 
			   adf_fb_gid adf_omim);
	    }
	    elsif ($dataset eq 'rnorvegicus_gene_ensembl'){
		@data = qw(ensembl_gene_id ensembl_transcript_id adf_embl adf_refseq adf_entrezgene
			   adf_swall adf_swissprot adf_pdb interpro family adf_omim);
	    }
	    elsif ($dataset eq 'drerio_gene_ensembl'){
		@data = qw(ensembl_gene_id ensembl_transcript_id adf_embl adf_refseq adf_entrezgene
			   adf_swissprot  interpro family);
	    }
	    elsif ($dataset eq 'frubripes_gene_ensembl'){
		@data = qw(ensembl_gene_id ensembl_transcript_id adf_embl
			   adf_swall adf_swissprot interpro family adf_omim);
	    }
	    elsif ($dataset eq 'agambiae_gene_ensembl'){
		@data = qw(ensembl_gene_id ensembl_transcript_id adf_embl
			   adf_swall adf_swissprot interpro family);
	    }
	    elsif ($dataset eq 'celegans_gene_ensembl'){
		@data = qw(ensembl_gene_id ensembl_transcript_id adf_embl
			   adf_swall adf_swissprot adf_pdb interpro family adf_wb_gid adf_wb_tid);
	    }
	    else{
		$error = 'ADF is not compatible for this dataset';
	    }

	    # add the attribute corresponding to the id list being used
	    # if id list not set set error
	    my $id_filter = $CGI->param($dataset.'_id_list_limit_filters');
	    if ($id_filter){
		my $filter_entry = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset)->
		    getConfigurationTree->getOptionByName($id_filter)->filter;
		my $attribute_entry = $filter_entry->attribute;
		$query->addAttribute($attribute_entry) if ($attribute_entry);
		push @display_fields, 'Reporter Name';
	    }
	    else{
		$error = 'No ID list filter set';
	    }

	    # add the other attributes
	    foreach (@data){
		my $entry = $REGISTRY->getDatasetByName($CGI->param('schema'),$dataset)->
		    getConfigurationTree->getAttributeByName($_);
		next if (!$entry);
		$query->addAttribute($entry) if ($entry);
		push @display_fields, 'Reporter BioSequence Database Entry ['.$entry->displayName.']';
	    }	   
	}
	
	else{
         foreach my $ct(@config_trees){
          next if ($ct->dataSetName ne $dataset);# just show main dataset atts for now 
	  foreach my $fpage (@{$ct->getAllAttributeTrees}){
	      next if ($fpage->name ne $outtype);
	      
	      AGROUP:foreach my $fgroup (@{$fpage->getAllAttributeGroups}){#fgroup = block
		     my $attGroupSummary = '';
		 ACOLLECTION:foreach my $fcollection (@{$fgroup->getAllCollections}){
		     if(  $CGI->param('collection_'.$fcollection->name) ){
			 # stop ref problem bug - structure and compara mart bug should be fixed
			 my $attributes = [ @{$fcollection->getAllAttributes} ];
			 #foreach my $ad( @{$fcollection->getAllAttributes} ){
			 foreach my $entry( @$attributes ){
			     #my $entry = $ad;#ref problem
			     my $name = $entry->name;
			     my $original_entry = $entry;
			     if ($name =~ /\./){#deal with atts from other datasets
				 my @names = split(/\./,$name);

				 if ($names[1] eq 'filter'){# for filters in an att page
				      # add a filter form
				      next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
				      my $entry = $REGISTRY->getDatasetByName($CGI->param('schema'),$names[0])->
					  getConfigurationTree->getFilterByName($names[2]);
				      next if (!$entry);

				      # Are there CGI values for this entry?
				      my @values = $CGI->param( $entry->name );
				      #my $value  = $values[0] || next ACOLLECTION;
					 my $value  = $values[0];
					 if (!$value && $value ne "0"){next ACOLLECTION;}				      

				      my $att_table = BioMart::AttributeTable->new();
				      # may be a comma separated list
				      my @values = split('\,',$value);
				      foreach (@values){
					  $att_table->addRow([$_]);
				      }
				      next if ($entry->isa("BioMart::Configuration::BooleanFilter"));
				      $entry->setTable($att_table);
				      $query->addFilter($entry);
				      next ACOLLECTION;
				  }
				 
				 
				 else{
				     #warn("TESTING $names[0] AND $names[1]");
				     next if (!$REGISTRY->getDatasetByName($CGI->param('schema'),$names[0]));
				     $entry = $REGISTRY->getDatasetByName($CGI->param('schema'),$names[0])->
					 getConfigurationTree->getAttributeByName($names[1]);
				     #warn("GOT $names[0] AND $names[1]");
				     next if (!$entry);
				     if ($fcollection->maxSelect == 1 && $fcollection->name ne 'seq_scope_type'){
					 my @values = $CGI->param( 'collection_'.$fcollection->name );
					 #my $value  = $values[0] || next;
					 my $value  = $values[0];
					 if (!$value && $value ne "0"){next;}				
	
					 @values = $CGI->param( 'collection_'.$fcollection->name.'_this' );
					 @values = grep{ $entry->name eq $_ } @values;
					 #$value  = $values[0] || next;
					 $value  = $values[0];
					 if (!$value && $value ne "0"){next;}
	
				     }
				     else{
					 my @values = $CGI->param( 'collection_'.$fcollection->name );
					 #my $value  = $values[0] || next;
					 my $value  = $values[0];
					 if (!$value && $value ne "0"){next;}
	
					 @values = grep{ $entry->name eq $_ } @values;
					 #$value  = $values[0] || next;
					 $value  = $values[0];
					 if (!$value && $value ne "0"){next;}
				
				     }
				     #warn("STILL GOT $names[0] AND $names[1]");
				     my @path = $REGISTRY->getPath($CGI->param('schema'),$ct->dataSetName, 
								   $names[0]);
				     foreach (my $j = 1; $j < @path; $j++){
					 my $link = $REGISTRY->getLinkBetween($CGI->param('schema'),$path[$j-1], 
									      $path[$j]);
					  my $attributeLink = $entry->datasetLink;
				          if ($attributeLink && ($path[$j] eq $names[0])){
					      $link->defaultLink($attributeLink);
					  }
					 #warn("LINK ADDED  AND DEF IS ".$link->defaultLink) ;
					 $query->addLinks($link);
				     }
				 }
			     }
			     
			     # Are there CGI values for this entry?
			     
			     
			     if ($fcollection->maxSelect == 1 && $fcollection->name ne 'seq_scope_type'){
				 my @values = $CGI->param( 'collection_'.$fcollection->name );
				 #my $value  = $values[0] || next;
				 my $value  = $values[0];
				 if (!$value && $value ne "0"){next;}
				 
				 @values = $CGI->param( 'collection_'.$fcollection->name.'_this' );
				 @values = grep{ $entry->name eq $_ } @values;
				 #$value  = $values[0] || next;
				 $value  = $values[0];
				 if (!$value && $value ne "0"){next;}

			     }
			     else{
				 my @values = $CGI->param( 'collection_'.$fcollection->name );
				 #my $value  = $values[0] || next;
				 my $value  = $values[0];
				 if (!$value && $value ne "0"){next;}
				 
				@values = grep{ $entry->name eq $_ } @values;
				 #$value  = $values[0] || next;
				 $value  = $values[0];
				 if (!$value && $value ne "0"){next;}
			     }

			     if($entry)
                             {
                                        my $sadArr = $query->getAllAttributes;
                                        my $flag_exists = 0;
                                        foreach my $element (@$sadArr)
                                        { $flag_exists = 1   if($element->name eq $entry->name); }
                                        $query->addAttribute($entry)   if (!$flag_exists);
                             }
			
			     
			     if (length($entry->displayName) > $entry->width){
				 push @widths, length($entry->displayName);
			     }
			     else{
				 push @widths, $entry->width;
			     }
			     push @display_fields, $entry->name;# should be displayNames but breaks
			     if( ! exists( $fields{$entry->name} ) ){
				 $fields{$entry->name} = { result_idx => $i++ };
			     }
			     if ($entry->displayName){
				 $fields{$entry->name}{displayName} = $entry->displayName;
			     }
			     if ($entry->link){
				 $fields{$entry->name}{link} = $entry->link;
				 my @links = split(/\|/,$entry->link);
				 if(@links > 2 && ( $CGI->param('outformat') eq 'html' or
				   $CGI->param('outformat') eq 'excel' )){
				     for (my $j = 2;$j < @links;$j++){
					 my $link_att = $fpage->getAttributeByName
					     ($links[$j]);
					 next if (!$link_att);
					 $query->addAttribute($link_att) 
					     if ( ! exists( $fields{$links[$j]} ) );;
					 $fields{$links[$j]} = { result_idx => $i++ } 
					     if ( ! exists( $fields{$links[$j]} ) );
				     }
				 }
			     }
			     $entry = $original_entry;#attempt to fix ref bug
			 } # End entry attribute
		     }# End form entry
		 }
	     }
	  }
        }
       }
      }# End of output stage
  }# End of stages

  my $results;
  

  # Fixed widths (certain attributes only)
  my %fixed_width = ( html => 1, xls => 1, fwv => 1, txt => 1 );
  if( ( $CGI->param('outtype') eq 'feature_page' or
	$CGI->param('outtype') eq 'snp' or
	$CGI->param('outtype') eq 'structure' ) and 
      $fixed_width{$CGI->param('outformat')} ){ #calculate widths - already done above
  }
  else{ # Leave widths blank
    @widths = map{ '' } @display_fields;
  }


  if ($CGI->param('second_dataset') && ${$query->getAllFilters
      ($CGI->param('second_dataset'))}[0]){
      my @path = $REGISTRY->getPath($CGI->param('schema'),$CGI->param('second_dataset'), $CGI->param('dataset'));
      foreach (my $j = 1; $j < @path; $j++){
	  my $link = $REGISTRY->getLinkBetween($CGI->param('schema'),$path[$j-1], $path[$j]);
	  $link->defaultLink($CGI->param('default_link')) if ($j == 1 && 
							     $CGI->param('default_link') && $CGI->param('default_link') ne 'default_link');
	  $query->addLinks($link);
      }
  }

  #return $error || ( $m_adpt, \%fields, \@display_fields, \@widths);

  return $error || ( $query, \%fields, \@display_fields, \@widths);
}



#----------------------------------------------------------------------
sub new_dbh{# no longer needed
#  my $database_specifier = uc(shift);#equal to focus
  # if the usual EnsMart foci then use the db specified in MULT.ini by ENSEMBL_MART, else
  # use the one specified by "FOCUS"_MART
  # later may change MULTI.ini to have separate lines for GENE_MART, EST_GENE_MART, VEGA_GENE_MART and SNP_MART
  # and can then remove below hack
#  if (($database_specifier eq 'GENE') || ($database_specifier eq 'EST_GENE') || ($database_specifier eq 'VEGA_GENE') || ($database_specifier eq 'SNP') || ($database_specifier eq 'WORMBASE_GENE')){
#    $database_specifier = 'ENSEMBL';
#  }
#  $database_specifier = $database_specifier.'_MART';
  #warn("DATABASE SPECIFIER\t$database_specifier\n");#
#  my $dbh_hashref = EnsEMBL::DB::Mart::get_databases($database_specifier);
#  if( ! $dbh_hashref )       { die( 'Bad config for MULTI mart DB' ) }
#  if( $dbh_hashref->{error} ){ die( $dbh_hashref->{error} ) }
#  if( $dbh_hashref->{non_fatal_error} ){ die $dbh_hashref->{non_fatal_error} }
#  return $dbh_hashref->{$database_specifier};
#}
#----------------------------------------------------------------------
# Uses the blast ticket to generate a list of ENST or ENSP ID's and 
# initialise the CGI accordingly

	    

sub import_blast_data{
  my $ticket = $CGI->param('_blast_ticket') ||
    ( add_warning( 'start', 'focus','Missing BlastView ticket' ) &&
      return );
  my( $res_id ) = $CGI->param('_blast_result') ||
    ( add_warning( 'start', 'focus','Missing BlastView result ID' ) &&
      return );

  require EnsEMBL::DB::Core;
  my $blast_adpt = &EnsEMBL::DB::Core::get_blast_database ||
    EnsEMBL::HTML::Page->ensembl_exception
      ( add_warning( 'start', 'focus',"Can't get_blast_database" ) );

  require Bio::Tools::Run::EnsemblSearchMulti;
  my $blast = Bio::Tools::Run::EnsemblSearchMulti->retrieve( $ticket,
							     $blast_adpt ) ||
    ( add_warning( 'start', 'focus',"BlastView ticket $ticket not found" ) &&
      return );

  my( $runnable ) = $blast->runnables_like( -result_token=>$res_id );
  if( ! $runnable ){
    add_warning( 'start', 'focus', 
		 "Blastview result $res_id not found ".
		 "for ticket $ticket" );
    return;
  }
  my $result = $runnable->result;

  my $gene_filter = ($result->database_name =~ /(CDNA)/ ? 'FG_ens_transcript_ID':'FG_ens_peptide_ID' );

  my $gene_list = ( join ',', 
		    map{ $_->name =~ /([^:]+)$/ } 
		    $result->hits );

  $CGI->param( 'stage', 'output');
  $CGI->param( -name=>'stage_initialised', -value=>['start','filter'] );
  $CGI->param( 'species', $result->species );
  $CGI->param( 'focus', 'gene' );
  $CGI->param( 'named_gene', 1 );
  $CGI->param( 'named_gene_filter', $gene_filter );
  $CGI->param( 'named_gene_list', $gene_list );
  return 1;
}

#----------------------------------------------------------------------
# Generates Javascript that sets drop down menu
#
sub set_jscript_setOptions{
  my $form_obj = shift;
  my $filters_copy = shift;
  my $dataset_name = shift;
  my $javascript_code = shift;


  # Define templates
  my $FUNCTION = '
<SCRIPT LANGUAGE="JavaScript" >
set%sOptions( );
function set%sOptions( )
{

  // Check browser
  var b = navigator.appName;
  var v = parseInt( navigator.appVersion );
  var ns = false;
  var n6 = false;
  var ie = false;
  if( b=="Netscape" ){ 
    if( v > 4 ){ n6 = true }
    else       { ns = true }      
  }
  else{ ie = true }
  

  // Get forms to process
  var fromSlct    = document.settings.%s;
  var toSlct = document.settings.%s;

  // Get current region values
  var fromVal    = fromSlct.options[fromSlct.selectedIndex].value;
  var oldVal = document.settings.%s_last.value;

  // Clear the toSlct
  if( ns == true ){
      while( toSlct.options.length > 0 ){ 
        toSlct.options[0] = null; 
      }
  }
  else{
      while( toSlct.length > 0 ){ 
        toSlct.remove(0);
      }
  }
  
  var new_options = new Array( "---" );
  switch( fromVal ){%s
  }

  // Assign array values to select options
  if( new_options.length ){
      var use_options = new_options;
      var frSelIdx = 0;
      for ( var i = 0; i < use_options.length; i++ ){
	  var txt = use_options[i];
	  var val = use_options[i];
	  var sel = false;
	  if( txt == "---" ){ val = "" }
          // hack
	  //frSelIdx = 1;
	  if( val == oldVal ){ frSelIdx = i };
	  
          if( ns == true ){ 
	      toSlct.options[i] = new Option( txt,val,sel,sel );
	  }
	  else{
	      var newElem1 = document.createElement("OPTION");
	      newElem1.text     = txt;
	      newElem1.value    = val;
	      newElem1.selected = sel;
	      if( ie == true ){
		  toSlct.add(newElem1 );
	      }
	      else{
		  toSlct.add(newElem1, null);
	      }
	  }
      }
      toSlct.options[frSelIdx].selected = true;      
  }
}
</SCRIPT>';


  my $CASE = '
    case "%s":
      new_options = new Array(%s)
      break ';

  # Populate templates
 
     my $case_str = '';
     my ($options_str, $from_filter, $to_filter, $fn_name, $second, $second_func_str);
     my $filters = $filters_copy;
     my $i = 0;
     # loop for each push action ref in the filter - create a javascript for each one
     my $firstOptions = $$filters[0]->getAllOptions;
     my $firstOption = $$firstOptions[0];
     my $firstPushActions = $firstOption->getAllPushActions;
     foreach(@$firstPushActions){
         
         my $ref = $_->ref;
         if ($ref =~ /\./){
	      my @ref = split(/\./,$ref);
	      $ref = $ref[1];
	 }
         $fn_name = $ref;
         $to_filter = $dataset_name.'_'.$ref;
         foreach my $filter(@$filters){
             $from_filter = $dataset_name.'_'.$filter->name;# if ($from_filter ne $to_filter);# in case both in same collection
             my $options = $filter->getAllOptions;
             foreach my $option(@$options){
                #my $choice = $option->name;
                my $choice = $option->value;
                $choice =~ s/ /\*/g;#to match drop down values
                #$choice = substr($choice,0,30);


                my $push_actions = $option->getAllPushActions;
                next if (!($$push_actions[0]));
                
 
                my $pa_options = $$push_actions[$i]->getAllOptions;
                
                my @bands = map {substr($_->name,0,40)} @$pa_options;
                $options_str = '"' . join( '", "', @bands ) . '"' ;

                # call 2nd level jscript generation if necessary ie Uniprot division->species->component
                if ($$pa_options[0]->getAllPushActions->[0] && (!($second))){
                    #set_jscript_setSecondOptions($form_obj,$to_filter,$filter,$dataset_name,$javascript_code);
                    $second_func_str = set_jscript_setSecondOptions($form_obj,$to_filter,$filter,$dataset_name,$javascript_code);
                    $second++;
                }
               
               $case_str .= sprintf( $CASE, $choice, $options_str );
            }
       }
       my $func_str = sprintf( $FUNCTION, uc($dataset_name).uc($fn_name), uc($dataset_name).uc($fn_name), $from_filter, $to_filter, $to_filter, $case_str );
       $form_obj->set_jscript($func_str);  
       push @$javascript_code, $func_str;
       push @$javascript_code, $second_func_str if ($second_func_str);
       $i++;
     }
}

#----------------------------------------------------------------------
# Generates Javascript that sets second level drop down menu - can maybe combine with above
#
sub set_jscript_setSecondOptions{
  my $form_obj = shift;
  my $from_filter = shift;
  my $filter_obj = shift;
  my $dataset_name = shift;
  my $javascript_code = shift;

  # Define templates
  my $FUNCTION = '
<SCRIPT LANGUAGE="JavaScript" >
set%sOptions( );
function set%sOptions( )
{

  // Check browser
  var b = navigator.appName;
  var v = parseInt( navigator.appVersion );
  var ns = false;
  var n6 = false;
  var ie = false;
  if( b=="Netscape" ){ 
    if( v > 4 ){ n6 = true }
    else       { ns = true }      
  }
  else{ ie = true }

  // Get forms to process
  var fromSlct    = document.settings.%s;
  var toSlct = document.settings.%s;

  // Get current region values
  var fromVal    = fromSlct.options[fromSlct.selectedIndex].value;
  var oldVal = document.settings.%s_last.value;


  // Clear the toSlct
  if( ns == true ){
      while( toSlct.options.length > 0 ){ 
        toSlct.options[0] = null; 
      }
  }
  else{
      while( toSlct.length > 0 ){ 
        toSlct.remove(0);
      }
  }
  
  var new_options = new Array( "---" );
  switch( fromVal ){%s
  }

  // Assign array values to select options
  if( new_options.length ){
      var use_options = new_options;
      var frSelIdx = 0;
      for ( var i = 0; i < use_options.length; i++ ){
	  var txt = use_options[i];
	  var val = use_options[i];
	  var sel = false;
	  if( txt == "---" ){ val = "" }
          // hack
	  //frSelIdx = 1;
	  if( val == oldVal ){ frSelIdx = i };
	  
          if( ns == true ){ 
	      toSlct.options[i] = new Option( txt,val,sel,sel );
	  }
	  else{
	      var newElem1 = document.createElement("OPTION");
	      newElem1.text     = txt;
	      newElem1.value    = val;
	      newElem1.selected = sel;
	      if( ie == true ){
		  toSlct.add(newElem1 );
	      }
	      else{
		  toSlct.add(newElem1, null);
	      }
	  }
      }
      toSlct.options[frSelIdx].selected = true;      
  }
}
</SCRIPT>';


  my $CASE = '
    case "%s":
      new_options = new Array(%s)
      break ';

  # Populate templates
 
     my $case_str = '';
     my ($options_str, $to_filter, $fn_name);

     #my $filters = $fcollection_obj->getAllFilters;
     #foreach my $filter(@$filters){
         #$from_filter = $;
      my $filter_options = $filter_obj->getAllOptions;
      foreach (@$filter_options){
        foreach my $push_action_obj(@{$_->getAllPushActions}){
         my $options = $push_action_obj->getAllOptions;
           foreach my $option(@$options){
             my $choice = $option->name;
             $choice = substr($choice,0,40);
             my $push_actions = $option->getAllPushActions;
             foreach my $push_action(@$push_actions){
                $fn_name = $push_action->ref;
                if ($fn_name =~ /\./){
		    my @fn_name = split(/\./,$fn_name);
		    $fn_name = $fn_name[1];
		}
                $to_filter = $dataset_name.'_'.$fn_name;
                
                my $pa_options = $push_action->getAllOptions;
                
                my @bands = map {$_->name} @$pa_options;
                $options_str = '"' . join( '", "', @bands ) . '"' ;
             } 
             $case_str .= sprintf( $CASE, $choice, $options_str );
         }
       }
     }
    
     my $func_str = sprintf( $FUNCTION, uc($dataset_name).uc($fn_name), uc($dataset_name).uc($fn_name), $from_filter, $to_filter, $to_filter, $case_str );

     $form_obj->set_jscript($func_str);
     return $func_str;
     #push @$javascript_code,$func_str;
     
     
}

#----------------------------------------------------------------------
# Generates Javascript that sets the links menu
#
sub set_jscript_setLinks{
  my $form_obj = shift;
  my $dataset = shift;
  my @possible_links = @_;
  # Define templates
  my $FUNCTION = '
<SCRIPT LANGUAGE="JavaScript" >
// Store initial name->label settings to array
var linkLabels = new Array();
var linkSlct   = document.settings.default_link;
for( var i = 0; i < linkSlct.options.length; i++ ){
  linkLabels[linkSlct.options[i].value] = linkSlct.options[i].text;
}
setLinkOptions( );
function setLinkOptions( )
{

  // Check browser
  var b = navigator.appName;
  var v = parseInt( navigator.appVersion );
  var ns = false;
  var n6 = false;
  var ie = false;
  if( b=="Netscape" ){ 
    if( v > 4 ){ n6 = true }
    else       { ns = true }      
  }
  else{ ie = true }

  // Get forms to process
  var fromSlct    = document.settings.second_dataset;
  var toSlct = document.settings.default_link;

  // Get current region values
  var fromVal = fromSlct.options[fromSlct.selectedIndex].value;
  var oldVal  =  toSlct.options[toSlct.selectedIndex].value;
  //var oldVal = document.settings.default_link_last.value;

  // Clear toSlct
  if( ns == true ){
      while( toSlct.options.length > 0 ){ 
        toSlct.options[0] = null; 
      }
  }
  else{
      while( toSlct.length > 0 ){ 
        toSlct.remove(0);
      }
  }
  
  // Create arrays of new values
  var new_options = new Array( "---" );
  switch( fromVal ){%s
  }

  // Assign array values to select options
  if( new_options.length ){
      var use_options = new_options;
      var frSelIdx = 0;
      for ( var i = 0; i < use_options.length; i++ ){
          //var txt = use_options[i];
	  var val = use_options[i];
          var txt = linkLabels[val];
	  var sel = false;
	  if( txt == "---" ){ val = "" }
          //frSelIdx = 1;
	  if( val == oldVal ){ frSelIdx = i };
	  if( ns == true ){ 
	      toSlct.options[i] = new Option( txt,val,sel,sel );
	  }
	  else{
	      var newElem1 = document.createElement("OPTION");
	      newElem1.text     = txt;
	      newElem1.value    = val;
	      newElem1.selected = sel;
	      if( ie == true ){
		  toSlct.add(newElem1 );
	      }
	      else{
		  toSlct.add(newElem1, null);
	      }
	  }
      }
      toSlct.options[frSelIdx].selected = true;      
  }
}
</SCRIPT>';


  my $CASE = '
    case "%s":
      new_options = new Array(%s)
      break ';

  # Populate templates
 
     my $case_str = '';
     foreach my $linked_dataset(@possible_links){
         my $path = $REGISTRY->getPath($CGI->param('schema'),$linked_dataset,$dataset);
         my $link_obj = $REGISTRY->getLinkBetween($CGI->param('schema'),$linked_dataset,$$path[1]);# only 1 direction
         my $link_options = $link_obj->getAllLinks || ();

         my @options;
         my $default = $link_obj->defaultLink;
         push @options, $default;# to make sure the default one at the top of the list
         foreach (@$link_options){
            push @options, $_ if ($_ ne $default);
         }
         my $options_str = '"' . join( '", "', @options ) . '"' ;
     
         $case_str .= sprintf( $CASE, $linked_dataset, $options_str );
     }
     
     my $func_str = sprintf( $FUNCTION, $case_str );
     $form_obj->set_jscript($func_str);  
}

# Sets the JavaScript for the start page
sub set_jscript_setStartOptions{
  my $form_obj = shift;
  my $schs = shift;
  my $javascript_code = shift;
  my @schemas = @$schs; 
  # Define templates
  my $FUNCTION = '
  <SCRIPT LANGUAGE="JavaScript" >
  setStartOptions( );
  function setStartOptions( )
  {

  // Check browser
  var b = navigator.appName;
  var v = parseInt( navigator.appVersion );
  var ns = false;
  var n6 = false;
  var ie = false;
  if( b=="Netscape" ){ 
    if( v > 4 ){ n6 = true }
    else       { ns = true }      
  }
  else{ ie = true }

  if( ns == true ){
    alert( "BioMart no longer supports Netscape 4" );
    return;
  }

  // Get forms to process
  var schemaSlct   = document.settings.schema;
  var databaseSlct = document.settings.database;
  var datasetSlct  = document.settings.dataset;

  // Get current values
  var schemaVal;
  var databaseVal;
  var datasetVal;
  if( schemaSlct && (schemaSlct.selectedIndex>=0) ){
    schemaVal = schemaSlct.options[schemaSlct.selectedIndex].value;
  }
  if( databaseSlct && (databaseSlct.selectedIndex>=0) ){
    databaseVal = databaseSlct.options[databaseSlct.selectedIndex].value;
  }
  if( datasetSlct && (datasetSlct.selectedIndex>=0) ){
    datasetVal = datasetSlct.options[datasetSlct.selectedIndex].value;
  }
  
  
// Create arrays of new values
  var databaseBySchemaOptions = new Array( "---","" );
  switch( schemaVal ){%s
  }
  var datasetBySchemaOptions = new Array( "---","" );
  switch( schemaVal ){%s
  }

  // Get the defaultDatabase
  var defaultDatabase;
  if( schemaSlct ){
    switch( schemaVal ){%s
    }
  }
  

  // Clear out old values
  if( schemaSlct && databaseSlct ){
    // Clear databaseSlct
    while( databaseSlct.length > 0 ){ 
      databaseSlct.remove(0);
    }
  }
  if( ( schemaSlct || databaseSlct ) && datasetSlct ){
    // Clear datasetSlct
    while( datasetSlct.length > 0 ){ 
      datasetSlct.remove(0);
    }
  }
  
  // Add new database values

  if( schemaSlct && databaseSlct ){
    var selDatabase = false;
    for ( var i = 0; i < databaseBySchemaOptions.length; i = i + 2 ){
      var txt = databaseBySchemaOptions[i+1];
      var val = databaseBySchemaOptions[i];
      var sel = false;
      if( val == databaseVal ){ 
        sel = true;
        selDatabase = true;
      }
      var newElem1 = document.createElement("OPTION");
      newElem1.text     = txt;
      newElem1.value    = val;
      newElem1.selected = sel;
      if( ie == true ){
	databaseSlct.add(newElem1 );
      }
      else{
	databaseSlct.add(newElem1, null);
      }
    }
    if( selDatabase == false ){
      for( var i=0; i<databaseSlct.length; i++ ){
        if( databaseSlct[i].value == defaultDatabase ){
          databaseSlct[i].selected = true;
          break;
        }
      }
    }
  }

  // Re-Get database val - may have changed
  if( databaseSlct && (databaseSlct.selectedIndex>=0) ){
    databaseVal = databaseSlct.options[databaseSlct.selectedIndex].value;
  }

  var datasetByDatabaseOptions = new Array( "---","" );
  switch( databaseVal ){%s
  }
  var defaultDataset;
  if( schemaSlct && ! databaseSlct ){
    switch( schemaVal ){%s
    }
  }
  if( databaseSlct ){
    switch( databaseVal ){%s
    }
  }

  // Add new dataset values
  if( ( schemaSlct || databaseSlct ) && datasetSlct ){
    var selDataset = false;
    var options;
    if( databaseSlct ){
      options = datasetByDatabaseOptions;
    } else {
      options = datasetBySchemaOptions;
    }
    for ( var i = 0; i < options.length; i = i + 2 ){
       
      var txt = options[i+1];
      var val = options[i];
      var sel = false;
      if( val == datasetVal ){ selDataset = true; sel = true };
      var newElem1 = document.createElement("OPTION");
      newElem1.text     = txt;
      newElem1.value    = val;
      newElem1.selected = sel;
      if( ie == true ){
	datasetSlct.add(newElem1 );
      }
      else{
	datasetSlct.add(newElem1, null);
      }
    }
    if( selDataset == false ){
      for( var i=0; i<datasetSlct.length; i++ ){
        if( datasetSlct[i].value == defaultDataset ){
          datasetSlct[i].selected = true;
          break;
        }
      }
    }
  }
  }
  </SCRIPT>';


  my $database_by_schema_t = '
    case "%s":
      databaseBySchemaOptions = new Array(%s)
      break ';
  my $dataset_by_schema_t = '
    case "%s":
      datasetBySchemaOptions = new Array(%s)
      break ';
  my $dataset_by_database_t = '
    case "%s":
      datasetByDatabaseOptions = new Array(%s)
      break ';
  my $def_dataset_t = '
    case "%s":
      defaultDataset = "%s"
      break ';
  my $def_database_t = '
    case "%s":
      defaultDatabase = "%s"
      break ';


  my %database_by_schema = ();
  my %dataset_by_schema = ();
  my %dataset_by_database = ();
  my %def_dataset_by_schema = ();
  my %def_dataset_by_database = ();
  my %def_database_by_schema = ();

  foreach my $schema(@schemas){         
    $database_by_schema{$schema} ||= [];
    $dataset_by_schema{$schema}  ||= [];
    if( my $db = $REGISTRY->getDefaultDatabase($schema) ){
      $db =~ s/\s//g; # Strip whitespace. Hacky and may break stuff
      $def_database_by_schema{$schema} = $db;
    }
    foreach my $database( @{$REGISTRY->getAllDatabaseNames($schema,1)} ){
      my $database_name = $database; #join( '_', $schema, $database );
      $database_name =~ s/\s//g; # Strip whitespace. Hacky and may break stuff

      $database_name = $database_name.'__'.$schema;

      $dataset_by_database{$database_name} ||= [];
      my $database_display = $database;
      push( @{$database_by_schema{$schema}}, $database_name, $database_display);

      DATASET:foreach my $dataset_name(
        sort @{$REGISTRY->getAllDataSetsByDatabaseName($schema,$database,1)} ){
	  # if dataset already added for a database then skip
	  my $dataset = $REGISTRY->getDatasetByName($schema,$dataset_name) || next;
	  my $version = '';
	  $version = ' ('.$dataset->version.')' if ($dataset->version);
          #my $dataset_display = $dataset->displayName.$version || $dataset_name;
          my $dataset_display = $dataset->displayName || $dataset_name;
	  my @options = @{$dataset_by_database{$database_name}||[]};
	  for (my $i = 0; $i < @options; $i += 2){
	      if ($options[$i] eq $dataset_name){
		  # add to schema though first
		  push( @{$dataset_by_schema{$schema}}, $dataset_name, $dataset_display);
		  next DATASET;
	      }
	  }
	  push( @{$dataset_by_schema{$schema}}, $dataset_name, $dataset_display);
	  push( @{$dataset_by_database{$database_name}}, $dataset_name, $dataset_display);
	  if( $dataset->getConfigurationTree->defaultDataset eq 'true' ){
            $def_dataset_by_schema{$schema} ||= $dataset_name;
            $def_dataset_by_database{$database_name} ||= $dataset_name;
          }
        }
    }
  }

  my $database_by_schema_str  = '';
  my $dataset_by_schema_str   = '';
  my $dataset_by_database_str = '';
  my $def_database_by_schema_str = '';
  my $def_dataset_by_schema_str = '';
  my $def_dataset_by_database_str = '';
  foreach my $schema( keys %database_by_schema ){
    my @options = @{$database_by_schema{$schema}};


    my $array_str = join( ',', map{"\"$_\""} @options );
    $database_by_schema_str .= sprintf( $database_by_schema_t,$schema,$array_str );
  }
  foreach my $schema( keys %dataset_by_schema ){
    my @options = @{$dataset_by_schema{$schema}};
    my $array_str = join( ',', map{"\"$_\""} @options );
    $dataset_by_schema_str .= sprintf( $dataset_by_schema_t,$schema,$array_str );
  }
  foreach my $database( keys %dataset_by_database ){
    my @options = @{$dataset_by_database{$database}};
    my $array_str = join( ',', map{"\"$_\""} @options );
    $dataset_by_database_str .= sprintf( $dataset_by_database_t,$database,$array_str);
  }
  foreach my $schema( keys %def_database_by_schema ){
    #my $def = $def_database_by_schema{$schema};
    my $def = $def_database_by_schema{$schema}.'__'.$schema;
    $def_database_by_schema_str .= sprintf( $def_database_t,$schema,$def );
  }
  foreach my $schema( keys %def_dataset_by_schema ){
    my $def = $def_dataset_by_schema{$schema};
    $def_dataset_by_schema_str .= sprintf( $def_dataset_t,$schema,$def );
  }
  foreach my $database( keys %def_dataset_by_database ){
    my $def = $def_dataset_by_database{$database};
    $def_dataset_by_database_str .= sprintf( $def_dataset_t,$database,$def );
  }

  # Populate master template
  my $func_str = sprintf( $FUNCTION, 
                          $database_by_schema_str, 
                          $dataset_by_schema_str,
                          $def_database_by_schema_str,
                          $dataset_by_database_str,
                          $def_dataset_by_schema_str,
                          $def_dataset_by_database_str );

  # Add code to form
  $form_obj->set_jscript($func_str);  
  push @$javascript_code, $func_str;
}

sub sequence_jscript{

    my $gene_disables = shift; # Unused
    my $seq_conversion = shift;

    my $jscript1 = $SiteDefs::ENSEMBL_SITETYPE eq 'EBI' ? '/BioMart/js/ua.js' :'/js/ua.js';
    my $jscript2 = $SiteDefs::ENSEMBL_SITETYPE eq 'EBI' ? '/BioMart/js/xbDOM.js' : '/js/xbDOM.js';
    my $jscript3 = $SiteDefs::ENSEMBL_SITETYPE eq 'EBI' ? '/BioMart/js/xbStyle.js' : '/js/xbStyle.js';
    my $form_number = $SiteDefs::ENSEMBL_SITETYPE eq 'EBI' ? 2 : 0;

    return 
    qq(<SCRIPT LANGUAGE="JavaScript"></SCRIPT>
    <SCRIPT LANGUAGE="JavaScript" SRC=\"$jscript1\"></SCRIPT>
    <SCRIPT LANGUAGE="JavaScript" SRC=\"$jscript2\"></SCRIPT>
    <SCRIPT LANGUAGE="JavaScript" SRC=\"$jscript3\"></SCRIPT>
    <SCRIPT language="JavaScript">

    var srcPrefix = "/gfx/EnsMart/gene_schematic_"; 

    var seqConversion = new Array( $seq_conversion );

    //----------------------------------------------------------------------
    // Initialises the seqType/seqScope forms
    //
    function initialiseSeqType(){
        var seqType;
    
        var seqTypeElement  = document.settings.collection_seq_scope_type;
        for( var i=0; i<seqTypeElement.length; i++ ){
            if( seqTypeElement[i].defaultChecked ){
                seqType = seqTypeElement[i].value;
            }
        }   
        changeImage( seqType );
    }

    //----------------------------------------------------------------------
    // Changes the gene_schematic image when the seq type is changed
    //
    function changeImage( seqType ){

        var seqTypeElement = document.settings.collection_seq_scope_type;
        var seqImage;
        for( var i=0; i<seqTypeElement.length; i++ ){
            if( seqTypeElement[i].value == seqType ){
                seqImage = seqConversion[i];
            }
        }   
        var srcSufix  = ".gif";
        var newSrc = "http://" + location.host + srcPrefix + seqImage + srcSufix;
        //alert(newSrc);
        document.seq_scope_img.src = newSrc;
    }         

    </SCRIPT>);#end of java script

    }
}


#----------------------------------------------------------------------
# Generates the ontology picker tool
my( $COUNT, $TMPL, $ONT_TMP_DIR );

sub generate_ontology_picker_tool{
    my $filter = shift;
    my $dataset_name = shift;

    my $configurationFile = shift;
    my $fh = IO::File->new($configurationFile, "<");

    $TMPL    = "TE.A(%u,%u,'%s');\n";
    $ONT_TMP_DIR = "${SiteDefs::ENSEMBL_TMP_DIR}/_ontology";
    if (!(-e $ONT_TMP_DIR)) {
	mkdir( $ONT_TMP_DIR ) or die( "Could not mkdir $ONT_TMP_DIR: $!" );
    }
    
    my $ontology = $filter->name;
    $ontology =~ tr/ /_/;
		   
    # Get the filehandle
    
    my $fh = start_ontology_file($ontology, $dataset_name);
    # Kick off the file-build
    $COUNT = 0;
    
    recurse_ontology( $fh, $COUNT, $filter );
		   
    # Clean up
    end_ontology_file( $fh );
		  
    return 1;
}


# Recursive function for descending eVoc heirarchy
sub recurse_ontology{

    my $fh      = shift; # Filehandle to write to
    my $p_id    = shift; # ID of parent node
    my $configuration_object = shift; # Filter/Option
    my $options = $configuration_object->getAllOptions;
    foreach my $option( @$options ){
	my $text = $option->displayName;
	my $t_id = ++ $COUNT;
	$text =~ s/'/\\'/g;
	printf $fh ( $TMPL,  $t_id, $p_id, $text );
	recurse_ontology( $fh, $t_id, $option );
    }
}


# Creates an appropriate ontology file and returns an open file handle
sub start_ontology_file{

    my $ontology = shift || die( "Need an ontology identifier" );
    my $dataset = shift;
    my $filename = "${ONT_TMP_DIR}/_${ontology}.html";
  my $fh = IO::File->new( ">$filename" )
      or die( "Could not open $filename for write: $!" );

    warn( "[MARTCONF][INFO] Writing ontology picker $filename" );

    my $jscript1 = $SiteDefs::ENSEMBL_SITETYPE eq 'EBI' ? '/BioMart/js/ebi_hdropd.js' :'/js/hdropd.js';

  $fh->print( qq|
<!--#set var="decor" value="none"-->
<html>
<head>
  <title>$ontology</title>
  <script type="text/javascript" src="$jscript1"></script>
<head>
<body onMouseDown="Reset()">
<form>
<table width="100%" cellspacing="0" cellpadding="0" border="1">
 <tr width="100%">
  <td width="100%" align="right"><input type="button" value="Close" onclick="javascript:window.close()" /></td>
 </tr>
</table>
</form>
<script type="text/javascript">
<!--
              function MenuBuild(){
pForm = " |
    .$dataset.'_'.qq |${ontology}"; //Form in parent window to update with sel value - new for martp website compatible
    is = new BrowserCheck();  //Checking browser version
    TE = new TreeItem(0,0,""); \n | );

	      return $fh;
	  }


# Adds closing text and closes the ontology filehandle
sub end_ontology_file{
    my $fh = shift || die( "Need a file handle" );

    print $fh qq|
	TE.WriteCSS();
    TE.WriteDiv();
    TE.Reset();
}
MenuBuild();
MenuInit();
//-->
    </script> \n|;

$fh->close();

return 1;
}






1;
