#!/usr/bin/perl
# This is the code for SIXPACK, a bibligraphy database manager.

# Copyright (C) 1997  by Sixten Boeck 
# (as implied by the web page http://crysta.physik.hu-berlin.de/~boeck/Sixpack/ )
#     
#        This program is free software; you can redistribute it and/or modify
#	it under the terms of the GNU General Public License as published by
#	the Free Software Foundation; either version 2 of the License, or
#	(at your option) any later version.
#	
#	This program is distributed in the hope that it will be useful,
#	but WITHOUT ANY WARRANTY; without even the implied warranty of
#	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#	GNU General Public License for more details.
#	
#	You should have received a copy of the GNU General Public License
#	along with this program; if not, write to the Free Software
#	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
						

my $VERSION="0.99(=0.0.6)" ;

# Variables with external influence:

my %ConfArray ;

require Cwd ;

my $home ;
findhome() ;


my $CONFFILE =  convPath("~/.sixpack.rc") ;
my $globalCONFFILE = "/etc/sixpack.rc" ;

#Added by Chris Kuklewicz <chrisk@mit.edu>
# I think the Normal LyX default is ~/.lyx/ not /tmp/
# but I cannot put pipes in the network AFS home directory that I have
# so I moved mine to /tmp/
$ConfArray{"LYXPIPE"} = "~/.lyx/.lyxpipe.in";
#$ConfArray{"LYXPIPE"} = "/tmp/.lyxpipe.in";

$ConfArray{"GNUDOIT"} = "gnuclient -batch -eval";


if( defined $ENV{'USER'} ) {	     
  $ConfArray{"USER"} = "$ENV{'USER'}" ;
} else {
  $ConfArray{"USER"} = "you" ;
}
	   
$ConfArray{"PIDFILE"} = "$ENV{'HOME'}/.sixpack.pid" ;
$ConfArray{"TMP"} = "/tmp/$ENV{'USER'}";
$ConfArray{"CONV"} = "/usr/local/bin/bibconv";
$ConfArray{"EDITOR"} = "/usr/bin/vim -f";
if( defined $ENV{'EDITOR'} ) {
  $ConfArray{"EDITOR"} = $ENV{'EDITOR'} ;
}
$ConfArray{"MISCHANDLE"} = '/bin/echo no handler for file %s' ;
$ConfArray{"PICSDIR"} = "/usr/local/lib/sixpack/Pics";
$ConfArray{"BIBXRESFILE"} = "/usr/local/lib/sixpack/Bib" ;
$ConfArray{"PAPERS"} = "$ENV{'HOME'}/papers";
$ConfArray{'BACKUPEXT'} = ".bak" ;
$ConfArray{'BPHOME'} = "/usr/local/lib/bp" ;
$ConfArray{'SIXDOC'} = "/usr/local/lib/sixpack/doc" ;
$ConfArray{'DISPLAYLINE'} = "" ;

$ConfArray{'ENTRIESPERMENU'} = 16 ;

$ConfArray{'CITEID'} = "LACHMANN,98" ;

$ConfArray{'TITLEIGNORE'} = "the a of in and from on" ;
$ConfArray{'HISTORY'} = 500 ;
$ConfArray{'HISTORYFILE'} = "$ENV{'HOME'}/.sixpack.his" ;
$ConfArray{'RECENTFILES'} = 5 ;



if( !(-e $CONFFILE) ) { $CONFFILE = $globalCONFFILE ; }      

