Merge commit 'biblibre/3.2_biblibre' into to-push
[koha_fer] / C4 / Search.pm
index f1b68b5..16c6a55 100644 (file)
@@ -19,7 +19,7 @@ use strict;
 # use warnings; # FIXME
 require Exporter;
 use C4::Context;
 # use warnings; # FIXME
 require Exporter;
 use C4::Context;
-use C4::Biblio;    # GetMarcFromKohaField
+use C4::Biblio;    # GetMarcFromKohaField, GetBiblioData
 use C4::Koha;      # getFacets
 use Lingua::Stem;
 use C4::Search::PazPar2;
 use C4::Koha;      # getFacets
 use Lingua::Stem;
 use C4::Search::PazPar2;
@@ -27,6 +27,9 @@ use XML::Simple;
 use C4::Dates qw(format_date);
 use C4::XSLT;
 use C4::Branch;
 use C4::Dates qw(format_date);
 use C4::XSLT;
 use C4::Branch;
+use C4::Debug;
+use YAML;
+use URI::Escape;
 
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG);
 
 
 use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $DEBUG);
 
@@ -54,43 +57,20 @@ This module provides searching functions for Koha's bibliographic databases
 
 @ISA    = qw(Exporter);
 @EXPORT = qw(
 
 @ISA    = qw(Exporter);
 @EXPORT = qw(
-  &findseealso
   &FindDuplicate
   &SimpleSearch
   &searchResults
   &getRecords
   &buildQuery
   &NZgetRecords
   &FindDuplicate
   &SimpleSearch
   &searchResults
   &getRecords
   &buildQuery
   &NZgetRecords
+  &AddSearchHistory
+  &GetDistinctValues
+  &BiblioAddAuthorities
 );
 );
+#FIXME: i had to add BiblioAddAuthorities here because in Biblios.pm it caused circular dependencies (C4::Search uses C4::Biblio, and BiblioAddAuthorities uses SimpleSearch from C4::Search)
 
 # make all your functions, whether exported or not;
 
 
 # make all your functions, whether exported or not;
 
-=head2 findseealso($dbh,$fields);
-
-C<$dbh> is a link to the DB handler.
-
-use C4::Context;
-my $dbh =C4::Context->dbh;
-
-C<$fields> is a reference to the fields array
-
-This function modifies the @$fields array and adds related fields to search on.
-
-FIXME: this function is probably deprecated in Koha 3
-
-=cut
-
-sub findseealso {
-    my ( $dbh, $fields ) = @_;
-    my $tagslib = GetMarcStructure(1);
-    for ( my $i = 0 ; $i <= $#{$fields} ; $i++ ) {
-        my ($tag)      = substr( @$fields[$i], 1, 3 );
-        my ($subfield) = substr( @$fields[$i], 4, 1 );
-        @$fields[$i] .= ',' . $tagslib->{$tag}->{$subfield}->{seealso}
-          if ( $tagslib->{$tag}->{$subfield}->{seealso} );
-    }
-}
-
 =head2 FindDuplicate
 
 ($biblionumber,$biblionumber,$title) = FindDuplicate($record);
 =head2 FindDuplicate
 
 ($biblionumber,$biblionumber,$title) = FindDuplicate($record);