if( -e $CONFFILE ) {
   my ($name,$value,$line) ;
   open(CONF,$CONFFILE) || die "Can't open $CONFFILE\n" ;
   while( (defined($line=<CONF>) ) ) {
       chomp $line ;
       $line =~ /([^#]*)#?.*/ ;
       $line = $1 ;
       if( $line =~ s/\\\s*$// ) {
       	$line .= <CONF> ;
	redo unless eof(CONF) ;
      }
       if(!( $line =~ /^\s*$/ )) {
         ($name,$value) = split( /\s*=\s*/, $line, 2) ;
         $value =~ s/\n//g ;
	 $value =~ s/\s+$// ;  # new command to remove trailing space
         $ConfArray{$name} = $value ;
       }
   }
   close CONF ;
}


#while (<>) {

#s/#.*//; # remove comment
#next if /^\s*$/; # skip blank lines
#redo if s/\\$// and $_ .= <>; # handle continuations
#
#print;
#}
   
open(PIDF,">".$ConfArray{"PIDFILE"}) ;
print PIDF $$ ;
close PIDF ;

sub myexit
{
   unlink ($ConfArray{"PIDFILE"}) ;
   writeHistory () ;
   print "bye now!\n" ;
}

$SIG{'USR1'} = 'signalImport' ;

my $TMP = $ConfArray{"TMP"} ;
my $CONV = $ConfArray{"CONV"} ;
my $EDIT = $ConfArray{"EDITOR"} ;
my $LESS = $ConfArray{"LESS"} ;
my $MISCHANDLE = $ConfArray{"MISCHANDLE"} ;
my $PICSDIR = $ConfArray{"PICSDIR"} ;


if( !defined($ENV{'BPHOME'}) || $ENV{'BPHOME'} eq "" ) {
    $ENV{'BPHOME'} = $ConfArray{'BPHOME'} ;
}

my (@bpInSupported,@bpOutSupported); 
bpsupport() ;


# Sixten Boeck
# email: boeck@physik.hu-berlin.de
# see:   http://crysta.physik.hu-berlin.de/~boeck

# Modified by Michael Lachmann
# email: dirk@santafe.edu
# see: http://www.santafe/edu/~dirk/sixpack


##############################################################################
##############################################################################
##############################################################################
##############################################################################
# Tk environment

  my $ww = 80;                           #  widget width 
# my $geometry = "887x637";
  my $geometry = "692x729+1+1";
# my $fn = "9x15";                       #  font used for widgets
  my $fn = "7x13";                       #  font used for widgets
 my $sliderWidth = 11;                   #  slider width in pixel
#  my $sliderWidth = 7;                   #  slider width in pixel
  my $background1 = "grey20";            #  
  my $background2 = "#00004f";           #  highlighted item and status bar
  my $background3 = "red4";              #  ERROR background of status bar
  my $background4 = "blue3" ;            #  select 
  my $foreground1 = "blue3";             #
  my $foreground2 = "brown4";            #
  my $foreground3 = "red";               #  required fields
  my $foreground4 = "green4";            #  optional fields
  my $foreground5 = "black";            #  other fields
  my $foreground6 = "yellow";            #  highlighted item and status bar
  my $foreground7 = "white";             #  ERROR foreground of status bar

##############################################################################
# global variables:
#$EDIT   = "vim";  # don't fork editor!!!
#$EDIT   = "gvim -f";  # don't fork editor!!!
# my $EDIT;

my $WINID   = $ENV{'WINDOWID'}; 
#if ($WINID)  {
#	open (INFO, "xwininfo -id $WINID | grep geometry |"); $_=<INFO>; s/\n//g; $EDIT = "gvim -f $_"; close (INFO);
#}


my ( $CITEID ,
     $BIBTYPE,
     $AUTHOR ,
     $TITLE,
     $JOURNAL,
     $VOLUME,
     $NUMBER,
     $PAGES,
     $MONTH,
     $YEAR,
     $KEY,
     $ABSTRACT,
     $NOTE,        
     $EDITOR,    
     $PUBLISHER,
     $SERIES    ,
     $ADDRESS   ,
     $EDITION,
     $CHAPTER,
     $HOWPUBLISHED,
     $BOOKTITLE,
     $ORGANISATION,
     $SCHOOL ,
     $INSTITUTION,
     $TYPE,
     $FILEN, 
     $URL,
     $SOURCEBIB,
     $ANNOTE,
     $CROSSREF,
     $MISC)                              = (0..100) ;
my $MAXFIELDS  = $MISC;   # maximum number of fields in bibtex entries

my $MAXKEYS = $MAXFIELDS;
my ($KEYANY) = (++$MAXKEYS);

my (@TYPES, @KEYS);
( $TYPES[$BIBTYPE],      $TYPES[$CITEID]    ) = ( "Bibtype",      "CiteID"); 
( $TYPES[$AUTHOR],       $TYPES[$TITLE]     ) = ( "Author",       "Title");  
( $TYPES[$JOURNAL],      $TYPES[$VOLUME]    ) = ( "Journal",      "Volume");
( $TYPES[$NUMBER],       $TYPES[$PAGES]     ) = ( "Number",       "Pages");
( $TYPES[$MONTH],        $TYPES[$YEAR]      ) = ( "Month",        "Year");   
( $TYPES[$KEY],          $TYPES[$ABSTRACT]  ) = ( "Keywords",     "Abstract"); 
( $TYPES[$NOTE],         $TYPES[$EDITOR]    ) = ( "Note",         "Editor");
( $TYPES[$PUBLISHER],    $TYPES[$SERIES]    ) = ( "Publisher",    "Series"); 
( $TYPES[$ADDRESS],      $TYPES[$EDITION], $TYPES[$CHAPTER]   ) = ( "Address",  "Edition",    "Chapter");
( $TYPES[$HOWPUBLISHED], $TYPES[$BOOKTITLE] ) = ( "HowPublished","Booktitle"); 
( $TYPES[$ORGANISATION], $TYPES[$SCHOOL]    ) = ( "Organization", "School");   
( $TYPES[$INSTITUTION],  $TYPES[$TYPE]      ) = ( "Institution",  "Type");
( $TYPES[$FILEN],  $TYPES[$URL], $TYPES[$SOURCEBIB] ) = ( "file",  "url", "SourceBibFile");
( $TYPES[$ANNOTE],$TYPES[$CROSSREF],$TYPES[$MISC]             ) = ( "Annote","CrossRef","Miscellaneous");
( $TYPES[$KEYANY] ) = ("All") ;

( $KEYS[$BIBTYPE]     , $KEYS[$CITEID]     , $KEYS[$AUTHOR]      ) = ("bt", "id", "au");
( $KEYS[$TITLE]       , $KEYS[$JOURNAL]    , $KEYS[$VOLUME]      ) = ("ti", "jo", "vo");
( $KEYS[$NUMBER]      , $KEYS[$PAGES]      , $KEYS[$MONTH]       ) = ("nu", "pa", "mo");
( $KEYS[$YEAR]        , $KEYS[$KEY]        , $KEYS[$ABSTRACT]    ) = ("yr", "kw", "ab");
( $KEYS[$NOTE]        , $KEYS[$EDITOR]     , $KEYS[$PUBLISHER]   ) = ("no", "ed", "pu");
( $KEYS[$SERIES]      , $KEYS[$ADDRESS]    , $KEYS[$EDITION], $KEYS[$CHAPTER]     ) = ("se", "ad", "en", "ch");
( $KEYS[$HOWPUBLISHED], $KEYS[$BOOKTITLE]  , $KEYS[$ORGANISATION]) = ("hp", "tb", "or");
( $KEYS[$SCHOOL]      , $KEYS[$INSTITUTION], $KEYS[$TYPE]        ) = ("sc", "in", "ty"); 
( $KEYS[$FILEN], $KEYS[$URL],$KEYS[$SOURCEBIB]                   ) = ("fi","ur","sb");
( $KEYS[$ANNOTE], $KEYS[$CROSSREF], $KEYS[$MISC]                 ) = ("an","cr","mi");
( $KEYS[$KEYANY] ) = ( "al") ;

my @FIELDS = (0..$MAXFIELDS) ;

$FIELDS[$KEYANY] = join( ",",(0..$MAXFIELDS)) ;

my @EntryFields = ( $CITEID, $BIBTYPE, $JOURNAL, $VOLUME, $NUMBER, $PAGES, $MONTH,
                    $YEAR, $EDITION, $CHAPTER, $HOWPUBLISHED, $BOOKTITLE, $ORGANISATION,
		    $SCHOOL, $INSTITUTION, $TYPE,$FILEN,$URL,$SOURCEBIB,$CROSSREF) ;

my @TextFields = ( $TITLE, $AUTHOR, $KEY, $ABSTRACT, $NOTE,$ANNOTE, $EDITOR, $SERIES, $ADDRESS, $MISC,$PUBLISHER) ;
my @FieldsH ;
( $FieldsH[$TITLE], $FieldsH[$AUTHOR], 
  $FieldsH[$KEY], $FieldsH[$ABSTRACT], $FieldsH[$NOTE],$FieldsH[$ANNOTE], 
  $FieldsH[$EDITOR], $FieldsH[$SERIES], $FieldsH[$ADDRESS], 
  $FieldsH[$MISC],$FieldsH[$PUBLISHER]) =
  ( 4,       2,    
    2,         8,     7,      7,       
    2,       2,        3,     
    2,         2);
						 
my @WidgetOrder = (	 $BIBTYPE,	  
                         $CITEID,       
			 $AUTHOR,
	                 $TITLE,	     
			 $JOURNAL,	  
			 $YEAR,
			 $VOLUME,
			 $NUMBER,	     
			 $PAGES,	     
			 $MONTH,
			 $ABSTRACT,
			 $NOTE,	
			 $ANNOTE,         
			 $KEY,	 
			 $CROSSREF,
			 $FILEN, 
			 $URL,
			 $MISC,   
			 $EDITOR,
			 $PUBLISHER,
			 $SERIES,	      
			 $ADDRESS,	
			 $EDITION,
			 $CHAPTER,
			 $HOWPUBLISHED, 
			 $BOOKTITLE,   
			 $ORGANISATION,
			 $SCHOOL,	     
			 $INSTITUTION, 
			 $TYPE ,
			 $SOURCEBIB ) ;

#	print join(", ", @WidgetOrder ) ;

my %revKEYS ;



##############################################################################
##############################################################################
#########   program source code starts here  #################################
##############################################################################
##############################################################################

use File::stat;

use strict;
use Tk;
#use Tk::Xrm;
require Tk::Dialog ;
require Tk::DialogBox ;
require Tk::FileSelect;
require Tk::Text;
require Tk::After;
require Tk::Balloon;


unshift(@INC, $ENV{'BPHOME'})  if defined $ENV{'BPHOME'};
require "bp.pl";
require "bp-cs-tex.pl" ;
require "bp-cs-8859-1.pl" ;


my @bib;                   # -  List contains bibtex entries without any newline character
my @Lol=();                   # -  List of list, bibtex entries
my @LoM;                   # -  List of matches, contains id numbers of matching entries
my @LonM;                  # -  List of matches: numbers of matching entries
my @LoMCmdLn;              # -  List of matches: command line strings
my @queryList;             # -  List of splitted query commands (a and b --> [a, b, and])
my @selectList;            # -  List of selected entries (0 or 1)
my $nSelected;             # -  number of selected entries
my @cmdln;                 # -  history of commands
my @idx;                   # -  indexlist, used for sorting 
my $match;
my $entry;                 # -  id of entry
my $lastMatch;             # -  used in evalQueryList
my $databaseName;          # - name of current database

my $SixSelection = "" ;

my $sortBeforeSave = 0 ;

my %databases ;      # currently open databases, and their types.
my %databaseModified  ;

my $ui;
my ($history) = (0);

my ($logWinView) = (0) ;

my ($importhtml, $importselection) = (0,0) ;

my $curFileSelectDir = "." ;


sub mod ($$)
{
	my ($a, $b) = @_;
	my $c;
	$c = sprintf ("%d", $a / $b);
	return ($a == $b * $c);
}


sub findhome
{
  my $cwd = Cwd::getcwd() ;
  chdir( $ENV{'HOME'} ) ;
  $home = Cwd::getcwd() ;
  chdir( $cwd ) ;
}     
sub initDatabase
{
#	splice (@bib,  0);
	splice (@Lol,  0);
	splice (@LoM,  0);
	splice (@LonM, 0);
	splice (@LoMCmdLn, 0);
	splice (@queryList, 0);
	splice (@selectList, 0);
	$nSelected = 0; $match = 0; $entry = 0; $lastMatch = 0;
	undef %databaseModified ;
	undef %databases ;
	$databaseName = "" ;
}

sub getMiscField
{
   my ($contents) = @_;
	my (@list, $i, $tmp, $res);
   $res = $tmp = "";
	$$contents =~ s/\n\s*\n/\n/g;           # remove empty lines
	$$contents =~ s/^\s*\@\w*\s*\{\s*\w*\s*,//;                # remove bibtype
#   $$contents =~ s/\w+\s*,//g;             # remove bib id
	$$contents =~ s/(.*)}\s*$/$1/g;         # remove last '}' parenthesis
	while ($$contents =~ s/^\s*\n//g)  {};  # remove empty lines
	$$contents =~ s/,\s$//g;                #remove last comma
	while ($$contents =~ s/!#!#!/\\"/g) {} ; # replace <SHIFT>-<13131> with \";
	return $$contents;
}


####
# find matching closing braket }. returns two strings, the part inside the brakets,
# and the part after the closing braket.
sub matchingB 
{
   my ($str) = @_ ;
   my $rstr = "" ;
   my ($s1, $s2, $s3, $rest) ;
   if( $str =~ /^([^{}]*)[{]([.\n])*/ )  {
     $s1 = $1 ;
     ($s2, $rest) = matchingB($2.$') ; #'
     ($s3, $rest) = matchingB($rest) ;
     return ($s1."{".$s2."}".$s3,$rest) ;
   } elsif ( $str =~ /^([^{}]*)[}]([.\n]*)/ ) {
     return ($1,$2.$') ; #'
   }
}



sub getField
{
	my ( $field, $contents ) = @_; 
   my ($res, $rest, $s1,$s2,$s3);

	$$contents =~ s/\\"/!#!#!/g;       # replace \" with <SHIFT>-<13131>
#   $$contents =~ s/}\s*\n\s*}\s*$/},\n}/g;  # append comma to last '}'
#   $$contents =~ s/([^\s,}])\s*\n\s*}\s*$/$1,\n}/g;  # append comma to last '}'   
#   $$contents =~ s/([^\s,}])\s*\n\s*}\s*$/$1,\n}/g;  # append comma to last '}'      

   # FIELD = "blablabla",
	if ( $$contents =~ /\b($field)\s*=\s*"/i ) {
	    $$contents =~ /\b($field)\s*=\s*"([^"]*)"\s*,?/i   ;
		$res = $2;
		$$contents = "$`$'"; 
	}
   # FIELD = {blab{la}bla},
     	elsif ( $$contents =~ /\b($field)\s*=\s*{/i )  {
	                ($s1,$s2) = ($`,$') ;         #'
			($res,$s3) = matchingB($s2) ;
			$res = $res ;
			$s3 =~ /^[\s\n]*,?/ ;
			$s3 = $';        #'
			$$contents = $s1 . $s3;
      }  
#     	elsif ( $$contents =~ /.*\b($field)\s*=\s*{(.*?)}\s*,/i )  {
#			$res = $2;          
#			$$contents = "$`$'";
#			$res =~ s/}\s*,.*//g;
#			$res =~ s/\n/ /g;
#     }  
	# FIELD = 15,
	   elsif ( $$contents=~ /\b($field)\s*=\s*(\d+)\s*,/i )    {
	      $res= $2;
			$$contents = "$`$'";
      }
	# FIELD = abc,
	   elsif ( $$contents=~ /\b($field)\s*=\s*([^,\n{}"]+)\s*,?/i )    {
	      $res= $2;
			$$contents = "$`$'";
      }
	   else  {
		   $res= "";
		 }
#	$res =~ s/"|{|}//g;      
	$res =~ s/\s*\n\s*/\n/g;
	$res =~ s/^\s*//g;
	$res =~ s/\s*$//g;
	
	$res =~ s/!#!#!/\\"/g;  # replace <SHIFT>-<13131> with \";

	return $res;
}


sub getDBField
{
	my ( $field, $contents ) = @_; 
   my $res = "";

   $$contents =~ s/}\n\s*}/},\n}/sg;  # append comma to last '}'
	
   # FIELD = {blablabla}
   if ($$contents =~ /.*\b($field)\s*=\s*{(.*?)}\s*,/i )  {
		$res = $2;          
		$$contents = "$`$'";
		$res =~ s/}\s*,.*//g;
#		$$contents =~ s/\s*\b$field\s*=\s*{.*?[}]\s*,//sg;      # remove field

	$res =~ s/^\s*//g;
	$res =~ s/\s*$//g;

		$res =~ s/\s+/ /g;        
	}
	return $res;
}

sub bpsupport
{
    open (FILE, "$ConfArray{'GREP'} \"\'explode\" $ConfArray{'BPHOME'}/bp-*pl|" ) ;
    my (@inlist, @outlist) ;
    while(<FILE>) {
      chop ;
      my ($file,$line) = split(":",$_,2) ;
      next if ( $line =~ /^\s*\#/ ) ;
      next if ( $line =~ /unsupported/ ) ;
      next if ( $line =~ /unimplemented/ ) ;
      $file =~ s/(.*\/bp-)([^\/]*)\.pl/$2/ ;
      next if ( $file eq "bibtex" ) ;      
      push (@inlist, $file) ;
      
    }
    open (FILE, "$ConfArray{'GREP'} \"\'implode\" $ConfArray{'BPHOME'}/bp-*pl|" ) ;
    while(<FILE>) {
      chop ;
      my ($file,$line) = split(":",$_,2) ;
      next if ( $line =~ /^\s*\#/ ) ;
      next if ( $line =~ /unsupported/ ) ;
      next if ( $line =~ /unimplemented/ ) ;
      $file =~ s/(.*\/bp-)([^\/]*)\.pl/$2/ ;
      next if ( $file eq "bibtex" ) ;      
      push (@outlist, $file) ;
      
    }
    @bpInSupported = @inlist ;
    @bpOutSupported = @outlist ;
}

##############################################################################
# read a bibtex file
# usage:
#       readBibTexFile ("file.bib");
# manipulated global variables: 
#       @bib, @Lol, @LoM, @LoMCmdLn, @queryList, @selectList
#       $match, $entry, $lastMatch

sub readBibTexFile
{
	my $i=-1;
	my $empty =0;
	my ($file, $type) = @_;
	my $s1 ;
	if( !defined($type) ) { $type = "";}
	my (@bibtype, @citeid);
	splice (@bib,  0);
	
	if( $#Lol <= 0 ) { $empty = 1 ;}
	my ($nEntries, $percent);
	my $madebysixpack = 0 ;
	my $fileread = 0 ;
	my $brefname ="";
	$file =~ s/\n//g;
	if (-e "$file")  { 
		open (INFILE, "<$file") ;
		if( $ConfArray{'BIBWITHBREF'} eq "1" ) {		
		  while( <INFILE> ) {
		    if( /^\s*%\s*Sixpack/ ) {
			$madebysixpack = 1 ;
		    }
		    if( /^\s*%\s*Corresponding\s+sixpack\s+database:\s+(.*)\s*$/ ) {
		   	$brefname = $1 ;
			last ;
		    }
		    if( !( (/^\s*%/) || (/\s*/)) ) {
		   	last ;
		    }
	          }
		  close(INFILE) ;
		if( ($madebysixpack == 1) && (-e $brefname) ) {
		       print "checking dates....\n" ;
		       my $bibtime = stat($file)->mtime;
		       my $sixtime = stat($brefname)->mtime;
		       if( $sixtime >= $bibtime ) {
		          print "loading bref\n" ;
		          readRefFile( $brefname ) ;
			  $fileread = 1 ;
		       }
		}
		}
		if( $fileread == 0 ) {
		open (INFILE, "<$file") ;
		$nEntries = getFileEntries ($file);
		$nSelected = 0; $match = 0; $entry = 0; $lastMatch = 0;
		while (<INFILE>)  {
			next if ( /^\s*\n/ );  #skip empty lines
			next if ( /^\s*%/ );
			next if ( /setting\s*options/ ) ; #skip retun from bp
                        $_ =~ s/\cM\n/\n/g; # Convert dos line endings to unix
			                    # Chris Kuklewicz
			$s1 = $_ ;
			if ( /@([^{]*){/ )  {
				$i++;
				$bib[$i] = "";
				$bibtype[$i] = $1;
				if( lc($bibtype[$i]) eq "string" ) {
				  $citeid[$i] = "" ;
				  $s1 = $' ; #'
				} else {
				  $citeid[$i]  = $';  #'
				  $citeid[$i] =~ s/[\n,]//g ;
#				  chop($citeid[$i]);  # chop newline
#				  chop($citeid[$i]);  # chop comma
				  $s1 = "" ;
				}				
				if (mod ($i, 50))  {
					$percent = 100 * $i / $nEntries;
					$percent = sprintf ("%d", $percent);
					printStatus ("BUSY", "Loading $i of $nEntries ($percent%)");
				}
				
			}
			$s1 = bp_cs_tex'tocanon($s1,0) ;
			$s1 = bp_cs_88591'fromcanon($s1,0) ;
			if( $i > -1) {$bib[$i] = $bib[$i] . $s1;}
		}
		close (INFILE);
		parseTexFile (\@bibtype, \@citeid, $nEntries, $type,$file);
		}
	}  else  {
			print "file '$file' doesn't exist!\n";
		return 0;
	}
	if( $empty == 1 ) { 	deselectEntries ("all"); print "database was empty!\n"; }
	return 1;
}


##############################################################################
# read a sixpack format file
# usage:
#       readRefFile ();
# manipulated global variables:
#       @bib, @Lol, @LoM, @LonM, @LoMCmdLn, @QueryList, @selectList
#       $match, $entry, $lastMatch
#
sub readRefFile
{
	my ($file)  = @_;
	my ($i, $elem, $found);
	my (@buf, @list, @fbuf, $tmp, @SrchList);
	my ($res, $nEntries, $percent);
	my (@fkeys, @rkeys) ;
	my $version ;


        $elem = 0;
	$file =~ s/\n//g;
	if (-e "$file")  
	{ 
		open (INFILE, "<$file");
		($nEntries) = <INFILE> =~ /entries:\s*(\d+)/i;
		($version) = $' =~ /version:\s*(\d+)/i;
		if( !defined($version) ) {$version = "0.0" ;}
		@fkeys = split( ",", <INFILE> ) ;
		$fkeys[$#fkeys] =~ s/\n//g ;
		my @order = 0 x $MAXFIELDS;
		for( $i = 0; $i <= $#fkeys; $i++) {
		     $order[  $revKEYS{ $fkeys[$i] } ] = $i ;
		}
		while (<INFILE>)  {
		        s/<par>/\n/g ;
			@fbuf = split( /\x000/ ) ;
			if ($#fbuf == $#fkeys)  
			{ 
				@buf = @fbuf[@order] ;
				if( $version < "1.0" ) {
				  for( $i=0; $i<=$#buf; $i++) {
				      $buf[$i] = bp_cs_tex'tocanon($buf[$i],0) ;
				      $buf[$i] = bp_cs_88591'fromcanon($buf[$i],0) ;
				  }
				}
                                $buf[$SOURCEBIB] = $databaseName ;
				push @Lol, [ @buf ];
				$elem++;
				if (mod ($elem, 100) || $elem == $nEntries)  {
					$percent = 100 * $elem / $nEntries;
					$percent = sprintf ("%d", $percent);
					printStatus ("BUSY", "Loading $elem of $nEntries ($percent%)");
				}
			} else {
		  	@fbuf = split (/#/);
			if ($#fbuf == $#fkeys)  
			{ 
			        @buf = ("") x $MAXFIELDS ;
			        for( $i=0; $i <=$#fkeys; $i++ )
				{
				  $fbuf[$i] =~ s/<par>/\n/g ;
				     $buf[ $revKEYS{ $fkeys[$i] } ]  = $fbuf[$i] ;
				}
				$buf[$SOURCEBIB] = $databaseName ;
				push @Lol, [ @buf ];
				$elem++;
				if (mod ($elem, 50) || $elem == $nEntries)  {
					$percent = 100 * $elem / $nEntries;
					$percent = sprintf ("%d", $percent);
					printStatus ("BUSY", "Loading $elem of $nEntries ($percent%)");
				}
			} 			  }
			  
		}
		close (INFILE);
		initIdx ();
		
	}  
	else  
	{
		print "file '$file' doesn't exist!\n";
		return 0;
	}
	printStatus ("OK", "Done.");
	deselectEntries ("all");
	return 1;
}

sub openRefFile
{
    my ($file,$Act) = @_ ;
    if( defined( $databases{$file} ) ) {
      if( !closeDatabase($file) ) {
        return 0;
      }
    }
    if( (!defined($Act) || !($Act eq "new")) && (-e $file) ) {
#      initDatabase() ;
      printStatus("BUSY","Loading file '$file'.") ;
      $databaseName = $file ;
      $databases{$file} = "sixtex" ;
      readRefFile ($file) ;
      unModify($file);
       return 1;
    } 
    else {
      $databaseName = $file ;
      $databases{$file} = "sixtex" ;
      unModify($file);
      printStatus("INFO","Created new database '$file'.") ;
      return 1 ;
    }
}

sub openBibFile
{
    my ($file,$Act) = @_ ;
    if( defined( $databases{$file} ) ) {
      if( !closeDatabase($file) ) {
        return 0;
      }
    }
    if( (!(defined($Act) && ($Act eq "new"))) && -e $file ) {
#      initDatabase() ;
      printStatus("BUSY","Loading file '$file'.") ;
      $databaseName = $file ;
      $databases{$file} = "bibtex" ;
      readBibTexFile ($file) ;
      unModify($file);
#      $databaseModified{$file} = 0 ;
    } else {
      $databaseName = $file ;
      $databases{$file} = "bibtex" ;
      unModify($file);
      printStatus("INFO","Created new database '$file'.") ;
      return 1 ;
    }
    return 1;
}

sub mergeRefFile
{
    my ($file) = @_ ;
    if( -e $file ) {    
      printStatus("BUSY","Loading file '$file'.") ;
      readRefFile ($file) ;
      Modify($databaseName);
#      $databaseModified{$databaseName} = 1 ;
      updateHistory("merge $file") ;    
    } else {
      printStatus("ERROR","File '$file' does not exist.") ;
    }
}

sub selectDatabase
{
   my ($f) = @_ ;
   my @temp ;
   my $i ;
   @temp = searchEntries( $SOURCEBIB, $f ) ;
   @selectList = (0) x $#Lol ;
   foreach $i (@temp) { $selectList[$idx[$i]] = 1 ; }
   $nSelected = $#temp+1 ;
}

sub saveDatabaseByName
{
   my ($f,$saveS) = @_ ;
   my @temp1 ;
   my @temp2 ;
   my ($n,$i);
   if( $saveS ) {
     @temp1 = @selectList ;
     $n = $nSelected ;
   }
   selectDatabase($f) ;
   if( $databases{$f} eq "bibtex" ) {
     saveBibFile($f) ;
   } else {
     saveRefFile($f,"selected") ;
   }
      unModify($f);
#   $databaseModified{$f} = 0 ;
   if( $saveS ) {
      @selectList = @temp1 ;
      $nSelected = $n ;
   }
}

sub newDatabase
{
   my $i ;
   foreach $i ( keys(%databases) ) {
       if( !closeDatabase($i) ) {
          return 0;
       }
   }
   initDatabase ();	
   return 1 ;
}

sub writeCollection
{
   my ($file) = @_ ;
   open(FILE,">$file") ;
   my $k ;
   foreach $k (keys(%databases)) {
     if( $databases{$k} eq "bibtex" ) {
       print FILE "bibopen $k\n" ;
     } elsif ( $databases{$k} eq "sixtex" ) {
       print FILE "open $k\n" ;
     }
   }
   close (FILE) ;
}

sub saveAllDatabases
{
    my ($force) = @_;
    my @db = keys(%databases) ;
    my $f ;
    my @temp1 = @selectList ;
    my $n = $nSelected ;
    foreach $f (@db) {
      if( ($force==1) || $databaseModified{$f} ) {
        saveDatabaseByName( $f, 0 ) ;
      }
    }
    @selectList = @temp1 ;
}
	   
sub closeDatabase
{
   my ($f,$force) = @_ ;

   if( $ui eq "gui" && $databaseModified{$f} && $force ne "force")  {
      if( askYesNo("Database $f modified! Close anyway?","No") ) { $force = "force";}
   }				     


   if( $force eq "force" || !$databaseModified{$f} ) {
     my @temp1 = @selectList ;
     my $n = $nSelected ;
     selectDatabase($f) ;
     deleteEntries() ;
     delete $databases{$f} ;
     delete $databaseModified{$f} ;
     $nSelected =  0 ;
     @selectList = (0) x $#Lol ;
     return 1 ;
   } else {
     printStatus ("ERROR","Database $f modified. Save or force close.") ;
     return 0 ;
   }
}


##############################################################################
# save entries in sixpack format
# usage: 
#       saveRefFile ();
# global variables (no manipulation):
#       @Lol
#
sub saveRefFile 
{
        my $SAVEREFVERSION = "1.0" ;
	my ($file, $method) = @_;
	my ($string, $input, @list); 
	my ($i, $j, $nEntries, $elem, $percent);
	rename($file, "$file" . $ConfArray{'BACKUPEXT'});
	$file =~ s/\n//g;
	open (OUTFILE, ">$file")  || die "can't open file $file\n";
	$nEntries = $#Lol+1;
	$elem = 0;
	if ($method eq "all")  {
		print OUTFILE "Number of entries: $nEntries version: $SAVEREFVERSION\n";
		print OUTFILE "$KEYS[0]" ;
		for ( $i=1; $i<=$MAXFIELDS; $i++) {
                       print OUTFILE ",$KEYS[$i]" ;
		}
		print OUTFILE "\n";
		for ($i=0; $i<=$#Lol; $i++)  {
			splice (@list, 0);
			for ($j=0; $j<=$MAXFIELDS; $j++)  { push @list, $Lol[$idx[$i]][$j]; }
			$list[$SOURCEBIB] = "" ;

			$string = join ("\x000", @list) ;
			$string =~ s/\n/<par>/g ;
			$string .= "\n";

			print OUTFILE $string;
			$elem++;
			if (mod ($elem, 50) || $i == $#Lol)  {
				$percent = 100 * $elem / $nEntries;
				$percent = sprintf ("%d", $percent);
				printStatus ("BUSY", "Saving $elem of $nEntries ($percent%)");
			}
		}
		$databaseName = $file ;
		unModify($file);
#		$databaseModified{$file} = 0 ;
	}  else  {  # only save marked entries
		print OUTFILE "Number of entries: $nSelected\n";
		print OUTFILE "$KEYS[0]" ;
		for ( $i=1; $i<=$MAXFIELDS; $i++) {
                       print OUTFILE ",$KEYS[$i]" ;
		}
		print OUTFILE "\n";
		for ($i=0; $i<=$#Lol; $i++)  {
			next if ( $selectList[$idx[$i]] == 0);
			splice (@list, 0);
			for ($j=0; $j<=$MAXFIELDS; $j++)  {
				push @list, $Lol[$idx[$i]][$j]; 
			}

			$string = join ("\x000", @list) ;
			$string =~ s/\n/<par>/g ;
			$string .= "\n";

			print OUTFILE $string;
			$elem++;
			if (mod ($elem, 50) || ($i == $#Lol))  {
				$percent = 100 * $elem / $nSelected;
				$percent = sprintf ("%d", $percent);
				printStatus ("BUSY", "Saving $elem of $nSelected ($percent%)");
			}
		}
   }
	printStatus ("OK", "Done.");
	close (OUTFILE);
}

sub niceformat
{
	my ($name,$vall) = @_ ;
	my $str ;
	$vall =~ s/^(\s\n)*//g ;
	$vall =~ s/(\s\n)*$//g ;
	if( $vall =~ /^\w+$/ ) {
	    if( length($name) > 18 ) {
		$str = $name . " " ;
	    } else {
		$str = $name . " " x 20 ;
		$str = substr( $str,0,19) . " ";
	    }
	    return "$str= $vall" ;
	}
	my @pars = split( /(\s*\n+\s*)+/, $vall ) ;
	my @words ;
	my $word ;
	my $par ;
	my $line ;
	my @lines ;
	foreach $par (@pars) {
		@words = split( /\s+/, $par ) ;
		while( $#words >= 0
		     ) {
		     $line = shift( @words ) ;
		     while( length($line) < 55 ) {
		        last if( $#words < 0 
			       ) ;
		     	$line = $line . " " . shift( @words ) ;
		     }
		     push( @lines, $line ) ;
		}
	}	
        my ( $s) ;
	if( length($name) > 18 ) {
		$str = $name . " = { " ;
	} else {
		$str = $name . " " x 20 ;
		$str = substr( $str,0,19) . " = { ";
	}
	$s = "\n". (" " x 24) ;
	$str .= join( $s, @lines ) . " }" ;
   	return $str ;
}	

sub niceformatold
{
    my ($name,$vall) = @_ ;
#    if( length($vall) <= 75 ) {
# Still has problems with @string... don't know what to do.
#        if( $vall =~ /[ -]/ ) {
#   	  return " " . $name." = { ".$vall ."}";
#	} else {
#	  return $name." = ".$vall ;
#	}
#    }
    my ($str, $s) ;
    $str = "" ;
    $s = " " x 20 ;
    $s = " " . $name . " =" . $s ;
    
    $s = substr( $s, 0, 19 ) . "{" ;
    my $val ;
    my @vals = split( /(\s*\n+\s*)+/,$vall ) ;
    foreach $val ( @vals ) {
      my @words = split( /\s+/, $val ) ;
      
      while( $#words 
	     > 0 ) {  
        $s = $s . " " . shift( @words ) ;
	if( length($s) >= 75 ) {
	  if( $#words > 0 ) {
            if( $str ne "" ) {
	      $str = $str . "\n" . $s ;
            } else {
	      $str = $str . $s ;
            }
            $s = " " x 20 ;
	  }
	  else { 
            if( $str ne "" ) {
	      $str = $str . "\n" . $s ;
            } else {
	      $str = $str . $s ;
            }
            $s = " " x 20  ;
	  }
	}
      }
      if( $str ne ""  ) {
	$str = $str . "\n" . $s ;
      } else {
	$str = $str . $s ;
      }
      $s = " " x 20 ;
    }
    $str = $str . " }" ;
    $str =~ s/\n\s*}/}/g ;
#    $str =~ s/\n\s*}\s*^/}/gi ;
    return $str ;
}


sub saveBibFile
{
	my ($file) = @_;
	my ($brefname);
	my ($i, $j, $types);
	my ($elem, $nEntries, $percent);
	my ($name, $date);
	my $s ;
	my $printed = 0 ;
	open (OUTFILE, ">$file")  or die "can't open file $file\n";
	$name = getUID ();   chop $name ;
	$date = getDate ();  chop $date ;

        if( $sortBeforeSave ) {
	  sortIdxForSave() ;
	}

	print OUTFILE "% Sixpack $VERSION\n";
	print OUTFILE "% Bibliography: $file\n";
	if( $ConfArray{'BIBWITHBREF'} == 1 ) {
		print OUTFILE "% Corresponding sixpack database: $file.bref\n" ;
	}
	print OUTFILE "% created by $name on $date\n";
        if( $nSelected == 0 ) {  	$nEntries = $#Lol+1;}
        else {      	$nEntries = $nSelected;  } 
	print OUTFILE "% #entries: $nEntries $nSelected\n%\n";
	$elem = 0;
	for ($i=0; $i<=$#Lol; $i++)  {
	    if( $nSelected == 0 || $selectList[$idx[$i]] == 1) {
		print OUTFILE "\@$Lol[$idx[$i]][$BIBTYPE]\{$Lol[$idx[$i]][$CITEID]";
		if(  $Lol[$idx[$i]][$CITEID] =~ /^\s*$/ ) {
		  $printed = 0 ;
		} else {
		  $printed = 1 ;
		}
		for ($j=$AUTHOR; $j<=$MAXFIELDS-1; $j++)  {  # don't save miscellaneous field
			if ( $Lol[$idx[$i]][$j] ne "" && $j != $SOURCEBIB)  {
 			  if( $printed) {
			    print OUTFILE ",\n" ;
			  } else {
			    print OUTFILE "\n" ;
			  }
			  $types = lc ($TYPES[$j]);
			  $s = $Lol[$idx[$i]][$j] ;
#			$s = bp_cs_88951'tocanon($s,1) ;
			$s = bp_cs_tex'fromcanon($s,0) ;
			  
			  print OUTFILE niceformat($types,$s);
			  $printed = 1 ;
			}
		}
		if (! ($Lol[$idx[$i]][$MISC] =~ /^[\s\n]*$/))  { 
		if( $printed) {
		   print OUTFILE ",\n" ;
		 } else {
		   print OUTFILE "" ;
		 }
		print OUTFILE "\t$Lol[$idx[$i]][$MISC]\n"; 
		}
		else { print OUTFILE "\n" ; }

		print OUTFILE "\}\n\n";
		$elem++;
		if (mod ($elem, 50) || $i == $#Lol)  {
			$percent = 100 * $elem / ($#Lol+1);
			$percent = sprintf ("%d", $percent);
			printStatus ("BUSY", "Writing $elem of $nEntries ($percent)");
		}
	    }
	}
	printStatus ("OK", "Done.");
	close (OUTFILE);
	if( $ConfArray{'BIBWITHBREF'} eq "1" ) {
		$brefname = $file.".bref" ;
	         saveRefFile($brefname,"selected") ;
	}
}

sub signalImport
{
    my $pid = $$ ;
     open(FTYPE, $TMP."-sig-".$pid) ;
     my $type = <FTYPE> ;
     $type =~ s/\n.*// ;
     close FTYPE ;
     open(FTYPE, ">".$TMP."-sig-".$pid) ;
     print FTYPE "workinging" ;
     close FTYPE ;

     my @arglist = split(/\#\#/,$type) ;
     my $rpid = pop @arglist;

     my $command = join(" ",@arglist) ;

     if( execCommand( $command) == 1 ) {
        updateHistory ($command);
	if( defined($rpid) && ($rpid > 0) ) {
	  kill 'USR1', $rpid ;
	}
	if( $ui eq "gui" ) {
          displayTitles ();
	  displayMarkCB ("all");
	  Modify($databaseName);
	}
     } else {
       open(FTYPE, ">".$TMP."-sig-".$pid) ;
       print FTYPE "command $command not found!" ;
       close FTYPE ;
       kill 'USR2',$rpid ;
     }
       
}
        

sub importFile 
{
	my ($type, $file) ;
	my ($string, $nElem);
	my $html = $importhtml ;
	$nElem = $#Lol;
	if ($ui eq "cmd")  {
		$type = $1; $file = $2;
		if ($2 eq "")  {
			$file=$1;
			print "filter={bibtex, simple[bibtex], refer, endnote, tib, procite, rfc1807,\n";
			print "        text, cstra, inspec, medline, melvyl ieee, powells     back}\n";
			print "import> ";
			$type = <>;	chop $type;
			if ($type =~ /back/)  { return; }
		}
	}  else  {
	   $file = shift;
		$type = shift;
	}
        if( defined( $ConfArray{'WGET'} ) && $ConfArray{'WGET'} ne "" && defined($file) && $file =~ /\w+:\/\// ) {
           $file =~ /\s*(\w+:\/\/.*)\s*/ ;
	   my $url = $1 ;
	   system($ConfArray{'WGET'} . " -q -O " . $TMP . "-url \"" . $url . "\"") ;
	   $file = $TMP . "-url" ;
	}
   if  ($type eq "simplebibtex" || $type eq "simple")  {
		readBibTexFile ($file, "simplebibtex");
   }  else  {
		system ("touch $TMP-file.log; ". $ConfArray{"RM"} . " $TMP-file.log");
		printStatus ("INFO", "Converting $type to simple bibtex...");
		if( $type eq "bibtex" ) {
		  $string = "$CONV -inopts=html=$html -inopts=complex=0 -format=$type,bibtex $file > $TMP-file.bib 2> $TMP-file.log";
		} elsif( $type eq "crosbibtex" ) {
		  $string = "$CONV -inopts=html=$html -inopts=complex=0 -inopts=crossref=1 -format=$type,bibtex $file > $TMP-file.bib 2> $TMP-file.log";		
		} else {
		  $string = "$CONV -inopts=html=$html -format=$type,bibtex $file > $TMP-file.bib 2> $TMP-file.log";
		}
                system ($string);
		open (LOGF, "$TMP-file.log") ;
		my @log = (<LOGF>) ;
		close LOGF ;
		printLOG("INFO",join('',@log)) ;
		printStatus ("INFO", "Parsing bibtex...");
		readBibTexFile ("$TMP-file.bib", "simple");
		unlink "$TMP-file.bib" ;
#		system ($ConfArray{"RM"} . " $TMP-file.log; " );
		# . $ConfArray{"RM"} . " $TMP-file.bib");
	}
	if( $file eq $TMP."-url" ) {
#	  unlink $file ;
	}
	$nElem = $#Lol - $nElem ;
	printStatus ("INFO", "$nElem items converted, included and selected.");
}

sub exportFile 
{
	my ($type, $file);
	my ($string, $nElem);
	$nElem = $#Lol + 1;
	if ($ui eq "cmd")  {
		$type = $2; $file = $1;
		if ($2 eq "")  {
			$file=$1;
			print "filter={bibtex, refer, endnote, tib, procite, rfc1807, text\n";
			print "        cstra, inspec, medline, melvyl ieee, powells   back}\n";
			print "export> ";
			$type = <>;	chop $type;
			if ($type =~ /back/)  { return; }
		}
	}  else  {
	   $file = shift;
		$type = shift;
	}
   if ($type eq "bibtex" || $type eq "simple")  { 
		saveBibFile ($file, "bibtex");
	}  else  {
#      saveBibFile ("$TMP-$file.bib");
      saveBibFile ("$TMP-file.bib");      
      rename($file,"$file" . $ConfArray{'BACKUPEXT'});
	$string = "$CONV -inopts=complex=0 -format=bibtex,$type $TMP-file.bib -to $file 2> $TMP-file.log";
		system ($string);
		open (LOGF, "$TMP-file.log") ;
		my @log = (<LOGF>) ;
		close LOGF ;
		printLOG("INFO",join('',@log)) ;
	}
	unlink "$TMP-file.bib" ;
	unlink "$TMP-file.log" ;
	if( $nSelected > 0 ) {
	  printStatus ("INFO", "$nSelected entries exported.");
	} else {
	  printStatus ("INFO", "$nElem entries exported.");
	}
}


sub getDate
{
  require "ctime.pl";
  return ctime(time) ;
}

sub getUID
{
  if( !defined($ConfArray{'USERNAME'}) ) {
    my $user = $ConfArray{'USER'};
    my @e = getpwnam( $user ) ;
    return $e[6] ;
  } else {
    return ConfArray{'USERNAME'} ;
  }
}
	

sub getFileEntries
{
	my ($file) = @_;
	printStatus ("BUSY", "counting for entries.");
	open (WC, $file) ;
	my $e = 0 ;
	while( <WC> ) {
	  if( /^\s*@/ ) { $e++; }
	}
	close WC ;
	return $e ;
}


##############################################################################
# add a new entry - command line version
# usage:
#       addEntryCmdLn ($string); $string = "journal", "book",...
# manipulated global variables:
#       @Lol
#
sub addEntryCmdLn
{
	my ($type);
	my ($required, $optional, $other, @tmpList, $i, $str);
   my (@buf, $field);
	if ($1 eq "")  {
		print "type={article, book, inbook, booklet, conference, incollection\n";
		print "      proceedings inproceedings manual, masterthesis, phd-thesis\n";
		print "      rechreport unpublished miscellaneous string     back}\n";
		print "add> ";
		$type = <>; chop $type;
		if ($type =~ /back/)  { return; }
	}  else  { $type = $1; }
	
	($required, $optional, $other) = getEditFields ($type);
   $str =        "############################################################\n";
   $str = $str . "# Add new '$type' entry.\n";
   $str = $str . "# Please fill in all required fields.\n";
   $str = $str . "# You can use comma separated lists where appropriate.\n";
   $str = $str . "#\n";
   foreach $i (@$required)  {
     if( $i == $BIBTYPE ) {
       $str = sprintf ("%s# %-14.13s (required)\n%s\n", $str, $TYPES[$i],$type);
     } else {
       $str = sprintf ("%s# %-14.13s (required)\n\n", $str, $TYPES[$i]);
     }
   }
   foreach $i (@$optional)  { $str = sprintf ("%s# %-14.13s (optional)\n\n", $str, $TYPES[$i]); }
   foreach $i (@$other)     { $str = sprintf ("%s# %-14.13s (other)\n\n", $str, $TYPES[$i]); }
  
   open (OUTFILE, ">$TMP-ref.biblio")  || die "can't open file $TMP-ref.biblio\n";
   print OUTFILE "$str";
   close (OUTFILE);
   
   system ("$EDIT $TMP-ref.biblio");
  
   @buf = ("") x $MAXFIELDS ;

   open (INFILE, "<$TMP-ref.biblio")  || die "can't open file $TMP-ref.biblio\n";
   while (<INFILE>)  {
	  for ($i=0; $i<=$MAXFIELDS; $i++)  {
		  if ( /^#\s*$TYPES[$i]/i )  { $field = $i; next; }
	  }
	  next if ( /#/ );
	  next if ( /^\s*\n/ || /^\s*,\s*\n/);
	  if ( /,\s*\n/ )  { $_ = $`; } 
	  s/\n//g;
	  if ($buf[$field] ne "")  { $buf[$field] = $buf[$field] . ':'; }
	  $buf[$field] = $buf[$field] . $_;
	    
  }
  $buf[$SOURCEBIB] =$databaseName;
  close (INFILE);
  unlink "$TMP-ref.biblio";
  push @Lol, [ @buf ];
  initIdx() ;
}


##############################################################################
# edit entry
# usage:
#       editEntryCmdLn ($elem);
# manipulated global variables:
#       @Lol
#
sub editEntryCmdLn
{
   my ($elem) = @_;
	my ($required, $optional, $other, @tmpList, $i, $str);
   my (@buf, $field, $type);
	$type = $Lol[$idx[$elem]][$BIBTYPE];
	$type =~ s/\n//g;

   ($required, $optional, $other) = getEditFields ($type);
   $str =        "############################################################\n";
   $str = $str . "# Edit '$type' entry (id=$elem).\n";
   $str = $str . "# Please fill in all required fields.\n";
   $str = $str . "# You can use comma separated lists where appropriate.\n";
   $str = $str . "#\n";
   foreach $i (@$required)  { 
		$str = sprintf ("%s# %-14.13s (required)\n", $str, $TYPES[$i]); 
		$str = $str . $Lol[$idx[$elem]][$i] . "\n\n";
	}
   foreach $i (@$optional)  { 
		$str = sprintf ("%s# %-14.13s (optional)\n", $str, $TYPES[$i]); 
		$str = $str . $Lol[$idx[$elem]][$i] . "\n\n";
	}
   foreach $i (@$other)  { 
		$str = sprintf ("%s# %-14.13s (other)\n", $str, $TYPES[$i]); 
		$str = $str . $Lol[$idx[$elem]][$i] . "\n\n";
	}
	
   open (OUTFILE, ">$TMP-ref.biblio")  || die "can't open file $TMP-ref.biblio\n";
   print OUTFILE "$str";
   close (OUTFILE);
  
   system ("$EDIT $TMP-ref.biblio");

   for ($i=0; $i<=$MAXFIELDS; $i++)  { $buf[$i] = ""; }
   open (INFILE, "<$TMP-ref.biblio")  || die "can't open file $TMP-ref.biblio\n";
   while (<INFILE>)  {
	  for ($i=0; $i<=$MAXFIELDS; $i++)  {
		  if ( /^#\s*$TYPES[$i]/i )  { $field = $i; next; }
	  }
	  next if ( /#/ );
	  next if ( /^\s*\n/ || /^\s*,\s*\n/);
	  if ( /,\s*\n/ )  { $_ = $`; } 
	  s/\n//g;
	  if ($buf[$field] ne "")  { $buf[$field] = $buf[$field] . ':'; }
	  $buf[$field] = $buf[$field] . $_;
	    
  }
  close (INFILE);
  unlink "$TMP-ref.biblio" ;
  for ($i=0; $i<=$MAXFIELDS; $i++)  { $Lol[$idx[$elem]][$i] = $buf[$i]; }	
	
}

sub getEditFields
{
	my ($bibtype) = @_;
	my (@fields, @required, @optional, @other, $i, $j, $inList);
	$_ = lc($bibtype);
   switch: {
	  if ( /^article/i       )  { 
		  @required = ($AUTHOR, $TITLE, $JOURNAL, $YEAR); 
		  @optional = ($VOLUME, $NUMBER, $PAGES, $MONTH, $ABSTRACT, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^book/i          )  { 
		  @required = ($AUTHOR, $TITLE, $PUBLISHER, $YEAR); 
		  @optional = ($VOLUME, $SERIES, $ADDRESS, $EDITION, $EDITOR, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^inbook/i        )  {
		  @required = ($AUTHOR, $TITLE, $CHAPTER, $PAGES, $PUBLISHER, $YEAR); 
		  @optional = ($VOLUME, $SERIES, $ADDRESS, $EDITION, $EDITOR, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^booklet/i       )  { 
		  @required = ($TITLE);
		  @optional = ($AUTHOR, $HOWPUBLISHED, $ADDRESS, $MONTH, $YEAR, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^conference/i    )  { 
		  @required = ($AUTHOR, $TITLE, $BOOKTITLE, $YEAR); 
		  @optional = ($EDITOR, $PAGES, $ORGANISATION, $PUBLISHER, $ADDRESS, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^incollection/i  )  { 
		  @required = ($AUTHOR, $TITLE, $BOOKTITLE, $YEAR); 
		  @optional = ($EDITOR, $ORGANISATION, $PUBLISHER, $ADDRESS, $PAGES, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^proceedings/i   )  { 
		  @required = ($TITLE, $YEAR); 
		  @optional = ($EDITOR, $PUBLISHER, $ORGANISATION, $ADDRESS, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^inproceedings/i )  { 
		  @required = ($AUTHOR, $TITLE, $BOOKTITLE, $YEAR); 
		  @optional = ($EDITOR, $PAGES, $PUBLISHER, $ORGANISATION, $ADDRESS, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^manual/i        )  { 
		  @required = ($TITLE);
		  @optional = ($AUTHOR, $ORGANISATION, $ADDRESS, $EDITOR, $MONTH, $YEAR, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^masterthesis/i  )  { 
		  @required = ($AUTHOR, $TITLE, $SCHOOL, $YEAR); 
		  @optional = ($ADDRESS, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^phdthesis/i     )  { 
		  @required = ($AUTHOR, $TITLE, $SCHOOL, $YEAR); 
		  @optional = ($ADDRESS, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^techreport/i    )  { 
		  @required = ($AUTHOR, $TITLE, $INSTITUTION, $YEAR);
		  @optional = ($TYPE, $NUMBER, $ADDRESS, $MONTH, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^unpublished/i   )  { 
		  @required = ($AUTHOR, $TITLE, $NOTE); 
		  @optional = ($MONTH, $YEAR, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^misc/i          )  { 
		  @required = ();
		  @optional = ($AUTHOR, $TITLE, $HOWPUBLISHED, $MONTH, $YEAR, $NOTE, $KEY,$FILEN, $URL);
		  next switch; }
	  if ( /^string/i          )  { 
		  @required = ($MISC);
		  @optional = ();
		  next switch; }
  } 
  if( !/^string/ ) { 
    unshift (@required, $CITEID);
    push    (@optional, $MISC);
    push    (@optional, $CROSSREF) ;
  }
  unshift (@required, $BIBTYPE);
  @fields = (0..$MAXFIELDS-1);
  foreach $i (@fields)  {
	  $inList = 0;
	  foreach $j (@required)  {
		  if ($i == $j) { $inList = 1; last;}
	  }	
	  foreach $j (@optional)  {
		  if ($i == $j) { $inList = 1; last;}
	  }	
	  if ($inList == 0)  { push @other, $i; }
  }
  return (\@required, \@optional, \@other);
}

##############################################################################
# parse tex entries, update @Lol
## usage:
#       parseTexFile ($bibentries);
# manipulated global variables: 
#       @Lol @selectList
#
sub parseTexFile
{
	deselectEntries ("all");    
	my ($bibtype, $citeid, $nEntries, $type,$file) = @_;
	my ($i);
	my ($elem, @list, $percent);
#   my $getField = $type =~ /simple/ ? \&getDBField : \&getField;
   my $getField = $type =~ /simple/ ? \&getField : \&getField;

	for ($elem = 0; $elem <= $#bib; $elem++)  {
		
		if (mod ($elem, 5) || $elem == $#bib)  {
			$percent = 100 * $elem / $nEntries;
			$percent = sprintf ("%d", $percent);
			printStatus ("BUSY", "Parsing $elem of $nEntries ($percent%)");
		}
		
		splice (@list, 0);
		
		$list[$CITEID]       = $$citeid[$elem];
		$list[$BIBTYPE]      = $$bibtype[$elem];
	
	        for ($i=$AUTHOR; $i<=$MAXFIELDS; $i++)   {
			$list[$i] = &$getField (lc ($TYPES[$i]), \$bib[$elem]);
		}
		$list[$MISC]         = getMiscField (\$bib[$elem]);
		$list[$SOURCEBIB] = $databaseName ;
      push @Lol, [@list];
      push @selectList, 1; $nSelected++;
	}
	initIdx ();
	splice (@$citeid, 0);
	splice (@$bibtype, 0);
}

##################################################
# select entries according to a .aux file
sub auxSelect
{
  my ($filename,$de) = @_ ;
  open( AUXFILE,"<$filename") ;
  my @plist ;
  my $i ;
  while( <AUXFILE> ) { 
    if( /\\(citation|bibcite)\{([^}]*)\}/ ) {
      foreach $i ( split(",",$2 ) ) {
        push @plist, $i ;
      }
    }
  }
  close(AUXFILE) ;
  my $pat = "^(".join("|",@plist).")\$" ;
  my @list = regexSearchEntries( $CITEID, $pat ) ;
  if( $de == 1 ) {
    foreach $i ( @list ) {
      deselectEntries( $i ) ;
    }
  } else {
    foreach $i ( @list ) {
      selectEntries( $i ) ;
    }
  }
  return 1+$#list ;
}
  
	


##############################################################################
# search for doubled entries
# usage:
#       if (doubleEntry ($bibtype, $authors, $title) == 1)  { removeEntry (); }
sub doubleEntry
{
	my ($bibtype, $authors, $title) = @_;
	my ($found, $i);
	my (@list, @SrchList);

	@SrchList = split (/:/, $authors);
	$found = 1;
	foreach $i (@SrchList)  {
		$i =~ s/\ /\\s*/g;     # replace spaces with \_
		$i =~ s/.*?[.]//g;     # remove firstnames
		@list = searchEntries ($AUTHOR, $i);
		if ($#list < 0 )  { $found = 0; }
	}
	$title  =~ s/\ /\\s*/g;     # replace spaces with \_
	@list = searchEntries ($TITLE, $title);
	if ( $#list  < 0 )  { $found = 0; }
   @list = searchEntries ($BIBTYPE, $bibtype);	
	if ( $found == 1 )  { print "remove entry $authors, $title\n"; }
	return $found;
}

###################
# mark entries with same citeid
#

sub markDoubleCitedid
{
    deselectEntries("all") ;
    my ($i) ;
    my $n=0 ;
    sortIdx( $CITEID ) ;
    for ($i=0; $i < $#Lol; $i++) {
      if( $Lol[$idx[$i]][$CITEID] eq $Lol[$idx[$i+1]][$CITEID] ) {
	 $n++ ;
         selectEntries($i) ;
	 $i++;
         selectEntries($i) ;
	 $i--;	 
      }
    }
    if( $n > 0 ) {
      printStatus("INFO","$n double CITEIDs found. These entries marked.") ;
    } else {
      printStatus("INFO","No double CITEIDs found.") ;
    }
    updateHistory("select double") ;
}






##############################################################################
# combine matches with and/or; returns id list of matching entries
# usage:
#       @list = combineMatches (1, 3, "and");
# global variables (no manipulation):
#       @LoM, @LonM
#
sub combineMatches
{
	my ($match1, $match2, $type)  = @_;
	my (@list, $elem, $i, $j, $tmp);
	$elem = 0;
	if ( $type  =~ /or/ )  {
		for ($i=0; $i<$LonM[$match1]; $i++)  {
			$list[$elem++] = $LoM[$match1][$i];
		}
		for ($i=0; $i<$LonM[$match2]; $i++)  {
			$list[$elem++] = $LoM[$match2][$i];
		}
	}
	if ( $type =~ /and/ )  {
		for ($i=0; $i<$LonM[$match1]; $i++)  {
			for ($j=0; $j<$LonM[$match2]; $j++)  {
				$tmp = $LoM[$match1][$i];
				if ( $tmp == $LoM[$match2][$j] )  { $list[$elem++] = $tmp; }
			}
		}
	}
	@list = sort @list;
	$tmp = $list[0];
	for ($i=1; $i<=$#list; $i++)  {
		if ($list[$i] == $tmp)  { 
			splice (@list, $i, 1); $i--; 
		}  else  {
			$tmp = $list[$i];
		}
	}
   return @list;		
}

##############################################################################
# search for entries including a special pattern
# usage:
#       @list = searchEntries ($AUTHOR, /abcde/);
# global variabls (no manipulation):
#       @Lol
#
sub searchEntries 
{
	my ($field, $pattern) = @_;
	my @fieldList ;
	my (@list, $i,$j, $string, $elem, $res);
	$elem = 0;
	$pattern = lc ($pattern);
	
	@fieldList = split( ",", $FIELDS[$field] );
 
        for ($i=0; $i<=$#Lol; $i++)  {
	   foreach $field (@fieldList) {
		$string = $Lol[$idx[$i]][$field];
		$string =~ s/[{}]//g ;
		if ( index (lc($string), $pattern) > -1)  { $list[$elem++] = $i; last; }
	   }
	}
	return @list;
}

sub regexSearchEntries
{
	my ($field, $pattern ) = @_ ;
	my @fieldList ;
	my (@list, $i,$j, $string, $elem, $res);
	$elem = 0;
	
	@fieldList = split( ",", $FIELDS[$field] );
 
        for ($i=0; $i<=$#Lol; $i++)  {
	   foreach $field (@fieldList) {
		$string = $Lol[$idx[$i]][$field];
		if( $string =~ /$pattern/ ) { $list[$elem++] = $i; last; }
	   }
	}
	return @list;
}

##############################################################################
# parse query string (without parentheses
# usage:
#       $lastMatch = 10;
#       $parseError = parseInnerQuery ($queryString);
# manipulated global variables:
#       $lastMatch, @queryList
#
sub parseInnerQuery
{
	my ($query) = @_;
	my (@list) = split (/(\ and\ |\ or\ )/, $query);  #vielleicht mit & oder | ersetzen
	my ($i, $str, $bool1, $bool2, $elem1, $elem2, $last);
	my ($k1, $k2, $k3, $go) = (0, 0, 0, 1);
	my ($localcnt, $bestkey, $maxlen, $error) = (0, 0, 0, 0);
	my $cnt = $lastMatch;
	my $firstRefer = "";
	my $firstRun = 1;
	my $foundKey = 0;
	my $logical = "";
	my $saveQuery = $query;
	my $position = 0;
	my (@templist);
	
	while ($query) {
		$maxlen = 0; 	$bestkey = "NULL";
	        foreach $k1 (@KEYS) {
			if ($query =~ /(.+)\s+(and|or)\s+((($k1)=(.+?))|#(\d+?))\s*$/) {
				if ($maxlen < length $1) {
					 $maxlen = length $1; $bestkey = $k1;
				}  
			}  
		}
		if ($bestkey ne "NULL") {
			$query =~ /(.+)\s*(and|or)\s*((($bestkey)=(.+?))|#(\d+?))\s*$/;
			push (@templist, $3, $2); $localcnt++;
			$query = $1;
		} else {
			$query =~ /^\s*(.+?)\s*$/;
			push (@templist, $1); $localcnt++;
			$query = "";
		}  
	}
	
	@templist = reverse @templist;
	
# error check: check all elements of templist for syntax errors
	foreach $i (@templist)  { 
		if ($i =~ /\s+(and|or)\s*$/) {
			printStatus ("ERROR","syntax error: '$1' at end of search string '$i'");
			$error = 1;
		} elsif ($i =~ /\s*and\s+(.+)$/) {
			printStatus ("ERROR","syntax error: logical 'and' before '$1' in '$i' not expected");
			$error = 2;
		} elsif ($i =~ /\s*or\s+(.+)$/) {
			printStatus ("ERROR","syntax error: logical 'or' before '$1' in '$i' not expected");
			$error = 3;
		} elsif ($i =~ /.*(=).*(=).*/) {
			printStatus ("ERROR","syntax error: only one '=' allowed in expression '$i'");
			$error = 4;
		} elsif ($i =~ /^\s*#\d+\s+(.+?)$/) {
			$i =~ /^\s*(#\d+)\s+(.+?)$/;
			printStatus ("ERROR","syntax error: no second expression ('$2') allowed after '$1' in '$i'");
			$error = 5;
		} else { 
			foreach $k1 (@KEYS) {
				if ($i =~ /^\s*$k1(\s+)=.+?$/) {
					printStatus ("ERROR","syntax error: '$1' before '=' in '$i'");
					$error = 6;
					} elsif ($i =~ /^\s*$k1=(\s+).+?$/) {
					printStatus ("ERROR","syntax error: '$1' after '=' in '$i'");
					$error = 7;
					}  elsif ($i =~ /^\s*(\w\w)=.+$/) {
					if ($1 eq $k1) {
						$foundKey = 1;
					}
				}
			}  
			if (!$error && !$foundKey && $i =~ /^\s*(\w\w)=.+$/) {
				printStatus ("ERROR","syntax error: '$1' is no keyword in '$i'");
				$error = 8;
			} elsif (!$error && !$foundKey && !($i =~ /^\s*#(\d+)\s*/ || $i =~ /^\s*(and|or)\s*/)) {
				printStatus ("ERROR","syntax error: no expression found in '$i'");
				$error = 9;
			}
		}
		if (!$error) {
			$position += length ($i) + 1;
		}
	}
	
#	if ($error) {
#		printf ("$saveQuery\n");
#		for ($i = 0; $i < $position; $i++) {
#			printf ("-");
#		}
#		printf ("^\n");
#	}
		
# examine this templist: for all queries of type ??=(*): push query in list and replace
# query by new reference number, for all reference type queries simply hold the number
		
	for ($localcnt = 0; $localcnt <= $#templist; $localcnt++)  { 
		if ($templist[$localcnt] =~ /^\s*(\w\w=.+)\s*$/) {
			push @queryList, "$1";	
			$templist[$localcnt] = sprintf ("$cnt");
			$cnt++;
		} elsif ($templist[$localcnt] =~ /^\s*#(\d+?)\s*$/) {
			$templist[$localcnt] = sprintf ("$1");
			if ($1 > $lastMatch) {
				printStatus ("ERROR","query reference too large ($1 > $lastMatch)");
				$error = 10;
			}
		}
	}

# put queries int query list, UPN!
# first element has to be expression, au=test or #1
# actually, all elements are logicals or query references now.

	$localcnt = 3; 
	if ($#templist >= 2) {
		push @queryList, "$templist[0] $templist[1] $templist[2]"; $cnt++;
		while ($templist[$localcnt + 1]) {
			$k1 = $cnt-1;
			push @queryList, "$k1 $templist[$localcnt++] $templist[$localcnt++]";
			$cnt++;
		}	
	}

	$lastMatch = $cnt;
	
	return ($error);
}


##############################################################################
# sort
sub sortBy
{
   my ($key) = @_ ;
   my $i = $revKEYS{$key} ;
   if( $i eq "" ) { 
      printStatus("ERROR", "Field '$key' not found.\n");
      return ;
   }
   sortIdx( $i ) ;
}


##############################################################################
# parse for substrings in queries with parentheses
# usage:
#       $string = "(ab=abc and de=def) or fg=hij";
#       parseQuery ($string); 
# 
sub parseQuery
{
	my ($str) = @_;
	my ($i, $j);
	my ($bra, $ket);
	my $buf = reverse $str;
	my $len = length ($str);
	my $parseError = 0;

	$ket = index ($str, ')');	
	if ($ket < 0)  {
		$parseError = parseInnerQuery ($str);
		return $parseError; 
	} 
	$bra = $len - index ($buf, '(', $len-$ket);
	my $tmp = substr ($str, $bra, $ket-$bra);
#	print ">$tmp<\n";
	$parseError = parseInnerQuery (substr ($str, $bra, $ket-$bra));
	if (!$parseError) {
		$buf = sprintf ("%s#%d%s", substr ($str, 0, $bra-1), $lastMatch-1,
				substr ($str, $ket+1));
		$parseError = parseQuery ($buf);
	}
	return $parseError;
}


##############################################################################
# evaluate query command
# usage:
#       $string = "(ab=abc and de=def) or fg=hij";
#       evalQueryList ($string);
# manipulated global variables:
#       @queryList, @LoM, @LonM, @LoMCmdLn
#       $lastMatch, $match, $entry
#
sub evalQueryList
{
	my ($str) = @_;
	my ($field, $pattern, @list);
	my ($key, $elem1, $elem2, $i, $j);
	my ($firstElem);
	my $queryError = 0;


	$lastMatch = ($#LoM <  0) ? 0 : $#LoM+1;
	$firstElem = ($#LoM <  0) ? 0 : $#LoM+1;
	splice (@queryList, 0);
	$queryError = parseQuery ($str);

	if (!$queryError) {
		for ($i=0; $i<=$#queryList; $i++)  {
		        
			if ($queryList[$i] =~ /^(\w\w)=([a-z\xc0-\xff]*)/i) {
			        print "1= $1, 2=$2 \n";
				$key = $1, $pattern = $2;
				for ($j=0; $j <= $MAXKEYS; $j++)  {
					if ($key eq $KEYS[$j])  { $field = $j; }
				}
				@list = searchEntries ($field, $pattern);
				push @LoM, [@list]; push @LonM, $#list+1; push @LoMCmdLn, "$key=$pattern";
				$match++; $entry=0;
			}
			if ($queryList[$i] =~ /\s*(\d+)\s*(and|or)\s*(\d+)/)  {
				$elem1 = $1, $elem2 = $3;
				@list = combineMatches ($elem1, $elem2, $2);
				push @LoM, [@list]; push @LonM, $#list+1; push @LoMCmdLn, "$elem1 $2 $elem2";
				$match++; $entry=0;
			}	
		}
		splice (@LoM, $firstElem); splice (@LonM, $firstElem); splice (@LoMCmdLn, $firstElem);
		push @LoM, [@list]; push @LonM, $#list+1; push @LoMCmdLn, $str;
		$match = $firstElem; $entry=0;
		return 0 ;
	} else {
	        return $queryError ;
	}
}

sub selectEntries
{
    my ($i) = @_ ;
    if( $i eq "all" ) {
		for ($i=0; $i<=$#Lol; $i++)  { $selectList[$i] = 1; }
		$nSelected = $#Lol+1 ;
    } else {
       if( $selectList[$idx[$i]] == 0 ) { $nSelected++ ; $selectList[$idx[$i]] = 1;}
    }
}

sub flipMarks
{
	my $i;	
	$nSelected = $#Lol - $nSelected +1;
	for ($i=0; $i<=$#Lol; $i++)  {
		$selectList[$i] = $selectList[$i] == 1 ? 0 : 1;
	}
}    

##############################################################################
# select entries
# usage:
#       selectEntries ($string);   $string = "all", "##", "##-##"; # .. decimal 
# maipulated global variables:
#       @selectList
#
sub selectEntriesCmdLn
{
	my ($string) = @_;
	my ($i, $tmp);
	if ( $string =~ /^all/                  )  { 
          selectEntries("all") ;
	}
	if ( $string =~ /^\s*(\d+)\n*/           )  {
          selectEntries($1) ;
	}
	if ( $string =~ /^\s*(\d+)\s*-\s*(\d+)/ )  { 
		for ($i=$1; $i<=$2; $i++)  { 
                  selectEntries($i) ;
		}
	}
	if ( $string =~ /^\s*aux\s+/ ) {
		auxSelect( $',0 ) ; #'
	}
}



sub modifiedSelected
{
   my $i ;
   for( $i=0; $i<=$#Lol; $i++) {
     if( $selectList[$i]==1 ) { Modify($Lol[$i][$SOURCEBIB])  ;}
   }
}

sub someModified
{
   my $i ;
   foreach $i ( values(%databaseModified) ) { 
     if( $i ) { return 1 ; }
   }
   0 ;
}

sub deleteEntry
{
    my ($elem) = @_;

    if( $selectList[$idx[$elem]] == 1 ) { $nSelected-- ; }
    Modify($Lol[$idx[$elem]][$SOURCEBIB]) ;
    splice (@selectList, $idx[$elem], 1);
    splice (@Lol, $idx[$elem], 1);
    my $i ;
    for( $i=0; $i <= $#idx; $i++) {
      if( $idx[$i] >$idx[$elem] ) { $idx[$i]-- ;}
    }
    splice (@idx, $elem, 1) ;
    if( $ui eq "gui" ) { deleteEntryDisplayCB( $elem) ;} 
}


sub deleteEntries
{
   my $i; 
   # going backwards, so that the list doesn't change while we modify it.
   if( $ui eq "gui" ) {
	for ($i=$#Lol; $i>=0; $i--)  {
		if ($selectList[$idx[$i]]==1)  {
		  deleteEntryDisplayCB( $i ) ;
		}
	}	
   }
   # here using idx won't work, because Lol changes
	for ($i=0; $i<=$#Lol; $i++)  {
		if ($selectList[$i]==1)  {
			splice (@Lol, $i, 1);
			splice (@selectList, $i, 1);
			$i--;
		}
	}	
	$nSelected = 0;
	initIdx ();
}

sub deselectEntries
{
    my ($i) = @_ ;
    if( $i eq "all" ) {
		for ($i=0; $i<=$#Lol; $i++)  { $selectList[$i] = 0; }
		$nSelected = 0 ;
    } else {
       if( $selectList[$idx[$i]] == 1 ) { $nSelected-- ; $selectList[$idx[$i]] = 0;}
    }
}



##############################################################################
# deselect entries
# usage:
#       deselectEntries ($string);   $string = "all", "##", "##-##"; # .. decimal 
# maipulated global variables:
#       @selectList
#
sub deselectEntriesCmdLn
{
	my ($string) = @_;
	my ($i, $elem);
	if ( $string =~ /^all/ )  {
           deselectEntries("all") ;
	}
	if ( $string =~ /^\s*(\d+)\n*/ )  {
	   deselectEntries($1) ;
	}
   if ( $string =~ /^\s*(\d+)\s*-\s*(\d+)/  ) {
		for ($elem=$1; $elem <= $2; $elem++)  {
                    deselectEntries( $elem ) ;
		}
	}
	if ( $string =~ /^\s*aux\s+/ ) {
		auxSelect( $',1 ) ; #'
	}
}

sub markMatches
{
	my $i;
	deselectEntries ("all");
	print "deselect\n" ;
	for ($i=0; $i<$LonM[$match]; $i++)  { $selectList[$idx[$LoM[$match][$i]]] = 1;}	
	print "marked...\n" ;
	if ($ui eq "gui")  {displayMarkCB ("all");    }
	print "displayed\n";
	$nSelected = $LonM[$match];
}

sub Modify
{
  my ($f) = @_ ;
  $databaseModified{$f} = 1   ;
  if( $ui eq "gui" ) { updateDBWindow("all") ;}
}
sub unModify
{
  my ($f) = @_ ;
  $databaseModified{$f} = 0   ;
  if( $ui eq "gui" ) { updateDBWindow("all") ;}
}

sub saveMarks
{
   my (@list, $i);
 
   for ($i=0; $i<=$#Lol; $i++)  {
		if ( $selectList[$idx[$i]] ==1 )  { push @list, $i; }
   }
   $match = ($#LoM <  0) ? 0 : $#LoM+1;
   push @LoM, [@list]; push @LonM, $#list+1; push @LoMCmdLn, "mark";
  if( $ui eq "gui" ) {  updateQueryWindow ("single"); }

}


##############################################################################
# get all selected entries of @Lol
# usage:
#        $string = outputSelected ()
sub outputSelected 
{
   my ($i);
   for ($i=0; $i<=$#Lol; $i++)  {
		if ($selectList[$idx[$i]] == 1)  {
			outputString (getEntry ($i));
		}
	}
}

##############################################################################
# print a string to standard out
# usage:
#       outputString ($string);
#
sub outputString
{
	my ($string) = @_;
	print $string;
	print "\n";
}

sub printStatus
{
	my ($status, $string) = @_;
	my ($str, $i);
	if ($ui eq "gui")  { printStatusGUI ($status, $string); }  
	else {	
		$str = "";
		$string = sprintf ("%-70s", $string);
		for ($i=0; $i<70; $i++)  { $str = $str . "\r"; }
		print "$string $str";
	}
	
}


sub printLOG
{
  my ($status,$string) = @_ ;
  if( $ui eq "gui" ) {
    printLOGGUI( $status, $string ) ;
  } else {
    print $string ;
  }
}
  

##############################################################################
# get query command lines
# usage:
#       $string = getLoMCmdLn ();
# global variables (no manipulation):
#       $match, @LoM, @LonM, @LoMCmdLine
#
sub getLoMCmdLn
{
	my ($i, $list, $str);
	$str="";
	for ($i=0; $i<=$#LoM; $i++)  {
		if ($i == $match)  { $str = $str . "* ";}  else  { $str = $str . "  "; }
		$str = sprintf ("%s%2d:\t%d matches   %s\n", $str, $i, $LonM[$i], $LoMCmdLn[$i]);
	}
	return $str;
}



##############################################################################
# get command history
# usage:
#       $string = getHistory ()
# global variables (no manipulation):
#       @cmdln;
#
sub getHistory
{
	my ($i, $str);
	$str="";
	for ($i=0; $i<=$#cmdln; $i++)  {
		$str = sprintf ("%s%2d:\t%s\n", $str, $i+1, $cmdln[$i]);
	}	
	return $str;
}


sub readHistory
{
      $ConfArray{"HISTORYFILE"} = convPath($ConfArray{"HISTORYFILE"}) ;
      open HISTFILE, "<".$ConfArray{"HISTORYFILE"} ;
      while( <HISTFILE> ) {
        chop ;
        push(@cmdln, $_ ) ;
      }
      $history = $#cmdln+1 ;
      close HISTFILE ;
}

sub writeHistory
{
      $ConfArray{"HISTORYFILE"} = convPath($ConfArray{"HISTORYFILE"}) ;
      my ($s,$e,$i,$l)  ;
      $e = $#cmdln ;
      $s = $e - $ConfArray{"HISTORY"} ;
      if( $s < 0 ) { $s = 0 ; } ;
#      @cmdln = @cmdln[$s..$e] ;
      open HISTFILE, ">".$ConfArray{"HISTORYFILE"} ;
      foreach $i ( $s..$e ) {
          $l = $cmdln[$i] ;
	  $l =~ s/\n//g ;
          print HISTFILE $l."\n" ;
      }
      close HISTFILE ;
}

sub grepHistory
{
      my @l;
      my @l2 ;
      my $i ;
      @l = reverse(grep( /^\s*(open|import|bibopen)/, @cmdln )) ;
      $i = shift( @l ) ;
      $i =~ s/^\s*// ;
      push( @l2, $i) ;
      foreach $i (@l) {
          $i =~ s/^\s*// ;
          if( !($i eq $l2[$#l2]) ) {
	      push(@l2,$i) ;
	  }
	  last if( $#l2 >= $ConfArray{"RECENTFILES"} ) ;
      }
      return @l2 ;
}

##############################################################################
# get marked entry 
# usaged:
#        $string = ogetEntry (5);
# global varibales (no manipulation):
#        @Lol
#
sub getEntry
{
   my ($elem) = @_;
	my ($required, $i, $str, $buf);

   $str = "" ;
   $str = sprintf ("%s%-14.13s= %d\n", $str, "#", $elem);
   ($required) = getEditFields ($Lol[$idx[$elem]][$BIBTYPE]);
   foreach $i (@$required)  { 
		$buf = $Lol[$idx[$elem]][$i];
		$buf =~ s/:/\//g;
		$str = sprintf ("%s%-14.13s= %s\n", $str, $TYPES[$i], $buf);
	}
   $str = sprintf ("%s%s\n", $str, $Lol[$idx[$elem]][$MISC]);
	return $str;
}

##############################################################################
# get fields of all entries
# usage:
#       $string = getEntries ($AUTHOR)
# global variables (no manipulation):
#       @Lol
#
sub getEntries
{
	my ($field) = @_;
	my $i;
	my $str="";
	for ($i=0; $i <= $#Lol ; $i++)  {
		$str = $str . $Lol[$idx[$i]][$field] . "\n";
	}
	return $str;
}

##############################################################################
# get number of entries
# usage:
#       $string = getStatus ();
# global variables (no manipulation):
#       @Lol
#
sub getStatus
{
	my $str="";
	my $len = $#Lol + 1;
	if ( $#Lol == -1 )  {
		$str = $str . "#entries:   empty\n";
	} else {
		$str = $str . "#entries:   $len\n";
	}
	return $str;
}


sub authList
{
    my ($i,$texconv) = @_;
    my @l ;
    my $auth = $Lol[$idx[$i]][$AUTHOR] ;
    if( $auth =~ /^\s*$/ ) {
      $auth = $Lol[$idx[$i]][$EDITOR] ;
    }
    my @au = split( /\s+and\s+/,$auth) ;
    foreach $auth ( @au ) {
       $auth = bp_cs_tex'fromcanon($auth,0) ;
       if( $auth =~ /,/ ) {
          my @name = split( /\s*,\s*/,$auth,2 ) ;
	  push( @l, $name[0]) ;
	  push( @l, $name[1]) ;
       } else {
          my @name = split( /\s+/,$auth ) ;
	  push( @l, pop(@name) ) ;
	  push( @l, join(" ",@name) );
       }
    }
    return @l ;
}


sub lastNameFirstAuth
{
    my ($i) = @_;
    my @l = authList($i,0) ;
    return $l[0] ;
}

sub firstNameFirstAuth
{
    my ($i) = @_;
    my @l = authList($i,0) ;
    return $l[1] ;
}


# Added by Chris Kuklewicz <chrisk@mit.edu>, perl newbie
# LyX can take commands on its named pipe.  This code works for me.
# It is called from the Edit menu and bound to Alt-l
sub tellLyx
{
    my ($i) = @_;

    # Need not be a fatal error
    open(LYX,">> ".convPath($ConfArray{"LYXPIPE"})) || die "Could not open >> LyX pipe at ".$ConfArray{"LYXPIPE"};
    # I do not really understand the command syntax, but this works:
    # LYXCMD = [Maybe] send to the command window (like in emacs, the special 
    #          bottom line text input widget thingy)
    # echo = Interpret as if the user typed it in?
    # citation-insert = The command we need to invoke (similar to emacs)
    # $Lol[$idx[$i]][$CITEID] = The citation id field to refer the bibtex entry
    # "\n" = Completes and executes the command in LyX, otherwise LyX waits
    # print "LYXCMD:echo:citation-insert ".$Lol[$idx[$i]][$CITEID]."\n";
    print LYX "LYXCMD:echo:citation-insert ".$Lol[$idx[$i]][$CITEID]."\n";
    # When I did not say close() the second time tellLyx was called it hung
    # (probably on the open command, I bet)
    close LYX;
}

##############################
# tellLyxs
#
sub tellLyxs
{
    my ($type) = @_ ;
    if( $type eq "selected" ) {
      my $i;
      for ($i=0; $i<=$#Lol; $i++)  {
	 if ($selectList[$idx[$i]]==1)  {
	    tellLyx($i);
	 }
      }
    } else {
	    tellLyx($type) ;
    }
#    updateHistory("tellyx $type") ;
}


sub tellEmacs
{
    my ($i) = @_;

    # Need not be a fatal error
#    open(LYX,">> ".convPath($ConfArray{"LYXPIPE"})) || die "Could not open >> LyX pipe at ".$ConfArray{"LYXPIPE"};
    # I do not really understand the command syntax, but this works:
    # LYXCMD = [Maybe] send to the command window (like in emacs, the special 
    #          bottom line text input widget thingy)
    # echo = Interpret as if the user typed it in?
    # citation-insert = The command we need to invoke (similar to emacs)
    # $Lol[$idx[$i]][$CITEID] = The citation id field to refer the bibtex entry
    # "\n" = Completes and executes the command in LyX, otherwise LyX waits
    # print "LYXCMD:echo:citation-insert ".$Lol[$idx[$i]][$CITEID]."\n";
#    print LYX "LYXCMD:echo:citation-insert ".$Lol[$idx[$i]][$CITEID]."\n";
    # When I did not say close() the second time tellLyx was called it hung
    # (probably on the open command, I bet)
#    close LYX;


}

##############################
# tellLyxs
#
sub tellEmacss
{
    my ($type) = @_ ;
    if( $type eq "selected" ) {
      my $i;
      my $first = "" ;
      system($ConfArray{"GNUDOIT"}." '(insert \"\\\\cite{\")' >/dev/null") ;
      for ($i=0; $i<=$#Lol; $i++)  {
	 if ($selectList[$idx[$i]]==1)  {
           system($ConfArray{"GNUDOIT"}." '(insert \"".$first.$Lol[$idx[$i]][$CITEID]."\")' >/dev/null") ;
	   $first = "," ;
         }
      }
      system($ConfArray{"GNUDOIT"}." '(insert \"}\")' >/dev/null") ;
    } else {
      system($ConfArray{"GNUDOIT"}." '(insert \"\\\\cite{".$Lol[$idx[$type]][$CITEID]."}\")' >/dev/null") ;
    }
#    updateHistory("tellemacs $type") ;
}


##################################
# query MEDLINE
sub queryMEDLINE
{
     my ($query,$numres) = @_ ;
     my $oldhtml = $importhtml ;
     $importhtml = 1 ;
     $query =~ s/\s+/+/g ;
     my $url = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=search&db=PubMed&term=$query&doptcmdl=MEDLINE&dispmax=$numres" ;
     printStatus("INFO","Contacting Entrez for import.....") ;
     importFile($url,"medline") ;
     $importhtml = $oldhtml ;
}



##############################
# Make CITEID
#

sub seperate
{
  my $s = shift ;
  my @list = @_ ;
  my ($l, $i) ;
  for( $l=length($list[0]); $l >0; $l--) {
    $i = substr($list[0],0,$l) ;
    if(  $s  =~ /$i/ ) { 
      last ; 
    }
  }
  if( $l == length($list[0])) { $l = 100 ;}
  $i=$#list ;
  my $j ;
  $list[0] = substr($list[0],0,2) ;
  foreach $j ( reverse(@list) ) {
    if( $s =~ /$j/ ) {
      last ;
    }
    $i-- ;
  }
  return ($i,$l) ;
}

sub chcase
{
   my ($s,$case) = @_ ;
   if( $case eq "nc" ) {
     $s = lc($s) ;
     substr($s,0,1) = uc(substr($s,0,1)) ;
   } elsif( $case eq "uc" ) { $s = uc($s);
   } elsif( $case eq "lc" ) { $s = lc($s);
   }
   return $s ;
}

sub firstLetters
{
    my $s = "" ;
    my @l = @_ ;
    my $i ;
    foreach $i (@l) {
      $s .= substr($i,0,1) ;
    }
    return $s ;
}

sub makeID
{ # Introduction to produce citeids for sixpack, G Lachmann and Z Bergstrom and Y Knot and X Moore
   my ($auth,$year,$title,$pages,$month) = @_ ;
   my @auth = split(/#/,$auth) ;
   my @s = split(/,/,$ConfArray{"CITEID"}) ;
   my ($i,$cite,$case,$useinit,$l,$n,$w,$j) ;
   $useinit = 0 ;
   $cite = "" ;
   foreach $i ( @s ) {
     my $ausep = "" ;
     my $ausuf = "" ;
     if( $i =~ /98/ ) { $i = substr($year,-length($i)) ;}
     elsif( $i =~ /1234/ ) { $i = $pages;}
     else {
       if( $i =~ /^[A-Z][A-Z]/ ) {$case = "uc" ;}
       elsif( $i =~ /^[a-z][a-z]/ ) {$case = "lc" ;}
       else { $case = "nc" ; }
       if( $i =~ /(and)/i ) { $ausep = $1 ;}
       if( $i =~ /(etal)/i ) {
         $ausuf = $1 ;
	 if( $ausuf =~/ET/ ) { $ausep = "AND" ;}
	 elsif( $ausuf =~/Et/ ) { $ausep = "And" ;}
	 else {$ausep = "and";}
       }
       if(  $i =~ /\+/ ) {
         $ausuf = "+" ;
	 $ausep = "" ;
       }
       
       $i = lc($i) ;
       $l = length($i) ;
       if( $i =~ /^in/ ) {
         my $ignore = $ConfArray{'TITLEIGNORE'} ;
         if( $i =~ /to/ ) { ($n,$l) = seperate($i,"introduction","to","pr","ci","fo","si") ; $ignore = "" ;}
         elsif( $i =~ /^in/ ) { ($n,$l) = seperate($i,"introduction","pr","ci","si") ; }
	 my @t = split( /\s+/,$title ) ;
	 $title =~ s/\W//g ;
	 $i = "" ;
	 foreach $w ( @t ) {
	   if( !($ignore =~ /\b$w\b/i ) ) {
	       $i .= chcase(substr($w,0,$l),$case) ;
   	       last if( $n-- == 0 ) ;	       
	   } ;

	 }
       } elsif( $i =~ /la/ ) {
	 if( $i =~ /^g/ ) {
	    $i =~ s/g//g ;
	    $i =~ s/z//g ;
	    $i =~ s/y//g ;
	    $i =~ s/x//g ;
	    $useinit = 1 ;
	 } 
	 if( $i =~ /g/ ) {
	    $i =~ s/g//g ;
	    $i =~ s/z//g ;
	    $i =~ s/y//g ;
	    $i =~ s/x//g ;
	    $useinit = 2 ;
	 } 
	 ($n,$l) = seperate($i,"lachmann","be","kn","mo") ;
         if( $i =~ /(etal|\+)/i  ) {
	   if( $#auth >= 5 
	   ) {
	     splice( @auth, 2) ;
	   } else {
	     $ausuf = "" ;
	   }
	   $n = 100 ;
	 } 
	 $i = "" ; $n *= 2 ;
	 if( $n > $#auth
	    ) {$n = $#auth;
	      } ;
	 for($j=0; $j<= $n ;
	       $j+=2 ) {
	       if( $j > 0 ) {$i .= $ausep ;}
	       if( $useinit == 1 ) { $i .= uc(join("",firstLetters(split(/\W+/,$auth[$j+1])))) ; }
	       $i .= chcase(substr($auth[$j],0,$l),$case) ;
	       if( $useinit == 2 ) { $i .= uc(join("",firstLetters(split(/\W+/,$auth[$j+1]))) ); }
	 } 	       
	 $i .= $ausuf ;

       } elsif( $i =~ /fe/ ) {
         $i = chcase( substr($month,0,length($i)), $case ) ;
       }
       if( $case eq "lc" ) { $i = lc($i) ;}
     }
     $cite .= $i ;
   }
   $cite =~ s/[ (){}"'\\`^]//g ;
   return $cite ;
}


sub makeCITEID
{
    my ($i) = @_ ;
    my $c ;
    $Lol[$idx[$i]][$PAGES] =~ /^\s*(\d+)/ ;
    my $pages = $1 ;
    my $month="" ;
    if( $Lol[$idx[$i]][$MONTH] =~ /([a-zA-Z]+)/ ) { $month = $1 ; } 
    my $au = join("#",authList($i,1)) ;
    $c = makeID($au, $Lol[$idx[$i]][$YEAR], $Lol[$idx[$i]][$TITLE], $pages,$month) ;
    
#    $c =~ s/[^\w]//g ;  #remove non alpha
#    $c =~ y/a-z/A-Z/;   #make uppercase
    
    $Lol[$idx[$i]][$CITEID] = $c ;
    Modify($Lol[$idx[$i]][$SOURCEBIB] ) ;    
}

##############################
# Make CITEID
#
sub makeCITEIDs
{
    my ($type) = @_ ;
    if( $type eq "selected" ) {
      my $i;
      for ($i=0; $i<=$#Lol; $i++)  {
	 if ($selectList[$idx[$i]]==1)  {
	    makeCITEID($i);
	 }
      }
    } else {
	    makeCITEID($type) ;
    }
    updateHistory("makeid $type") ;
}


################################
# Put title uppercase in brackets
sub bracketTITLE
{
     my ($i) = @_ ;
#     $Lol[$idx[$i]][$TITLE] =~ s/([^{]\b)([A-Z]{1,})([^}])/$1{$2}$3/g ;
     $Lol[$idx[$i]][$TITLE] =~ s/(.)([A-Z]{1,})([^}])/$1\{$2\}$3/g ;
}
     


sub bracketTITLEs
{
    my ($type) = @_ ;
    if( $type eq "selected" ) {
      my $i;
      for ($i=0; $i<=$#Lol; $i++)  {
	 if ($selectList[$idx[$i]]==1)  {
	    bracketTITLE($i);
	 }
      }
    } else {
	    bracketTITLE($type) ;
    }
    updateHistory("bracket $type") ;
}




##############################################################################
# init sorting index
# usage:
#       initIndex ();
# global variables:
#       @Lol, @idx
#
sub initIdx 
{
        @idx = (0..$#Lol) ;
}



##############################################################################
# sort database
# usage:
#        initIdx ();
#        sortIdx ($AUTHOR);
# global variables:
#        @idx, @Lol
#


sub sortIdx
{
	initIdx ();
	my ($field) = @_;
	my @Skeys;
	splice(@Skeys,0);
        my ($i);
	if( $field == $AUTHOR ) {
	  for( $i=0; $i<=$#Lol; $i++) {
	       push( @Skeys, lastNameFirstAuth ( $i ) . firstNameFirstAuth($i) . "" );
	  }
	} else 
        {
	  for( $i=0; $i<=$#Lol; $i++) {
	    push( @Skeys, $Lol[$i][$field] );
	  }
	}
	@idx = sort { $Skeys[$a] cmp $Skeys[$b] }  @idx ;
}


sub saveOrder
{
   print "$Lol[$b][$BIBTYPE] $Lol[$a][$BIBTYPE] \n" ;
   if( lc( $Lol[$a][$BIBTYPE] ) =~ /string/ ) {
     if( lc( $Lol[$b][$BIBTYPE] ) =~ /string/ ) {
       $Lol[$a][$MISC] =~ /\b(\w+)\s*=(.*)/ ;
       my ($na,$va) = ($1,$2) ;
       $Lol[$b][$MISC] =~ /\b(\w+)\s*=(.*)/ ;
       my ($nb,$vb) = ($1,$2) ;
       if( $vb =~ /$na/ ) {
         print "$na is in $vb\n" ;
         return -1 ;
       } elsif( $va =~ /$nb/ ) {
         print "$nb is in $va\n" ;
         return 1 ;
       }
         print "$na is not in $vb " ;
         print "$nb is not in $va\n" ;       
       return 0 ;
     } else {return -1 ;}
   } elsif ( lc ( $Lol[$b][$BIBTYPE] ) =~ /string/ ) {
       return 1 ;
   } else {
     if ( $Lol[$a][$CROSSREF] =~ /^\s*$/ ) {
       # a is empty
       if(  $Lol[$b][$CROSSREF] =~ /^\s*$/ ) {
         return 0 ;   # both are empty
       } else {       #b isn't empty
         if( $Lol[$b][$CROSSREF] =~ /\b$Lol[$a][$CITEID]\b/ ) {
           return 1 ; #a is contained in b
         } else {
	   return 0 ; #a isn't in b
	 }
       }
     } else {   #a isn't empty
         if( $Lol[$a][$CROSSREF] =~ /\b$Lol[$b][$CITEID]\b/ ) {
           return -1 ; #b is contained in a
         } 
	 if( $Lol[$b][$CROSSREF] =~ /\s*/ ) {
           return 0 ;   # b is empty, and b isn't in a
	 } else { #b isn't empty
           if( $Lol[$b][$CROSSREF] =~ /\b$Lol[$a][$CITEID]\b/ ) {
             return 1 ; #a is contained in b
           } 
	 }
     }
   }
   return 0 ;
}
	 
     

sub sortIdxForSave
{
   my ($i, @sl, @rl,@cl) ;
   for( $i=0; $i<=$#Lol; $i++
      ) {
      if( lc($Lol[$idx[$i]][$BIBTYPE]) =~ /string/ ) {
        push(@sl, $i) ;  #strings
      } elsif( $Lol[$idx[$i]][$CROSSREF] =~ /^\s*$/ ) {
        push (@rl,$i) ;  #the rest
      } else {
        push (@cl,$i) ; #cross referefences
      }
   }
   my @sl1;
   my $j ;
   foreach $i (@sl) {
     $Lol[$idx[$i]][$MISC] =~ /\b(\w+)\s*=(.*)/ ;
     my ($ni,$vi) = ($1,$2) ;
     for( $j=0; $j <= $#sl1+1; $j++) {
       if( $j == $#sl1+1 ) {
         push(@sl1,$i) ;
	 last ;
       }
       $Lol[$idx[$sl1[$j]]][$MISC] =~ /\b(\w+)\s*=(.*)/ ;
       my ($nj,$vj) = ($1,$2) ;
       if( $vj =~ /$ni/ ) {
         splice( @sl1, $j,0,$i) ;
	 last ;
       }
    }
  }
  my @cl1 ;
  foreach $i (@cl) {
    for( $j=0; $j<=$#cl1+1; $j++
       ) {
       if( $j == $#cl1+1 ) {
         push(@cl1,$i) ;
	 last ;
       }
      if( $Lol[$idx[$i]][$CROSSREF] =~ /\b$Lol[$idx[$cl1[$j]]][$CITEID]\b/ ) {
        splice( @cl1, $j, 0, $i) ;
        last ;
      }
    }
    if( $i eq "" ) {
        push(@cl1,$i) ;
	last ;
    }
  }
  @sl = () ;
  foreach $i (@sl1) { push(@sl,$idx[$i]) ;}
  foreach $i (@cl1) { push(@sl,$idx[$i]) ;}
  foreach $i (@rl) { push(@sl,$idx[$i]) ;}  
  @idx = @sl ;
}

sub sortIdxAuth
{
#	initIdx ();
	my ($field) = @_;
	my ($k, $j, $temp);
	
	my (@auths) ;
	for( $k=0; $k<=$#Lol;$k++) {
	   $auths[$k] = lastNameFirstAuth ( $k ) . $Lol[$idx[$k]][$AUTHOR] ;
	   print "$k $auths[$k]\n" ;
	}
	for ($k=0; $k<=$#Lol; $k++)  {
	for ($j=$k+1; $j<=$#Lol; $j++)  {
	                if( !defined($auths[$k]) || !defined($auths[$j])) {
			  print "$k $j \n" ;
			}
			if ($auths[$idx[$k]]  gt $auths[$idx[$j]])  {
				$temp    = $idx[$k];
				$idx[$k] = $idx[$j];
				$idx[$j] = $temp;
			}
		}
	}
}

##############################################################################
# print all commands of sixpack to standard out
# usage:
#       listCommands ()
#
sub listCommands
{
	print "commands:\n";
	print "\thelp [query]            list commands\n";
	print "\topen  file              read reference file    (ext = .bref)\n";
	print "\tmerge file              include reference file (ext = .bref)\n";
	print "\tsave [force][all|marked] file  save reference file    (ext = .bref)\n";
	print "\timport [type] file  [text/html]    import file, using format 'type'\n";
        if( defined( $ConfArray{'WGET'} ) && $ConfArray{'WGET'} ne "" ) {
	  print "\timport [type] URL      import from URL, using format 'type'\n";
	} else {
	  print "\timport [type] URL      disabled, variable WGET not set in sixpack.rc\n";
	}

	print "\thtml                    imports are done from html files\n";
	print "\tnohtml                  imports are not done from html files\n";	
	print "\texport [type] file      export file, using format 'type'\n";
	print "\ttitles                  list of titles\n";
	print "\tadd item                add a new item\n";
	print "\tsort key                sort database by key\n";
	print "\tmark                    store current marks in the query databse\n";
	print "\tsort key                sort database by key\n";	
	print "\tedit ./d                edit current entry/entry number d\n";
	print "\ttellyx ./d                insert citation number d into lyx\n" ;
	print "\tshow selected           show line # of matching list\n";
	print "\tshow #                  show line # of matching list\n";
	print "\t.*/+/-                  show this/next/previous entry\n";
	print "\t:query                  search pattern: see 'help query\n";
	print "\tmedline: query          search pattern on medline, and import results\n" ;
	print "\t#                       copy number #\n";
	print "\t(de)select all          (de)select all entries\n";
	print "\t           d            (de)select entry number d\n";
	print "\t           d1-d2        (de)select entries d1 to d2\n";
	print "\t           aux file     (de)select entries according to aux file\n";	
	print "\t makeid d/selected      make CITEID for entry, or selected entries\n";
	print "\t bracket d/selected     put {} arround uppercase in title for entry, or selected entries\n";
        print "\tflip                    flip marks\n";	
	print "\thistory                 show command line history\n";
	print "\tsys command             execute command\n";
	print "\tgui                     start graphical user interface\n";
	print "\texit                    exit program\n";	
	print "shortcuts:\n";
	print "\thistory                 hist\n";
	print "\thelp                    h\n";
	print "\t& / |                   and / or\n";
	print "\texit                    x\n";
}


sub listQueryCommands
{
	my ($i);
	print ":query       search pattern\n";
	print " query->     xx=pattern\n";
   print " xx          field:\n";
	for ($i=0; $i <= $MAXKEYS; $i++)  {
		printf ("\t %-14.12s: %s\n", $TYPES[$i], $KEYS[$i]);
	}
	print "example:      :(au=myauthor and ti=mytitle) or jo=myjournal\n";
	print "\n";
}

sub sourceFile
{
     my ($file) = @_ ;
     my $line ;
     $file = convPath( $file ) ;
     if( -e $file ) {
       open(FILE,"<$file") ;
       while( (defined($line=<FILE>) ) ) {
         chomp $line ;
         $line =~ /([^#]*)#?.*/ ;
         $line = $1 ;
         if( $line =~ s/\\\s*$// ) {
       	   $line .= <FILE> ;
	   redo unless eof(FILE) ;
         }
         execCommand($line) ;
       }
       close( FILE ) ;
     }
}

sub execCommand
{
	my ($string) = @_;
        $_ = $string;
	switch:  {
		if ( /^\s*help\s*$/ || /^\s*h\s*$/ ) 
		                                  { listCommands; next switch; }
		if ( /^\s*help\s*query\s*$/  )    { listQueryCommands; next switch; }
		if ( /^\s*history\s*$/ || /^\s*hist\s*$/ ) 
		                                  { outputString (getHistory); next switch; }
		if ( /^\s*source\s*/ ) {  sourceFile( $' ) ; next switch; } #'				  
		if ( /^\s*new/               )    { newDatabase (); next switch; }
		if ( /^\s*db\s*/ ) { my @g = grep( /$'/, keys(%databases) ) ; if ($#g >= 0 ) { $databaseName = $g[0] ;} ; next switch;} #'
		if ( /^\s*open\s+/           )    { openRefFile (convPath($')); next switch; } #'
		if ( /^\s*write\s*col/           )    { writeCollection (convPath($')); next switch; } #'		
		if ( /^\s*bibopen\s+/           )    { openBibFile (convPath($')); next switch; } #'		
		if ( /^\s*merge\s+/          )    { if( readRefFile ($')){ Modify($databaseName);} next switch; } #'
		if ( /^\s*save\s*$/ ) { saveDatabaseByName( $databaseName,1 ); next switch; }
		if ( /^\s*save\s+([\w|.]+)\s*$/ ) { saveRefFile ($1, "all"); next switch; } 
		if ( /^\s*save\s*all\s*$/ ) 
		                                  { saveAllDatabases (0); next switch; } 
		if ( /^\s*save\s*force\s*all\s*$/ ) 
		                                  { saveAllDatabases (1); next switch; } 
		if ( /^\s*show\s*dbs/ ) { print join("\n",keys(%databases)) ; next switch; }
		if ( /^\s*force\s*close/ ) { closeDatabase( $databaseName , "force") ; next switch;}
		if ( /^\s*close/ ) { closeDatabase( $databaseName ) ; next switch;}		
		if ( /^\s*save\s+marked\s+([\w|.]+)\s*$/ ) 
		                                  { saveRefFile ($1, "marked"); next switch; } 
		if ( /^\s*import\s+(\S+)\s+(\S*)\s+html/ ) 
		                                  { my $prevhtml = $importhtml; $importhtml = 1; importFile ($2, $1); $importhtml = $prevhtml ;next switch; }
		if ( /^\s*import\s+(\S+)\s+(\S*)\s+text/ ) 
		                                  { my $prevhtml = $importhtml; $importhtml = 0; importFile ($2, $1); $importhtml = $prevhtml ;next switch; }
		if ( /^\s*import\s+(\S+)\s+(\S*)/ ) 
		                                  { importFile ($2, $1); next switch; }
		if ( /^\s*export\s+([\w|.]+)\s*([\w|.]*)/ ) 
		                                  { exportFile ($2, $1); next switch; } 
		if ( /^\s*status/            )    { outputString (getStatus); next switch; }
		if ( /^\s*titles/            )    { outputString(getEntries ($TITLE)); next switch; }
		if ( /^\s*ls\s*$/            )    { system ("ls -alF *.bref *.bib"); next switch; }
		if ( /^\s*\+\s*$/            )    { if ($entry < $LonM[$match]-1)  { 
			                                   outputString(getEntry ($LoM[$match][++$entry])); } 
											           next switch; }
		if ( /^\s*\-\s*$/            )    { if ($entry > 0)  {
			                                   outputString(getEntry ($LoM[$match][--$entry])); }
													     next switch; }
		if ( /^\s*\.\s*$/ || /^\s*\*\s*$/ )   
		                                  { if ($LonM[$match])  {
  	                                         outputString(getEntry ($LoM[$match][$entry]));  } 
			                                   next switch; }
		if ( /^\s*tel+yx\s*selected/ ) { tellLyxs( "selected" ) ; next switch;}
		if ( /^\s*tel+yx\s*(\d+)/ ) { tellLyx( $1 ) ; next switch;}
		if ( /^\s*tel+yx\s*\./ ) { tellLyx( $LoM[$match][$entry] ) ; next switch;}
		if ( /^\s*tel+emacs\s*selected/ ) { tellEmacss( "selected" ) ; next switch;}
		if ( /^\s*tel+emacs\s*(\d+)/ ) { tellEmacss( $1 ) ; next switch;}
		if ( /^\s*tel+emacs\s*\./ ) { tellEmacss( $LoM[$match][$entry] ) ; next switch;}
                if ( /^\s*mark\s*/         )    { saveMarks (); next switch; }
                if ( /^\s*flip\s*/         )    { flipMarks (); next switch; }
                if ( /^\s*html\s*/         )    { $importhtml=1; next switch; }
                if ( /^\s*nohtml\s*/         )    { $importhtml=0 ; next switch; }		
                if ( /^\s*select\s*/         )    { selectEntriesCmdLn ($'); next switch; } #'
		if ( /^\s*deselect\s*/       )    { deselectEntriesCmdLn ($'); next switch; } #'
		if ( /^\s*add\s*(\w*)/       )    { addEntryCmdLn ($1); next switch; }
		if ( /^\s*edit\s*(\d+)/      )    { editEntryCmdLn ($1); next switch; }
		if ( /^\s*edit\s*./          )    { editEntryCmdLn ($LoM[$match][$entry]); next switch; }
		if ( /^\s*delete\s*(\d+)/      )    { deleteEntry ($1); next switch; }               
                if ( /^\s*delete\s*./        )    { deleteEntry ($LoM[$match][$entry]); next switch; }
		if ( /^\s*delete\s*selected/ )    { deleteEntries (); next switch; }
		if ( /^\s*makeid\s*(\d+)/      )    { makeCITEIDs ($1); next switch; }               
		if ( /^\s*makeid\s*selected/ )    { makeCITEIDs ("selected"); next switch; }
		if ( /^\s*bracket\s*(\d+)/      )    { bracketTITLEs ($1); next switch; }               
		if ( /^\s*bracket\s*selected/ )    { bracketTITLEs ("selected"); next switch; }
		if ( /^show\s*selected\s*$/  )    { outputSelected (); next switch; }
		if ( /^select\s*double$/  )    { markDoubleCiteid (); next switch; }		
		if ( /^show\s*(\d+)\s*$/     )    {  outputString (getEntry ($1)); next switch; }
		if ( /^:(.+?)$/              )    { evalQueryList ($1); markMatches ();  next switch; }
		if( /^medline:(.+)$/ ) { queryMEDLINE($1,50); next switch;}
		if ( /^\s*sort\s*(\w+)/      )    { sortBy ($1); next switch; }		
		if ( /^\s*(\d+)\s*$/         )    { print ">>> \n";
			                                 push @LoM, $LoM[$1-1]; 
			                                 push @LonM, $LonM[$1-1]; 
													   push @LoMCmdLn, "$1";
												      $match++; $entry=0;
		                                    next switch; }
		if ( /^\s*exit\s*$/ || /^\s*x\s*$/ ) 
			                               { myexit; exit; next switch; }
	        if ( /^\s*sys\s*(.*)\s*$/ ) { system_exec( $1 ); next switch;}
		return 0;
	}
	return 1;
}

################################################################################
################################################################################
##                                                                            ##
##                          command line interface                            ##
##                                                                            ##
################################################################################
################################################################################

sub cmd
{
	my $string;
   $entry = -1;
     while (<STDIN>)  {
		$string = $_;
		chop $string; 
		next if ($string eq "");	
		if ( $string =~ /^\s*gui\n/ )    { guiMain ();next switch; }
	   if ( $string =~ /!(\d+)/ ) { $string = $cmdln[$1-1]; }
if (execCommand ($string) == 1)  {
			$cmdln[$history++] = $string;
		}  else  {
			printStatus("ERROR", "Command '$string' not found. Use 'help' or '?'.\n");
		}
		outputString (getLoMCmdLn ());
		my $a = $#LoM ;
		print $a ;
		if ($a eq "-1")  {
			printf (">%%%d [0 of 0] %s>", $history, $databaseName);
		}  else {
			printf (">%%%d [%d of %d] %s>", $history, $entry+1, $LonM[$match], $databaseName );
		}
	}
}


sub convPath
{
   my ($val) = @_;
   if (substr($val,0,1) eq '~') {
      if (substr($val,1,1) eq '/') {
	 $val = $home . substr($val,1);
      } else
      {my ($uid,$rest) = ($val =~ m#^~([^/]+)(/.*$)#
      );
      $val = (getpwnam($uid))[7] . $rest;
      }
   }
   return $val ;
}

sub fixfilename
{
	my ($file) = @_ ;
	if( $file =~ /(\/|^)(~.*)$/ ) {
		$file = convPath($file) ;
	}
	if( $file =~ /(^|[^:])\/\// ) {
		$file = "/".$' ; #'
	}
	return $file ;
}
							   

###############################################################################
# main
#
my $i;
for( $i=0; $i<=$MAXKEYS; $i++) {
   $revKEYS{$KEYS[$i]} = $i ;
}

Tk::CmdLine::SetArguments();
 
	        
my $args = join (":", @ARGV);
$ui = "cmd";
if ( $args =~ /-help/ )  {
	print "usage:\n";
	print " 	c.pl [-help] [-gui] [-{bibtex|sixtex}=file.{bib.ref}]\n";
	print "  options:\n";
	print "    -help    print out this message\n";
	print "    -gui     load graphical user interface\n";
	print "    -sixtex  include sixpack bibliography format\n";
	print "\n";
	myexit; exit;
}
# -sixtex=file.ref


my $bibtexname = "";

initDatabase ();

if ($args =~ /-sixtex=:?([^:]+)/ )  {
        $databaseName = convPath($1) ;      	
} elsif ($args =~ /-bibtex=:?([^:]+)/ )  {
        $bibtexname = convPath($1) ;      	
}

if( $databaseName ne "" ) {
  if (!openRefFile ($databaseName)) { myexit; exit; }
} elsif( $bibtexname ne "" ) {
  openBibFile ($bibtexname, "bibtex");
}

readHistory () ;
# -gui
if ($args =~ /.*:*-gui:*.*/)  { guiMain (); myexit; exit;}


print "\nSixPack 97\n";

print "%0 [0 of 0]>";
cmd ();


################################################################################
################################################################################
##                                                                            ##
## guimain              graphical user interface                              ##
##                                                                            ##
################################################################################
################################################################################

my ($top, $listWin,$Balloon);               # -  $top level window
my $balloonOn=(1==1);
my $MedlineQUERY = 0 ;
my ($mainFrame, $mainCanvas, $statusLabel, $statusDummyLabel);
my (%menu, @buttonList, @buttonXpm);

my ($logWin, $logListbox, $logCommand);
my ($queryWin, $queryListbox, $queryWinView);
my ($DBWin, $DBListbox, $DBWinView);
my ($queryEntry, $queryString);
my ($listText);              # -  Text()-widget: title list
my ($citeidText,     $bibtypeText,     $authorText);
my ($titleText,      $journalText,     $volText);
my ($numberText,     $pagesText,       $monthText);
my ($yearText,       $keywordsText,    $abstractText);
my ($noteText,       $editorText,      $publishText);
my ($seriesText,     $addressText,     $chapterText);
my ($howpublishText, $booktitleText,   $organisationText);
my ($schoolText,     $institutionText, $typeText);
my ($miscText);

my ($citeidRef,     $bibtypeRef,     $authorRef);
my ($titleRef,      $journalRef,     $volRef);
my ($numberRef,     $pagesRef,       $monthRef);
my ($yearRef);                                     #key and abstract are fields using a slider;
my (                $editorRef,      $publishRef); #note uses a slider;
my ($seriesRef,                      $chapterRef); # chapter uses a slider too;
my ($howpublishRef, $booktitleRef,   $organisationRef);
my ($schoolRef,     $institutionRef, $typeRef);
my ($miscRef);

my $highlightedEntry;

my @FRAME;
my @TEXT;
my @LABEL;   
my @REF;        # reference variable, contains user input
my @DISPLAYED;  # if true show this field
my $FIRSTFOCUS ;
my $editUnlocked; # if set it is impossible to edit an entry
my @tmpDisplayed;

my $Fbrowser;
my $UFbrowser;

my $statusExpired; 


sub system_exec
{
        my ($command) = @_ ;
## jwh: 19.10.00-- handle variables in command
# michael: Nov 2, 0 enable also file dialog.
	 my @com_parts ;
 	 my ($before,$part) ;
	 while( $command =~ /\{/ )  {
	   $before = $` ;
	   if( !( $before =~ /^\s*$/ ) ) {
	     push @com_parts,split(/\s+/,$before) ;
	   }
	   ($part,$command) = matchingB($'    #'
		                               );
	   $part = eval($part) ;
	   push @com_parts,$part ;
	 } 
	 $before = $command ;
	 if( !( $before =~ /^\s*$/ ) ) {
	     push @com_parts,split(/\s+/,$before) ;
	 }
	my $exp_command = join(" ",@com_parts) ;

	 system( $exp_command ) ;
}

sub sortCB
{
     my ($field) = @_;
     if( $field eq "save" ) {
       sortIdxForSave() ;
     } else {
       sortBy($field) ;
     }
     print "finished sorting..\n" ;
     displayTitles () ;     
     print "displayed\n" ;
     displayMarkCB ("all");
     print "display mark\n" ;
     updateHistory("sort $field") ;
}


sub printQueryCB
{
	my ($string) = @_;
	$queryString = $queryString . $string;
	my $len = length ($queryString);
	$queryEntry->icursor ($len);
}

sub printQueryHistCB
{
	my ($dir) = pop;
	if ($dir eq "prev" && $match > 0)  {
	  	$match--;
		$queryString = $LoMCmdLn[$match];
	}
	if ($dir eq "next" && $match < $#LonM)  {
		$match++;
		$queryString = $LoMCmdLn[$match];
	}
}

sub evalQueryCB
{
	my ($i, $nMatches);
	if ($queryString ne "")  {
#		splice (@LoM, 0);
            if( $MedlineQUERY ) {
		      queryMEDLINE($queryString,50) ;
		      updateHistory("medline: $queryString") ;
		      displayTitles() ;
		      displayMarkCB("all") ;
	    } else { 
	    print " query: $queryString\n";
		$queryString = bp_cs_tex'tocanon($queryString,0) ;
		$queryString = bp_cs_88591'fromcanon($queryString,0) ;

		my $err = evalQueryList ($queryString);
		if( $err < 1 ) {
		$nMatches = $LonM[$match]; 
		if ( $nMatches == 0 )  {	
			printStatusGUI ("INFO", "Sorry. No match found.    :'-("); 
		   return;
		}
		if ( $nMatches == 1 )  {
			printStatusGUI ("INFO", "One match found and selected.    :)");         
		}
		if ( $nMatches >  1 )  {	
			printStatusGUI ("INFO", "$nMatches matches found and selected.    =:)");     
		}
		markMatches ();
                updateQueryWindow ("single");
		updateHistory (":$queryString");
		}
	    }
	}  else  {
		printStatusGUI ("INFO", "Please enter a query string.");
	}
	
}

sub markDoubleCiteidCB
{
   markDoubleCitedid ;
   displayTitles () ;     
   displayMarkCB ("all");     
}   

sub markAuxCB
{
 my $types = [
	     ['LaTeX aux file',   '.aux'],
	     ['sixpack collection',   '.six'],
             ['BibTeX files',       '.bib'],
	     ['sixpack database',      '.bref'           ],
	     ['All Files',        '*',             ],
	     ];
	 my $file = $listWin->getOpenFile(-filetypes=>$types, -title=>"choose LaTeX aux file");

   		my $nMatches = auxSelect( $file, 0 ) ;
		if ( $nMatches == 0 )  {	
			printStatusGUI ("INFO", "No citation matches"); 
		   return;
		}
		if ( $nMatches == 1 )  {
			printStatusGUI ("INFO", "One match found and selected.    :)");         
		}
		if ( $nMatches >  1 )  {	
			printStatusGUI ("INFO", "$nMatches matches found and selected.    =:)");     
		}
   updateHistory("select aux $file") ;
   displayMarkCB ("all");     
}   

sub pagingCB
{
	my $type = pop;
	my $found = 0;
	my ($i, $entry);
	if ($type eq "prev")     { $entry = $highlightedEntry-1; }
	if ($type eq "next")     { $entry = $highlightedEntry+1; }
	if ($type eq "pageup")   { $entry = $highlightedEntry > 8       ? $highlightedEntry - 8 : 0;     }
	if ($type eq "pagedown") {	$entry = $highlightedEntry < $#Lol-8 ? $highlightedEntry + 8 : $#Lol; }
	if ($type eq "home")     { $entry = 0; }
	if ($type eq "end" )     { $entry = $#Lol; }
	if ($type eq "prevsel")  {  
		$entry = $highlightedEntry;
		if ($nSelected >= 1 && $highlightedEntry > 0)  {
			for ($i=$highlightedEntry-1; $i>=0 && $found==0; $i--)  {
				if ($selectList[$idx[$i]]==1)  { $found = 1; $entry = $i; }
			}
		}
	}
	if ($type eq "nextsel")  {  
		$entry = $highlightedEntry;
		if ($nSelected >= 1 && $highlightedEntry < $#Lol)  {
			for ($i=$highlightedEntry+1; $i<=$#Lol && $found==0; $i++)  {
				if ($selectList[$idx[$i]]==1)  { $found = 1; $entry = $i; }
			}
		}
	}
	if ($entry >= 0 && $entry <= $#Lol)  { displayEntryCB   ( ("", $entry )); }
}

sub askYesNo
{
    my ($quest,$ans) = @_ ;
    my $response = $top->messageBox(-icon => 'questhead',
	                             -message => $quest,
				     -type => 'YesNo', -default => $ans);
     if( $response eq "Yes" ) { return 1 ; }
     else { return 0 ;}
}


sub exitIfUnmod
{
    my $response ;
    if( !someModified () ) {
       myexit; exit ;
    } else {
        $response = $top->messageBox(-icon => 'questhead', 
	                             -message => 'Databases modified! Save before exiting?', 
				     -title => 'Databases Modified', -type => 'YesNoCancel', -default => 'Cancel');
	if( $response eq "Yes" ) {
	  saveAllDatabases(0) ;
	} 
	if( $response eq "Cancel" ) {
	  return ;
	}
	myexit; exit ;
#        printStatus("ERROR","File modified: save or force Quit from menu");
    }
}

sub openRefFileCB
{
        my ($Act) = @_ ;
	my $oldname = $databaseName ;
	my ($file);

#        $Fbrowser->configure (-directory=>$curFileSelectDir, -filter=>"*.bref",-create=>1);

#	$file = $Fbrowser->Show ();
 my $types = [
	     ['sixpack database',      '.bref'           ],
	     ['sixpack collection',   '.six'],
             ['BibTeX files',       '.bib'],
	     ['All Files',        '*',             ],
	     ];
	 if( $Act eq "new" ) {
	 $file = $listWin->getSaveFile(-filetypes=>$types, -title=>"choose new sixpack database");
	 } else {
	 $file = $listWin->getOpenFile(-filetypes=>$types, -title=>"choose sixpack database to load");
	}
	if( defined($file) && $file ne "" ) {	
	       my $nElem = $#Lol+1;
	       my $readOK =0;
	       if( $Act eq "merge" ) {
	           $readOK = readRefFile($file) ;
		   if( $readOK ) {Modify($databaseName ) ;}
		   updateHistory("merge $file") ;
	       } else {
	           $readOK = openRefFile($file,$Act) ;
		   updateHistory("open $file") ;
	       }
               if( $readOK ) {
	         if( !($Act eq "new") ) {
	           $nElem = $#Lol+1-$nElem;
		   displayTitles ();
		   printStatus ("INFO", "$nElem items included.");
		 } 
	         displayEntryCB (0);
	       }
       }
}

sub writeCollectionCB
{
        my ($Act) = @_ ;
	my $oldname = $databaseName ;
	my ($file);

#        $Fbrowser->configure (-directory=>$curFileSelectDir, -filter=>"*.six",-create=>1);

#	$file = $Fbrowser->Show ();
 my $types = [
	     ['sixpack collection',   '.six'],
             ['BibTeX files',       '.bib'],
	     ['sixpack database',      '.bref'           ],
	     ['All Files',        '*',             ],
	     ];
	 $file = $listWin->getSaveFile(-filetypes=>$types, -title=>"choose sixpack script to save");
	
	if( defined($file) && $file ne "" ) {	
	   $curFileSelectDir=$Fbrowser->cget('-directory');
	   writeCollection( $file ) ;
        }
	updateHistory("write col $file") ;
}

sub sourceFileCB
{
        my ($Act) = @_ ;
	my $oldname = $databaseName ;
	my ($file);

#        $Fbrowser->configure (-directory=>$curFileSelectDir, -filter=>"*.six",-create=>0);

#	$file = $Fbrowser->Show ();

 my $types = [
	     ['sixpack collection',   '.six'],
             ['BibTeX files',       '.bib'],
	     ['sixpack database',      '.bref'           ],
	     ['All Files',        '*',             ],
	     ];
	 $file = $listWin->getOpenFile(-filetypes=>$types, -title=>"choose sixpack script to load");

	if( defined($file) && $file ne "" ) {
	   if( -e $file ) {
	     sourceFile( $file ) ;
	     displayTitles ();
	     displayMarkCB ("all");
	     updateDBWindow("all") ;
	   } else {
	      printStatus("ERROR","file '$file' does not exist.") ;
	   }
       }
       updateHistory("source $file") ;
}


sub openBibFileCB
{
        my ($Act) = @_ ;
	my $oldname = $databaseName ;
	my ($file);


         my $types = [
             ['BibTeX files',       '.bib'],
	     ['sixpack database',      '.bref'           ],
	     ['sixpack collection',   '.six'],
	     ['All Files',        '*',             ],
	     ];

        if( $Act eq "new" ) {
	  $file = $listWin->getSaveFile(-filetypes=>$types, -title=>"choose new bibtex file");
	} else {
	  $file = $listWin->getOpenFile(-filetypes=>$types,-title=>"Select bibtex file to load");
	}

											  
	if( defined($file) && $file ne "" ) {	
	   $curFileSelectDir=$Fbrowser->cget('-directory');
	       my $nElem = $#Lol+1;
               if( openBibFile($file,$Act) ) {
	         if( !($Act eq "new") ) {
                   $nElem = $#Lol+1-$nElem;
		   displayTitles ();
		   printStatus ("INFO", "$nElem items included.");
		   updateHistory( "bibopen $file") ;
		 }
	         displayEntryCB (0);
	       }
       }
}

sub closeDatabaseCB
{
    my ($force) = @_ ;
    
    if( closeDatabase( $databaseName, $force ) ) {
      printStatus("INFO","Database $databaseName closed.") ;
      my @k = keys( %databases ) ;
      if( $#k >= 0 ) {
        ($databaseName) = keys( %databases ) ;
	displayTitles ();
	updateDBWindow() ;
	displayEntryCB (0);
      } else {
        initDatabase ();	
	updateDBWindow() ;   
	displayTitles ();
	for ($i=0; $i<=$MAXFIELDS; $i++)  { 
	  $FRAME[$i]->packForget (); 
	}
      }
    } 
    updateHistory("close") ;
}

sub newDatabaseCB
{
   if( !newDatabase() ) {
          updateDBWindow() ;
	  displayTitles ();
          return ;
   } else {
     updateDBWindow() ;   
     displayTitles ();
     for ($i=0; $i<=$MAXFIELDS; $i++)  { 
       $FRAME[$i]->packForget (); 
     }
   }
   updateHistory ("new");
}


sub saveRefFileCB
{
	my ( $method) = @_;
	my ($dialog, $file);
#	$Fbrowser->configure (-directory=>$curFileSelectDir, -filter=>"*.bref", -create=>1);
#	$file = $Fbrowser->Show ();
 my $types = [
	     ['sixpack database',      '.bref'           ],
             ['BibTeX files',       '.bib'],
	     ['sixpack collection',   '.six'],
	     ['All Files',        '*',             ],
	     ];
	 $file = $listWin->getSaveFile(-filetypes=>$types,-title=>"sixpack database to save");
	if( $file ne "" ) {	
	   $curFileSelectDir=$Fbrowser->cget('-directory');	
	 saveRefFile ($file, $method);
         if ($method eq "all")  { 
		printStatusGUI ("INFO", "Database has been saved."); 
		updateHistory ("save all $file");
#	        $databaseModified = 0 ;	
	 }	else  { 
		printStatusGUI ("INFO", "$nSelected entries of database have been saved.");
		updateHistory ("save marked $file");
	 }
	}

}

sub saveCurRefFileCB
{
        my($file);
        $file = $databaseName ;
	if( $file ne ""  ) {
  	  saveDatabaseByName ($file, 1);
	  unModify($file) ;
	  printStatusGUI ("INFO", "Database has been saved."); 
	  updateHistory ("save");
	} else {
	  saveRefFileCB("all") ;
	}
}


sub URLValidate
{
   my ($a,$cw,$name,$orig) = @_ ;

   if( $name =~ /\s*\w+:\/\// ) {
      $cw->Accept ;
   } else {
      return( $cw->validateFile($name));
   }
}
   

sub importCB
{
   my $td;
   my ($type) = @_;
        if( $databaseName eq "" ) {
	   printStatus("ERROR","No database open. Open a database first") ;
	} else {
	my ($file, $string);
   if( $importselection ) {
       my $selection = $mainFrame->SelectionGet() ;
       open (FSEL, ">$TMP-sel" ) ;
       print FSEL $selection ;
       close (FSEL) ;
       $file = "$TMP-sel" ;
   } else {
        if ($type eq "bibtex")  { 
		$UFbrowser->configure (-title=>"Import BibTeX file", -directory=>$curFileSelectDir, -filter=>"*.bib");
	}  else  {
		$UFbrowser->configure (-title=>"Import $type file", -directory=>$curFileSelectDir, -filter=>"*");
	}
					
	$file = $UFbrowser->Show ();
   }
   if( defined($file) && $file ne "" ) {
   $curFileSelectDir=$UFbrowser->cget('-directory');
   $file = fixfilename($file) ;
   importFile ($file, $type);
   if( $importselection ) {
     unlink $file ;
   }
   displayTitles ();
   displayMarkCB ("all");
   Modify($databaseName);
   if( $importhtml ) {
     updateHistory ("import $type $file html");
   } else {
     updateHistory ("import $type $file");
   }
   }
   }
}

sub giveSelection
{
  my ($offset, $maxbytes )=@_;
  return substr( $SixSelection, $offset, $maxbytes ) ;
}

sub copyCB
{
  my $temp = $importselection ;
  $importselection = 1 ;
  if( $nSelected > 0 ) {
    exportCB("simple") ;
  } else {
    selectEntries( $highlightedEntry ) ;
    exportCB("simple") ;
    deselectEntries( $highlightedEntry ) ; ;
  }
  $importselection = $temp ;
}

sub pasteCB
{
  my $temp = $importselection ;
  $importselection = 1 ;
  importCB("simple") ;
  $importselection = $temp ;
}

sub cutCB
{
  copyCB ;
  if( $nSelected > 0 ) {
    deleteEntryCB( "selected" ) ;
  } else {
    deleteEntryCB() ;
  }
}

  
sub exportCB
{
   my ($type) = @_;
   my ($file, $string);
   if( $importselection ) {
     $file = "$TMP-sel" ;
   } else {
     if ($type eq "bibtex")  { 
       $Fbrowser->configure (-title=>"Export BibTeX file", -directory=>$curFileSelectDir, -filter=>"*.bib", -create=>1);
     }  else  {
       $Fbrowser->configure (-title=>"Export $type file", -directory=>$curFileSelectDir, -filter=>"*",-create=>1);
     }
     $file = $Fbrowser->Show ();
     if( defined($file) && $file ne "" ) {	
       $curFileSelectDir=$Fbrowser->cget('-directory');	
     }
   }
   $file = fixfilename($file) ;
   if( defined($file) && $file ne "" ) {	
     $file = fixfilename($file) ;
     exportFile ($file, $type);
     updateHistory ("export $type $file");
     if( $importselection ) {
       open(FSEL,"$TMP-sel") ;
       my @sel = <FSEL>;
       $SixSelection = join("\n",@sel) ;
       close(FSEL) ;
       $top->SelectionHandle("") ;
       $top->SelectionHandle( \&giveSelection ) ;
       $top->SelectionOwn() ; 
       $top->clipboardClear() ;
       $top->clipboardAppend("--",$SixSelection) ;
     }
   }
}

sub addEntryDialogCB
{
    if( $databaseName eq "" ) {
	   printStatus("ERROR","No database open. Open a database first") ;
    } else {
	my $who = pop;
	
	my ($listTop, $listBox, $buttonFrame, $i, $select);
   $select = 0;	
	$listTop = $top->Toplevel ();
	$listBox = $listTop->ScrlListbox (-label=>"Please specify the type of the new entry",
		                                     	-selectmode=>"single");
	foreach $i (qw (Article Book Inbook Booklet Conference Incollection Proceedings
			          Inproceedings Manual Masterthesis PhD-Thesis Techreport
						 unpublished miscellaneous String))  { 
		$listBox->insert ("end", $i);
	}
	$listBox->pack (-fill=>"both", -expand=>"yes");
	$listBox->focus () ;
	
	$buttonFrame = $listTop->Frame ();
	$buttonFrame->Button (-text=>"OK", -command=>sub{addEntryCB ($listBox->Getselected()); $listTop->destroy()})->pack (-side=>"left");
	$listBox->bind ("<Double-Button-1>", sub{addEntryCB ($listBox->Getselected()); $listTop->destroy()});
	$listBox->bind ("<Return>", sub{$listBox->BeginSelect($listBox->index('active')); addEntryCB ($listBox->Getselected()); $listTop->destroy()});	
	$buttonFrame->Button (-text=>"Cancel", -command=>sub{$listTop->destroy();})->pack (-side=>"right");
	$buttonFrame->pack ();
     }
}

sub addEntryCB
{
        if( $databaseName eq "" ) {
	   printStatus("ERROR","No database open. Open a database first") ;
	} else {
	my ($type) = pop;
	my $elem  = 0;
	my $i ;
	my @list ;
	for ($i=$AUTHOR; $i<=$MAXFIELDS; $i++)   {
	$list[$i] = "";
	}
	$list[$MISC]         = "";
	$list[$SOURCEBIB] = $databaseName ;
	push @Lol, [@list];
	push @selectList, 0; 
	initIdx () ;
	$elem=$#Lol;
	
	for ($i=0; $i<=$MAXFIELDS; $i++) { $REF[$i] = ""; }
	$Lol[$idx[$elem]][$BIBTYPE] = $type;
	$REF[$BIBTYPE]        = $type;
	$Lol[$idx[$elem]][$AUTHOR]  = "(unknown)";
	$Lol[$idx[$elem]][$TITLE]   = "(new entry)";
	$listText->configure (-state=>"normal");
	displayTitleCB ($elem, "insert");
#	displayTitles ();
        highLightEntry ($elem);
	$listText->configure (-state=>"disabled");
	$editUnlocked = 1;
	$Lol[$idx[$elem]][$AUTHOR] = ""; $Lol[$idx[$elem]][$TITLE] = "";
	editEntryCB ("Add");
	updateHistory ("add $type");
	$selectList[$idx[$elem]] = 0;
	}
}

sub editEntryCB
{
   if( $#Lol >= 0 ) {
        my ($mw) = @_ ;
	my $who = pop;
	my ($i, $elem, $field);
	my $s ;
	$elem = $highlightedEntry;
	if ($who eq "Button" || $who eq "Key")  {
		$editUnlocked = $editUnlocked == 1 ? 0 : 1;
	}
	if ($editUnlocked)  {
		if ($who eq "Button" || $who eq "Key" || $who eq "Menu")  { updateHistory ("edit $elem"); }
		$buttonList[3]->configure (-image => $buttonXpm [14]);  # /qw(load
		printStatusGUI ("INFO", "Red fields are required, green ones are optional. To save this entry lock it again!");
	   for ($field=0; $field <= $MAXFIELDS; $field++)  { 	
			$tmpDisplayed[$field] = $DISPLAYED[$field];  
			$DISPLAYED[$field]    = 1; 
		}
		unlockAllFields ();
	displayEntryCB ($highlightedEntry);
	$FIRSTFOCUS->focus () ;
	}  else {
		$buttonList[3]->configure (-image => $buttonXpm [3]);
		lockAllFields ();
		foreach $i ( @EntryFields)  {
		    $s = $REF[$i] ;
		    $s = bp_cs_tex'tocanon($s,0) ;
		    $s = bp_cs_88591'fromcanon($s,0) ;
		    $Lol[$idx[$elem]][$i] = $s;	
		    $Lol[$idx[$elem]][$i] =~ s/\n/ /g;
		}
		foreach $i ( @TextFields)  {
			$s = $TEXT[$i]->get ("1.0", "end");
			$s = bp_cs_tex'tocanon($s,0) ;
			$s = bp_cs_88591'fromcanon($s,0) ;
			$Lol[$idx[$elem]][$i] = $s ;
#                        $Lol[$idx[$elem]][$i] =~ s/\n/ /g;
                        chop $Lol[$idx[$elem]][$i];
		}
	   for ($field=0; $field <= $MAXFIELDS; $field++)  { 	
			$DISPLAYED[$field] = $tmpDisplayed[$field]; 
		}

                $listText->configure (-state=>"normal");
		displayTitleCB ($highlightedEntry, "replace");
		displayTitleCB ($idx[$elem], "replace");		
		$listText->configure (-state=>"disabled");
		updateDBWindow("all") ;

		printStatusGUI ("INFO", "Changes has been saved. Entry is locked.");
		Modify($Lol[$idx[$elem]][$SOURCEBIB]) ;
	displayEntryCB ($highlightedEntry);
	$queryEntry->focus ();

	}
	displayMarkCB($highlightedEntry) ;
    }
}

sub tellLyxCB
{
    if( $nSelected > 0 ) {
      tellLyxs( "selected" ) ;
      updateHistory("tellyx selected") ;
    } else {
      tellLyxs ($highlightedEntry) ;
      updateHistory("tellyx $highlightedEntry") ;
    }
}

sub tellEmacsCB
{
    if( $nSelected > 0 ) {
      tellEmacss( "selected" ) ;
      updateHistory("tellemacs selected") ;
    } else {
      tellEmacss ($highlightedEntry) ;
      updateHistory("tellemacs $highlightedEntry") ;
    }
}


sub makeCITEIDCB
{
    if( $nSelected > 0 ) {
      makeCITEIDs( "selected" ) ;
    } else {
      makeCITEIDs ($highlightedEntry) ;
    }
      displayEntryCB ($highlightedEntry);
}

sub bracketTITLECB
{
    if( $nSelected > 0 ) {
      bracketTITLEs( "selected" ) ;
      displayTitles() ;
      displayMarkCB ("all");
    } else {
      bracketTITLEs ($highlightedEntry) ;
      displayEntryCB ($highlightedEntry);
    }
}


sub deleteEntryDisplayCB
{
    my ($tag) = @_ ;
    $tag = $tag+1 ;
    my $tag1 = $tag+1 ;
    $listText->configure (-state=>"normal");
    $listText->delete("$tag.0","$tag1.0"); 
    $listText->configure (-state=>"disabled");
}

sub deleteEntryCB
{
    my ($type) = @_ ;
    if( $type eq "selected" ) {

        if ($nSelected > 0)  {
	   modifiedSelected () ;
	   deleteEntries ();
	   updateHistory ("delete selected");
#	   displayTitles ();
	   highLightEntry ($highlightedEntry);
	   my $i;
	   foreach $i ( keys(%databases) ) {
  	     Modify($i);
	   }
	} else {
		printStatus ("ERROR", "Nothing selected.");
	}
     }	else  {
	deleteEntry ($highlightedEntry);
#	displayTitles ();
	displayEntryCB ($highlightedEntry);
	updateHistory ("delete $highlightedEntry");
    }
}

sub dothingsToMiscURLCB
{
   my $misc = $Lol[$idx[$highlightedEntry]][$MISC] ;
   my $s = $misc;
   my $command ;
   if( $Lol[$idx[$highlightedEntry]][$URL] ne "" && defined($ConfArray{"URLHANDLE"}) ) {
      my $url=$Lol[$idx[$highlightedEntry]][$URL] ;
      $command = $ConfArray{"URLHANDLE"} ;
      if( $command =~ s/%s/$url/g) {
         $command = $command . " &" ;
      } else {
         $command = $command . " " . $url . " &" ;
      }
      system( $command ) ;
      return 1;
   }
   return 0;
}


sub dothingsToMiscCB
{
   my $misc = $Lol[$idx[$highlightedEntry]][$MISC] ;
   my $s = $misc;
   my $command ;
   if( $Lol[$idx[$highlightedEntry]][$FILEN] ne "" ) {
     my $file=$Lol[$idx[$highlightedEntry]][$FILEN] ;
     $s = $file;
     $s =~ /[~\.]*\.(.*?)$/;
     $s = $1 ;
     my $exthand = "EXTHANDLE." . $s ;
     while( !defined($ConfArray{$exthand})  && !($s =~ /./) ) {
#       print "\n$s\n" ;
       $s =~ /[~\.]*\.(.*?)$/;
       $s = $1 ;
       $exthand = "EXTHANDLE." . $s ;     
     } 
     if( $ConfArray{$exthand} ne "" ) {
        $file = convPath( $ConfArray{'PAPERS'} ) . "/" . $file ;
        $command = $ConfArray{$exthand} ;
        if( $command =~ s/%s/$file/g) {
           $command = $command . " &" ;
        } else {
           $command = $command . " " . $file . " &" ;
        }
        system( $command ) ;
     } else {
        $file = convPath( $ConfArray{'PAPERS'} ) . "/" . $file ;
        $command = $ConfArray{"MISCHANDLE"} ;
        if( $command =~ s/%s/$file/g) {
           $command = $command . " &" ;
        } else {
           $command = $command . " " . $file . " &" ;
        }
        system( $command ) ;
     }
   } else {dothingsToMiscURLCB ();}
}


sub lockAllFields
{
	my $i;
	for ($i=0; $i<=$MAXFIELDS; $i++)  {
		$TEXT[$i]->configure (-state=>"disabled", -takefocus => 0);
	}
	$editUnlocked = 0;
}

sub unlockAllFields
{
	my $i;
	for ($i=0; $i<=$MAXFIELDS; $i++)  {
		$TEXT[$i]->configure (-state=>"normal", -takefocus => 1);
	}
	$editUnlocked = 1;

}

sub highLightEntry
{
	my ($i) = @_;
	my ($fg,$bg);

	if ($editUnlocked == 0)  {
	  $bg = $background1 ;
	  $fg = int ($highlightedEntry/2)*2 == $highlightedEntry ? $foreground1 : $foreground2;
	  if( $selectList[$idx[$highlightedEntry]]==1 ) { $bg = $background4 ; $fg = $foreground7;}

          $listText->tag("delete","highlight") ;
	  $highlightedEntry = $i;
	  my $tag = $highlightedEntry+1 ;
	  $listText->tag("add","highlight","$tag.0","$tag.end") ;
	  $listText->tag("configure", "highlight", -foreground=>$foreground6, -background=>$background2);
	  $listText->see ("$tag.0");
	  printStatusGUI ("OK");
	}
}


sub displayEntryCB
{
	my $elem = pop;
	my ($tag);
	my ($required, $optional, $other, $i, $frameHeight);
	my ($fg1, $fg2, $fg3);
	my ($elem1, $nElem) = ($elem+1, $#Lol+1
	                      );

	if ($editUnlocked == 0)  {
		$fg1 = $foreground1;
		$fg2 = $foreground1;
		$fg3 = $foreground1;
	}  else	{ 
		if ($elem != $highlightedEntry) { 
			printStatusGUI ("INFO", "Please lock this entry first.");
			return; 
		}
		$fg1 = $foreground3;
		$fg2 = $foreground4;
		$fg3 = $foreground5;
	}
	if ($elem > -1)  {highLightEntry ($elem);}
 	for ($i=0; $i<=$MAXFIELDS; $i++)  { 
		$FRAME[$i]->packForget (); 
	}
#	for ($i=0; $i<=$MAXFIELDS; $i++)  { 
#		if ($DISPLAYED[$i] == 1)  { $FRAME[$i]->pack (-fill=>"x", -expand=>"yes"); }
#	}
        if( $#Lol >= 0 ) {
        ($required, $optional, $other) = getEditFields ($Lol[$idx[$elem]][$BIBTYPE]);
	$FIRSTFOCUS = "" ;
	foreach $i (@$required)  {
		if ($DISPLAYED[$i] == 1 && $Lol[$idx[$elem]][$i] ne "" || $editUnlocked != 0)  {
			$FRAME[$i]->pack (-fill=>"x");
			$LABEL[$i]->configure (-foreground=>$fg1);
			$TEXT[$i] ->configure (-foreground=>$fg1);
			if( $FIRSTFOCUS eq "" && $i != $BIBTYPE) {
			   $FIRSTFOCUS = $TEXT[$i] ;}
		}
	}
	foreach $i (@$optional)  {
		if ($DISPLAYED[$i] == 1 && $Lol[$idx[$elem]][$i] ne "" || $editUnlocked != 0)  {
			$FRAME[$i]->pack (-fill=>"x");
			$LABEL[$i]->configure (-foreground=>$fg2);
			$TEXT[$i] ->configure (-foreground=>$fg2);
			if( $FIRSTFOCUS eq "" ) {
			   $FIRSTFOCUS = $TEXT[$i] ;}		}
	}
	foreach $i (@$other)  {
		if ($DISPLAYED[$i] == 1 && (defined $Lol[$idx[$elem]][$i]) && $Lol[$idx[$elem]][$i] ne "" || $editUnlocked != 0)  {
			$FRAME[$i]->pack (-fill=>"x");
			$LABEL[$i]->configure (-foreground=>$fg3);
			$TEXT[$i] ->configure (-foreground=>$fg3);
			if( $FIRSTFOCUS eq "" ) {
			   $FIRSTFOCUS = $TEXT[$i] ;}		}
	}
	$mainFrame->update (); $frameHeight = $mainFrame->winfo ("reqheight");
 	$mainCanvas->configure (-scrollregion => [0, 0, 0, $frameHeight]);

	foreach $i ( @EntryFields )  {
		$REF[$i] = $Lol[$idx[$elem]][$i];
	}
	foreach $i ( @TextFields )  {
		$TEXT[$i]->configure(-state=>"normal");
		$TEXT[$i]->delete ("1.0", "end");
		$TEXT[$i]->insert ("1.0", $Lol[$idx[$elem]][$i]);
		if ($editUnlocked == 0)  { $TEXT[$i]->configure(-state=>"disabled") ; }
	}
	}
}



sub markEntryCB
{
	$listText->configure (-state=>"normal");
	selectEntries($highlightedEntry) ;
#       $selectList[$highlightedEntry] = 1; $nSelected++;
	displayTitleCB ($highlightedEntry, "replace");
	displayMarkCB ($highlightedEntry);
	$listText->configure (-state=>"disabled");
#   highLightEntry ($highlightedEntry);
#	printStatusGUI ("INFO", "To mark an entry you can use the right mouse button.");
   updateHistory ("select $highlightedEntry");
	pagingCB("next");   
}

sub unmarkEntryCB
{  
	my $i;
	$listText->configure (-state=>"normal");
	deselectEntries($highlightedEntry) ;
#	$selectList[$highlightedEntry] = 0;
	displayTitleCB ($highlightedEntry, "replace");
	displayMarkCB ($highlightedEntry);
	$listText->configure (-state=>"disabled");
#       highLightEntry ($highlightedEntry);
#	printStatusGUI ("INFO", "To unmark an entry you can use the right mouse button.");
#	$nSelected = 0;
#	foreach $i (@selectList)  { $nSelected += $i; }
        updateHistory ("deselect $highlightedEntry");
	pagingCB("next");
}

sub markAllEntriesCB
{
	my $i;
	selectEntries("all") ;
#        for ($i=0; $i<=$#Lol; $i++)  {
#		$selectList[$i] = 1;
#	}
#	$nSelected = $#Lol;
	displayMarkCB ("all");
   highLightEntry ($highlightedEntry);
	printStatusGUI ("INFO", "All entries marked.");
   updateHistory ("select all");	
}

sub unmarkAllEntriesCB
{
	my $i;
	deselectEntries ("all");
	displayMarkCB ("all");
   highLightEntry ($highlightedEntry);
	printStatusGUI ("INFO", "All marks removed.");
   updateHistory ("deselect all");	
}

sub flipMarksCB
{
   flipMarks () ;
   displayMarkCB ("all");
   highLightEntry ($highlightedEntry);
   updateHistory ("flip");
}


sub selectEntryCB
{
	my $i = pop;
	if ($selectList[$idx[$i]] == 1)  { $selectList[$idx[$i]] = 0;  $nSelected--; }
	else                       { $selectList[$idx[$i]] = 1; 	$nSelected++; }
	$listText->configure (-state=>"normal");
   displayTitleCB ($i, "replace");
	displayMarkCB ($i);
   highLightEntry ($i);
	displayEntryCB ($i);
	$listText->configure (-state=>"disabled");
   updateHistory ("flip $i");	
}


sub displayMarkCB
{
	$listText->configure (-state=>"normal");
	my ($elem) = @_;
	my ($fg,$bg) ;
	my ($i, $selected,$j);
	if ($elem eq "all")  {
	        $listText->tag("delete","selected","1.0","end") ;
		for ($i=1; $i<=$#Lol+1; $i++)  {
		     $j = $i-1;
		     if( $selectList[$idx[$i-1]] == 1 ) {
		         $listText->tag("add","selected","$i.0","$i.end") ;
		     } 
		}
	}  else  {
		$i = $elem+1;
	        $listText->tag("remove","selected","$i.0","$i.end") ;
		
		if( $selectList[$idx[$i-1]] == 1 ) {
		    $listText->tag("add","selected","$i.0","$i.end") ;
		}
	}		
	$listText->tag("bind", "selected", '<Button-1>' => [\&displayclickCB,Ev('@')] );
	$listText->tag("bind", "selected", '<Button-2>' => [\&selectclickCB,Ev('@')] );
	$listText->tag("configure", "selected", 
	               -foreground=>$foreground7, 
		       -background=>$background4);		
	$listText->configure (-state=>"disabled");	
}


sub displayclickCB
{
     my( $dont,$place) = @_ ;
     my @entry = split(/\./,$listText->index($place) );
     displayEntryCB( $entry[0]-1 ) ;
}


sub selectclickCB
{
     my( $dont,$place) = @_ ;
     my @entry = split(/\./,$listText->index($place) );
     selectEntryCB( $entry[0]-1 ) ;
}

sub displayTitleCB
{
#########
# look in Tk::Text
        my ($i, $method) = @_;
	my ($fg, $selected, $string,$s);

	if( lc($Lol[$idx[$i]][$BIBTYPE]) eq "string" ) {
	  $s = $Lol[$idx[$i]][$MISC] ;
	  $s =~ s/\s+/ /g ;
	  $string = sprintf ("   %-17.17s  %.88s", "\@string", $s );
	} else {
	  if( $ConfArray{'DISPLAYLINE'} eq "" ) {
	    if( $Lol[$idx[$i]][$AUTHOR] =~ /^\s*$/ ) {
	      $string = sprintf ("  %-17.17s  %-100.100s", $Lol[$idx[$i]][$EDITOR], $Lol[$idx[$i]][$TITLE]);
	    } else {
	      $string = sprintf ("  %-17.17s  %-100.100s", $Lol[$idx[$i]][$AUTHOR], $Lol[$idx[$i]][$TITLE]);
	    }
	  } else {
	    my ($l, $f, $j) ;
	    $string = "  " ;
	    foreach $j ( split(/,/,$ConfArray{'DISPLAYLINE'}) ) {
	      $j =~ s/\s*//g ;
	      ($f,$l) = split(/:/,$j) ;
	      if( $f eq $KEYS[$AUTHOR] && $Lol[$idx[$i]][$AUTHOR] =~ /^\s*$/ ) {
		$f = $KEYS[$EDITOR] ;
	      }
	      $string .= sprintf("%-".$l.".".$l."s  ",$Lol[$idx[$i]][$revKEYS{$f}]) ;
	    }
	  }
	}
	$string =~ s/\n/ /g ;
#	if ($i <= $#Lol
#	    )  { 
	    $string = $string . "\n"; 
#	    }
	if( $method eq "insertend" ) {
   	   $listText->insert("end", $string);
	} else {
   	   $listText->insert(($i+1).".0", $string);
	}
	if (mod ($i, 2) == 1)  
	{ $listText->tag("add","unselected1",($i+1).".0",($i+1).".end") ; }
	else
	{ $listText->tag("add","unselected2",($i+1).".0",($i+1).".end") ; }
	if ($method eq "replace")  {
		$listText->delete (($i+2).".0", ($i+3).".0"); 
	}
}	

sub displayTitles
{
   my ($i);
#   my $ORIGINAL_CURSOR = ($top->configure(-cursor))[3]; # restore this cursor
#   $top->configure(-cursor=>'watch') ;
   updateDBWindow ("all") ;   
   $listText->configure (-state=>"normal");
#   for ($i=$#Lol; 
#	$i>=0; $i--)  { $listText->tag ("delete", "listtag$i"); }
   $listText->delete ("1.0", "end");
   for ($i=0; $i<=$#Lol; 
	$i++)  { displayTitleCB ($i, "insertend"); }
   $listText->tag("configure", "unselected1", 
		               -foreground=>$foreground1, 
			       -background=>$background1);		
   $listText->tag("configure", "unselected2",
		               -foreground=>$foreground2, 
			       -background=>$background1);		
   $listText->configure (-state=>"disabled");
   $listText->tag("bind", "unselected1", '<Button-1>' => [\&displayclickCB,Ev('@')] );
   $listText->tag("bind", "unselected1", '<Button-2>' => [\&selectclickCB,Ev('@')] );
   $listText->tag("bind", "unselected2", '<Button-1>' => [\&displayclickCB,Ev('@')] );
   $listText->tag("bind", "unselected2", '<Button-2>' => [\&selectclickCB,Ev('@')] );

   $listText->tag("add","highlight","$highlightedEntry.0","$highlightedEntry.end") ;
#   displayMarkCB ("all");
#   $top->configure(-cursor=>$ORIGINAL_CURSOR) ;   

}

sub displayTitles2
{
   my ($i);
   updateDBWindow ("all") ;
   $listText->configure (-state=>"normal");
#   for ($i=$#Lol; 
#	$i>=0; $i--)  { $listText->tag ("delete", "listtag$idx[$i]"); }
   $listText->delete ("1.0", "end");
   for ($i=0; $i<=$#Lol; 
	$i++)  { displayTitleCB ($idx[$i], "insert"); }
   $listText->configure (-state=>"disabled");
   displayMarkCB ("all");
}

sub MyNextPage
{
    $mainCanvas->yview('scroll',  1, 'pages') ;
}

sub MyPrevPage
{
    $mainCanvas->yview('scroll',  -1, 'pages') ;
}

sub addEntryWidget 
{
	my ($field) = @_;
	my $label = $TYPES[$field];
	$FRAME[$field] = $mainFrame->Frame ();
	$LABEL[$field] = $FRAME[$field]->Label (-text => "$label:", -font=>$fn)
         			  ->pack(-side=>"left");
	$TEXT[$field]  = $FRAME[$field]->Entry (-textvariable => \$REF[$field], 
			                                  -width=>$ww, -font=>$fn)
      				  ->pack(-side=>"right");
	$TEXT[$field]->bind("<Alt-Return>",           [\&editEntryCB, "Key" ]);
	$TEXT[$field]->bind("<Return>",[sub {$TEXT[$field]->focusNext()}]);	
	$TEXT[$field]->bind("<Prior>",[\&MyPrevPage,$field]);
	$TEXT[$field]->bind("<Next>",[\&MyNextPage,$field]);	
#	$TEXT[$field]->bind("<Insert>",[sub{$TEXT[$field]->Insert($TEXT[$field]->SelectionGet() ) }]);	
}

sub addTextWidget
{
	my ($field,$hight) = @_;
	my $label   = $TYPES[$field];
	my $yscroll;
	my $width=$ww - 2 ;

	$FRAME[$field] = $mainFrame->Frame  ();
	$LABEL[$field] = $FRAME[$field]->Label  (-text=>"$label:", -font=>$fn)->pack(-side=>"left");
	$TEXT[$field]  = $FRAME[$field]->Text (-width=>$width, -height=>$hight, -wrap => "word", -font=> $fn);
 	$yscroll       = $FRAME[$field]->Scrollbar (  -takefocus => 0, -orient=>"vertical", -width=>$sliderWidth,
			                                 -command => [yview=>$TEXT[$field]]);
 	$TEXT[$field]  ->configure (-yscrollcommand => [set => $yscroll]);
 	$yscroll       ->pack (-side=>"right", -fill=>"both");
 	$TEXT[$field]  ->pack (-fill=>"both", -side=>"right");
 	$TEXT[$field]  ->configure ("-cursor"=>"top_left_arrow");
	$TEXT[$field]->bind("<Alt-Return>",           [sub{ editEntryCB("Key"); Tk::break;} ]);
	$TEXT[$field]->bind("<Insert>", [sub{$TEXT[$field]->Insert($TEXT[$field]->SelectionGet() ) }]);	


#	$TEXT[$field]->bind("<Return>",[sub {$TEXT[$field]->focusNext()}]);	
	
	$TEXT[$field]->bind("<Tab>",[sub {$TEXT[$field]->focusNext(); Tk::break}]);
	$TEXT[$field]->bind("<Prior>",[\&MyPrevPage,$field]);
	$TEXT[$field]->bind("<Next>",[\&MyNextPage,$field]);	
	$TEXT[$field]->bindtags(['all',$TEXT[$field],,$TEXT[$field]->toplevel,ref($TEXT[$field])]) ;
#	print join(",",$TEXT[$field]->bindtags)."\n" ;
}

sub printLOGGUI
{
  my ($status, $string) = @_;
  my $d = $top->DialogBox(-title=>"Log",-buttons=>["OK"]) ;
  my $f = $d->add("Frame")->pack(-side=>"left") ;
  my $t = $f->Text(-width=>50,-height=>10,-wrap=>"word",-font=>$fn )->pack(-padx=>5);
  $t->insert("0.0",$string) ;
  my $y = $f->Scrollbar( -takefocus => 0, 
			 -orient=>"vertical", 
			 -width=>$sliderWidth,
			 -command => [yview=>$t]);

  $t  ->configure (-yscrollcommand => [set => $y]);
  $y       ->pack (-side=>"right",-pady=>5);
  $t  ->pack (-fill=>"both", -side=>"left");
  $y       ->pack (-side=>"right", -fill=>"both");
  
  $d->Show ;
}

sub printStatusGUI 
{
	my ($status, $string) = @_;
	my ($modflag) ;
	if( someModified () ) {
	  $modflag = "Y" ;
	  } else {
	  $modflag = "N" ;
	  }
	if ($status eq "ERROR")  {
		$statusLabel->configure (-foreground=>$foreground7,
				                   -background=>$background3);
		$statusDummyLabel->configure (-foreground=>$foreground7,
				                        -background=>$background3);
	}
	if ($status eq "OK")  {
		if ($#Lol < 0)  {
			$string = sprintf ("Mod:%s Status: OK    empty database",$modflag);
		} else {
			$string = sprintf ("Mod:%s Status: OK    %05d of %05d (%05d selected)", $modflag, $highlightedEntry+1, $#Lol+1
			, $nSelected);
		}
		if ( $databaseName ne "" ) {
		  $string = $string . "   Database: " . $databaseName ;
		}
		$statusLabel->configure (-text=>$string, 
				                   -foreground=>$foreground6,
				                   -background=>$background2);
		$statusDummyLabel->configure (-foreground=>$foreground6,
				                        -background=>$background2);
	}  else  {
		$statusExpired++;
		$string = sprintf ("Mod:%s Status: %-4s    %s Database: %s", $modflag,$status, $string,$databaseName);
		$statusLabel->configure (-text=>$string);
		$listWin->update ();
		$listWin->Tk::after (10000, \&cleanStatusBar);
	}
}

sub cleanStatusBar
{
	my $string;
	my ($modflag) ;
	if( someModified ) {
	  $modflag = "Y" ;
	  } else {
	  $modflag = "N" ;
	  }
	$statusExpired--;
	if ($statusExpired <= 1)  {
		if ($#Lol < 0)  {
			$string = sprintf ("Mod:%s Status: OK    empty database",$modflag);
		} else {
			$string = sprintf ("Mod:%s Status: OK    %05d of %05d (%05d selected)", $modflag,$highlightedEntry+1, $#Lol+1
			, $nSelected);
		}
		if ( $databaseName ne "" ) {
		  $string = $string . "   Database: " . $databaseName ;
		}
		$statusLabel->configure (-text=>$string, 
				                   -foreground=>$foreground6,
				                   -background=>$background2);
		$statusDummyLabel->configure (-foreground=>$foreground6,
				                        -background=>$background2);
	}
}


sub destroyLogWindowCB
{
   $logWinView = 0;
}

sub execLogCommandCB
{
	my $res;
   if (execCommand ($logCommand) == 1)  {
		updateHistory ($logCommand);
		$_ = $logCommand;
		if ( /read/ || /import/ || /merge/ ) { 
			displayTitles;	displayEntryCB (0);
		}
		if ( /show/) { markMatches; }
		if ( /^\s*:/   ) { markMatches; updateQueryWindow ("all"); }
		$logCommand = "";
		printStatus ("OK");
		displayTitles () ;     
		displayMarkCB ("all");
	}  else  {
		printStatusGUI ("ERROR", "Command '$logCommand' not found.");
	}
}

sub execCommandCB
{
   my ($command) = @_ ;
	my $res;
   if (execCommand ($command) == 1)  {
		updateHistory ($command);
		$_ = $command;
		if ( /read/ || /import/ || /merge/ || /[^\s]+\s*:/ ) { 
			displayTitles;	displayEntryCB (0);
		}
		if ( /show/) { markMatches; }
		if ( /:/   ) { markMatches; updateQueryWindow ("all"); }
		$logCommand = "";
		printStatus ("OK");
		displayTitles () ;     
		displayMarkCB ("all");
	}  else  {
		printStatusGUI ("ERROR", "Command '$logCommand' not found.");
	}
}

sub manageLogWindowCB
{
	my $who = pop;
	if ($who eq "Button")  {
		$logWinView = $logWinView == 1 ? 0 : 1;
	}
	if ($logWinView == 0)  {$logWin->destroy ();}
	else                   {showLogWindow (); }
}

sub updateHistory 
{
	updateLogWindow ("single", @_);
}

sub updateLogWindow
{
	my ($type, $string) = @_;
	my ($str, $i);
	if ($type eq "all" && $logWinView == 1)  {
		$logListbox->delete ("1.0", "end");
		for ($i=0; $i<=$#cmdln; $i++)  {
			$str = sprintf ("%-3d  %s", $i, $cmdln[$i]);
			$logListbox->insert ("end", $str);
		}
	}
	if ($type eq "single")  {
		$cmdln[$history] = $string;
		if ($logWinView == 1)  {
			$str = sprintf ("%-3d  %s", $history, $string);
			$logListbox->insert ("end", $str);
		}
		$history++;
	}
	if ($logWinView == 1 )  { $logListbox->see ("end") }
}

sub askOpenFile
{
	my $title = shift( @_ ) ;
	my @filetypes = @_ ;

	if( $ui eq "gui" ) {
		push @filetypes,['All Files', '*' ] ;
		
		return $listWin->getOpenFile(-title=>$title) ;
	} else {
		my $rep ;
		print $title." " ;
		$rep = <>; chop $rep ;
		return $rep ;
	}
}

sub askSaveFile
{
	my $title = shift( @_ ) ;
	my @filetypes = @_ ;

	if( $ui eq "gui" ) {
		push @filetypes,['All Files', '*' ] ;
		
		return $listWin->getSaveFile(-title=>$title) ;
	} else {
		my $rep ;
		print $title." " ;
		$rep = <>; chop $rep ;
		return $rep ;
	}
}


sub historyFind
{
	my ($command, $index) = @_ ;
	my $i ;
	my @l ;
	for( $i=$history-1; $i >=0; $i-- ) {
		if( $cmdln[$i] =~ /^$command/ ) {
			if( !defined($index) || ($index eq "" ) ) {
				return( $' ) ; #'
			}
			@l = split( /\s+/, $cmdln[$i] ) ;
			return $l[$index] ;
		}
        }
	return "" ;
}

sub showLogWindow
{
	if ($logWinView == 1)  {
                my ($logFrame, $logButtonFrame, $logButton, $logEntry);
		$logWin     = $top->Toplevel (Name=>"LogWindow");
		$logWin->wm ("title", "History Window");
		$logFrame   = $logWin->Frame ();
		$logListbox = $logFrame->ScrlListbox (-label=>"Command line history",
			                                   -height=>10, -width=>35, -font=>$fn,
									   			     -selectmode=>"single",
													     -exportselection=>0)
			->pack(-expand=>"yes", -fill=>"both");
		$logEntry   = $logFrame->Entry (-textvariable=>\$logCommand, -font=>$fn)
			->pack(-expand=>"yes", -fill=>"x", -pady=>5);
#		$logEntry->focus ();
		$logButton  = $logFrame->Button (-text=>"Execute", -font=>$fn,
				                           -command=>[\&execLogCommandCB])
			->pack (-pady=>5);
		$logFrame->pack (-expand=>"yes", -fill=>"both");
		$logEntry  ->bind("<Destroy>",           [\&destroyLogWindowCB]);
		$logEntry  ->bind("<Return>",            [\&execLogCommandCB]);
		$logEntry  ->bind("<KP_Enter>",          [\&execLogCommandCB]);
		$logListbox->bind("<Double-Button-1>", 
		sub{ ($logCommand) = $logListbox->Getselected =~ /^\s*\d+\s*(.+?)$/ });

		my $g = $top->geometry() ;
		$g =~ /^(\d*)x(\d*)\+(\d+)\+(\d+)/ ;
		my ($w,$h,$xpos,$ypos) = ($1,$2,$3,$4) ;
		$xpos -= 278 ;
		$ypos += 200 ;
		if( $xpos < 0 ) { $xpos = $xpos +278 + $w ;}
		if( $ypos < 0 ) { $ypos = 0 ;}
		
		$logWin->geometry( "+$xpos+$ypos" ) ;


		updateLogWindow ("all");
		$logListbox->see ("end");
	}
}

sub destroyQueryWindowCB
{
   $queryWinView = 0;
}

sub manageQueryWindowCB
{
	my $who = pop;
	if ($who eq "Button")  {
		$queryWinView = $queryWinView == 1 ? 0 : 1;
	}
	if ($queryWinView == 0)  {$queryWin->destroy ();}
	else                     {showQueryWindow (); }
}

sub updateQueryWindow
{
	my ($type) = @_;
	my ($str, $i);
	if ($queryWinView == 1)  {
		if ($type eq "all")  {
			$queryListbox->delete ("1.0", "end");
			for ($i=0; $i<=$#LoM; $i++)  {
		      $str = sprintf ("#%-3d:  %d matches   %s", $i, $LonM[$i], $LoMCmdLn[$i]);
				$queryListbox->insert ("end", $str);
				$queryListbox->selection ("clear", 0, "end");
				if ($match >= 0)  { $queryListbox->selection("set", $match); }
			}
		}  else  {
		   $str = sprintf ("#%-3d:  %d matches   %s", $match, $LonM[$match], $LoMCmdLn[$match]);
         $queryListbox->insert ("end", $str);
			$queryListbox->selection ("clear", 0, "end");
			if ($match >= 0)  { $queryListbox->selection("set", $match); }
		}
		$queryListbox->see ("end");
	}
}
sub showQueryWindow
{
    if ($queryWinView == 1)  {
		my ($queryFrame);
		$queryWin     = $top->Toplevel (Name=>"QueryWindow");
		$queryWin->wm("title", "Query Window");
		$queryFrame   = $queryWin->Frame ();
		$queryListbox = $queryFrame->ScrlListbox (-label=>"Search results",
			                                       -height=>10, -width=>35, -font=>$fn,
									   			         -selectmode=>"single",
													         -exportselection=>0)
			->pack(-expand=>"yes", -fill=>"both");
		$queryFrame->pack (-expand=>"yes", -fill=>"both");
		$queryWin->bind("<Destroy>",         [\&destroyQueryWindowCB]);
		$queryWin->bind("<Double-Button-1>", 
				sub{ ($match) = $queryListbox->Getselected =~ /^#\s*(\d+)/; 
				markMatches; printStatusGUI ("OK");
				updateHistory ("show $match");
				});
		
		my $g = $top->geometry() ;
		$g =~ /^(\d*)x(\d*)\+(\d+)\+(\d+)/ ;
		my ($w,$h,$xpos,$ypos) = ($1,$2,$3,$4) ;
		$xpos -= 278 ;
		$ypos += 500 ;
		if( $xpos < 0 ) { $xpos = $xpos +278 + $w ;}
		if( $ypos < 0 ) { $ypos = 0 ;}
		
		$queryWin->geometry( "+$xpos+$ypos" ) ;

updateQueryWindow ("all");
	 }	 
}

sub destroyDBWindowCB
{
   $DBWinView = 0;
}

sub manageDBWindowCB
{
	my $who = pop;
	if ($who eq "Button")  {
		$DBWinView = $DBWinView == 1 ? 0 : 1;
	}
	if ($DBWinView == 0)  {$top->focus(); $DBWin->destroy ();$queryEntry->focus()}
	else                     {showDBWindow (); }
}

sub updateDBWindow
{

	my ($type) = @_;
	my ($str, $i);
	if ($DBWinView == 1)  {
          if ($type eq "all")  {
	    $DBListbox->delete ("0.0", "end");
			foreach $i ( keys(%databases))  {
                          my $g = $i  ;
                          $i =~ s/^$home/~/ ;
			  $str = sprintf ("%s %s", $databaseModified{$g}?"+":"-",$i) ;
			  $DBListbox->insert (0, $str);
			  if( $g eq $databaseName ) { $DBListbox->selection("set",0);}
#			  if( $g ) { DBListbox->Getselected(0);} ;
			}
#			$DBListbox->selection ("clear", 0, "end");
		}  
		$DBListbox->see ("end");
	}
}

sub showDBWindow
{
    if ($DBWinView == 1)  {
		my ($DBFrame);
		$DBWin     = $top->Toplevel (Name=>"DatabaseWindow");
		$DBWin->wm("title", "Database Window");
		$DBFrame   = $DBWin->Frame ();
		$DBListbox = $DBFrame->ScrlListbox (-label=>"Databases",
		                                    -height=>10, -width=>35, -font=>$fn
						    ,-selectmode=>"single"
#						    ,-takefocus => 0
#						    ,-exportselection=>0
                                                    )
						    ->pack(-expand=>"yes", -fill=>"both");
		$DBListbox ->focus() ;
		$DBFrame->pack (-expand=>"yes", -fill=>"both");
		$DBWin->bind("<Destroy>",         [\&destroyDBWindowCB]);
		$DBWin->bind("<Tab>",         [sub {$queryEntry->focus(); $DBListbox->break();}]);		
		$DBWin->bind("<Double-Button-1>", 
				sub{ ($databaseName) = $DBListbox->Getselected =~ /^[-+] ([^\s]*)/;
				$databaseName =~ s/^~\//$home\// ;
				updateHistory( "db $databaseName") ;				
				printStatusGUI ("OK");
				});
	$DBListbox->bind ("<Return>", sub{$DBListbox->BeginSelect($DBListbox->index('active'));($databaseName) = $DBListbox->Getselected =~ /^[-+] ([^\s]*)/;
				$databaseName =~ s/^~\//$home\// ;
				updateHistory( "db $databaseName") ;
				printStatusGUI ("OK");});	
	$DBListbox->bind ("<Alt-Return>", sub{$DBListbox->BeginSelect($DBListbox->index('active'));($databaseName) = $DBListbox->Getselected =~ /^[+-] ([^\s]*)/;
				$databaseName =~ s/^~\//$home\// ; 
				updateHistory( "db $databaseName") ;
#				$DBWin->destroy() ;
				$queryEntry->focus() ;
				printStatusGUI ("OK");});
		my $g = $top->geometry() ;
		$g =~ /^(\d*)x(\d*)\+(\d+)\+(\d+)/ ;
		my ($w,$h,$xpos,$ypos) = ($1,$2,$3,$4) ;
		$xpos -= 278 ;
		if( $xpos < 0 ) { $xpos = $xpos +278 + $w ;}
		if( $ypos < 0 ) { $ypos = 0 ;}
		
		$DBWin->geometry( "+$xpos+$ypos" ) ;
		
		updateDBWindow ("all");
	 }	 
}

sub openhelpCB
{
     my ($topic) = @_ ;
     my $url ;
     if( $topic eq "topics" ) {
        $url = "file:".$ConfArray{'SIXDOC'}."/t1.html" ;
     } elsif( $topic eq "formats" ) {
        $url = "file:".$ConfArray{'SIXDOC'}."/x683.html" ;
      } elsif( $topic eq "bibtex" ) {
        $url = "http://hypatia.dcs.qmw.ac.uk/html/bibliography.html" ;
      } elsif( $topic eq "pubmed jo" ) {
        $url = "http://www.ncbi.nlm.nih.gov:80/entrez/journals/loftext_noprov.html" ;
      } elsif( $topic eq "pubmed qu" ) {
        $url = "http://www.ncbi.nlm.nih.gov:80/entrez/query/static/help/pmhelp.html#SearchFieldDescriptionsandTags" ;
      }
      my $command;
      if( defined $ConfArray{"HELPHANDLE"} ) {
       $command = $ConfArray{"HELPHANDLE"} ;
      } else {
       $command = $ConfArray{"URLHANDLE"} ;
      }
      if( $command =~ s/%s/$url/g) {
         $command = $command . " &" ;
      } else {
         $command = $command . " " . $url . " &" ;
      }
      system( $command ) ;
}

sub initMenubar
{
	my ($menuFrame, $menuFile, $menuEntry, $menuTransfer, $menuView, $menuQuery, $menuHelp);
   my ($i, $field, $string );
	$menuFrame = $listWin->Frame (Name=>"menu");
#  FILE ----------------------------------------------------------------------------
	$menuFile = $menuFrame->Menubutton(-text=>"File", -underline=>0, -font=>$fn);
	my $Nm = -1 ;
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"New Database", 
			                                -command =>sub{openRefFileCB("new")});
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"New BibTex", 
			                                -command =>sub{openBibFileCB("new")});
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Open Database      Alt-o", 
			                                -underline=>0,-command =>sub{openRefFileCB("old")});
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Open BibTex        Alt-b", 
			                                -underline=>5,-command =>sub{openBibFileCB("open")});
							
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Close cur Database  ", 
			                                -underline=>0,-command =>sub{closeDatabaseCB()});
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Force Close cur Database", 
			                                -command =>sub{closeDatabaseCB("force")});
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Save Database      Alt-s", 
			                                -underline=>0,-command => sub{ saveCurRefFileCB });
	$menu{'File'}[++$Nm] = $menuFile->checkbutton(-label=>"Sort str&cross when save",
			                                    -underline=>0,-variable=>\$sortBeforeSave,
							    );
	$menu{'File'}[++$Nm] =$menuFile->cascade( -label=>"Recent",-underline=>0 ) ;
	my $recentMenu = $menuFile->menu->Menu( -font=>$fn) ;
	my @recent = grepHistory () ;
	my $cmd ;
	foreach $cmd ( @recent ) {
	   if( !($cmd =~ /^\s*$/ )){
	      $menu{'File'}[++$Nm] = $recentMenu->command(-label=>"$cmd ",
			                                  -command => [\&execCommandCB," $cmd"]);
	   }
	}
	$menuFile->entryconfigure("Recent",-menu=>$recentMenu) ;

        $menuFile->separator ();
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Read Collection     ", 
			                                -underline=>0, -command =>sub{sourceFileCB (); $DBWinView=1; showDBWindow() ; } );
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Write Collection     ", 
			                                -underline=>0, -command =>sub{writeCollectionCB ()} );
	                   $menuFile->separator ();			   
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Close all databases     ", 
			                                -command =>sub{newDatabaseCB ()} );
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Save modified Databases      ", 
			                                -underline=>5,-command => sub{ saveAllDatabases (0) });
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Force Save All Databases      ", 
			                                -underline=>11,-command => sub{ saveAllDatabases (1) });
	                   $menuFile->separator ();
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Merge Database           ", 
			                                -underline=>0,-command=>sub { openRefFileCB("merge") } );
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Save all Databases as    ", 
			                                -underline=>19,-command => sub{ saveRefFileCB("all") });
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Save marked Entries as  ", 
			                                -command=>sub { saveRefFileCB("marked") } );
	                   $menuFile->separator ();
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Load Logfile             ", 
			                                -state=>"disabled");
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Save Logfile             ", 
			                                -state=>"disabled");
	                   $menuFile->separator ();
	my ($exec_title, $exec_com, $make_sep) ;
	$make_sep=0 ;
	for( $i=0; $i<10; $i++) {
	    if( defined( $ConfArray{'MENUEXEC'.$i} ) ) {
	    	my ($exec_title,$exec_com) = split(/\s*:\s*/, $ConfArray{'MENUEXEC'.$i}) ;
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>$exec_title, 
			                                -command=>sub { sourceFile( $exec_com) ; updateHistory("source $exec_com") } );
		$make_sep=1 ;
	   }
	}
	if( $make_sep==1) { $menuFile->separator() ;}
	     
							 
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Exit               Alt-x", 
			                                -underline=>1, -command => sub {exitIfUnmod});
	$menu{'File'}[++$Nm] = $menuFile->command(-label=>"Force Quit (no save)", 
			                                -underline=>6, -command => sub {myexit; exit 0});
	$menuFile->pack(-side=>"left");
	for ($i=0; $i<=$Nm; $i++)  {	$menu{'File'}[$i]->configure (-font=>$fn); }
#  EDIT ----------------------------------------------------------------------------
	$menuEntry = $menuFrame->Menubutton(-text=>"Edit", -underline=>0, -font=>$fn);
	$Nm = -1 ;
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Copy                Ctl c", 
			                                 -underline=>0,-command=>sub{ copyCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Cut                 Ctl x", 
			                                 -underline=>0,-command=>sub{ cutCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Paste               Ctl v", 
			                                 -underline=>0,-command=>sub{ pasteCB });
	                   $menuEntry->separator ();
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>"Add new reference     Alt-ins", 
			                                 -underline=>4,-command =>sub{ addEntryDialogCB("Menu");} );
	$menu{'Edit'}[++$Nm] = $menuEntry->checkbutton(-label=>"Edit reference  Alt-enter", 
	                                                 -underline=>0,-variable=>\$editUnlocked ,
							 -command =>sub{ editEntryCB ("Menu") } );
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>"Remove selected references",
		  			                           -command=>sub{ deleteEntryCB("selected") });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>"Remove reference     Alt-del",
		  			                           -command=>sub{ deleteEntryCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>"Make CITEID for reference(s)   ",
		  			                           -underline=>5,-command=>sub{ makeCITEIDCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>"Bracket {C}apitalized for reference(s)",
		  			                           -underline=>5,-command=>sub{ bracketTITLECB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Insert in LyX       Alt l",
		  			                           -underline=>10,-command=>sub{ tellLyxCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Insert in Emacs     Alt m", -underline=>11,
		  			                           -command=>sub{ tellEmacsCB });
	                   $menuEntry->separator ();
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Mark entry          Alt +", 
			                                 -underline=>0,-command=>sub{ markEntryCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Unmark entry        Alt -", 
			                                 -underline=>0,-command=>sub{ unmarkEntryCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Mark all entries    Alt a", 
			                                 -underline=>5,-command=>sub{ markAllEntriesCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Unmark all entries  Alt u", 
			                                 -command=>sub{ unmarkAllEntriesCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Flip all marks   ", 
			                                 -underline=>0,-command=>sub{ flipMarksCB } );
	                   $menuEntry->separator ();
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Mark Double CITEIDs", 
			                                 -command=>sub{ markDoubleCiteidCB });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Mark according to aux file", 
			                                 -command=>sub{ markAuxCB });
	                   $menuEntry->separator ();
        $menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Sort by Author", 
			                                 -underline=>0,-command=>sub{ sortCB( $KEYS[$AUTHOR] ) });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Sort by Title", 
			                                 -underline=>8,-command=>sub{ sortCB( $KEYS[$TITLE] ) });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Sort by Journal", 
			                                 -underline=>8,-command=>sub{ sortCB( $KEYS[$JOURNAL] ) });
	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Sort by Year", 
			                                 -underline=>8,-command=>sub{ sortCB( $KEYS[$YEAR] ) });
#	$menu{'Edit'}[++$Nm] = $menuEntry->command(-label=>    "Sort by Year", 
#			                                 -underline=>8,-command=>sub{ sortCB( "save" ) });
	$menuEntry->pack(-side=>"left");
	for ($i=0; $i<=$Nm; $i++)  {	$menu{'Edit'}[$i]->configure (-font=>$fn); }
#  TRANSFER ------------------------------------------------------------------------
	$menuTransfer = $menuFrame->Menubutton(-text=>"Transfer", -underline=>0, -font=>$fn);
	$Nm = -1 ;
	$menu{'Transfer'}[++$Nm] = $menuTransfer->checkbutton(-label=>"import is raw html",
			                                    -underline=>0,-variable=>\$importhtml);
	$menu{'Transfer'}[++$Nm] = $menuTransfer->checkbutton(-label=>"use selection for import/export",
			                                    -underline=>0,-variable=>\$importselection);
	$menu{'Transfer'}[++$Nm] =$menuTransfer->cascade( -label=>"Import" ) ;
	my $importMenu = $menuTransfer->menu->Menu ;
	  $menu{'Transfer'}[++$Nm]  = $importMenu->command(-label=>"Import simple bibtex (keep everything)",
			                                         -command=>sub{ importCB ("simple") } );
	  $menu{'Transfer'}[++$Nm]  = $importMenu->command(-label=>"Import complex bibtex (convert \@strings)",
			                                         -command=>sub{ importCB ("bibtex") } );
	  $menu{'Transfer'}[++$Nm]  = $importMenu->command(-label=>"Import more complex bibtex (convert crossref)",
			                                         -command=>sub{ importCB ("crosbibtex") } );
	foreach $i ( @bpInSupported ) {
	  $menu{'Transfer'}[++$Nm]  = $importMenu->command(-label=>"Import $i",
			                                         -command=>sub{ importCB ($i) } );
	}
	$menuTransfer->entryconfigure("Import",-menu=>$importMenu) ;
	$menu{'Transfer'}[++$Nm] =$menuTransfer->cascade( -label=>"Export") ;
        my $exportMenu = $menuTransfer->menu->Menu ;
	  $menu{'Transfer'}[++$Nm]  = $exportMenu->command(-label=>"Export bibtex",
			                                         -command=>sub{ exportCB ("bibtex") } );
	$menu{'Transfer'}[++$Nm] = $exportMenu->checkbutton(-label=>"Sort str&cross when save",
			                                    -underline=>0,-variable=>\$sortBeforeSave,
							    );
	foreach $i ( @bpOutSupported ) {
	  $menu{'Transfer'}[++$Nm]  = $exportMenu->command(-label=>"Export $i",
			                                         -command=>sub{ exportCB ($i) } );
	}
	$menuTransfer->entryconfigure("Export",-menu=>$exportMenu) ;
	$menu{'Transfer'}[++$Nm] = $menuTransfer->command(-label=>"View file externally  Alt-v",    
			                                         -underline=>0,-command=>sub{ dothingsToMiscCB });
	$menu{'Transfer'}[++$Nm] = $menuTransfer->command(-label=>"View url externally ",    
			                                         -underline=>5,-command=>sub{ dothingsToMiscURLCB });
	$menuTransfer->pack (-side=>"left");
	for ($i=0; $i<=$Nm; $i++)  {	$menu{'Transfer'}[$i]->configure (-font=>$fn); }
#  Display ----------------------------------------------------------------------------
	$menuView = $menuFrame->Menubutton(-text=>"Display", -underline=>0, -font=>$fn);
	$Nm = -1 ;
	$menu{'View'}[++$Nm] = $menuView->checkbutton(-label=>"Database window",
			                                    -underline=>0,-variable=>\$DBWinView,
							    -command=>[\&manageDBWindowCB, "Menu"]);
	$menu{'View'}[++$Nm] = $menuView->checkbutton(-label=>"History window",
			                                    -underline=>0,-variable=>\$logWinView,
			                                    -command=>[\&manageLogWindowCB, "Menu"]);
	$menu{'View'}[++$Nm] = $menuView->checkbutton(-label=>"Query window",
			                                    -underline=>0,-variable=>\$queryWinView,
							    -command=>[\&manageQueryWindowCB, "Menu"]);
	                   $menuView->separator ();
	$menu{'View'}[++$Nm] = $menuView->command(-label=>"previous query    Alt-up",
			                                -command=>[\&printQueryHistCB, "prev"]);
	$menu{'View'}[++$Nm] = $menuView->command(-label=>"next query        Alt-next",
			                                -command=>[\&printQueryHistCB, "next"]);
	                   $menuView->separator ();
			   
	$menuView->pack(-side=>"left");
        my $temp_menu=$menuView ;
	my $n = 0 ;
        for ($field=0; $field <= $MAXFIELDS; $field++)  { 
		$n++ ;
		if( $n >  $ConfArray{'ENTRIESPERMENU'}  ) {
		        $temp_menu->cascade( -label=>"More" ) ;
		        my $next_temp_menu = $temp_menu->menu->Menu ;
			$temp_menu->entryconfigure("More",-menu=>$next_temp_menu) ;
			$temp_menu = $next_temp_menu ;
#			$temp_menu->pack(-side=>"left") ;
			$n=0 ;
		 }
		$DISPLAYED[$field] = 1;
		$menu{'View'}[++$Nm] = $temp_menu->checkbutton(-label=>"$TYPES[$field]", 
				                                           -variable=> \$DISPLAYED[$field],
									   -command=>[\&displayEntryCB,-1] );
	}
	for ($i=0; $i<=$Nm; $i++)  {	$menu{'View'}[$i]->configure (-font=>$fn); }
#  QUERY ---------------------------------------------------------------------------
	$menuQuery = $menuFrame->Menubutton(-text=>"Query", -underline=>0, -font=>$fn);
	$Nm = -1 ;
	$menu{'Query'}[++$Nm] = $menuQuery->command(-label=>"Store current marks", 
							                      -command=>sub{saveMarks () });
	                    $menuQuery->separator ();
	$menu{'Query'}[++$Nm] = $menuQuery->checkbutton(-label=>"Web query on PubMed",
			                                    -underline=>0,-variable=>\$MedlineQUERY);
	$menu{'Query'}[++$Nm] =$menuQuery->cascade( -label=>"PubMed") ;
	my $menuPubMed ;
	$menuPubMed = $menuQuery->menu->Menu( -font=>$fn) ;
	$menuQuery->entryconfigure("PubMed",-menu=>$menuPubMed) ;
	$menu{'Query'}[++$Nm] = $menuPubMed->command(-label=>"JTB ",
			                                  -command=>sub{printQueryCB ("J Theor Biol [TA] ") }) ;
	$menu{'Query'}[++$Nm] = $menuPubMed->command(-label=>"PNAS ",
			                                  -command=>sub{printQueryCB ("PNAS [TA] ") }) ;
	$menu{'Query'}[++$Nm] = $menuPubMed->command(-label=>"Proc Roy Soc ",
			                                  -command=>sub{printQueryCB ("Proc R Soc Lond B Biol Sci [TA]") }) ;
	$menu{'Query'}[++$Nm] = $menuPubMed->command(-label=>"date (yyyy/mm/dd)",
			                                  -command=>sub{printQueryCB (" [dp] ") }) ;

	                    $menuQuery->separator ();
	$string = sprintf ("%-15s %s", "Parenthesis", "(");
	$menu{'Query'}[++$Nm] = $menuQuery->command(-label=>$string, 
							                      -command=>sub{printQueryCB (" ( ") });
	$string = sprintf ("%-15s %s", "Parenthesis", ")");
	$menu{'Query'}[++$Nm] = $menuQuery->command(-label=>$string, 
							                      -command=>sub{printQueryCB(" ) ") });
	$string = sprintf ("%-15s %s", "And", "and");
	                    $menuQuery->separator ();
	$menu{'Query'}[++$Nm] = $menuQuery->command(-label=>$string, 
							                      -command=>sub{printQueryCB (" AND ")} );
	$string = sprintf ("%-15s %s", "Or", "or");
	$menu{'Query'}[++$Nm] = $menuQuery->command(-label=>$string, 
							                      -command=>sub{printQueryCB (" OR ") });
	$menuQuery->separator ();
	$menuQuery->pack(-side=>"left");
        $temp_menu=$menuQuery ;
	$n = 0 ;
        for ($field=0; $field <= $MAXKEYS; $field++)  { 
		$n++ ;
		if( $n > $ConfArray{'ENTRIESPERMENU'}  ) {
		        $temp_menu->cascade( -label=>"More" ) ;
		        my $next_temp_menu = $temp_menu->menu->Menu ;
			$temp_menu->entryconfigure("More",-menu=>$next_temp_menu) ;
			$temp_menu = $next_temp_menu ;
#			$temp_menu->pack(-side=>"left") ;
			$n=0 ;
		 }
		 $string = sprintf ("%-15s %s", $TYPES[$field], $KEYS[$field]);
		 $menu{'Query'}[++$Nm] = $temp_menu->command(-label=>$string, 
								                             -command=>[\&printQueryCB," $KEYS[$field]="]);

   }
	for ($i=0; $i<=$Nm; $i++)  {	$menu{'Query'}[$i]->configure (-font=>$fn); }
#  HELP ----------------------------------------------------------------------------
	$menuHelp = $menuFrame->Menubutton(-text=>"Help", -underline=>0, -font=>$fn);
	$Nm = -1 ;
	$menu{'Help'}[++$Nm] = $menuHelp->checkbutton(-label=>"Balloon help",
			                                    -underline=>0,-variable=>\$balloonOn,
							    -command=>sub{if($balloonOn){$Balloon->configure(-state=>'both');}else{$Balloon->configure(-state=>'none');}});
	$menu{'Help'}[++$Nm] = $menuHelp->command(-label=>"About....", 
			                                -state=>"disabled");
	                   $menuHelp->separator ();
	$menu{'Help'}[++$Nm] = $menuHelp->command(-label=>"Topics", 
			                                -command=>sub{openhelpCB("topics");});
	$menu{'Help'}[++$Nm] = $menuHelp->command(-label=>"BibTeX", 
			                                -command=>sub{openhelpCB("bibtex");});
	$menu{'Help'}[++$Nm] = $menuHelp->command(-label=>"PubMed journals", 
			                                -command=>sub{openhelpCB("pubmed jo");});
	$menu{'Help'}[++$Nm] = $menuHelp->command(-label=>"PubMed search fields", 
			                                -command=>sub{openhelpCB("pubmed qu");});
	                   $menuHelp->separator ();
	$menu{'Help'}[++$Nm] = $menuHelp->command(-label=>"Supported Formats",
			                               -command=>sub{openhelpCB("formats");});
	$menuHelp->pack(-side=>"right");
	for ($i=0; $i<=$Nm; $i++)  {	$menu{'Help'}[$i]->configure (-font=>$fn); }
#  ---------------------------------------------------------------------------------
	$menuFrame->pack (-fill=>"x");
	
}






sub guiMain
{
	my ($i);
        $editUnlocked     =  0;
	$statusExpired    =  0;
	$highlightedEntry = -1;
	$match            =  0;
	$logWinView       =  0;
	$queryWinView     =  0;
	$DBWinView     =  0;	
	$queryString      = "";
	$ui               = "gui";
#############
# 1st window
        Tk::CmdLine::LoadResources(-echo => \*STDERR,  -file     => $ConfArray{"BIBXRESFILE"}   , -priority => 40 ) ;
        $top = MainWindow->new (); 

	if( defined( $top->optionGet("font","") ) ) {
	        $fn = $top->optionGet("font","")  ;
	}
	if( defined( $top->optionGet("sliderWidth","") ) ) {
	        $sliderWidth = $top->optionGet("sliderWidth","")  ;
	}
	{my $color ;
	foreach my $name ( 
		"background1" ,
		"background2" ,		
		"background3" ,		
		"background4" ,		
		"foreground1" ,		
		"foreground2" ,		
		"foreground3" ,		
		"foreground4" ,		
		"foreground5" ,		
		"foreground6" ,		
		"foreground7" ) {
	if( defined( $top->optionGet($name,"") ) ) {
		$color = $top->optionGet($name,"") ;
		$color =~ s/^\s*// ;
		$color =~ s/\s*$// ;
	        eval( "\$$name = \$color" )  ;
	}
      }
      }
		

	$top -> wm ("title",    "Sixpack");
	$top -> wm ("iconname", "Sixpack");
	if( defined( $top->optionGet("geometry","") ) ) {
	        $geometry = $top->optionGet("geometry","Default")  ;
	}
#	$top -> wm ("geometry", $geometry);
#	$top->gemetry("640x480") ;
#        $top->bind("<Destroy>",           [sub{exitIfUnmod(); $top->break();}]);
	$listWin = $top->Frame (Name=>"listFrame");

        if( defined($ConfArray{'BALLOONHELP'}) && 
	    $ConfArray{'BALLOONHELP'} =~ /^(f.*|off|n.*)/i ) {
	    $balloonOn = 0 ;
	} else {
	    $balloonOn = 1 ;
	}
        $Balloon = $top->Balloon(Name=>"balloon");
        if($balloonOn){$Balloon->configure(-state=>'both');}else{$Balloon->configure(-state=>'none');}
   initMenubar ();	

        #title list
	my ($listFrame, $listyscroll);
	$listFrame   = $listWin->Frame  (Name=>"entryFrame");
        $listText    = $listFrame->Text (-height=>15, -wrap => "none", -font=> $fn);
        # button bar included
	my ($refFrame);
	$refFrame  = $listWin->Frame (Name=>"newFrame");
	for $i ( qw(sixpack_load 	sixpack_save 	sixpack_add  sixpack_edit 	sixpack_trash 
					sixpack_search sixpack_cmdln 	sixpack_label sixpack_help sixpack_view 
			      sixpack_prev 	sixpack_next 	sixpack_prev sixpack_next 	sixpack_lock )) {
		push @buttonXpm, $refFrame->Pixmap ('-file' => "$PICSDIR/sixpack/$i.xpm");
	}
	$buttonList[ 0] = $refFrame->Button (-image => $buttonXpm[0], 
			                                -command=> sub {openRefFileCB (); })
		             ->pack (-side=>"left");
	$Balloon->attach($buttonList[0],-balloonmsg => "Open Database");   
	$buttonList[ 1] = $refFrame->Button (-image => $buttonXpm[1],-command=> sub {newDatabaseCB(); openRefFileCB (); } )->pack (-side=>"left");
			     $refFrame->Frame( -width=>8 )->pack(-side=>"left") ;
	$Balloon->attach($buttonList[1],-balloonmsg => "New Database");   
	$buttonList[ 2] = $refFrame->Button (-image => $buttonXpm[2],
			                               -command=>sub{addEntryDialogCB ("Button");})->pack (-side=>"left");
	$Balloon->attach($buttonList[2],-balloonmsg => "Add new entry");
	$buttonList[ 3] = $refFrame->Button (-image => $buttonXpm[3], 
			                               -command=> sub { editEntryCB ("Button"); })
		             ->pack (-side=>"left");
			     $refFrame->Frame( -width=>8 )->pack(-side=>"left") ;
	$Balloon->attach($buttonList[3],-balloonmsg => "Edit current entry");   
	$buttonList[ 4] = $refFrame->Button (-image => $buttonXpm[4],
			                               -command=> sub { manageDBWindowCB ("Button"); })->pack (-side=>"left");
	$Balloon->attach($buttonList[4],-balloonmsg => "Show databases window");   
	$buttonList[ 6] = $refFrame->Button (-image => $buttonXpm[6],
			                               -command=> sub{ manageLogWindowCB ("Button") })->pack (-side=>"left");
	$Balloon->attach($buttonList[6],-balloonmsg => "Show history window");   
	$buttonList[ 5] = $refFrame->Button (-image => $buttonXpm[5],
			                               -command=> sub{ manageQueryWindowCB ("Button" )})->pack (-side=>"left");
			     $refFrame->Frame( -width=>8 )->pack(-side=>"left") ;
	$Balloon->attach($buttonList[5],-balloonmsg => "Show query window");   
        $buttonList[ 7] = $refFrame->Button (-image => $buttonXpm[7],
	-command=> sub { sortCB ($KEYS[$AUTHOR]); }
	)->pack (-side=>"left");
	$Balloon->attach($buttonList[7],-balloonmsg => "Sort by author");   
	$buttonList[ 8] = $refFrame->Button (-image => $buttonXpm[8],
	-command=> sub { sortCB ($KEYS[$TITLE]); }	
	)->pack (-side=>"left");
	$Balloon->attach($buttonList[8],-balloonmsg => "Sort by title");   
	$buttonList[ 9] = $refFrame->Button (-image => $buttonXpm[9],
	-command=> sub { dothingsToMiscCB; }
	)->pack (-side=>"left");
	$Balloon->attach($buttonList[9],-balloonmsg => "Open external viewer for reference");   
	$buttonList[10] = $refFrame->Button (-image => $buttonXpm[10], 
			                                -command=> sub{pagingCB("prev");})
		             ->pack (-side=>"right");
	$Balloon->attach($buttonList[10],-balloonmsg => "Previous entry");   
	$buttonList[11] = $refFrame->Button (-image => $buttonXpm[11], 
			                                -command=> sub{pagingCB("next");})
		             ->pack (-side=>"right");
	$Balloon->attach($buttonList[11],-balloonmsg => "Next entry");   
	$buttonList[12] = $refFrame->Button (-image => $buttonXpm[12], 
			                                -command=> sub{pagingCB("prevsel");})
		             ->pack (-side=>"right");
	$Balloon->attach($buttonList[12],-balloonmsg => "Previous selected entry");
	$buttonList[13] = $refFrame->Button (-image => $buttonXpm[13], 
			                                -command=> sub{pagingCB("nextsel");})
		             ->pack (-side=>"right");
	$Balloon->attach($buttonList[13],-balloonmsg => "Next selected entry");   
	$refFrame->pack(-fill=>"x");
	
#query frame
	my ($queryFrame, $querySearchButton, $queryClearButton);
	$queryFrame = $listWin->Frame (Name=>"queryFrame");
	$queryFrame->Button (-height=>1, -text=>"Clear", -font=>$fn,
	                     -command=>
								sub{$queryString="";})->pack (-side=>"right");
	$queryFrame->Button (-height=>1, -text=>"OR", -font=>$fn,
	                     -command=>
								sub{printQueryCB(" OR ");})->pack (-side=>"right");
	$queryFrame->Button (-height=>1, -text=>"AND",  -font=>$fn,
	                     -command=>
								sub{printQueryCB (" AND ");})->pack (-side=>"right");
	$queryFrame->Button (-text=>"Search:", -font=>$fn,
			               -command=>sub {evalQueryCB ();}) ->pack (-side=>"left");
	$queryEntry = $queryFrame->Entry (-textvariable=>\$queryString, -font=>$fn)
		        ->pack (-side=>"right", -fill=>"x", -expand=>"yes");

	$Balloon->attach($queryEntry,-balloonmsg => "Enter query. For example:\nau=einstein\nti=origins");   	
# keybindings
	$queryEntry->bind("<Return>",              [\&evalQueryCB ]);
	$queryEntry->bind("<KP_Enter>",            [\&evalQueryCB ]);
	$queryEntry->bind("<Up>",                  [\&pagingCB,     "prev"     ]);
	$queryEntry->bind("<Down>",                [\&pagingCB,     "next"     ]);
	$queryEntry->bind("<Shift-Up>",            [\&pagingCB,     "prevsel"  ]);
	$queryEntry->bind("<Shift-Down>",          [\&pagingCB,     "nextsel"  ]);
	$queryEntry->bind("<Home>",                [\&pagingCB,     "home"     ]);
	$queryEntry->bind("<End>",                 [\&pagingCB,     "end"      ]);
	$queryEntry->bind("<Prior>",               [\&pagingCB,     "pageup"   ]);
	$queryEntry->bind("<Next>",                [\&pagingCB,     "pagedown" ]);
	$queryEntry->bind("<Alt-Up>",          [\&printQueryHistCB, "prevsel" ]);
	$queryEntry->bind("<Alt-Down>",        [\&printQueryHistCB, "nextsel" ]);
	$queryEntry->bind("<Control-Up>",          [\&printQueryHistCB, "prevsel" ]);
	$queryEntry->bind("<Control-Down>",        [\&printQueryHistCB, "nextsel" ]);
	$queryEntry->bind("<Alt-o>",           [\&openRefFileCB]);
	$queryEntry->bind("<Alt-s>",           [\&saveCurRefFileCB]);
	$queryEntry->bind("<Alt-b>",           [\&openBibFileCB]);	
	$queryEntry->bind("<Alt-x>",           [\&exitIfUnmod]);
#	$listWin->bind("<Destroy>",           [sub { exitIfUnmod(); $listWin->break();}]);
	$queryEntry->bind("<Alt-Insert>",      [\&addEntryDialogCB, "Key"]);
	$queryEntry->bind("<Alt-Delete>",      [\&deleteEntryCB]);
	$queryEntry->bind("<Alt-BackSpace>",      [\&deleteEntryCB]);	
	$queryEntry->bind("<Alt-Return>",           [\&editEntryCB, "Key" ]);	
	$queryEntry->bind("<Alt-l>",           [sub {&tellLyxCB }]);
	$queryEntry->bind("<Alt-m>",           [sub {&tellEmacsCB }]);
	$queryEntry->bind("<Alt-plus>",        [\&markEntryCB]);
	$queryEntry->bind("<Alt-equal>",        [\&markEntryCB]);	
	$queryEntry->bind("<Alt-KP_Add>",      [\&markEntryCB]);
	$queryEntry->bind("<Alt-minus>",       [\&unmarkEntryCB]);
	$queryEntry->bind("<Alt-underscore>",       [\&unmarkEntryCB]);	
	$queryEntry->bind("<Alt-KP_Subtract>", [\&unmarkEntryCB]);
	$queryEntry->bind("<Alt-a>",           [\&markAllEntriesCB]);
	$queryEntry->bind("<Alt-u>",           [\&unmarkAllEntriesCB]);
	$queryEntry->bind("<Alt-v>",           [\&dothingsToMiscCB]);	
	$queryEntry->bind("<Control-c>",           [\&copyCB]);	
	$queryEntry->bind("<Control-x>",           [\&cutCB]);	
	$queryEntry->bind("<Control-v>",           [sub {pasteCB();Tk::break;}]);	
	$queryEntry->bindtags(['all',$queryEntry,,$queryEntry->toplevel,ref($queryEntry)]) ;
	$queryFrame->pack (-fill=>"x");


#title list continues here
 	$listyscroll = $listWin->Scrollbar (-orient=>"vertical", -width=>$sliderWidth, -command => [yview=>$listText]);
 	$listText    ->configure (-yscrollcommand => [set => $listyscroll], -takefocus => 0);
 	$listText    ->configure (-state=>"disabled");
 	$listyscroll->pack (-side=>"right", -fill=>"both");
 	$listText->pack (-fill=>"x", -side=>"right", -expand=>"yes");
 	$listFrame->pack(-fill=>"x");
 	$listText->configure ("-cursor"=>"top_left_arrow");
	
#Canvas
	my $yscroll;
	$mainCanvas = $top->Canvas (Name=>"entryFrame");
	$mainFrame  = $mainCanvas->Frame ();
#	$top->bind('all',"<Alt-Return>",           [\&editEntryCB, "Key" ]);	
 	$yscroll    = $mainCanvas->Scrollbar (-orient=>"vertical", -width=>$sliderWidth, 
			                                 -command => [yview=>$mainCanvas]);
 	$mainCanvas->configure (-yscrollcommand => ['set', $yscroll], -takefocus => 0);
 	$yscroll->pack (-side=>"right", -fill=>"y");

        my @g ;
#	print join(", ", @WidgetOrder ) ;
        foreach $i (@WidgetOrder) {
	  
	   @g = grep(/^$i$/,@TextFields) ;
	   if( $#g < 0 ) { 
	      addEntryWidget($i) ;	   
	   } else {
	      addTextWidget($i,$FieldsH[$i]) ;
	   }
	}

#Status bar
	my ($statusFrame);
	$statusFrame = $top->Frame ();
	$statusLabel = $statusFrame->Label (-text=>"Welcome to sixpack", 
			                              -relief=>"flat", -font=>$fn,
													-foreground=>$foreground6, -background=>$background2);
	$statusDummyLabel  = $statusFrame->Label ( 
			                              -relief=>"flat", -font=>$fn,
													-foreground=>$foreground6, -background=>$background2);
    	
	$statusLabel->pack(-anchor=>"w", side=>"left");
	$statusDummyLabel->pack(-fill=>"x", -expand=>"yes", side=>"right");
	
	

	
	$mainCanvas->create (("window", 0, 0), -anchor=>"nw", -window=>$mainFrame);

	$listWin   ->pack (-fill=>"x");
	$mainCanvas->pack (-fill=>"both", -expand=>"yes");
	$statusFrame->pack (-fill=>"x");

        lockAllFields () ;
	
	$queryEntry->focus ();
	$Fbrowser = $listWin->FileSelect ();
        if( defined( $ConfArray{'WGET'} ) && $ConfArray{'WGET'} ne "" ) {
	   $UFbrowser = $listWin->FileSelect ();
	   $UFbrowser->Subwidget('file_entry')->bind('<Return>' => [\&URLValidate, $UFbrowser, Ev(['get'])]);
	   $UFbrowser->Subwidget('file_entry')->configure( -label => "URL/File" );
	} else {
	   $UFbrowser = $Fbrowser ;
	}
        if( $#Lol>0 ) {
#        readRefFile($databaseName);
          initIdx () ;
	  displayTitles ();
	  displayEntryCB (0);
	  displayMarkCB("all") ;
        }
        showLogWindow ();
	showQueryWindow ();
	showDBWindow ();	
	MainLoop;
}