@@ -201,7 +181,6 @@ for my $i (0..$hits) {
     my $biblio = TransformMarcToKoha(C4::Context->dbh,$marcrecord,'');
 
     #build the hash for the template.
     my $biblio = TransformMarcToKoha(C4::Context->dbh,$marcrecord,'');
 
     #build the hash for the template.
-    $resultsloop{highlight}       = ($i % 2)?(1):(0);
     $resultsloop{title}           = $biblio->{'title'};
     $resultsloop{subtitle}        = $biblio->{'subtitle'};
     $resultsloop{biblionumber}    = $biblio->{'biblionumber'};
     $resultsloop{title}           = $biblio->{'title'};
     $resultsloop{subtitle}        = $biblio->{'subtitle'};
     $resultsloop{biblionumber}    = $biblio->{'biblionumber'};
@@ -218,13 +197,13 @@ $template->param(result=>\@results);
 
 sub SimpleSearch {
     my ( $query, $offset, $max_results, $servers )  = @_;
 
 sub SimpleSearch {
     my ( $query, $offset, $max_results, $servers )  = @_;
-    
+
     if ( C4::Context->preference('NoZebra') ) {
         my $result = NZorder( NZanalyse($query) )->{'biblioserver'};
         my $search_result =
           (      $result->{hits}
               && $result->{hits} > 0 ? $result->{'RECORDS'} : [] );
     if ( C4::Context->preference('NoZebra') ) {
         my $result = NZorder( NZanalyse($query) )->{'biblioserver'};
         my $search_result =
           (      $result->{hits}
               && $result->{hits} > 0 ? $result->{'RECORDS'} : [] );
-        return ( undef, $search_result, scalar($search_result) );
+        return ( undef, $search_result, scalar($result->{hits}) );
     }
     else {
         # FIXME hardcoded value. See catalog/search.pl & opac-search.pl too.
     }
     else {
         # FIXME hardcoded value. See catalog/search.pl & opac-search.pl too.
@@ -304,7 +283,7 @@ sub SimpleSearch {
     );
 
 The all singing, all dancing, multi-server, asynchronous, scanning,
     );
 
 The all singing, all dancing, multi-server, asynchronous, scanning,
-searching, record nabbing, facet-building 
+searching, record nabbing, facet-building
 
 See verbse embedded documentation.
 
 
 See verbse embedded documentation.
 
@@ -346,40 +325,21 @@ sub getRecords {
 
         # Check if we've got a query_type defined, if so, use it
         eval {
 
         # Check if we've got a query_type defined, if so, use it
         eval {
-            if ($query_type)
-            {
-                if ( $query_type =~ /^ccl/ ) {
-                    $query_to_use =~
-                      s/\:/\=/g;    # change : to = last minute (FIXME)
-                    $results[$i] =
-                      $zconns[$i]->search(
-                        new ZOOM::Query::CCL2RPN( $query_to_use, $zconns[$i] )
-                      );
-                }
-                elsif ( $query_type =~ /^cql/ ) {
-                    $results[$i] =
-                      $zconns[$i]->search(
-                        new ZOOM::Query::CQL( $query_to_use, $zconns[$i] ) );
-                }
-                elsif ( $query_type =~ /^pqf/ ) {
-                    $results[$i] =
-                      $zconns[$i]->search(
-                        new ZOOM::Query::PQF( $query_to_use, $zconns[$i] ) );
-                }
-            }
-            else {
-                if ($scan) {
-                    $results[$i] =
-                      $zconns[$i]->scan(
-                        new ZOOM::Query::CCL2RPN( $query_to_use, $zconns[$i] )
-                      );
-                }
-                else {
-                    $results[$i] =
-                      $zconns[$i]->search(
-                        new ZOOM::Query::CCL2RPN( $query_to_use, $zconns[$i] )
-                      );
+            if ($query_type) {
+                if ($query_type =~ /^ccl/) {
+                    $query_to_use =~ s/\:/\=/g;    # change : to = last minute (FIXME)
+                    $results[$i] = $zconns[$i]->search(new ZOOM::Query::CCL2RPN($query_to_use, $zconns[$i]));
+                } elsif ($query_type =~ /^cql/) {
+                    $results[$i] = $zconns[$i]->search(new ZOOM::Query::CQL($query_to_use, $zconns[$i]));
+                } elsif ($query_type =~ /^pqf/) {
+                    $results[$i] = $zconns[$i]->search(new ZOOM::Query::PQF($query_to_use, $zconns[$i]));
+                } else {
+                    warn "Unknown query_type '$query_type'.  Results undetermined.";
                 }
                 }
+            } elsif ($scan) {
+                    $results[$i] = $zconns[$i]->scan(  new ZOOM::Query::CCL2RPN($query_to_use, $zconns[$i]));
+            } else {
+                    $results[$i] = $zconns[$i]->search(new ZOOM::Query::CCL2RPN($query_to_use, $zconns[$i]));
             }
         };
         if ($@) {
             }
         };
         if ($@) {
@@ -427,7 +387,7 @@ sub getRecords {
                 $sort_by .= "1=4 >i ";
             }
             else {
                 $sort_by .= "1=4 >i ";
             }
             else {
-                warn "Ignoring unrecognized sort '$sort' requested";
+                warn "Ignoring unrecognized sort '$sort' requested" if $sort_by;
             }
         }
         if ($sort_by) {
             }
         }
         if ($sort_by) {
@@ -499,34 +459,20 @@ sub getRecords {
                     #warn $servers[$i-1]."\n".$record; #.$facet_record->title();
                         if ($facet_record) {
                             for ( my $k = 0 ; $k <= @$facets ; $k++ ) {
                     #warn $servers[$i-1]."\n".$record; #.$facet_record->title();
                         if ($facet_record) {
                             for ( my $k = 0 ; $k <= @$facets ; $k++ ) {
-
-                                if ( $facets->[$k] ) {
-                                    my @fields;
-                                    for my $tag ( @{ $facets->[$k]->{'tags'} } )
-                                    {
-                                        push @fields,
-                                          $facet_record->field($tag);
-                                    }
-                                    for my $field (@fields) {
-                                        my @subfields = $field->subfields();
-                                        for my $subfield (@subfields) {
-                                            my ( $code, $data ) = @$subfield;
-                                            if ( $code eq
-                                                $facets->[$k]->{'subfield'} )
-                                            {
-                                                $facets_counter->{ $facets->[$k]
-                                                      ->{'link_value'} }
-                                                  ->{$data}++;
-                                            }
-                                        }
+                                ($facets->[$k]) or next;
+                                my @fields = map {$facet_record->field($_)} @{$facets->[$k]->{'tags'}} ;
+                                for my $field (@fields) {
+                                    my @subfields = $field->subfields();
+                                    for my $subfield (@subfields) {
+                                        my ( $code, $data ) = @$subfield;
+                                        ($code eq $facets->[$k]->{'subfield'}) or next;
+                                        $facets_counter->{ $facets->[$k]->{'link_value'} }->{$data}++;
                                     }
                                     }
-                                    $facets_info->{ $facets->[$k]
-                                          ->{'link_value'} }->{'label_value'} =
-                                      $facets->[$k]->{'label_value'};
-                                    $facets_info->{ $facets->[$k]
-                                          ->{'link_value'} }->{'expanded'} =
-                                      $facets->[$k]->{'expanded'};
                                 }
                                 }
+                                $facets_info->{ $facets->[$k]->{'link_value'} }->{'label_value'} =
+                                    $facets->[$k]->{'label_value'};
+                                $facets_info->{ $facets->[$k]->{'link_value'} }->{'expanded'} =
+                                    $facets->[$k]->{'expanded'};
                             }
                         }
                     }
                             }
                         }
                     }
@@ -541,15 +487,15 @@ sub getRecords {
             if ( $servers[ $i - 1 ] =~ /biblioserver/ ) {
                 for my $link_value (
                     sort { $facets_counter->{$b} <=> $facets_counter->{$a} }
             if ( $servers[ $i - 1 ] =~ /biblioserver/ ) {
                 for my $link_value (
                     sort { $facets_counter->{$b} <=> $facets_counter->{$a} }
-                    keys %$facets_counter )
+                        keys %$facets_counter )
                 {
                     my $expandable;
                     my $number_of_facets;
                     my @this_facets_array;
                     for my $one_facet (
                         sort {
                 {
                     my $expandable;
                     my $number_of_facets;
                     my @this_facets_array;
                     for my $one_facet (
                         sort {
-                            $facets_counter->{$link_value}
-                              ->{$b} <=> $facets_counter->{$link_value}->{$a}
+                             $facets_counter->{$link_value}->{$b}
+                         <=> $facets_counter->{$link_value}->{$a}
                         } keys %{ $facets_counter->{$link_value} }
                       )
                     {
                         } keys %{ $facets_counter->{$link_value} }
                       )
                     {
@@ -571,25 +517,27 @@ sub getRecords {
 
                             # if it's a branch, label by the name, not the code,
                             if ( $link_value =~ /branch/ ) {
 
                             # if it's a branch, label by the name, not the code,
                             if ( $link_value =~ /branch/ ) {
-                                $facet_label_value =
-                                  $branches->{$one_facet}->{'branchname'};
+                                                               if (defined $branches
+                                                                       && ref($branches) eq "HASH"
+                                                                       && defined $branches->{$one_facet}
+                                                                       && ref ($branches->{$one_facet}) eq "HASH")
+                                                               {
+                                       $facet_label_value =
+                                               $branches->{$one_facet}->{'branchname'};
+                                                               }
+                                                               else {
+                                                                       $facet_label_value = "*";
+                                                               }
                             }
 
                             }
 
-                # but we're down with the whole label being in the link's title.
-                            my $facet_title_value = $one_facet;
-
-                            push @this_facets_array,
-                              (
-                                {
-                                    facet_count =>
-                                      $facets_counter->{$link_value}
-                                      ->{$one_facet},
-                                    facet_label_value => $facet_label_value,
-                                    facet_title_value => $facet_title_value,
-                                    facet_link_value  => $facet_link_value,
-                                    type_link_value   => $link_value,
-                                },
-                              );
+                            # but we're down with the whole label being in the link's title.
+                            push @this_facets_array, {
+                                facet_count       => $facets_counter->{$link_value}->{$one_facet},
+                                facet_label_value => $facet_label_value,
+                                facet_title_value => $one_facet,
+                                facet_link_value  => $facet_link_value,
+                                type_link_value   => $link_value,
+                            };
                         }
                     }
 
                         }
                     }
 
@@ -599,17 +547,14 @@ sub getRecords {
                           if ( ( $number_of_facets > 6 )
                             && ( $expanded_facet ne $link_value ) );
                     }
                           if ( ( $number_of_facets > 6 )
                             && ( $expanded_facet ne $link_value ) );
                     }
-                    push @facets_loop,
-                      (
-                        {
-                            type_link_value => $link_value,
-                            type_id         => $link_value . "_id",
-                            "type_label_" . $facets_info->{$link_value}->{'label_value'} => 1, 
-                            facets     => \@this_facets_array,
-                            expandable => $expandable,
-                            expand     => $link_value,
-                        }
-                      ) unless ( ($facets_info->{$link_value}->{'label_value'} =~ /Libraries/) and (C4::Context->preference('singleBranchMode')) );
+                    push @facets_loop, {
+                        type_link_value => $link_value,
+                        type_id         => $link_value . "_id",
+                        "type_label_" . $facets_info->{$link_value}->{'label_value'} => 1,
+                        facets     => \@this_facets_array,
+                        expandable => $expandable,
+                        expand     => $link_value,
+                    } unless ( ($facets_info->{$link_value}->{'label_value'} =~ /Libraries/) and (C4::Context->preference('singleBranchMode')) );
                 }
             }
         }
                 }
             }
         }
@@ -633,10 +578,10 @@ sub pazGetRecords {
     my $results_hashref = {};
     my $stats = XMLin($paz->stat);
     my $results = XMLin($paz->show($offset, $results_per_page, 'work-title:1'), forcearray => 1);
     my $results_hashref = {};
     my $stats = XMLin($paz->stat);
     my $results = XMLin($paz->show($offset, $results_per_page, 'work-title:1'), forcearray => 1);
-   
+
     # for a grouped search result, the number of hits
     # is the number of groups returned; 'bib_hits' will have
     # for a grouped search result, the number of hits
     # is the number of groups returned; 'bib_hits' will have
-    # the total number of bibs. 
+    # the total number of bibs.
     $results_hashref->{'biblioserver'}->{'hits'} = $results->{'merged'}->[0];
     $results_hashref->{'biblioserver'}->{'bib_hits'} = $stats->{'hits'};
 
     $results_hashref->{'biblioserver'}->{'hits'} = $results->{'merged'}->[0];
     $results_hashref->{'biblioserver'}->{'bib_hits'} = $stats->{'hits'};
 
@@ -668,7 +613,7 @@ sub pazGetRecords {
 
         push @{ $results_hashref->{'biblioserver'}->{'GROUPS'} }, $result_group;
     }
 
         push @{ $results_hashref->{'biblioserver'}->{'GROUPS'} }, $result_group;
     }
-    
+
     # pass through facets
     my $termlist_xml = $paz->termlist('author,subject');
     my $terms = XMLin($termlist_xml, forcearray => 1);
     # pass through facets
     my $termlist_xml = $paz->termlist('author,subject');
     my $terms = XMLin($termlist_xml, forcearray => 1);
@@ -702,19 +647,18 @@ sub _remove_stopwords {
 #       we use IsAlpha unicode definition, to deal correctly with diacritics.
 #       otherwise, a French word like "leçon" woudl be split into "le" "çon", "le"
 #       is a stopword, we'd get "çon" and wouldn't find anything...
 #       we use IsAlpha unicode definition, to deal correctly with diacritics.
 #       otherwise, a French word like "leçon" woudl be split into "le" "çon", "le"
 #       is a stopword, we'd get "çon" and wouldn't find anything...
-        foreach ( keys %{ C4::Context->stopwords } ) {
-            next if ( $_ =~ /(and|or|not)/ );    # don't remove operators
-            if ( $operand =~
-                /(\P{IsAlpha}$_\P{IsAlpha}|^$_\P{IsAlpha}|\P{IsAlpha}$_$|^$_$)/ )
-            {
-                $operand =~ s/\P{IsAlpha}$_\P{IsAlpha}/ /gi;
-                $operand =~ s/^$_\P{IsAlpha}/ /gi;
-                $operand =~ s/\P{IsAlpha}$_$/ /gi;
-                               $operand =~ s/$1//gi;
-                push @stopwords_removed, $_;
-            }
-        }
-    }
+#
+               foreach ( keys %{ C4::Context->stopwords } ) {
+                       next if ( $_ =~ /(and|or|not)/ );    # don't remove operators
+                       $debug && warn "$_ Dump($operand)";
+                       if ( my ($matched) = ($operand =~
+                               /([^\X\p{isAlnum}]\Q$_\E[^\X\p{isAlnum}]|[^\X\p{isAlnum}]\Q$_\E$|^\Q$_\E[^\X\p{isAlnum}])/gi))
+                       {
+                               $operand =~ s/\Q$matched\E/ /gi;
+                               push @stopwords_removed, $_;
+                       }
+               }
+       }
     return ( $operand, \@stopwords_removed );
 }
 
     return ( $operand, \@stopwords_removed );
 }
 
@@ -750,30 +694,25 @@ sub _detect_truncation {
 
 # STEMMING
 sub _build_stemmed_operand {
 
 # STEMMING
 sub _build_stemmed_operand {
-    my ($operand) = @_;
+    my ($operand,$lang) = @_;
+    require Lingua::Stem::Snowball ;
     my $stemmed_operand;
 
     # If operand contains a digit, it is almost certainly an identifier, and should
     # not be stemmed.  This is particularly relevant for ISBNs and ISSNs, which
     my $stemmed_operand;
 
     # If operand contains a digit, it is almost certainly an identifier, and should
     # not be stemmed.  This is particularly relevant for ISBNs and ISSNs, which
-    # can contain the letter "X" - for example, _build_stemmend_operand would reduce 
+    # can contain the letter "X" - for example, _build_stemmend_operand would reduce
     # "014100018X" to "x ", which for a MARC21 database would bring up irrelevant
     # results (e.g., "23 x 29 cm." from the 300$c).  Bug 2098.
     return $operand if $operand =~ /\d/;
 
 # FIXME: the locale should be set based on the user's language and/or search choice
     # "014100018X" to "x ", which for a MARC21 database would bring up irrelevant
     # results (e.g., "23 x 29 cm." from the 300$c).  Bug 2098.
     return $operand if $operand =~ /\d/;
 
 # FIXME: the locale should be set based on the user's language and/or search choice
-    my $stemmer = Lingua::Stem->new( -locale => 'EN-US' );
+    #warn "$lang";
+    my $stemmer = Lingua::Stem::Snowball->new( lang => $lang,
+                                               encoding => "UTF-8" );
 
 
-# FIXME: these should be stored in the db so the librarian can modify the behavior
-    $stemmer->add_exceptions(
-        {
-            'and' => 'and',
-            'or'  => 'or',
-            'not' => 'not',
-        }
-    );
     my @words = split( / /, $operand );
     my @words = split( / /, $operand );
-    my $stems = $stemmer->stem(@words);
-    for my $stem (@$stems) {
+    my @stems = $stemmer->stem(\@words);
+    for my $stem (@stems) {
         $stemmed_operand .= "$stem";
         $stemmed_operand .= "?"
           unless ( $stem =~ /(and$|or$|not$)/ ) || ( length($stem) < 3 );
         $stemmed_operand .= "$stem";
         $stemmed_operand .= "?"
           unless ( $stem =~ /(and$|or$|not$)/ ) || ( length($stem) < 3 );
@@ -844,13 +783,201 @@ sub _build_weighted_query {
     return $weighted_query;
 }
 
     return $weighted_query;
 }
 
+=head2 getIndexes
+
+Return an array with available indexes.
+
+=cut
+
+sub getIndexes{
+    my @indexes = (
+                    # biblio indexes
+                    'ab',
+                    'Abstract',
+                    'acqdate',
+                    'allrecords',
+                    'an',
+                    'Any',
+                    'at',
+                    'au',
+                    'aub',
+                    'aud',
+                    'audience',
+                    'auo',
+                    'aut',
+                    'Author',
+                    'Author-in-order ',
+                    'Author-personal-bibliography',
+                    'Authority-Number',
+                    'authtype',
+                    'bc',
+                    'biblionumber',
+                    'bio',
+                    'biography',
+                    'callnum',          
+                    'cfn',
+                    'Chronological-subdivision',
+                    'cn-bib-source',
+                    'cn-bib-sort',
+                    'cn-class',
+                    'cn-item',
+                    'cn-prefix',
+                    'cn-suffix',
+                    'cpn',
+                    'Code-institution',
+                    'Conference-name',
+                    'Conference-name-heading',
+                    'Conference-name-see',
+                    'Conference-name-seealso',
+                    'Content-type',
+                    'Control-number',
+                    'copydate',
+                    'Corporate-name',
+                    'Corporate-name-heading',
+                    'Corporate-name-see',
+                    'Corporate-name-seealso',
+                    'ctype',
+                    'date-entered-on-file',
+                    'Date-of-acquisition',
+                    'Date-of-publication',
+                    'Dewey-classification',
+                    'extent',
+                    'fic',
+                    'fiction',
+                    'Form-subdivision',
+                    'format',
+                    'Geographic-subdivision',
+                    'he',
+                    'Heading',
+                    'Heading-use-main-or-added-entry',
+                    'Heading-use-series-added-entry ',
+                    'Heading-use-subject-added-entry',
+                    'Host-item',
+                    'id-other',
+                    'Illustration-code',
+                    'ISBN',
+                    'ISSN',
+                    'itemtype',
+                    'kw',
+                    'Koha-Auth-Number',
+                    'l-format',
+                    'language',
+                    'lc-card',
+                    'LC-card-number',
+                    'lcn',
+                    'llength',
+                    'ln',
+                    'Local-classification',
+                    'Local-number',
+                    'Match-heading',
+                    'Match-heading-see-from',
+                    'Material-type',
+                    'mc-itemtype',
+                    'mc-rtype',
+                    'mus',
+                    'Name-geographic',
+                    'Name-geographic-heading',
+                    'Name-geographic-see',
+                    'Name-geographic-seealso',
+                    'nb',
+                    'Note',
+                    'ns',
+                    'nt',
+                    'pb',
+                    'Personal-name',
+                    'Personal-name-heading',
+                    'Personal-name-see',
+                    'Personal-name-seealso',
+                    'pl',
+                    'Place-publication',
+                    'pn',
+                    'popularity',
+                    'pubdate',
+                    'Publisher',
+                    'Record-type',
+                    'rtype',
+                    'se',
+                    'See',
+                    'See-also',
+                    'sn',
+                    'Stock-number',
+                    'su',
+                    'Subject',
+                    'Subject-heading-thesaurus',
+                    'Subject-name-personal',
+                    'Subject-subdivision',
+                    'Summary',
+                    'Suppress',
+                    'su-geo',
+                    'su-na',
+                    'su-to',
+                    'su-ut',
+                    'ut',
+                    'Term-genre-form',
+                    'Term-genre-form-heading',
+                    'Term-genre-form-see',
+                    'Term-genre-form-seealso',
+                    'ti',
+                    'Title',
+                    'Title-cover',
+                    'Title-series',
+                    'Title-uniform',
+                    'Title-uniform-heading',
+                    'Title-uniform-see',
+                    'Title-uniform-seealso',
+                    'totalissues',
+                    'yr',
+                    
+                    # items indexes
+                    'acqsource',
+                    'barcode',
+                    'bc',
+                    'branch',
+                    'ccode',
+                    'classification-source',
+                    'cn-sort',
+                    'coded-location-qualifier',
+                    'copynumber',
+                    'damaged',
+                    'datelastborrowed',
+                    'datelastseen',
+                    'holdingbranch',
+                    'homebranch',
+                    'issues',
+                    'itemnumber',
+                    'itype',
+                    'Local-classification',
+                    'location',
+                    'lost',
+                    'materials-specified',
+                    'mc-ccode',
+                    'mc-itype',
+                    'mc-loc',
+                    'notforloan',
+                    'onloan',
+                    'price',
+                    'renewals',
+                    'replacementprice',
+                    'replacementpricedate',
+                    'reserves',
+                    'restricted',
+                    'stack',
+                    'uri',
+                    'withdrawn',
+                    
+                    # subject related
+                  );
+                  
+    return \@indexes;
+}
+
 =head2 buildQuery
 
 ( $error, $query,
 $simple_query, $query_cgi,
 $query_desc, $limit,
 $limit_cgi, $limit_desc,
 =head2 buildQuery
 
 ( $error, $query,
 $simple_query, $query_cgi,
 $query_desc, $limit,
 $limit_cgi, $limit_desc,
-$stopwords_removed, $query_type ) = getRecords ( $operators, $operands, $indexes, $limits, $sort_by, $scan);
+$stopwords_removed, $query_type ) = buildQuery ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang);
 
 Build queries and limits in CCL, CGI, Human,
 handle truncation, stemming, field weighting, stopwords, fuzziness, etc.
 
 Build queries and limits in CCL, CGI, Human,
 handle truncation, stemming, field weighting, stopwords, fuzziness, etc.
@@ -861,16 +988,16 @@ See verbose embedded documentation.
 =cut
 
 sub buildQuery {
 =cut
 
 sub buildQuery {
-    my ( $operators, $operands, $indexes, $limits, $sort_by, $scan ) = @_;
+    my ( $operators, $operands, $indexes, $limits, $sort_by, $scan, $lang) = @_;
 
     warn "---------\nEnter buildQuery\n---------" if $DEBUG;
 
     # dereference
 
     warn "---------\nEnter buildQuery\n---------" if $DEBUG;
 
     # dereference
-    my @operators = @$operators if $operators;
-    my @indexes   = @$indexes   if $indexes;
-    my @operands  = @$operands  if $operands;
-    my @limits    = @$limits    if $limits;
-    my @sort_by   = @$sort_by   if $sort_by;
+    my @operators = $operators ? @$operators : ();
+    my @indexes   = $indexes   ? @$indexes   : ();
+    my @operands  = $operands  ? @$operands  : ();
+    my @limits    = $limits    ? @$limits    : ();
+    my @sort_by   = $sort_by   ? @$sort_by   : ();
 
     my $stemming         = C4::Context->preference("QueryStemming")        || 0;
     my $auto_truncation  = C4::Context->preference("QueryAutoTruncate")    || 0;
 
     my $stemming         = C4::Context->preference("QueryStemming")        || 0;
     my $auto_truncation  = C4::Context->preference("QueryAutoTruncate")    || 0;
@@ -880,9 +1007,10 @@ sub buildQuery {
 
     # no stemming/weight/fuzzy in NoZebra
     if ( C4::Context->preference("NoZebra") ) {
 
     # no stemming/weight/fuzzy in NoZebra
     if ( C4::Context->preference("NoZebra") ) {
-        $stemming      = 0;
-        $weight_fields = 0;
-        $fuzzy_enabled = 0;
+        $stemming         = 0;
+        $weight_fields    = 0;
+        $fuzzy_enabled    = 0;
+       $auto_truncation  = 0;
     }
 
     my $query        = $operands[0];
     }
 
     my $query        = $operands[0];
@@ -899,27 +1027,40 @@ sub buildQuery {
 
     my $stopwords_removed;    # flag to determine if stopwords have been removed
 
 
     my $stopwords_removed;    # flag to determine if stopwords have been removed
 
+    my $cclq;
+    my $cclindexes = getIndexes();
+    if( $query !~ /\s*ccl=/ ){
+        for my $index (@$cclindexes){
+            if($query =~ /($index)(,?\w)*[:=]/){
+                $cclq = 1;
+            }
+        }
+        $query = "ccl=$query" if($cclq);
+    }
+
 # for handling ccl, cql, pqf queries in diagnostic mode, skip the rest of the steps
 # DIAGNOSTIC ONLY!!
     if ( $query =~ /^ccl=/ ) {
 # for handling ccl, cql, pqf queries in diagnostic mode, skip the rest of the steps
 # DIAGNOSTIC ONLY!!
     if ( $query =~ /^ccl=/ ) {
-        return ( undef, $', $', $', $', '', '', '', '', 'ccl' );
+        return ( undef, $', $', "q=ccl=$'", $', '', '', '', '', 'ccl' );
     }
     if ( $query =~ /^cql=/ ) {
     }
     if ( $query =~ /^cql=/ ) {
-        return ( undef, $', $', $', $', '', '', '', '', 'cql' );
+        return ( undef, $', $', "q=cql=$'", $', '', '', '', '', 'cql' );
     }
     if ( $query =~ /^pqf=/ ) {
     }
     if ( $query =~ /^pqf=/ ) {
-        return ( undef, $', $', $', $', '', '', '', '', 'pqf' );
+        return ( undef, $', $', "q=pqf=$'", $', '', '', '', '', 'pqf' );
     }
 
     # pass nested queries directly
     # FIXME: need better handling of some of these variables in this case
     }
 
     # pass nested queries directly
     # FIXME: need better handling of some of these variables in this case
-    if ( $query =~ /(\(|\))/ ) {
-        return (
-            undef,              $query, $simple_query, $query_cgi,
-            $query,             $limit, $limit_cgi,    $limit_desc,
-            $stopwords_removed, 'ccl'
-        );
-    }
+    # Nested queries aren't handled well and this implementation is flawed and causes users to be
+    # unable to search for anything containing () commenting out, will be rewritten for 3.4.0
+#    if ( $query =~ /(\(|\))/ ) {
+#        return (
+#            undef,              $query, $simple_query, $query_cgi,
+#            $query,             $limit, $limit_cgi,    $limit_desc,
+#            $stopwords_removed, 'ccl'
+#        );
+#    }
 
 # Form-based queries are non-nested and fixed depth, so we can easily modify the incoming
 # query operands and indexes and add stemming, truncation, field weighting, etc.
 
 # Form-based queries are non-nested and fixed depth, so we can easily modify the incoming
 # query operands and indexes and add stemming, truncation, field weighting, etc.
@@ -966,13 +1107,18 @@ sub buildQuery {
                 # ISBN,ISSN,Standard Number, don't need special treatment
                 elsif ( $index eq 'nb' || $index eq 'ns' ) {
                     $indexes_set++;
                 # ISBN,ISSN,Standard Number, don't need special treatment
                 elsif ( $index eq 'nb' || $index eq 'ns' ) {
                     $indexes_set++;
-                    (   
+                    (
                         $stemming,      $auto_truncation,
                         $weight_fields, $fuzzy_enabled,
                         $remove_stopwords
                     ) = ( 0, 0, 0, 0, 0 );
 
                 }
                         $stemming,      $auto_truncation,
                         $weight_fields, $fuzzy_enabled,
                         $remove_stopwords
                     ) = ( 0, 0, 0, 0, 0 );
 
                 }
+                
+                if(not $index){
+                    $index = 'kw';
+                }
+                
                 # Set default structure attribute (word list)
                 my $struct_attr;
                 unless ( $indexes_set || !$index || $index =~ /(st-|phr|ext|wrdl)/ ) {
                 # Set default structure attribute (word list)
                 my $struct_attr;
                 unless ( $indexes_set || !$index || $index =~ /(st-|phr|ext|wrdl)/ ) {
@@ -992,6 +1138,16 @@ sub buildQuery {
                       if ( $stopwords_removed && $DEBUG );
                 }
 
                       if ( $stopwords_removed && $DEBUG );
                 }
 
+                if ($auto_truncation){
+                                       unless ( $index =~ /(st-|phr|ext)/ ) {
+                                               #FIXME only valid with LTR scripts
+                                               $operand=join(" ",map{ 
+                                                                                       (index($_,"*")>0?"$_":"$_*")
+                                                                                        }split (/\s+/,$operand));
+                                               warn $operand if $DEBUG;
+                                       }
+                               }
+
                 # Detect Truncation
                 my $truncated_operand;
                 my( $nontruncated, $righttruncated, $lefttruncated,
                 # Detect Truncation
                 my $truncated_operand;
                 my( $nontruncated, $righttruncated, $lefttruncated,
@@ -1011,29 +1167,23 @@ sub buildQuery {
                     $indexes_set = 1;
                     undef $weight_fields;
                     my $previous_truncation_operand;
                     $indexes_set = 1;
                     undef $weight_fields;
                     my $previous_truncation_operand;
-                    if ( scalar(@$nontruncated) > 0 ) {
+                    if (scalar @$nontruncated) {
                         $truncated_operand .= "$index_plus @$nontruncated ";
                         $previous_truncation_operand = 1;
                     }
                         $truncated_operand .= "$index_plus @$nontruncated ";
                         $previous_truncation_operand = 1;
                     }
-                    if ( scalar(@$righttruncated) > 0 ) {
-                        $truncated_operand .= "and "
-                          if $previous_truncation_operand;
-                        $truncated_operand .=
-                          "$index_plus_comma" . "rtrn:@$righttruncated ";
+                    if (scalar @$righttruncated) {
+                        $truncated_operand .= "and " if $previous_truncation_operand;
+                        $truncated_operand .= $index_plus_comma . "rtrn:@$righttruncated ";
                         $previous_truncation_operand = 1;
                     }
                         $previous_truncation_operand = 1;
                     }
-                    if ( scalar(@$lefttruncated) > 0 ) {
-                        $truncated_operand .= "and "
-                          if $previous_truncation_operand;
-                        $truncated_operand .=
-                          "$index_plus_comma" . "ltrn:@$lefttruncated ";
+                    if (scalar @$lefttruncated) {
+                        $truncated_operand .= "and " if $previous_truncation_operand;
+                        $truncated_operand .= $index_plus_comma . "ltrn:@$lefttruncated ";
                         $previous_truncation_operand = 1;
                     }
                         $previous_truncation_operand = 1;
                     }
-                    if ( scalar(@$rightlefttruncated) > 0 ) {
-                        $truncated_operand .= "and "
-                          if $previous_truncation_operand;
-                        $truncated_operand .=
-                          "$index_plus_comma" . "rltrn:@$rightlefttruncated ";
+                    if (scalar @$rightlefttruncated) {
+                        $truncated_operand .= "and " if $previous_truncation_operand;
+                        $truncated_operand .= $index_plus_comma . "rltrn:@$rightlefttruncated ";
                         $previous_truncation_operand = 1;
                     }
                 }
                         $previous_truncation_operand = 1;
                     }
                 }
@@ -1042,18 +1192,20 @@ sub buildQuery {
 
                 # Handle Stemming
                 my $stemmed_operand;
 
                 # Handle Stemming
                 my $stemmed_operand;
-                $stemmed_operand = _build_stemmed_operand($operand)
-                  if $stemming;
+                $stemmed_operand = _build_stemmed_operand($operand, $lang)
+                                                                               if $stemming;
+
                 warn "STEMMED OPERAND: >$stemmed_operand<" if $DEBUG;
 
                 # Handle Field Weighting
                 my $weighted_operand;
                 warn "STEMMED OPERAND: >$stemmed_operand<" if $DEBUG;
 
                 # Handle Field Weighting
                 my $weighted_operand;
-                $weighted_operand =
-                  _build_weighted_query( $operand, $stemmed_operand, $index )
-                  if $weight_fields;
+                if ($weight_fields) {
+                    $weighted_operand = _build_weighted_query( $operand, $stemmed_operand, $index );
+                    $operand = $weighted_operand;
+                    $indexes_set = 1;
+                }
+
                 warn "FIELD WEIGHTED OPERAND: >$weighted_operand<" if $DEBUG;
                 warn "FIELD WEIGHTED OPERAND: >$weighted_operand<" if $DEBUG;
-                $operand = $weighted_operand if $weight_fields;
-                $indexes_set = 1 if $weight_fields;
 
                 # If there's a previous operand, we need to add an operator
                 if ($previous_operand) {
 
                 # If there's a previous operand, we need to add an operator
                 if ($previous_operand) {
@@ -1101,20 +1253,21 @@ sub buildQuery {
     my $group_OR_limits;
     my $availability_limit;
     foreach my $this_limit (@limits) {
     my $group_OR_limits;
     my $availability_limit;
     foreach my $this_limit (@limits) {
-        if ( $this_limit =~ /available/ ) {
-
-# 'available' is defined as (items.onloan is NULL) and (items.itemlost = 0)
-# In English:
-# all records not indexed in the onloan register (zebra) and all records with a value of lost equal to 0
-            $availability_limit .=
-"( ( allrecords,AlwaysMatches='' not onloan,AlwaysMatches='') and (lost,st-numeric=0) )"; #or ( allrecords,AlwaysMatches='' not lost,AlwaysMatches='')) )";
-            $limit_cgi  .= "&limit=available";
-            $limit_desc .= "";
-        }
-
+#        if ( $this_limit =~ /available/ ) {
+#
+## 'available' is defined as (items.onloan is NULL) and (items.itemlost = 0)
+## In English:
+## all records not indexed in the onloan register (zebra) and all records with a value of lost equal to 0
+#            $availability_limit .=
+#"( ( allrecords,AlwaysMatches='' not onloan,AlwaysMatches='') and (lost,st-numeric=0) )"; #or ( allrecords,AlwaysMatches='' not lost,AlwaysMatches='')) )";
+#            $limit_cgi  .= "&limit=available";
+#            $limit_desc .= "";
+#        }
+#
         # group_OR_limits, prefixed by mc-
         # OR every member of the group
         # group_OR_limits, prefixed by mc-
         # OR every member of the group
-        elsif ( $this_limit =~ /mc/ ) {
+#        elsif ( $this_limit =~ /mc/ ) {
+        if ( $this_limit =~ /mc/ ) {
             $group_OR_limits .= " or " if $group_OR_limits;
             $limit_desc      .= " or " if $group_OR_limits;
             $group_OR_limits .= "$this_limit";
             $group_OR_limits .= " or " if $group_OR_limits;
             $limit_desc      .= " or " if $group_OR_limits;
             $group_OR_limits .= "$this_limit";
@@ -1150,18 +1303,20 @@ sub buildQuery {
     }
 
     # Normalize the query and limit strings
     }
 
     # Normalize the query and limit strings
+    # This is flawed , means we can't search anything with : in it
+    # if user wants to do ccl or cql, start the query with that
     $query =~ s/:/=/g;
     $limit =~ s/:/=/g;
     for ( $query, $query_desc, $limit, $limit_desc ) {
     $query =~ s/:/=/g;
     $limit =~ s/:/=/g;
     for ( $query, $query_desc, $limit, $limit_desc ) {
-        $_ =~ s/  / /g;    # remove extra spaces
-        $_ =~ s/^ //g;     # remove any beginning spaces
-        $_ =~ s/ $//g;     # remove any ending spaces
-        $_ =~ s/==/=/g;    # remove double == from query
+        s/  / /g;    # remove extra spaces
+        s/^ //g;     # remove any beginning spaces
+        s/ $//g;     # remove any ending spaces
+        s/==/=/g;    # remove double == from query
     }
     $query_cgi =~ s/^&//; # remove unnecessary & from beginning of the query cgi
 
     for ($query_cgi,$simple_query) {
     }
     $query_cgi =~ s/^&//; # remove unnecessary & from beginning of the query cgi
 
     for ($query_cgi,$simple_query) {
-        $_ =~ s/"//g;
+        s/"//g;
     }
     # append the limit to the query
     $query .= " " . $limit;
     }
     # append the limit to the query
     $query .= " " . $limit;
@@ -1192,25 +1347,15 @@ Format results in a form suitable for passing to the template
 # IMO this subroutine is pretty messy still -- it's responsible for
 # building the HTML output for the template
 sub searchResults {
 # IMO this subroutine is pretty messy still -- it's responsible for
 # building the HTML output for the template
 sub searchResults {
-    my ( $searchdesc, $hits, $results_per_page, $offset, $scan, @marcresults ) = @_;
+    my ( $searchdesc, $hits, $results_per_page, $offset, $scan, @marcresults, $hidelostitems ) = @_;
     my $dbh = C4::Context->dbh;
     my $dbh = C4::Context->dbh;
-    my $even = 1;
     my @newresults;
 
     my @newresults;
 
-    # add search-term highlighting via <span>s on the search terms
-    my $span_terms_hashref;
-    for my $span_term ( split( / /, $searchdesc ) ) {
-        $span_term =~ s/(.*=|\)|\(|\+|\.|\*)//g;
-        $span_terms_hashref->{$span_term}++;
-    }
-
     #Build branchnames hash
     #find branchname
     #get branch information.....
     my %branches;
     #Build branchnames hash
     #find branchname
     #get branch information.....
     my %branches;
-    my $bsth =
-      $dbh->prepare("SELECT branchcode,branchname FROM branches")
-      ;    # FIXME : use C4::Koha::GetBranches
+    my $bsth =$dbh->prepare("SELECT branchcode,branchname FROM branches"); # FIXME : use C4::Branch::GetBranches
     $bsth->execute();
     while ( my $bdata = $bsth->fetchrow_hashref ) {
         $branches{ $bdata->{'branchcode'} } = $bdata->{'branchname'};
     $bsth->execute();
     while ( my $bdata = $bsth->fetchrow_hashref ) {
         $branches{ $bdata->{'branchcode'} } = $bdata->{'branchname'};
@@ -1265,92 +1410,86 @@ sub searchResults {
     }
 
        my $marcflavour = C4::Context->preference("marcflavour");
     }
 
        my $marcflavour = C4::Context->preference("marcflavour");
+    # We get the biblionumber position in MARC
+    my ($bibliotag,$bibliosubf)=GetMarcFromKohaField('biblio.biblionumber','');
+    my $fw;
+
     # loop through all of the records we've retrieved
     for ( my $i = $offset ; $i <= $times - 1 ; $i++ ) {
         my $marcrecord = MARC::File::USMARC::decode( $marcresults[$i] );
     # loop through all of the records we've retrieved
     for ( my $i = $offset ; $i <= $times - 1 ; $i++ ) {
         my $marcrecord = MARC::File::USMARC::decode( $marcresults[$i] );
-        my $oldbiblio = TransformMarcToKoha( $dbh, $marcrecord, '' );
-        $oldbiblio->{subtitle} = C4::Biblio::get_koha_field_from_marc('bibliosubtitle', 'subtitle', $marcrecord, '');
+        if ($bibliotag<10){
+            $fw = GetFrameworkCode($marcrecord->field($bibliotag)->data);
+        }else{
+            $fw = GetFrameworkCode($marcrecord->subfield($bibliotag,$bibliosubf));
+        }
+
+        my $oldbiblio = TransformMarcToKoha( $dbh, $marcrecord, $fw );
+        $oldbiblio->{subtitle} = GetRecordValue('subtitle', $marcrecord, $fw);
         $oldbiblio->{result_number} = $i + 1;
 
         # add imageurl to itemtype if there is one
         $oldbiblio->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} );
 
         $oldbiblio->{'authorised_value_images'}  = C4::Items::get_authorised_value_images( C4::Biblio::get_biblio_authorised_values( $oldbiblio->{'biblionumber'}, $marcrecord ) );
         $oldbiblio->{result_number} = $i + 1;
 
         # add imageurl to itemtype if there is one
         $oldbiblio->{imageurl} = getitemtypeimagelocation( 'opac', $itemtypes{ $oldbiblio->{itemtype} }->{imageurl} );
 
         $oldbiblio->{'authorised_value_images'}  = C4::Items::get_authorised_value_images( C4::Biblio::get_biblio_authorised_values( $oldbiblio->{'biblionumber'}, $marcrecord ) );
-               $oldbiblio->{normalized_upc} = GetNormalizedUPC($marcrecord,$marcflavour);
-               $oldbiblio->{normalized_ean} = GetNormalizedEAN($marcrecord,$marcflavour);
+               $oldbiblio->{normalized_upc}  = GetNormalizedUPC(       $marcrecord,$marcflavour);
+               $oldbiblio->{normalized_ean}  = GetNormalizedEAN(       $marcrecord,$marcflavour);
                $oldbiblio->{normalized_oclc} = GetNormalizedOCLCNumber($marcrecord,$marcflavour);
                $oldbiblio->{normalized_isbn} = GetNormalizedISBN(undef,$marcrecord,$marcflavour);
                $oldbiblio->{content_identifier_exists} = 1 if ($oldbiblio->{normalized_isbn} or $oldbiblio->{normalized_oclc} or $oldbiblio->{normalized_ean} or $oldbiblio->{normalized_upc});
                $oldbiblio->{normalized_oclc} = GetNormalizedOCLCNumber($marcrecord,$marcflavour);
                $oldbiblio->{normalized_isbn} = GetNormalizedISBN(undef,$marcrecord,$marcflavour);
                $oldbiblio->{content_identifier_exists} = 1 if ($oldbiblio->{normalized_isbn} or $oldbiblio->{normalized_oclc} or $oldbiblio->{normalized_ean} or $oldbiblio->{normalized_upc});
+
+               # edition information, if any
+        $oldbiblio->{edition} = $oldbiblio->{editionstatement};
                $oldbiblio->{description} = $itemtypes{ $oldbiblio->{itemtype} }->{description};
  # Build summary if there is one (the summary is defined in the itemtypes table)
  # FIXME: is this used anywhere, I think it can be commented out? -- JF
         if ( $itemtypes{ $oldbiblio->{itemtype} }->{summary} ) {
             my $summary = $itemtypes{ $oldbiblio->{itemtype} }->{summary};
             my @fields  = $marcrecord->fields();
                $oldbiblio->{description} = $itemtypes{ $oldbiblio->{itemtype} }->{description};
  # Build summary if there is one (the summary is defined in the itemtypes table)
  # FIXME: is this used anywhere, I think it can be commented out? -- JF
         if ( $itemtypes{ $oldbiblio->{itemtype} }->{summary} ) {
             my $summary = $itemtypes{ $oldbiblio->{itemtype} }->{summary};
             my @fields  = $marcrecord->fields();
-            foreach my $field (@fields) {
-                my $tag      = $field->tag();
-                my $tagvalue = $field->as_string();
-                $summary =~
-                  s/\[(.?.?.?.?)$tag\*(.*?)]/$1$tagvalue$2\[$1$tag$2]/g;
-                unless ( $tag < 10 ) {
-                    my @subf = $field->subfields;
-                    for my $i ( 0 .. $#subf ) {
-                        my $subfieldcode  = $subf[$i][0];
-                        my $subfieldvalue = $subf[$i][1];
-                        my $tagsubf       = $tag . $subfieldcode;
-                        $summary =~
-s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
+
+            my $newsummary;
+            foreach my $line ( "$summary\n" =~ /(.*)\n/g ){
+                my $tags = {};
+                foreach my $tag ( $line =~ /\[(\d{3}[\w|\d])\]/ ) {
+                    $tag =~ /(.{3})(.)/;
+                    if($marcrecord->field($1)){
+                        my @abc = $marcrecord->field($1)->subfield($2);
+                        $tags->{$tag} = $#abc + 1 ;
                     }
                 }
                     }
                 }
-            }
-            # FIXME: yuk
-            $summary =~ s/\[(.*?)]//g;
-            $summary =~ s/\n/<br\/>/g;
-            $oldbiblio->{summary} = $summary;
-        }
 
 
-        # save an author with no <span> tag, for the <a href=search.pl?q=<!--tmpl_var name="author"-->> link
-        $oldbiblio->{'author_nospan'} = $oldbiblio->{'author'};
-        $oldbiblio->{'title_nospan'} = $oldbiblio->{'title'};
-        $oldbiblio->{'subtitle_nospan'} = $oldbiblio->{'subtitle'};
-        # Add search-term highlighting to the whole record where they match using <span>s
-        if (C4::Context->preference("OpacHighlightedWords")){
-            my $searchhighlightblob;
-            for my $highlight_field ( $marcrecord->fields ) {
-    
-    # FIXME: need to skip title, subtitle, author, etc., as they are handled below
-                next if $highlight_field->tag() =~ /(^00)/;    # skip fixed fields
-                for my $subfield ($highlight_field->subfields()) {
-                    my $match;
-                    next if $subfield->[0] eq '9';
-                    my $field = $subfield->[1];
-                    for my $term ( keys %$span_terms_hashref ) {
-                        if ( ( $field =~ /$term/i ) && (( length($term) > 3 ) || ($field =~ / $term /i)) ) {
-                            $field =~ s/$term/<span class=\"term\">$&<\/span>/gi;
-                        $match++;
+                # We catch how many times to repeat this line
+                my $max = 0;
+                foreach my $tag (keys(%$tags)){
+                    $max = $tags->{$tag} if($tags->{$tag} > $max);
+                 }
+
+                # we replace, and repeat each line
+                for (my $i = 0 ; $i < $max ; $i++){
+                    my $newline = $line;
+
+                    foreach my $tag ( $newline =~ /\[(\d{3}[\w|\d])\]/g ) {
+                        $tag =~ /(.{3})(.)/;
+
+                        if($marcrecord->field($1)){
+                            my @repl = $marcrecord->field($1)->subfield($2);
+                            my $subfieldvalue = $repl[$i];
+
+                            if (! utf8::is_utf8($subfieldvalue)) {
+                                utf8::decode($subfieldvalue);
+                            }
+
+                             $newline =~ s/\[$tag\]/$subfieldvalue/g;
                         }
                     }
                         }
                     }
-                    $searchhighlightblob .= $field . " ... " if $match;
+                    $newsummary .= "$newline\n";
                 }
                 }
-    
             }
             }
-            $searchhighlightblob = ' ... '.$searchhighlightblob if $searchhighlightblob;
-            $oldbiblio->{'searchhighlightblob'} = $searchhighlightblob;
-        }
 
 
-        # Add search-term highlighting to the title, subtitle, etc. fields
-        for my $term ( keys %$span_terms_hashref ) {
-            my $old_term = $term;
-            if ( length($term) > 3 ) {
-                $term =~ s/(.*=|\)|\(|\+|\.|\?|\[|\]|\\|\*)//g;
-                               foreach(qw(title subtitle author publishercode place pages notes size)) {
-                       $oldbiblio->{$_} =~ s/$term/<span class=\"term\">$&<\/span>/gi;
-                               }
-            }
+            $newsummary =~ s/\[(.*?)]//g;
+            $newsummary =~ s/\n/<br\/>/g;
+            $oldbiblio->{summary} = $newsummary;
         }
 
         }
 
-        ($i % 2) and $oldbiblio->{'toggle'} = 1;
-
         # Pull out the items fields
         my @fields = $marcrecord->field($itemtag);
 
         # Pull out the items fields
         my @fields = $marcrecord->field($itemtag);
 
@@ -1388,6 +1527,7 @@ s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
             foreach my $code ( keys %subfieldstosearch ) {
                 $item->{$code} = $field->subfield( $subfieldstosearch{$code} );
             }
             foreach my $code ( keys %subfieldstosearch ) {
                 $item->{$code} = $field->subfield( $subfieldstosearch{$code} );
             }
+
                        my $hbranch     = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'homebranch'    : 'holdingbranch';
                        my $otherbranch = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'holdingbranch' : 'homebranch';
             # set item's branch name, use HomeOrHoldingBranch syspref first, fall back to the other one
                        my $hbranch     = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'homebranch'    : 'holdingbranch';
                        my $otherbranch = C4::Context->preference('HomeOrHoldingBranch') eq 'homebranch' ? 'holdingbranch' : 'homebranch';
             # set item's branch name, use HomeOrHoldingBranch syspref first, fall back to the other one
@@ -1395,14 +1535,14 @@ s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
                 $item->{'branchname'} = $branches{$item->{$hbranch}};
             }
             elsif ($item->{$otherbranch}) {    # Last resort
                 $item->{'branchname'} = $branches{$item->{$hbranch}};
             }
             elsif ($item->{$otherbranch}) {    # Last resort
-                $item->{'branchname'} = $branches{$item->{$otherbranch}}; 
+                $item->{'branchname'} = $branches{$item->{$otherbranch}};
             }
 
                        my $prefix = $item->{$hbranch} . '--' . $item->{location} . $item->{itype} . $item->{itemcallnumber};
 # For each grouping of items (onloan, available, unavailable), we build a key to store relevant info about that item
             if ( $item->{onloan} ) {
                 $onloan_count++;
             }
 
                        my $prefix = $item->{$hbranch} . '--' . $item->{location} . $item->{itype} . $item->{itemcallnumber};
 # For each grouping of items (onloan, available, unavailable), we build a key to store relevant info about that item
             if ( $item->{onloan} ) {
                 $onloan_count++;
-                               my $key = $prefix . $item->{due_date};
+                               my $key = $prefix . $item->{onloan} . $item->{barcode};
                                $onloan_items->{$key}->{due_date} = format_date($item->{onloan});
                                $onloan_items->{$key}->{count}++ if $item->{$hbranch};
                                $onloan_items->{$key}->{branchname} = $item->{branchname};
                                $onloan_items->{$key}->{due_date} = format_date($item->{onloan});
                                $onloan_items->{$key}->{count}++ if $item->{$hbranch};
                                $onloan_items->{$key}->{branchname} = $item->{branchname};
@@ -1429,7 +1569,7 @@ s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
                 # is item in transit?
                 my $transfertwhen = '';
                 my ($transfertfrom, $transfertto);
                 # is item in transit?
                 my $transfertwhen = '';
                 my ($transfertfrom, $transfertto);
-                
+
                 unless ($item->{wthdrawn}
                         || $item->{itemlost}
                         || $item->{damaged}
                 unless ($item->{wthdrawn}
                         || $item->{itemlost}
                         || $item->{damaged}
@@ -1455,7 +1595,7 @@ s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
                 if (   $item->{wthdrawn}
                     || $item->{itemlost}
                     || $item->{damaged}
                 if (   $item->{wthdrawn}
                     || $item->{itemlost}
                     || $item->{damaged}
-                    || $item->{notforloan} 
+                    || $item->{notforloan}
                     || ($transfertwhen ne ''))
                 {
                     $wthdrawn_count++        if $item->{wthdrawn};
                     || ($transfertwhen ne ''))
                 {
                     $wthdrawn_count++        if $item->{wthdrawn};
@@ -1507,9 +1647,13 @@ s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
         }
 
         # XSLT processing of some stuff
         }
 
         # XSLT processing of some stuff
+       my $debug=1;
+       use C4::Charset;
+       SetUTF8Flag($marcrecord);
+       $debug && warn $marcrecord->as_formatted;
         if (C4::Context->preference("XSLTResultsDisplay") && !$scan) {
         if (C4::Context->preference("XSLTResultsDisplay") && !$scan) {
-            my $newxmlrecord = XSLTParse4Display($oldbiblio->{biblionumber}, $marcrecord, C4::Context->config('opachtdocs')."/prog/en/xslt/MARC21slim2OPACResults.xsl");
-            $oldbiblio->{XSLTResultsRecord} = $newxmlrecord;
+            $oldbiblio->{XSLTResultsRecord} = XSLTParse4Display(
+                $oldbiblio->{biblionumber}, $marcrecord, 'Results' );
         }
 
         # last check for norequest : if itemtype is notforloan, it can't be reserved either, whatever the items
         }
 
         # last check for norequest : if itemtype is notforloan, it can't be reserved either, whatever the items
@@ -1532,11 +1676,105 @@ s/\[(.?.?.?.?)$tagsubf(.*?)]/$1$subfieldvalue$2\[$1$tagsubf$2]/g;
         $oldbiblio->{damagedcount}         = $itemdamaged_count;
         $oldbiblio->{intransitcount}       = $item_in_transit_count;
         $oldbiblio->{orderedcount}         = $ordered_count;
         $oldbiblio->{damagedcount}         = $itemdamaged_count;
         $oldbiblio->{intransitcount}       = $item_in_transit_count;
         $oldbiblio->{orderedcount}         = $ordered_count;
-        push( @newresults, $oldbiblio );
+        $oldbiblio->{isbn} =~
+          s/-//g;    # deleting - in isbn to enable amazon content
+        push( @newresults, $oldbiblio )
+            if(not $hidelostitems
+               or (($items_count > $itemlost_count )
+                    && $hidelostitems));
     }
     }
+
     return @newresults;
 }
 
     return @newresults;
 }
 
+=head2 SearchAcquisitions
+    Search for acquisitions
+=cut
+
+sub SearchAcquisitions{
+    my ($datebegin, $dateend, $itemtypes,$criteria, $orderby) = @_;
+
+    my $dbh=C4::Context->dbh;
+    # Variable initialization
+    my $str=qq|
+    SELECT marcxml
+    FROM biblio
+    LEFT JOIN biblioitems ON biblioitems.biblionumber=biblio.biblionumber
+    LEFT JOIN items ON items.biblionumber=biblio.biblionumber
+    WHERE dateaccessioned BETWEEN ? AND ?
+    |;
+
+    my (@params,@loopcriteria);
+
+    push @params, $datebegin->output("iso");
+    push @params, $dateend->output("iso");
+
+    if (scalar(@$itemtypes)>0 and $criteria ne "itemtype" ){
+        if(C4::Context->preference("item-level_itypes")){
+            $str .= "AND items.itype IN (?".( ',?' x scalar @$itemtypes - 1 ).") ";
+        }else{
+            $str .= "AND biblioitems.itemtype IN (?".( ',?' x scalar @$itemtypes - 1 ).") ";
+        }
+        push @params, @$itemtypes;
+    }
+
+    if ($criteria =~/itemtype/){
+        if(C4::Context->preference("item-level_itypes")){
+            $str .= "AND items.itype=? ";
+        }else{
+            $str .= "AND biblioitems.itemtype=? ";
+        }
+
+        if(scalar(@$itemtypes) == 0){
+            my $itypes = GetItemTypes();
+            for my $key (keys %$itypes){
+                push @$itemtypes, $key;
+            }
+        }
+
+        @loopcriteria= @$itemtypes;
+    }elsif ($criteria=~/itemcallnumber/){
+        $str .= "AND (items.itemcallnumber LIKE CONCAT(?,'%')
+                 OR items.itemcallnumber is NULL
+                 OR items.itemcallnumber = '')";
+
+        @loopcriteria = ("AA".."ZZ", "") unless (scalar(@loopcriteria)>0);
+    }else {
+        $str .= "AND biblio.title LIKE CONCAT(?,'%') ";
+        @loopcriteria = ("A".."z") unless (scalar(@loopcriteria)>0);
+    }
+
+    if ($orderby =~ /date_desc/){
+        $str.=" ORDER BY dateaccessioned DESC";
+    } else {
+        $str.=" ORDER BY title";
+    }
+
+    my $qdataacquisitions=$dbh->prepare($str);
+
+    my @loopacquisitions;
+    foreach my $value(@loopcriteria){
+        push @params,$value;
+        my %cell;
+        $cell{"title"}=$value;
+        $cell{"titlecode"}=$value;
+
+        eval{$qdataacquisitions->execute(@params);};
+
+        if ($@){ warn "recentacquisitions Error :$@";}
+        else {
+            my @loopdata;
+            while (my $data=$qdataacquisitions->fetchrow_hashref){
+                push @loopdata, {"summary"=>GetBiblioSummary( $data->{'marcxml'} ) };
+            }
+            $cell{"loopdata"}=\@loopdata;
+        }
+        push @loopacquisitions,\%cell if (scalar(@{$cell{loopdata}})>0);
+        pop @params;
+    }
+    $qdataacquisitions->finish;
+    return \@loopacquisitions;
+}
 #----------------------------------------------------------------------
 #
 # Non-Zebra GetRecords#
 #----------------------------------------------------------------------
 #
 # Non-Zebra GetRecords#
@@ -1612,7 +1850,7 @@ sub NZanalyse {
             # depending of operand, intersect, union or exclude both lists
             # to get a result list
             if ( $operator eq ' and ' ) {
             # depending of operand, intersect, union or exclude both lists
             # to get a result list
             if ( $operator eq ' and ' ) {
-                return NZoperatorAND($leftresult,$rightresult);      
+                return NZoperatorAND($leftresult,$rightresult);
             }
             elsif ( $operator eq ' or ' ) {
 
             }
             elsif ( $operator eq ' or ' ) {
 
@@ -1620,13 +1858,13 @@ sub NZanalyse {
                 return $leftresult . $rightresult;
             }
             elsif ( $operator eq ' not ' ) {
                 return $leftresult . $rightresult;
             }
             elsif ( $operator eq ' not ' ) {
-                return NZoperatorNOT($leftresult,$rightresult);      
+                return NZoperatorNOT($leftresult,$rightresult);
             }
             }
-        }      
+        }
         else {
 # this error is impossible, because of the regexp that isolate the operand, but just in case...
             return $leftresult;
         else {
 # this error is impossible, because of the regexp that isolate the operand, but just in case...
             return $leftresult;
-        } 
+        }
     }
     warn "string :" . $string if $DEBUG;
     my $left = "";
     }
     warn "string :" . $string if $DEBUG;
     my $left = "";
@@ -1718,16 +1956,15 @@ sub NZanalyse {
         $left = 'subject'          if $left =~ '^su$';
         $left = 'koha-Auth-Number' if $left =~ '^an$';
         $left = 'keyword'          if $left =~ '^kw$';
         $left = 'subject'          if $left =~ '^su$';
         $left = 'koha-Auth-Number' if $left =~ '^an$';
         $left = 'keyword'          if $left =~ '^kw$';
+        $left = 'itemtype'         if $left =~ '^mc$'; # Fix for Bug 2599 - Search limits not working for NoZebra
         warn "handling leaf... left:$left operator:$operator right:$right" if $DEBUG;
         warn "handling leaf... left:$left operator:$operator right:$right" if $DEBUG;
+        my $dbh = C4::Context->dbh;
         if ( $operator && $left ne 'keyword' ) {
         if ( $operator && $left ne 'keyword' ) {
-
             #do a specific search
             #do a specific search
-            my $dbh = C4::Context->dbh;
             $operator = 'LIKE' if $operator eq '=' and $right =~ /%/;
             $operator = 'LIKE' if $operator eq '=' and $right =~ /%/;
-            my $sth =
-              $dbh->prepare(
+            my $sth = $dbh->prepare(
 "SELECT biblionumbers,value FROM nozebra WHERE server=? AND indexname=? AND value $operator ?"
 "SELECT biblionumbers,value FROM nozebra WHERE server=? AND indexname=? AND value $operator ?"
-              );
+            );
             warn "$left / $operator / $right\n" if $DEBUG;
 
             # split each word, query the DB and build the biblionumbers result
             warn "$left / $operator / $right\n" if $DEBUG;
 
             # split each word, query the DB and build the biblionumbers result
@@ -1755,20 +1992,16 @@ sub NZanalyse {
                 if ($results) {
                     warn "NZAND" if $DEBUG;
                     $results = NZoperatorAND($biblionumbers,$results);
                 if ($results) {
                     warn "NZAND" if $DEBUG;
                     $results = NZoperatorAND($biblionumbers,$results);
-                }
-                else {
+                } else {
                     $results = $biblionumbers;
                 }
             }
         }
         else {
                     $results = $biblionumbers;
                 }
             }
         }
         else {
-
       #do a complete search (all indexes), if index='kw' do complete search too.
       #do a complete search (all indexes), if index='kw' do complete search too.
-            my $dbh = C4::Context->dbh;
-            my $sth =
-              $dbh->prepare(
+            my $sth = $dbh->prepare(
 "SELECT biblionumbers FROM nozebra WHERE server=? AND value LIKE ?"
 "SELECT biblionumbers FROM nozebra WHERE server=? AND value LIKE ?"
-              );
+            );
 
             # split each word, query the DB and build the biblionumbers result
             foreach ( split / /, $string ) {
 
             # split each word, query the DB and build the biblionumbers result
             foreach ( split / /, $string ) {
@@ -1799,10 +2032,10 @@ sub NZanalyse {
 
 sub NZoperatorAND{
     my ($rightresult, $leftresult)=@_;
 
 sub NZoperatorAND{
     my ($rightresult, $leftresult)=@_;
-    
+
     my @leftresult = split /;/, $leftresult;
     warn " @leftresult / $rightresult \n" if $DEBUG;
     my @leftresult = split /;/, $leftresult;
     warn " @leftresult / $rightresult \n" if $DEBUG;
-    
+
     #             my @rightresult = split /;/,$leftresult;
     my $finalresult;
 
     #             my @rightresult = split /;/,$leftresult;
     my $finalresult;
 
@@ -1823,7 +2056,7 @@ sub NZoperatorAND{
     warn "NZAND DONE : $finalresult \n" if $DEBUG;
     return $finalresult;
 }
     warn "NZAND DONE : $finalresult \n" if $DEBUG;
     return $finalresult;
 }
-      
+
 sub NZoperatorOR{
     my ($rightresult, $leftresult)=@_;
     return $rightresult.$leftresult;
 sub NZoperatorOR{
     my ($rightresult, $leftresult)=@_;
     return $rightresult.$leftresult;
@@ -1831,7 +2064,7 @@ sub NZoperatorOR{
 
 sub NZoperatorNOT{
     my ($leftresult, $rightresult)=@_;
 
 sub NZoperatorNOT{
     my ($leftresult, $rightresult)=@_;
-    
+
     my @leftresult = split /;/, $leftresult;
 
     #             my @rightresult = split /;/,$leftresult;
     my @leftresult = split /;/, $leftresult;
 
     #             my @rightresult = split /;/,$leftresult;
@@ -1849,7 +2082,7 @@ sub NZoperatorNOT{
 =head2 NZorder
 
   $finalresult = NZorder($biblionumbers, $ordering,$results_per_page,$offset);
 =head2 NZorder
 
   $finalresult = NZorder($biblionumbers, $ordering,$results_per_page,$offset);
-  
+
   TODO :: Description
 
 =cut
   TODO :: Description
 
 =cut
@@ -1881,7 +2114,7 @@ sub NZorder {
             my $popularity = $sth->fetchrow || 0;
 
 # hint : the key is popularity.title because we can have
             my $popularity = $sth->fetchrow || 0;
 
 # hint : the key is popularity.title because we can have
-# many results with the same popularity. In this cas, sub-ordering is done by title
+# many results with the same popularity. In this case, sub-ordering is done by title
 # we also have biblionumber to avoid bug for 2 biblios with the same title & popularity
 # (un-frequent, I agree, but we won't forget anything that way ;-)
             $popularity{ sprintf( "%10d", $popularity ) . $title
 # we also have biblionumber to avoid bug for 2 biblios with the same title & popularity
 # (un-frequent, I agree, but we won't forget anything that way ;-)
             $popularity{ sprintf( "%10d", $popularity ) . $title
@@ -2140,6 +2373,264 @@ sub NZorder {
     }
 }
 
     }
 }
 
+=head2 enabled_staff_search_views
+
+%hash = enabled_staff_search_views()
+
+This function returns a hash that contains three flags obtained from the system
+preferences, used to determine whether a particular staff search results view
+is enabled.
+
+=over 2
+
+=item C<Output arg:>
+
+    * $hash{can_view_MARC} is true only if the MARC view is enabled
+    * $hash{can_view_ISBD} is true only if the ISBD view is enabled
+    * $hash{can_view_labeledMARC} is true only if the Labeled MARC view is enabled
+
+=item C<usage in the script:>
+
+=back
+
+$template->param ( C4::Search::enabled_staff_search_views );
+
+=cut
+
+sub enabled_staff_search_views
+{
+       return (
+               can_view_MARC                   => C4::Context->preference('viewMARC'),                 # 1 if the staff search allows the MARC view
+               can_view_ISBD                   => C4::Context->preference('viewISBD'),                 # 1 if the staff search allows the ISBD view
+               can_view_labeledMARC    => C4::Context->preference('viewLabeledMARC'),  # 1 if the staff search allows the Labeled MARC view
+       );
+}
+
+sub AddSearchHistory{
+       my ($borrowernumber,$session,$query_desc,$query_cgi, $total)=@_;
+    my $dbh = C4::Context->dbh;
+
+    # Add the request the user just made
+    my $sql = "INSERT INTO search_history(userid, sessionid, query_desc, query_cgi, total, time) VALUES(?, ?, ?, ?, ?, NOW())";
+    my $sth   = $dbh->prepare($sql);
+    $sth->execute($borrowernumber, $session, $query_desc, $query_cgi, $total);
+       return $dbh->last_insert_id(undef, 'search_history', undef,undef,undef);
+}
+
+sub GetSearchHistory{
+       my ($borrowernumber,$session)=@_;
+    my $dbh = C4::Context->dbh;
+
+    # Add the request the user just made
+    my $query = "SELECT FROM search_history WHERE (userid=? OR sessionid=?)";
+    my $sth   = $dbh->prepare($query);
+       $sth->execute($borrowernumber, $session);
+    return  $sth->fetchall_hashref({});
+}
+
+=head2 z3950_search_args
+
+$arrayref = z3950_search_args($matchpoints)
+
+This function returns an array reference that contains the search parameters to be
+passed to the Z39.50 search script (z3950_search.pl). The array elements
+are hash refs whose keys are name, value and encvalue, and whose values are the
+name of a search parameter, the value of that search parameter and the URL encoded
+value of that parameter.
+
+The search parameter names are lccn, isbn, issn, title, author, dewey and subject.
+
+The search parameter values are obtained from the bibliographic record whose
+data is in a hash reference in $matchpoints, as returned by Biblio::GetBiblioData().
+
+If $matchpoints is a scalar, it is assumed to be an unnamed query descriptor, e.g.
+a general purpose search argument. In this case, the returned array contains only
+entry: the key is 'title' and the value and encvalue are derived from $matchpoints.
+
+If a search parameter value is undefined or empty, it is not included in the returned
+array.
+
+The returned array reference may be passed directly to the template parameters.
+
+=over 2
+
+=item C<Output arg:>
+
+    * $array containing hash refs as described above
+
+=item C<usage in the script:>
+
+=back
+
+$data = Biblio::GetBiblioData($bibno);
+$template->param ( MYLOOP => C4::Search::z3950_search_args($data) )
+
+*OR*
+
+$template->param ( MYLOOP => C4::Search::z3950_search_args($searchscalar) )
+
+=cut
+
+sub z3950_search_args {
+    my $bibrec = shift;
+    $bibrec = { title => $bibrec } if !ref $bibrec;
+    my $array = [];
+    for my $field (qw/ lccn isbn issn title author dewey subject /)
+    {
+        my $encvalue = URI::Escape::uri_escape_utf8($bibrec->{$field});
+        push @$array, { name=>$field, value=>$bibrec->{$field}, encvalue=>$encvalue } if defined $bibrec->{$field};
+    }
+    return $array;
+}
+
+=head2 BiblioAddAuthorities
+
+( $countlinked, $countcreated ) = BiblioAddAuthorities($record, $frameworkcode);
+
+this function finds the authorities linked to the biblio
+    * search in the authority DB for the same authid (in $9 of the biblio)
+    * search in the authority DB for the same 001 (in $3 of the biblio in UNIMARC)
+    * search in the authority DB for the same values (exactly) (in all subfields of the biblio)
+OR adds a new authority record
+
+=over 2
+
+=item C<input arg:>
+
+    * $record is the MARC record in question (marc blob)
+    * $frameworkcode is the bibliographic framework to use (if it is "" it uses the default framework)
+
+=item C<Output arg:>
+
+    * $countlinked is the number of authorities records that are linked to this authority
+    * $countcreated
+
+=item C<BUGS>
+    * I had to add this to Search.pm (instead of the logical Biblio.pm) because of a circular dependency (this sub uses SimpleSearch, and Search.pm uses Biblio.pm)
+=back
+
+=cut
+
+
+sub BiblioAddAuthorities{
+  my ( $record, $frameworkcode ) = @_;
+  my $dbh=C4::Context->dbh;
+  my $query=$dbh->prepare(qq|
+SELECT authtypecode,tagfield
+FROM marc_subfield_structure
+WHERE frameworkcode=?
+AND (authtypecode IS NOT NULL AND authtypecode<>\"\")|);
+# SELECT authtypecode,tagfield
+# FROM marc_subfield_structure
+# WHERE frameworkcode=?
+# AND (authtypecode IS NOT NULL OR authtypecode<>\"\")|);
+  $query->execute($frameworkcode);
+  my ($countcreated,$countlinked);
+  while (my $data=$query->fetchrow_hashref){
+    foreach my $field ($record->field($data->{tagfield})){
+      next if ($field->subfield('3')||$field->subfield('9'));
+      # No authorities id in the tag.
+      # Search if there is any authorities to link to.
+      my $query='at='.$data->{authtypecode}.' ';
+      map {$query.= ' and he,ext="'.$_->[1].'"' if ($_->[0]=~/[A-z]/)}  $field->subfields();
+      my ($error, $results, $total_hits)=SimpleSearch( $query, undef, undef, [ "authorityserver" ] );
+    # there is only 1 result
+          if ( $error ) {
+        warn "BIBLIOADDSAUTHORITIES: $error";
+            return (0,0) ;
+          }
+      if ($results && scalar(@$results)==1) {
+        my $marcrecord = MARC::File::USMARC::decode($results->[0]);
+        $field->add_subfields('9'=>$marcrecord->field('001')->data);
+        $countlinked++;
+      } elsif (scalar(@$results)>1) {
+   #More than One result
+   #This can comes out of a lack of a subfield.
+#         my $marcrecord = MARC::File::USMARC::decode($results->[0]);
+#         $record->field($data->{tagfield})->add_subfields('9'=>$marcrecord->field('001')->data);
+  $countlinked++;
+      } else {
+  #There are no results, build authority record, add it to Authorities, get authid and add it to 9
+  ###NOTICE : This is only valid if a subfield is linked to one and only one authtypecode
+  ###NOTICE : This can be a problem. We should also look into other types and rejected forms.
+         my $authtypedata=C4::AuthoritiesMarc->GetAuthType($data->{authtypecode});
+         next unless $authtypedata;
+         my $marcrecordauth=MARC::Record->new();
+         my $authfield=MARC::Field->new($authtypedata->{auth_tag_to_report},'','',"a"=>"".$field->subfield('a'));
+         map { $authfield->add_subfields($_->[0]=>$_->[1]) if ($_->[0]=~/[A-z]/ && $_->[0] ne "a" )}  $field->subfields();
+         $marcrecordauth->insert_fields_ordered($authfield);
+
+         # bug 2317: ensure new authority knows it's using UTF-8; currently
+         # only need to do this for MARC21, as MARC::Record->as_xml_record() handles
+         # automatically for UNIMARC (by not transcoding)
+         # FIXME: AddAuthority() instead should simply explicitly require that the MARC::Record
+         # use UTF-8, but as of 2008-08-05, did not want to introduce that kind
+         # of change to a core API just before the 3.0 release.
+         if (C4::Context->preference('marcflavour') eq 'MARC21') {
+            SetMarcUnicodeFlag($marcrecordauth, 'MARC21');
+         }
+
+#          warn "AUTH RECORD ADDED : ".$marcrecordauth->as_formatted;
+
+         my $authid=AddAuthority($marcrecordauth,'',$data->{authtypecode});
+         $countcreated++;
+         $field->add_subfields('9'=>$authid);
+      }
+    }
+  }
+  return ($countlinked,$countcreated);
+}
+
+=head2 GetDistinctValues($field);
+
+C<$field> is a reference to the fields array
+
+=cut
+
+sub GetDistinctValues {
+    my ($fieldname,$string)=@_;
+    # returns a reference to a hash of references to branches...
+    if ($fieldname=~/\./){
+                       my ($table,$column)=split /\./, $fieldname;
+                       my $dbh = C4::Context->dbh;
+                       warn "select DISTINCT($column) as value, count(*) as cnt from $table group by lib order by $column ";
+                       my $sth = $dbh->prepare("select DISTINCT($column) as value, count(*) as cnt from $table ".($string?" where $column like \"$string%\"":"")."group by value order by $column ");
+                       $sth->execute;
+                       my $elements=$sth->fetchall_arrayref({});
+                       return $elements;
+   }
+   else {
+               $string||= qq("");
+               my @servers=qw<biblioserver authorityserver>;
+               my (@zconns,@results);
+        for ( my $i = 0 ; $i < @servers ; $i++ ) {
+               $zconns[$i] = C4::Context->Zconn( $servers[$i], 1 );
+                       $results[$i] =
+                      $zconns[$i]->scan(
+                        ZOOM::Query::CCL2RPN->new( qq"$fieldname $string", $zconns[$i])
+                      );
+               }
+               # The big moment: asynchronously retrieve results from all servers
+               my @elements;
+               while ( ( my $i = ZOOM::event( \@zconns ) ) != 0 ) {
+                       my $ev = $zconns[ $i - 1 ]->last_event();
+                       if ( $ev == ZOOM::Event::ZEND ) {
+                               next unless $results[ $i - 1 ];
+                               my $size = $results[ $i - 1 ]->size();
+                               if ( $size > 0 ) {
+                      for (my $j=0;$j<$size;$j++){
+                                               my %hashscan;
+                                               @hashscan{qw(value cnt)}=$results[ $i - 1 ]->display_term($j);
+                                               push @elements, \%hashscan;
+                                         }
+                               }
+                       }
+               }
+               return \@elements;
+   }
+}
+
+
 END { }    # module clean-up code here (global destructor)
 
 1;
 END { }    # module clean-up code here (global destructor)
 
 1;