Adding feature : multiple returns via moremember page.
[koha_fer] / C4 / Biblio.pm
old mode 100644 (file)
new mode 100755 (executable)
index d2d1f9a..bb81ed4
@@ -18,2885 +18,3121 @@ package C4::Biblio;
 # Suite 330, Boston, MA  02111-1307 USA
 
 use strict;
-require Exporter;
-use C4::Context;
-use C4::Database;
-use C4::Date;
+# use utf8;
 use MARC::Record;
 use MARC::File::USMARC;
 use MARC::File::XML;
+use ZOOM;
 
-use vars qw($VERSION @ISA @EXPORT);
-
-# set the version for version checking
-$VERSION = 0.01;
+use C4::Context;
+use C4::Koha;
+use C4::Branch;
+use C4::Dates qw/format_date/;
+use C4::Log; # logaction
+use C4::ClassSource;
 
-@ISA = qw(Exporter);
+use vars qw($VERSION @ISA @EXPORT);
 
-#
-# don't forget MARCxxx subs are exported only for testing purposes. Should not be used
-# as the old-style API and the NEW one are the only public functions.
-#
-@EXPORT = qw(
-  &newbiblio &newbiblioitem
-  &newsubject &newsubtitle &newitems 
-  
-  &modbiblio &checkitems &modbibitem
-  &modsubtitle &modsubject &modaddauthor &moditem
-  
-  &delitem &deletebiblioitem &delbiblio
-  
-  &getbiblio &bibdata &bibitems &bibitemdata 
-  &barcodes &ItemInfo &itemdata &itemissues &itemcount 
-  &getsubject &getaddauthor &getsubtitle
-  &getwebbiblioitems &getwebsites
-  &getbiblioitembybiblionumber
-  &getbiblioitem &getitemsbybiblioitem
-
-  &MARCfind_marc_from_kohafield
-  &MARCfind_frameworkcode
-  &find_biblioitemnumber
-  &MARCgettagslib
-
-  &NEWnewbiblio &NEWnewitem
-  &NEWmodbiblio &NEWmoditem
-  &NEWdelbiblio &NEWdelitem
-  &NEWmodbiblioframework
-
-  &MARCkoha2marcBiblio &MARCmarc2koha
-  &MARCkoha2marcItem &MARChtml2marc
-  &MARCgetbiblio &MARCgetitem
-  &XMLgetbiblio
-  &char_decode
-  
-  &FindDuplicate
-  &DisplayISBN
-);
+BEGIN {
+       $VERSION = 1.00;
 
-=head1 NAME
+       require Exporter;
+       @ISA = qw( Exporter );
 
-C4::Biblio - acquisition, catalog  management functions
+       # to add biblios
+       push @EXPORT, qw( 
+               &AddBiblio
+       );
 
-=head1 SYNOPSIS
+       # to get something
+       push @EXPORT, qw(
+               &GetBiblio
+               &GetBiblioData
+               &GetBiblioItemData
+               &GetBiblioItemInfosOf
+               &GetBiblioItemByBiblioNumber
+               &GetBiblioFromItemNumber
+
+               &GetMarcNotes
+               &GetMarcSubjects
+               &GetMarcBiblio
+               &GetMarcAuthors
+               &GetMarcSeries
+               GetMarcUrls
+               &GetUsedMarcStructure
+
+               &GetXmlBiblio
+
+               &GetAuthorisedValueDesc
+               &GetMarcStructure
+               &GetMarcFromKohaField
+               &GetFrameworkCode
+               &GetPublisherNameFromIsbn
+               &TransformKohaToMarc
+       );
 
-( lot of changes for Koha 3.0)
+       # To modify something
+       push @EXPORT, qw(
+               &ModBiblio
+               &ModBiblioframework
+               &ModZebra
+       );
 
-Koha 1.2 and previous version used a specific API to manage biblios. This API uses old-DB style parameters.
-They are based on a hash, and store data in biblio/biblioitems/items tables (plus additionalauthors, bibliosubject and bibliosubtitle where applicable)
+       # To delete something
+       push @EXPORT, qw(
+               &DelBiblio
+       );
 
-In Koha 2.0, we introduced a MARC-DB.
+       # Internal functions
+       # those functions are exported but should not be used
+       # they are usefull is few circumstances, so are exported.
+       # but don't use them unless you're a core developer ;-)
+       push @EXPORT, qw(
+               &ModBiblioMarc
+       );
 
-In Koha 3.0 we removed this MARC-DB for search as we wanted to use Zebra as search system.
+       # Others functions
+       push @EXPORT, qw(
+               &TransformMarcToKoha
+               &TransformHtmlToMarc2
+               &TransformHtmlToMarc
+               &TransformHtmlToXml
+               &PrepareItemrecordDisplay
+               &char_decode
+               &GetNoZebraIndexes
+       );
+}
 
-So in Koha 3.0, saving a record means :
- - storing the raw marc record (iso2709) in biblioitems.marc field. It contains both biblio & items informations.
- - storing the "decoded information" in biblio/biblioitems/items as previously.
- - using zebra to manage search & indexing on the MARC datas.
- In Koha, there is a systempreference saying "MARC=ON" or "MARC=OFF"
- * MARC=ON : when MARC=ON, koha uses a MARC::Record object (in sub parameters). Saving informations in the DB means : 
- - transform the MARC record into a hash
- - add the raw marc record into the hash
- - store them & update zebra
- * MARC=OFF : when MARC=OFF, koha uses a hash object (in sub parameters). Saving informations in the DB means :
- - transform the hash into a MARC record
- - add the raw marc record into the hash
- - store them and update zebra
-That's why we need 3 types of subs :
+=head1 NAME
 
-=head2 REALxxx subs
+C4::Biblio - cataloging management functions
 
-all I<subs beginning by REAL> does effective storage of information (with a hash, one field of the hash being the raw marc record). Those subs also update the record in zebra. REAL subs should be only for internal use (called by NEW or "something else" subs
+=head1 DESCRIPTION
 
-=head2 NEWxxx related subs
+Biblio.pm contains functions for managing storage and editing of bibliographic data within Koha. Most of the functions in this module are used for cataloging records: adding, editing, or removing biblios, biblioitems, or items. Koha's stores bibliographic information in three places:
 
 =over 4
 
-all I<subs beginning by NEW> use MARC::Record as parameters. it's the API that MUST be used in MARC acquisition system. They just create the hash, add it the raw marc record. Then, they call REALxxx sub.
+=item 1. in the biblio,biblioitems,items, etc tables, which are limited to a one-to-one mapping to underlying MARC data
 
-all subs requires/use $dbh as 1st parameter and a MARC::Record object as 2nd parameter. they sometimes requires another parameter.
+=item 2. as raw MARC in the Zebra index and storage engine
 
-=back
-
-=head2 something_elsexxx related subs
-
-=over 4
-
-all I<subs beginning by seomething else> are the old-style API. They use a hash as parameter, transform the hash into a -small- marc record, and calls REAL subs.
-
-all subs requires/use $dbh as 1st parameter and a hash as 2nd parameter.
+=item 3. as raw MARC the biblioitems.marc and biblioitems.marcxml
 
 =back
 
-=head1 API
-
-=cut
-
-sub zebra_create {
-       my ($biblionumber,$record) = @_;
-       # create the iso2709 file for zebra
-       my $cgidir = C4::Context->intranetdir ."/cgi-bin";
-       unless (opendir(DIR, "$cgidir")) {
-                       $cgidir = C4::Context->intranetdir."/";
-       } 
-       closedir DIR;
-       my $filename = $cgidir."/zebra/biblios/BIBLIO".$biblionumber."iso2709";
-       open F,"> $filename";
-       print F $record->as_usmarc();
-       close F;
-       my $res = system("cd $cgidir/zebra;/usr/local/bin/zebraidx update biblios");
-       unlink($filename);
-}
+In the 3.0 version of Koha, the authoritative record-level information is in biblioitems.marcxml
 
-=head2 @tagslib = &MARCgettagslib($dbh,1|0,$frameworkcode);
+Because the data isn't completely normalized there's a chance for information to get out of sync. The design choice to go with a un-normalized schema was driven by performance and stability concerns. However, if this occur, it can be considered as a bug : The API is (or should be) complete & the only entry point for all biblio/items managements.
 
 =over 4
 
-2nd param is 1 for liblibrarian and 0 for libopac
-$frameworkcode contains the framework reference. If empty or does not exist, the default one is used
-
-returns a hash with all values for all fields and subfields for a given MARC framework :
-        $res->{$tag}->{lib}        = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
-                    ->{tab}        = "";            # XXX
-                    ->{mandatory}  = $mandatory;
-                    ->{repeatable} = $repeatable;
-                    ->{$subfield}->{lib}              = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
-                                 ->{tab}              = $tab;
-                                 ->{mandatory}        = $mandatory;
-                                 ->{repeatable}       = $repeatable;
-                                 ->{authorised_value} = $authorised_value;
-                                 ->{authtypecode}     = $authtypecode;
-                                 ->{value_builder}    = $value_builder;
-                                 ->{kohafield}        = $kohafield;
-                                 ->{seealso}          = $seealso;
-                                 ->{hidden}           = $hidden;
-                                 ->{isurl}            = $isurl;
-                                 ->{link}            = $link;
-
-=back
-
-=cut
+=item 1. Compared with MySQL, Zebra is slow to update an index for small data changes -- especially for proc-intensive operations like circulation
 
-sub MARCgettagslib {
-    my ( $dbh, $forlibrarian, $frameworkcode ) = @_;
-    $frameworkcode = "" unless $frameworkcode;
-    $forlibrarian = 1 unless $forlibrarian;
-    my $sth;
-    my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
+=item 2. Zebra's index has been known to crash and a backup of the data is necessary to rebuild it in such cases
 
-    # check that framework exists
-    $sth =
-      $dbh->prepare(
-        "select count(*) from marc_tag_structure where frameworkcode=?");
-    $sth->execute($frameworkcode);
-    my ($total) = $sth->fetchrow;
-    $frameworkcode = "" unless ( $total > 0 );
-    $sth =
-      $dbh->prepare(
-"select tagfield,liblibrarian,libopac,mandatory,repeatable from marc_tag_structure where frameworkcode=? order by tagfield"
-    );
-    $sth->execute($frameworkcode);
-    my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
+=back
 
-    while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) = $sth->fetchrow ) {
-        $res->{$tag}->{lib}        = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
-        $res->{$tag}->{tab}        = "";            # XXX
-        $res->{$tag}->{mandatory}  = $mandatory;
-        $res->{$tag}->{repeatable} = $repeatable;
-    }
+Because of this design choice, the process of managing storage and editing is a bit convoluted. Historically, Biblio.pm's grown to an unmanagable size and as a result we have several types of functions currently:
 
-    $sth =
-      $dbh->prepare(
-"select tagfield,tagsubfield,liblibrarian,libopac,tab, mandatory, repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link from marc_subfield_structure where frameworkcode=? order by tagfield,tagsubfield"
-    );
-    $sth->execute($frameworkcode);
+=over 4
 
-    my $subfield;
-    my $authorised_value;
-    my $authtypecode;
-    my $value_builder;
-    my $kohafield;
-    my $seealso;
-    my $hidden;
-    my $isurl;
-       my $link;
+=item 1. Add*/Mod*/Del*/ - high-level external functions suitable for being called from external scripts to manage the collection
 
-    while (
-        ( $tag,         $subfield,   $liblibrarian,   , $libopac,      $tab,
-        $mandatory,     $repeatable, $authorised_value, $authtypecode,
-        $value_builder, $kohafield,  $seealso,          $hidden,
-        $isurl,                        $link )
-        = $sth->fetchrow
-      )
-    {
-        $res->{$tag}->{$subfield}->{lib}              = ($forlibrarian or !$libopac)?$liblibrarian:$libopac;
-        $res->{$tag}->{$subfield}->{tab}              = $tab;
-        $res->{$tag}->{$subfield}->{mandatory}        = $mandatory;
-        $res->{$tag}->{$subfield}->{repeatable}       = $repeatable;
-        $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
-        $res->{$tag}->{$subfield}->{authtypecode}     = $authtypecode;
-        $res->{$tag}->{$subfield}->{value_builder}    = $value_builder;
-        $res->{$tag}->{$subfield}->{kohafield}        = $kohafield;
-        $res->{$tag}->{$subfield}->{seealso}          = $seealso;
-        $res->{$tag}->{$subfield}->{hidden}           = $hidden;
-        $res->{$tag}->{$subfield}->{isurl}            = $isurl;
-        $res->{$tag}->{$subfield}->{link}            = $link;
-    }
-    return $res;
-}
+=item 2. _koha_* - low-level internal functions for managing the koha tables
 
-=head2 ($tagfield,$tagsubfield) = &MARCfind_marc_from_kohafield($dbh,$kohafield);
+=item 3. Marc management function : as the MARC record is stored in biblioitems.marc(xml), some subs dedicated to it's management are in this package. They should be used only internally by Biblio.pm, the only official entry points being AddBiblio, AddItem, ModBiblio, ModItem.
 
-=over 4
+=item 4. Zebra functions used to update the Zebra index
 
-finds MARC tag and subfield for a given kohafield
-kohafield is "table.field" where table= biblio|biblioitems|items, and field a field of the previous table
+=item 5. internal helper functions such as char_decode, checkitems, etc. Some of these probably belong in Koha.pm
 
 =back
 
-=cut
-
-sub MARCfind_marc_from_kohafield {
-    my ( $dbh, $kohafield,$frameworkcode ) = @_;
-    return 0, 0 unless $kohafield;
-    $frameworkcode='' unless $frameworkcode;
-       my $relations = C4::Context->marcfromkohafield;
-       return ($relations->{$frameworkcode}->{$kohafield}->[0],$relations->{$frameworkcode}->{$kohafield}->[1]);
-}
-
-=head2 $MARCRecord = &MARCgetbiblio($dbh,$biblionumber);
+The MARC record (in biblioitems.marcxml) contains the complete marc record, including items. It also contains the biblionumber. That is the reason why it is not stored directly by AddBiblio, with all other fields . To save a biblio, we need to :
 
 =over 4
 
-Returns a MARC::Record for the biblio $biblionumber.
+=item 1. save datas in biblio and biblioitems table, that gives us a biblionumber and a biblioitemnumber
 
-=cut
+=item 2. add the biblionumber and biblioitemnumber into the MARC records
 
-sub MARCgetbiblio {
+=item 3. save the marc record
 
-    # Returns MARC::Record of the biblio passed in parameter.
-    my ( $dbh, $biblionumber ) = @_;
-       my $sth = $dbh->prepare('select marc from biblioitems where biblionumber=?');
-       $sth->execute($biblionumber);
-       my ($marc) = $sth->fetchrow;
-       my $record = MARC::Record::new_from_usmarc($marc);
-    return $record;
-}
+=back
 
-=head2 $XML = &XMLgetbiblio($dbh,$biblionumber);
+When dealing with items, we must :
 
 =over 4
 
-Returns a raw XML for the biblio $biblionumber.
-
-=cut
-
-sub XMLgetbiblio {
-
-    # Returns MARC::Record of the biblio passed in parameter.
-    my ( $dbh, $biblionumber ) = @_;
-       my $sth = $dbh->prepare('select marcxml,marc from biblioitems where biblionumber=?');
-       $sth->execute($biblionumber);
-       my ($XML,$marc) = $sth->fetchrow;
-#      my $record =MARC::Record::new_from_usmarc($marc);
-#      warn "MARC : \n*-************************\n".$record->as_xml."\n*-************************\n";
-    return $XML;
-}
+=item 1. save the item in items table, that gives us an itemnumber
 
-=head2 $MARCrecord = &MARCgetitem($dbh,$biblionumber);
+=item 2. add the itemnumber to the item MARC field
 
-=over 4
+=item 3. overwrite the MARC record (with the added item) into biblioitems.marc(xml)
 
-Returns a MARC::Record with all items of biblio # $biblionumber
+When modifying a biblio or an item, the behaviour is quite similar.
 
 =back
 
-=cut
-
-sub MARCgetitem {
-
-    my ( $dbh, $biblionumber, $itemnumber ) = @_;
-       my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
-       # get the complete MARC record
-       my $sth = $dbh->prepare("select marc from biblioitems where biblionumber=?");
-       $sth->execute($biblionumber);
-       my ($rawmarc) = $sth->fetchrow;
-       my $record = MARC::File::USMARC::decode($rawmarc);
-       # now, find the relevant itemnumber
-       my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
-       # prepare the new item record
-       my $itemrecord = MARC::Record->new();
-       # parse all fields fields from the complete record
-       foreach ($record->field($itemnumberfield)) {
-               # when the item field is found, save it
-               if ($_->subfield($itemnumbersubfield) == $itemnumber) {
-                       $itemrecord->append_fields($_);
-               }
-       }
-
-    return $itemrecord;
-}
+=head1 EXPORTED FUNCTIONS
 
-=head2 sub find_biblioitemnumber($dbh,$biblionumber);
+=head2 AddBiblio
 
 =over 4
 
-Returns the 1st biblioitemnumber related to $biblionumber. When MARC=ON we should have 1 biblionumber = 1 and only 1 biblioitemnumber
-This sub is useless when MARC=OFF
+($biblionumber,$biblioitemnumber) = AddBiblio($record,$frameworkcode);
 
 =back
 
-=cut
-sub find_biblioitemnumber {
-       my ( $dbh, $biblionumber ) = @_;
-       my $sth = $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
-       $sth->execute($biblionumber);
-       my ($biblioitemnumber) = $sth->fetchrow;
-       return $biblioitemnumber;
-}
-
-=head2 $frameworkcode = MARCfind_frameworkcode($dbh,$biblionumber);
-
-=over 4
+Exported function (core API) for adding a new biblio to koha.
 
-returns the framework of a given biblio
+The first argument is a C<MARC::Record> object containing the
+bib to add, while the second argument is the desired MARC
+framework code.
 
-=back
+This function also accepts a third, optional argument: a hashref
+to additional options.  The only defined option is C<defer_marc_save>,
+which if present and mapped to a true value, causes C<AddBiblio>
+to omit the call to save the MARC in C<bibilioitems.marc>
+and C<biblioitems.marcxml>  This option is provided B<only>
+for the use of scripts such as C<bulkmarcimport.pl> that may need
+to do some manipulation of the MARC record for item parsing before
+saving it and which cannot afford the performance hit of saving
+the MARC record twice.  Consequently, do not use that option
+unless you can guarantee that C<ModBiblioMarc> will be called.
 
 =cut
 
-sub MARCfind_frameworkcode {
-       my ( $dbh, $biblionumber ) = @_;
-       my $sth = $dbh->prepare("select frameworkcode from biblio where biblionumber=?");
-       $sth->execute($biblionumber);
-       my ($frameworkcode) = $sth->fetchrow;
-       return $frameworkcode;
-}
+sub AddBiblio {
+    my $record = shift;
+    my $frameworkcode = shift;
+    my $options = @_ ? shift : undef;
+    my $defer_marc_save = 0;
+    if (defined $options and exists $options->{'defer_marc_save'} and $options->{'defer_marc_save'}) {
+        $defer_marc_save = 1;
+    }
 
-=head2 $MARCRecord = &MARCkoha2marcBiblio($dbh,$bibliohash);
+    my ($biblionumber,$biblioitemnumber,$error);
+    my $dbh = C4::Context->dbh;
+    # transform the data into koha-table style data
+    my $olddata = TransformMarcToKoha( $dbh, $record, $frameworkcode );
+    ($biblionumber,$error) = _koha_add_biblio( $dbh, $olddata, $frameworkcode );
+    $olddata->{'biblionumber'} = $biblionumber;
+    ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $olddata );
 
-=over 4
+    _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
 
-MARCkoha2marcBiblio is a wrapper between old-DB and MARC-DB. It returns a MARC::Record builded with old-DB biblio/biblioitem :
-all entries of the hash are transformed into their matching MARC field/subfield.
+    # now add the record
+    $biblionumber = ModBiblioMarc( $record, $biblionumber, $frameworkcode ) unless $defer_marc_save;
+      
+    &logaction(C4::Context->userenv->{'number'},"CATALOGUING","ADD",$biblionumber,"biblio") 
+        if C4::Context->preference("CataloguingLog");
 
-=back
+    return ( $biblionumber, $biblioitemnumber );
+}
 
-=cut
+=head2 ModBiblio
 
-sub MARCkoha2marcBiblio {
-
-       # this function builds partial MARC::Record from the old koha-DB fields
-       my ( $dbh, $bibliohash ) = @_;
-       # we don't have biblio entries in the hash, so we add them first
-       my $sth = $dbh->prepare("select * from biblio where biblionumber=?");
-       $sth->execute($bibliohash->{biblionumber});
-       my $biblio = $sth->fetchrow_hashref;
-       foreach (keys %$biblio) {
-               $bibliohash->{$_}=$biblio->{$_};
-       }
-       $sth = $dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
-       my $record = MARC::Record->new();
-       foreach ( keys %$bibliohash ) {
-               &MARCkoha2marcOnefield( $sth, $record, "biblio." . $_, $bibliohash->{$_}, '') if $bibliohash->{$_};
-               &MARCkoha2marcOnefield( $sth, $record, "biblioitems." . $_, $bibliohash->{$_}, '') if $bibliohash->{$_};
-       }
-
-       # other fields => additional authors, subjects, subtitles
-       my $sth2 = $dbh->prepare(" SELECT author FROM additionalauthors WHERE biblionumber=?");
-       $sth2->execute($bibliohash->{biblionumber});
-       while ( my $row = $sth2->fetchrow_hashref ) {
-               &MARCkoha2marcOnefield( $sth, $record, "additionalauthors.author", $bibliohash->{'author'},'' );
-       }
-       $sth2 = $dbh->prepare(" SELECT subject FROM bibliosubject WHERE biblionumber=?");
-       $sth2->execute($bibliohash->{biblionumber});
-       while ( my $row = $sth2->fetchrow_hashref ) {
-               &MARCkoha2marcOnefield( $sth, $record, "bibliosubject.subject", $row->{'subject'},'' );
-       }
-       $sth2 = $dbh->prepare(" SELECT subtitle FROM bibliosubtitle WHERE biblionumber=?");
-       $sth2->execute($bibliohash->{biblionumber});
-       while ( my $row = $sth2->fetchrow_hashref ) {
-               &MARCkoha2marcOnefield( $sth, $record, "bibliosubtitle.subtitle", $row->{'subtitle'},'' );
-       }
-       
-       return $record;
-}
+    ModBiblio( $record,$biblionumber,$frameworkcode);
+    Exported function (core API) to modify a biblio
 
-=head2 $MARCRecord = &MARCkoha2marcItem($dbh,$biblionumber,itemnumber);
+=cut
 
-MARCkoha2marcItem is a wrapper between old-DB and MARC-DB. It returns a MARC::Record builded with old-DB items :
-all entries of the hash are transformed into their matching MARC field/subfield.
+sub ModBiblio {
+    my ( $record, $biblionumber, $frameworkcode ) = @_;
+    if (C4::Context->preference("CataloguingLog")) {
+        my $newrecord = GetMarcBiblio($biblionumber);
+        &logaction(C4::Context->userenv->{'number'},"CATALOGUING","MODIFY",$biblionumber,"BEFORE=>".$newrecord->as_formatted);
+    }
+    
+    my $dbh = C4::Context->dbh;
+    
+    $frameworkcode = "" unless $frameworkcode;
 
-=over 4
+    # get the items before and append them to the biblio before updating the record, atm we just have the biblio
+    my ( $itemtag, $itemsubfield ) = GetMarcFromKohaField("items.itemnumber",$frameworkcode);
+    my $oldRecord = GetMarcBiblio( $biblionumber );
+    
+    # parse each item, and, for an unknown reason, re-encode each subfield 
+    # if you don't do that, the record will have encoding mixed
+    # and the biblio will be re-encoded.
+    # strange, I (Paul P.) searched more than 1 day to understand what happends
+    # but could only solve the problem this way...
+   my @fields = $oldRecord->field( $itemtag );
+    foreach my $fielditem ( @fields ){
+        my $field;
+        foreach ($fielditem->subfields()) {
+            if ($field) {
+                $field->add_subfields(Encode::encode('utf-8',$_->[0]) => Encode::encode('utf-8',$_->[1]));
+            } else {
+                $field = MARC::Field->new("$itemtag",'','',Encode::encode('utf-8',$_->[0]) => Encode::encode('utf-8',$_->[1]));
+            }
+          }
+        $record->append_fields($field);
+    }
+    
+    # update biblionumber and biblioitemnumber in MARC
+    # FIXME - this is assuming a 1 to 1 relationship between
+    # biblios and biblioitems
+    my $sth =  $dbh->prepare("select biblioitemnumber from biblioitems where biblionumber=?");
+    $sth->execute($biblionumber);
+    my ($biblioitemnumber) = $sth->fetchrow;
+    $sth->finish();
+    _koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
 
-=back
+    # update the MARC record (that now contains biblio and items) with the new record data
+    &ModBiblioMarc( $record, $biblionumber, $frameworkcode );
+    
+    # load the koha-table data object
+    my $oldbiblio = TransformMarcToKoha( $dbh, $record, $frameworkcode );
 
-=cut
+    # modify the other koha tables
+    _koha_modify_biblio( $dbh, $oldbiblio, $frameworkcode );
+    _koha_modify_biblioitem_nonmarc( $dbh, $oldbiblio );
+    return 1;
+}
 
-sub MARCkoha2marcItem {
+=head2 ModBiblioframework
 
-    # this function builds partial MARC::Record from the old koha-DB fields
-    my ( $dbh, $item ) = @_;
+    ModBiblioframework($biblionumber,$frameworkcode);
+    Exported function to modify a biblio framework
 
-    #    my $dbh=&C4Connect;
-    my $sth = $dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
-    my $record = MARC::Record->new();
+=cut
 
-       foreach( keys %$item ) {
-               if ( $item->{$_} ) {
-                       &MARCkoha2marcOnefield( $sth, $record, "items." . $_,
-                               $item->{$_},'' );
-               }
-       }
-    return $record;
+sub ModBiblioframework {
+    my ( $biblionumber, $frameworkcode ) = @_;
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare(
+        "UPDATE biblio SET frameworkcode=? WHERE biblionumber=?"
+    );
+    $sth->execute($frameworkcode, $biblionumber);
+    return 1;
 }
 
-=head2 MARCkoha2marcOnefield
+=head2 DelBiblio
 
-=over 4
+=over
 
-This sub is for internal use only, used by koha2marcBiblio & koha2marcItem
+my $error = &DelBiblio($dbh,$biblionumber);
+Exported function (core API) for deleting a biblio in koha.
+Deletes biblio record from Zebra and Koha tables (biblio,biblioitems,items)
+Also backs it up to deleted* tables
+Checks to make sure there are not issues on any of the items
+return:
+C<$error> : undef unless an error occurs
 
 =back
 
 =cut
 
-sub MARCkoha2marcOnefield {
-    my ( $sth, $record, $kohafieldname, $value,$frameworkcode ) = @_;
-    my $tagfield;
-    my $tagsubfield;
-    $sth->execute($frameworkcode,$kohafieldname);
-    if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
-        if ( $record->field($tagfield) ) {
-            my $tag = $record->field($tagfield);
-            if ($tag) {
-                $tag->add_subfields( $tagsubfield, $value );
-                $record->delete_field($tag);
-                $record->add_fields($tag);
-            }
-        }
-        else {
-            $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
-        }
+sub DelBiblio {
+    my ( $biblionumber ) = @_;
+    my $dbh = C4::Context->dbh;
+    my $error;    # for error handling
+    
+    # First make sure this biblio has no items attached
+    my $sth = $dbh->prepare("SELECT itemnumber FROM items WHERE biblionumber=?");
+    $sth->execute($biblionumber);
+    if (my $itemnumber = $sth->fetchrow){
+        # Fix this to use a status the template can understand
+        $error .= "This Biblio has items attached, please delete them first before deleting this biblio ";
     }
-    return $record;
-}
-
-=head2 $MARCrecord = MARChtml2marc($dbh,$rtags,$rsubfields,$rvalues,%indicators);
 
-=over 4
+    return $error if $error;
 
-transforms the parameters (coming from HTML form) into a MARC::Record
-parameters with r are references to arrays.
+    # Delete in Zebra. Be careful NOT to move this line after _koha_delete_biblio
+    # for at least 2 reasons :
+    # - we need to read the biblio if NoZebra is set (to remove it from the indexes
+    # - if something goes wrong, the biblio may be deleted from Koha but not from zebra
+    #   and we would have no way to remove it (except manually in zebra, but I bet it would be very hard to handle the problem)
+    ModZebra($biblionumber, "recordDelete", "biblioserver", undef);
 
-FIXME : should be improved for 3.0, to avoid having 4 differents arrays
+    # delete biblioitems and items from Koha tables and save in deletedbiblioitems,deleteditems
+    $sth =
+      $dbh->prepare(
+        "SELECT biblioitemnumber FROM biblioitems WHERE biblionumber=?");
+    $sth->execute($biblionumber);
+    while ( my $biblioitemnumber = $sth->fetchrow ) {
 
-=back
+        # delete this biblioitem
+        $error = _koha_delete_biblioitems( $dbh, $biblioitemnumber );
+        return $error if $error;
+    }
 
-=cut
+    # delete biblio from Koha tables and save in deletedbiblio
+    # must do this *after* _koha_delete_biblioitems, otherwise
+    # delete cascade will prevent deletedbiblioitems rows
+    # from being generated by _koha_delete_biblioitems
+    $error = _koha_delete_biblio( $dbh, $biblionumber );
 
-sub MARChtml2marc {
-       my ($dbh,$rtags,$rsubfields,$rvalues,%indicators) = @_;
-       my $prevtag = -1;
-       my $record = MARC::Record->new();
-#      my %subfieldlist=();
-       my $prevvalue; # if tag <10
-       my $field; # if tag >=10
-       for (my $i=0; $i< @$rtags; $i++) {
-               next unless @$rvalues[$i];
-               # rebuild MARC::Record
-#                      warn "0=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ";
-               if (@$rtags[$i] ne $prevtag) {
-                       if ($prevtag < 10) {
-                               if ($prevvalue) {
-                                       if ($prevtag ne '000') {
-                                               $record->add_fields((sprintf "%03s",$prevtag),$prevvalue);
-                                       } else {
-                                               $record->leader($prevvalue);
-                                       }
-                               }
-                       } else {
-                               if ($field) {
-                                       $record->add_fields($field);
-                               }
-                       }
-                       $indicators{@$rtags[$i]}.='  ';
-                       if (@$rtags[$i] <10) {
-                               $prevvalue= @$rvalues[$i];
-                               undef $field;
-                       } else {
-                               undef $prevvalue;
-                               $field = MARC::Field->new( (sprintf "%03s",@$rtags[$i]), substr($indicators{@$rtags[$i]},0,1),substr($indicators{@$rtags[$i]},1,1), @$rsubfields[$i] => @$rvalues[$i]);
-#                      warn "1=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
-                       }
-                       $prevtag = @$rtags[$i];
-               } else {
-                       if (@$rtags[$i] <10) {
-                               $prevvalue=@$rvalues[$i];
-                       } else {
-                               if (length(@$rvalues[$i])>0) {
-                                       $field->add_subfields(@$rsubfields[$i] => @$rvalues[$i]);
-#                      warn "2=>".@$rtags[$i].@$rsubfields[$i]." = ".@$rvalues[$i].": ".$field->as_formatted;
-                               }
-                       }
-                       $prevtag= @$rtags[$i];
-               }
-       }
-       # the last has not been included inside the loop... do it now !
-       $record->add_fields($field) if $field;
-#      warn "HTML2MARC=".$record->as_formatted;
-       return $record;
+    &logaction(C4::Context->userenv->{'number'},"CATALOGUING","DELETE",$biblionumber,"") 
+        if C4::Context->preference("CataloguingLog");
+    return;
 }
 
-
-=head2 $hash = &MARCmarc2koha($dbh,$MARCRecord);
+=head2 GetBiblioData
 
 =over 4
 
-builds a hash with old-db datas from a MARC::Record
+$data = &GetBiblioData($biblionumber);
+Returns information about the book with the given biblionumber.
+C<&GetBiblioData> returns a reference-to-hash. The keys are the fields in
+the C<biblio> and C<biblioitems> tables in the
+Koha database.
+In addition, C<$data-E<gt>{subject}> is the list of the book's
+subjects, separated by C<" , "> (space, comma, space).
+If there are multiple biblioitems with the given biblionumber, only
+the first one is considered.
 
 =back
 
 =cut
 
-sub MARCmarc2koha {
-       my ($dbh,$record,$frameworkcode) = @_;
-       my $sth=$dbh->prepare("select tagfield,tagsubfield from marc_subfield_structure where frameworkcode=? and kohafield=?");
-       my $result;
-       my $sth2=$dbh->prepare("SHOW COLUMNS from biblio");
-       $sth2->execute;
-       my $field;
-       while (($field)=$sth2->fetchrow) {
-#              warn "biblio.".$field;
-               $result=&MARCmarc2kohaOneField($sth,"biblio",$field,$record,$result,$frameworkcode);
-       }
-       $sth2=$dbh->prepare("SHOW COLUMNS from biblioitems");
-       $sth2->execute;
-       while (($field)=$sth2->fetchrow) {
-               if ($field eq 'notes') { $field = 'bnotes'; }
-#              warn "biblioitems".$field;
-               $result=&MARCmarc2kohaOneField($sth,"biblioitems",$field,$record,$result,$frameworkcode);
-       }
-       $sth2=$dbh->prepare("SHOW COLUMNS from items");
-       $sth2->execute;
-       while (($field)=$sth2->fetchrow) {
-#              warn "items".$field;
-               $result=&MARCmarc2kohaOneField($sth,"items",$field,$record,$result,$frameworkcode);
-       }
-       # additional authors : specific
-       $result = &MARCmarc2kohaOneField($sth,"bibliosubtitle","subtitle",$record,$result,$frameworkcode);
-       $result = &MARCmarc2kohaOneField($sth,"additionalauthors","additionalauthors",$record,$result,$frameworkcode);
-# modify copyrightdate to keep only the 1st year found
-       my $temp = $result->{'copyrightdate'};
-       if ($temp){
-               $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
-               if ($1>0) {
-                       $result->{'copyrightdate'} = $1;
-               } else { # if no cYYYY, get the 1st date.
-                       $temp =~ m/(\d\d\d\d)/;
-                       $result->{'copyrightdate'} = $1;
-               }
-       }
-# modify publicationyear to keep only the 1st year found
-       $temp = $result->{'publicationyear'};
-       $temp =~ m/c(\d\d\d\d)/; # search cYYYY first
-       if ($1>0) {
-               $result->{'publicationyear'} = $1;
-       } else { # if no cYYYY, get the 1st date.
-               $temp =~ m/(\d\d\d\d)/;
-               $result->{'publicationyear'} = $1;
-       }
-       return $result;
-}
+sub GetBiblioData {
+    my ( $bibnum ) = @_;
+    my $dbh = C4::Context->dbh;
 
-sub MARCmarc2kohaOneField {
+  #  my $query =  C4::Context->preference('item-level_itypes') ? 
+    #   " SELECT * , biblioitems.notes AS bnotes, biblio.notes
+    #       FROM biblio
+    #        LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
+    #       WHERE biblio.biblionumber = ?
+    #        AND biblioitems.biblionumber = biblio.biblionumber
+    #";
+    
+    my $query = " SELECT * , biblioitems.notes AS bnotes, itemtypes.notforloan as bi_notforloan, biblio.notes
+            FROM biblio
+            LEFT JOIN biblioitems ON biblio.biblionumber = biblioitems.biblionumber
+            LEFT JOIN itemtypes ON biblioitems.itemtype = itemtypes.itemtype
+            WHERE biblio.biblionumber = ?
+            AND biblioitems.biblionumber = biblio.biblionumber ";
+         
+    my $sth = $dbh->prepare($query);
+    $sth->execute($bibnum);
+    my $data;
+    $data = $sth->fetchrow_hashref;
+    $sth->finish;
 
-# FIXME ? if a field has a repeatable subfield that is used in old-db, only the 1st will be retrieved...
-    my ( $sth, $kohatable, $kohafield, $record, $result,$frameworkcode ) = @_;
-    #    warn "kohatable / $kohafield / $result / ";
-    my $res = "";
-    my $tagfield;
-    my $subfield;
-    ( $tagfield, $subfield ) = MARCfind_marc_from_kohafield("",$kohatable.".".$kohafield,$frameworkcode);
-    foreach my $field ( $record->field($tagfield) ) {
-               if ($field->tag()<10) {
-                       if ($result->{$kohafield}) {
-                               # Reverse array filled with elements from repeated subfields 
-                               # from first to last to avoid last to first concatenation of 
-                               # elements in Koha DB.  -- thd.
-                               $result->{$kohafield} .= " | ".reverse($field->data());
-                       } else {
-                               $result->{$kohafield} = $field->data();
-                       }
-               } else {
-                       if ( $field->subfields ) {
-                               my @subfields = $field->subfields();
-                               foreach my $subfieldcount ( 0 .. $#subfields ) {
-                                       if ($subfields[$subfieldcount][0] eq $subfield) {
-                                               if ( $result->{$kohafield} ) {
-                                                       $result->{$kohafield} .= " | " . $subfields[$subfieldcount][1];
-                                               }
-                                               else {
-                                                       $result->{$kohafield} = $subfields[$subfieldcount][1];
-                                               }
-                                       }
-                               }
-                       }
-               }
-    }
-#      warn "OneField for $kohatable.$kohafield and $frameworkcode=> $tagfield, $subfield";
-    return $result;
-}
+    return ($data);
+}    # sub GetBiblioData
 
-=head2 ($biblionumber,$biblioitemnumber) = NEWnewbibilio($dbh,$MARCRecord,$frameworkcode);
+=head2 &GetBiblioItemData
 
 =over 4
 
-creates a biblio from a MARC::Record.
+$itemdata = &GetBiblioItemData($biblioitemnumber);
+
+Looks up the biblioitem with the given biblioitemnumber. Returns a
+reference-to-hash. The keys are the fields from the C<biblio>,
+C<biblioitems>, and C<itemtypes> tables in the Koha database, except
+that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
 
 =back
 
 =cut
 
-sub NEWnewbiblio {
-    my ( $dbh, $record, $frameworkcode ) = @_;
-    my $biblionumber;
-    my $biblioitemnumber;
-    my $olddata = MARCmarc2koha( $dbh, $record,$frameworkcode );
-       $olddata->{frameworkcode} = $frameworkcode;
-    $biblionumber = REALnewbiblio( $dbh, $olddata );
-       $olddata->{biblionumber} = $biblionumber;
-       # add biblionumber into the MARC record (it's the ID for zebra)
-       my ( $tagfield, $tagsubfield ) =
-                                       MARCfind_marc_from_kohafield( $dbh, "biblio.biblionumber",$frameworkcode );
-       # create the field
-       my $newfield;
-       if ($tagfield<10) {
-               $newfield = MARC::Field->new(
-                       $tagfield, $biblionumber,
-               );
-       } else {
-               $newfield = MARC::Field->new(
-                       $tagfield, '', '', "$tagsubfield" => $biblionumber,
-               );
-       }
-       # drop old field (just in case it already exist and create new one...
-       my $old_field = $record->field($tagfield);
-       $record->delete_field($old_field);
-       $record->add_fields($newfield);
-
-       #create the marc entry, that stores the rax marc record in Koha 3.0
-       $olddata->{marc} = $record->as_usmarc();
-       $olddata->{marcxml} = $record->as_xml();
-       # and create biblioitem, that's all folks !
-    $biblioitemnumber = REALnewbiblioitem( $dbh, $olddata );
-
-    # search subtiles, addiauthors and subjects
-    ( $tagfield, $tagsubfield ) =
-      MARCfind_marc_from_kohafield( $dbh, "additionalauthors.author",$frameworkcode );
-    my @addiauthfields = $record->field($tagfield);
-    foreach my $addiauthfield (@addiauthfields) {
-        my @addiauthsubfields = $addiauthfield->subfield($tagsubfield);
-        foreach my $subfieldcount ( 0 .. $#addiauthsubfields ) {
-            REALmodaddauthor( $dbh, $biblionumber,
-                $addiauthsubfields[$subfieldcount] );
-        }
-    }
-    ( $tagfield, $tagsubfield ) =
-      MARCfind_marc_from_kohafield( $dbh, "bibliosubtitle.subtitle",$frameworkcode );
-    my @subtitlefields = $record->field($tagfield);
-    foreach my $subtitlefield (@subtitlefields) {
-        my @subtitlesubfields = $subtitlefield->subfield($tagsubfield);
-        foreach my $subfieldcount ( 0 .. $#subtitlesubfields ) {
-            REALnewsubtitle( $dbh, $biblionumber,
-                $subtitlesubfields[$subfieldcount] );
-        }
-    }
-    ( $tagfield, $tagsubfield ) =
-      MARCfind_marc_from_kohafield( $dbh, "bibliosubject.subject",$frameworkcode );
-    my @subj = $record->field($tagfield);
-    my @subjects;
-    foreach my $subject (@subj) {
-        my @subjsubfield = $subject->subfield($tagsubfield);
-        foreach my $subfieldcount ( 0 .. $#subjsubfield ) {
-            push @subjects, $subjsubfield[$subfieldcount];
-        }
-    }
-    REALmodsubject( $dbh, $biblionumber, 1, @subjects );
-    return ( $biblionumber, $biblioitemnumber );
-}
+#'
+sub GetBiblioItemData {
+    my ($biblioitemnumber) = @_;
+    my $dbh       = C4::Context->dbh;
+    my $query = "SELECT *,biblioitems.notes AS bnotes
+        FROM biblio LEFT JOIN biblioitems on biblio.biblionumber=biblioitems.biblioitemnumber ";
+    unless(C4::Context->preference('item-level_itypes')) { 
+        $query .= "LEFT JOIN itemtypes on biblioitems.itemtype=itemtypes.itemtype ";
+    }    
+    $query .= " WHERE biblioitemnumber = ? ";
+    my $sth       =  $dbh->prepare($query);
+    my $data;
+    $sth->execute($biblioitemnumber);
+    $data = $sth->fetchrow_hashref;
+    $sth->finish;
+    return ($data);
+}    # sub &GetBiblioItemData
 
-=head2 NEWmodbilbioframework($dbh,$biblionumber,$frameworkcode);
+=head2 GetBiblioItemByBiblioNumber
 
 =over 4
 
-modify the framework of a biblio
+NOTE : This function has been copy/paste from C4/Biblio.pm from head before zebra integration.
 
 =back
 
 =cut
 
-sub NEWmodbiblioframework {
-       my ($dbh,$biblionumber,$frameworkcode) =@_;
-       my $sth = $dbh->prepare("Update biblio SET frameworkcode=? WHERE biblionumber=?");
-       $sth->execute($frameworkcode,$biblionumber);
-       return 1;
-}
-
-=head2 NEWmodbiblio($dbh,$MARCrecord,$biblionumber,$frameworkcode);
-
-=over 4
-
-modify a biblio (MARC=ON)
+sub GetBiblioItemByBiblioNumber {
+    my ($biblionumber) = @_;
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("Select * FROM biblioitems WHERE biblionumber = ?");
+    my $count = 0;
+    my @results;
 
-=back
+    $sth->execute($biblionumber);
 
-=cut
+    while ( my $data = $sth->fetchrow_hashref ) {
+        push @results, $data;
+    }
 
-sub NEWmodbiblio {
-       my ($dbh,$record,$biblionumber,$frameworkcode) =@_;
-       $frameworkcode="" unless $frameworkcode;
-#      &MARCmodbiblio($dbh,$bibid,$record,$frameworkcode,0);
-       my $oldbiblio = MARCmarc2koha($dbh,$record,$frameworkcode);
-       
-       $oldbiblio->{frameworkcode} = $frameworkcode;
-       #create the marc entry, that stores the rax marc record in Koha 3.0
-       $oldbiblio->{marc} = $record->as_usmarc();
-       $oldbiblio->{marcxml} = $record->as_xml();
-       
-       REALmodbiblio($dbh,$oldbiblio);
-       REALmodbiblioitem($dbh,$oldbiblio);
-       # now, modify addi authors, subject, addititles.
-       my ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"additionalauthors.author",$frameworkcode);
-       my @addiauthfields = $record->field($tagfield);
-       foreach my $addiauthfield (@addiauthfields) {
-               my @addiauthsubfields = $addiauthfield->subfield($tagsubfield);
-               $dbh->do("delete from additionalauthors where biblionumber=$biblionumber");
-               foreach my $subfieldcount (0..$#addiauthsubfields) {
-                       REALmodaddauthor($dbh,$biblionumber,$addiauthsubfields[$subfieldcount]);
-               }
-       }
-       ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"bibliosubtitle.subtitle",$frameworkcode);
-       my @subtitlefields = $record->field($tagfield);
-       foreach my $subtitlefield (@subtitlefields) {
-               my @subtitlesubfields = $subtitlefield->subfield($tagsubfield);
-               # delete & create subtitle again because REALmodsubtitle can't handle new subtitles
-               # between 2 modifs
-               $dbh->do("delete from bibliosubtitle where biblionumber=$biblionumber");
-               foreach my $subfieldcount (0..$#subtitlesubfields) {
-                       foreach my $subtit(split /\||#/,$subtitlesubfields[$subfieldcount]) {
-                               REALnewsubtitle($dbh,$biblionumber,$subtit);
-                       }
-               }
-       }
-       ($tagfield,$tagsubfield) = MARCfind_marc_from_kohafield($dbh,"bibliosubject.subject",$frameworkcode);
-       my @subj = $record->field($tagfield);
-       my @subjects;
-       foreach my $subject (@subj) {
-               my @subjsubfield = $subject->subfield($tagsubfield);
-               foreach my $subfieldcount (0..$#subjsubfield) {
-                       push @subjects,$subjsubfield[$subfieldcount];
-               }
-       }
-       REALmodsubject($dbh,$biblionumber,1,@subjects);
-       return 1;
+    $sth->finish;
+    return @results;
 }
 
-=head2 NEWmodbilbioframework($dbh,$biblionumber,$frameworkcode);
+=head2 GetBiblioFromItemNumber
 
 =over 4
 
-delete a biblio
-
-=back
-
-=cut
-
-sub NEWdelbiblio {
-    my ( $dbh, $bibid ) = @_;
-    my $biblio = &MARCfind_oldbiblionumber_from_MARCbibid( $dbh, $bibid );
-    &REALdelbiblio( $dbh, $biblio );
-    my $sth =
-      $dbh->prepare(
-        "select biblioitemnumber from biblioitems where biblionumber=?");
-    $sth->execute($biblio);
-    while ( my ($biblioitemnumber) = $sth->fetchrow ) {
-        REALdelbiblioitem( $dbh, $biblioitemnumber );
-    }
-    &MARCdelbiblio( $dbh, $bibid, 0 );
-}
-
-=head2 $itemnumber = NEWnewitem($dbh, $record, $biblionumber, $biblioitemnumber);
+$item = &GetBiblioFromItemNumber($itemnumber,$barcode);
 
-=over 4
+Looks up the item with the given itemnumber. if undef, try the barcode.
 
-creates an item from a MARC::Record
+C<&itemnodata> returns a reference-to-hash whose keys are the fields
+from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
+database.
 
 =back
 
 =cut
 
-sub NEWnewitem {
-    my ( $dbh, $record, $biblionumber, $biblioitemnumber ) = @_;
-
-    # add item in old-DB
-       my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
-    my $item = &MARCmarc2koha( $dbh, $record,$frameworkcode );
-    # needs old biblionumber and biblioitemnumber
-    $item->{'biblionumber'} = $biblionumber;
-    $item->{'biblioitemnumber'}=$biblioitemnumber;
-       $item->{marc} = $record->as_usmarc();
-    my ( $itemnumber, $error ) = &REALnewitems( $dbh, $item, $item->{barcode} );
-       return $itemnumber;
+#'
+sub GetBiblioFromItemNumber {
+    my ( $itemnumber, $barcode ) = @_;
+    my $dbh = C4::Context->dbh;
+    my $sth;
+    if($itemnumber) {
+        $sth=$dbh->prepare(  "SELECT * FROM items 
+            LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
+            LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
+             WHERE items.itemnumber = ?") ; 
+        $sth->execute($itemnumber);
+    } else {
+        $sth=$dbh->prepare(  "SELECT * FROM items 
+            LEFT JOIN biblio ON biblio.biblionumber = items.biblionumber
+            LEFT JOIN biblioitems ON biblioitems.biblioitemnumber = items.biblioitemnumber
+             WHERE items.barcode = ?") ; 
+        $sth->execute($barcode);
+    }
+    my $data = $sth->fetchrow_hashref;
+    $sth->finish;
+    return ($data);
 }
 
-
-=head2 $itemnumber = NEWmoditem($dbh, $record, $biblionumber, $biblioitemnumber,$itemnumber);
+=head2 GetBiblio
 
 =over 4
 
-Modify an item
+( $count, @results ) = &GetBiblio($biblionumber);
 
 =back
 
 =cut
 
-sub NEWmoditem {
-    my ( $dbh, $record, $biblionumber, $biblioitemnumber, $itemnumber) = @_;
-    
-       my $frameworkcode=MARCfind_frameworkcode($dbh,$biblionumber);
-    my $olditem = MARCmarc2koha( $dbh, $record,$frameworkcode );
-       # add MARC record
-       $olditem->{marc} = $record->as_usmarc();
-       $olditem->{biblionumber} = $biblionumber;
-       $olditem->{biblioitemnumber} = $biblioitemnumber;
-       # and modify item
-    REALmoditem( $dbh, $olditem );
-}
-
+sub GetBiblio {
+    my ($biblionumber) = @_;
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber = ?");
+    my $count = 0;
+    my @results;
+    $sth->execute($biblionumber);
+    while ( my $data = $sth->fetchrow_hashref ) {
+        $results[$count] = $data;
+        $count++;
+    }    # while
+    $sth->finish;
+    return ( $count, @results );
+}    # sub GetBiblio
 
-=head2 $itemnumber = NEWdelitem($dbh, $biblionumber, $biblioitemnumber, $itemnumber);
+=head2 GetBiblioItemInfosOf
 
 =over 4
 
-delete an item
+GetBiblioItemInfosOf(@biblioitemnumbers);
 
 =back
 
 =cut
 
-sub NEWdelitem {
-    my ( $dbh, $bibid, $itemnumber ) = @_;
-    my $biblio = &MARCfind_oldbiblionumber_from_MARCbibid( $dbh, $bibid );
-    &REALdelitem( $dbh, $itemnumber );
-    &MARCdelitem( $dbh, $bibid, $itemnumber );
+sub GetBiblioItemInfosOf {
+    my @biblioitemnumbers = @_;
+
+    my $query = '
+        SELECT biblioitemnumber,
+            publicationyear,
+            itemtype
+        FROM biblioitems
+        WHERE biblioitemnumber IN (' . join( ',', @biblioitemnumbers ) . ')
+    ';
+    return get_infos_of( $query, 'biblioitemnumber' );
 }
 
+=head1 FUNCTIONS FOR HANDLING MARC MANAGEMENT
 
-=head2 $biblionumber = REALnewbiblio($dbh,$biblio);
+=head2 GetMarcStructure
 
 =over 4
 
-adds a record in biblio table. Datas are in the hash $biblio.
+$res = GetMarcStructure($forlibrarian,$frameworkcode);
+
+Returns a reference to a big hash of hash, with the Marc structure for the given frameworkcode
+$forlibrarian  :if set to 1, the MARC descriptions are the librarians ones, otherwise it's the public (OPAC) ones
+$frameworkcode : the framework code to read
 
 =back
 
 =cut
 
-sub REALnewbiblio {
-    my ( $dbh, $biblio ) = @_;
+sub GetMarcStructure {
+    my ( $forlibrarian, $frameworkcode ) = @_;
+    my $dbh=C4::Context->dbh;
+    $frameworkcode = "" unless $frameworkcode;
+    my $sth;
+    my $libfield = ( $forlibrarian eq 1 ) ? 'liblibrarian' : 'libopac';
 
-       $dbh->do('lock tables biblio WRITE');
-    my $sth = $dbh->prepare("Select max(biblionumber) from biblio");
-    $sth->execute;
-    my $data   = $sth->fetchrow_arrayref;
-    my $bibnum = $$data[0] + 1;
-    my $series = 0;
+    # check that framework exists
+    $sth =
+      $dbh->prepare(
+        "SELECT COUNT(*) FROM marc_tag_structure WHERE frameworkcode=?");
+    $sth->execute($frameworkcode);
+    my ($total) = $sth->fetchrow;
+    $frameworkcode = "" unless ( $total > 0 );
+    $sth =
+      $dbh->prepare(
+        "SELECT tagfield,liblibrarian,libopac,mandatory,repeatable 
+        FROM marc_tag_structure 
+        WHERE frameworkcode=? 
+        ORDER BY tagfield"
+      );
+    $sth->execute($frameworkcode);
+    my ( $liblibrarian, $libopac, $tag, $res, $tab, $mandatory, $repeatable );
+
+    while ( ( $tag, $liblibrarian, $libopac, $mandatory, $repeatable ) =
+        $sth->fetchrow )
+    {
+        $res->{$tag}->{lib} =
+          ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
+        $res->{$tab}->{tab}        = "";
+        $res->{$tag}->{mandatory}  = $mandatory;
+        $res->{$tag}->{repeatable} = $repeatable;
+    }
 
-    if ( $biblio->{'seriestitle'} ) { $series = 1 }
-    $sth->finish;
     $sth =
-      $dbh->prepare("insert into biblio set    biblionumber=?, title=?,                author=?,       copyrightdate=?,
-                                                                                       serial=?,               seriestitle=?,  notes=?,        abstract=?,
-                                                                                       unititle=?"
-    );
-    $sth->execute(
-        $bibnum,             $biblio->{'title'},
-        $biblio->{'author'}, $biblio->{'copyrightdate'},
-        $biblio->{'serial'},             $biblio->{'seriestitle'},
-        $biblio->{'notes'},  $biblio->{'abstract'},
-               $biblio->{'unititle'}
+      $dbh->prepare(
+            "SELECT tagfield,tagsubfield,liblibrarian,libopac,tab,mandatory,repeatable,authorised_value,authtypecode,value_builder,kohafield,seealso,hidden,isurl,link,defaultvalue 
+                FROM marc_subfield_structure 
+            WHERE frameworkcode=? 
+                ORDER BY tagfield,tagsubfield
+            "
     );
+    
+    $sth->execute($frameworkcode);
 
-    $sth->finish;
-       $dbh->do('unlock tables');
-    return ($bibnum);
+    my $subfield;
+    my $authorised_value;
+    my $authtypecode;
+    my $value_builder;
+    my $kohafield;
+    my $seealso;
+    my $hidden;
+    my $isurl;
+    my $link;
+    my $defaultvalue;
+
+    while (
+        (
+            $tag,          $subfield,      $liblibrarian,
+            ,              $libopac,       $tab,
+            $mandatory,    $repeatable,    $authorised_value,
+            $authtypecode, $value_builder, $kohafield,
+            $seealso,      $hidden,        $isurl,
+            $link,$defaultvalue
+        )
+        = $sth->fetchrow
+      )
+    {
+        $res->{$tag}->{$subfield}->{lib} =
+          ( $forlibrarian or !$libopac ) ? $liblibrarian : $libopac;
+        $res->{$tag}->{$subfield}->{tab}              = $tab;
+        $res->{$tag}->{$subfield}->{mandatory}        = $mandatory;
+        $res->{$tag}->{$subfield}->{repeatable}       = $repeatable;
+        $res->{$tag}->{$subfield}->{authorised_value} = $authorised_value;
+        $res->{$tag}->{$subfield}->{authtypecode}     = $authtypecode;
+        $res->{$tag}->{$subfield}->{value_builder}    = $value_builder;
+        $res->{$tag}->{$subfield}->{kohafield}        = $kohafield;
+        $res->{$tag}->{$subfield}->{seealso}          = $seealso;
+        $res->{$tag}->{$subfield}->{hidden}           = $hidden;
+        $res->{$tag}->{$subfield}->{isurl}            = $isurl;
+        $res->{$tag}->{$subfield}->{'link'}           = $link;
+        $res->{$tag}->{$subfield}->{defaultvalue}     = $defaultvalue;
+    }
+    return $res;
+}
+
+=head2 GetUsedMarcStructure
+
+    the same function as GetMarcStructure expcet it just take field
+    in tab 0-9. (used field)
+    
+    my $results = GetUsedMarcStructure($frameworkcode);
+    
+    L<$results> is a ref to an array which each case containts a ref
+    to a hash which each keys is the columns from marc_subfield_structure
+    
+    L<$frameworkcode> is the framework code. 
+    
+=cut
+
+sub GetUsedMarcStructure($){
+    my $frameworkcode = shift || '';
+    my $dbh           = C4::Context->dbh;
+    my $query         = qq/
+        SELECT *
+        FROM   marc_subfield_structure
+        WHERE   tab > -1 
+            AND frameworkcode = ?
+    /;
+    my @results;
+    my $sth = $dbh->prepare($query);
+    $sth->execute($frameworkcode);
+    while (my $row = $sth->fetchrow_hashref){
+        push @results,$row;
+    }
+    return \@results;
 }
 
-=head2 $biblionumber = REALmodbiblio($dbh,$biblio);
+=head2 GetMarcFromKohaField
 
 =over 4
 
-modify a record in biblio table. Datas are in the hash $biblio.
+($MARCfield,$MARCsubfield)=GetMarcFromKohaField($kohafield,$frameworkcode);
+Returns the MARC fields & subfields mapped to the koha field 
+for the given frameworkcode
 
 =back
 
 =cut
 
-sub REALmodbiblio {
-    my ( $dbh, $biblio ) = @_;
-    my $sth = $dbh->prepare("Update biblio set title=?,                author=?,       abstract=?,     copyrightdate=?,
-                                                                                               seriestitle=?,  serial=?,       unititle=?,     notes=?,        frameworkcode=? 
-                                                                                       where biblionumber = ?"
-    );
-    $sth->execute(
-               $biblio->{'title'},       $biblio->{'author'},
-               $biblio->{'abstract'},    $biblio->{'copyrightdate'},
-               $biblio->{'seriestitle'}, $biblio->{'serial'},
-               $biblio->{'unititle'},    $biblio->{'notes'},
-               $biblio->{frameworkcode},
-               $biblio->{'biblionumber'}
+sub GetMarcFromKohaField {
+    my ( $kohafield, $frameworkcode ) = @_;
+    return 0, 0 unless $kohafield;
+    my $relations = C4::Context->marcfromkohafield;
+    return (
+        $relations->{$frameworkcode}->{$kohafield}->[0],
+        $relations->{$frameworkcode}->{$kohafield}->[1]
     );
-       $sth->finish;
-       return ( $biblio->{'biblionumber'} );
-}    # sub modbiblio
+}
 
-=head2 REALmodsubtitle($dbh,$bibnum,$subtitle);
+=head2 GetMarcBiblio
 
 =over 4
 
-modify subtitles in bibliosubtitle table.
+Returns MARC::Record of the biblionumber passed in parameter.
+the marc record contains both biblio & item datas
 
 =back
 
 =cut
 
-sub REALmodsubtitle {
-    my ( $dbh, $bibnum, $subtitle ) = @_;
-    my $sth =
-      $dbh->prepare(
-        "update bibliosubtitle set subtitle = ? where biblionumber = ?");
-    $sth->execute( $subtitle, $bibnum );
-    $sth->finish;
-}    # sub modsubtitle
+sub GetMarcBiblio {
+    my $biblionumber = shift;
+    my $dbh          = C4::Context->dbh;
+    my $sth          =
+      $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
+    $sth->execute($biblionumber);
+     my ($marcxml) = $sth->fetchrow;
+     MARC::File::XML->default_record_format(C4::Context->preference('marcflavour'));
+     $marcxml =~ s/\x1e//g;
+     $marcxml =~ s/\x1f//g;
+     $marcxml =~ s/\x1d//g;
+     $marcxml =~ s/\x0f//g;
+     $marcxml =~ s/\x0c//g;  
+#   warn $marcxml;
+    my $record = MARC::Record->new();
+    if ($marcxml) {
+        $record = eval {MARC::Record::new_from_xml( $marcxml, "utf8", C4::Context->preference('marcflavour'))};
+        if ($@) {warn $@;}
+#      $record = MARC::Record::new_from_usmarc( $marc) if $marc;
+        return $record;
+    } else {
+        return undef;
+    }
+}
 
-=head2 REALmodaddauthor($dbh,$bibnum,$author);
+=head2 GetXmlBiblio
 
 =over 4
 
-adds or modify additional authors
-NOTE :  Strange sub : seems to delete MANY and add only ONE author... maybe buggy ?
+my $marcxml = GetXmlBiblio($biblionumber);
+
+Returns biblioitems.marcxml of the biblionumber passed in parameter.
+The XML contains both biblio & item datas
 
 =back
 
 =cut
 
-sub REALmodaddauthor {
-    my ( $dbh, $bibnum, @authors ) = @_;
-
-    #    my $dbh   = C4Connect;
+sub GetXmlBiblio {
+    my ( $biblionumber ) = @_;
+    my $dbh = C4::Context->dbh;
     my $sth =
-      $dbh->prepare("Delete from additionalauthors where biblionumber = ?");
-
-    $sth->execute($bibnum);
-    $sth->finish;
-    foreach my $author (@authors) {
-        if ( $author ne '' ) {
-            $sth =
-              $dbh->prepare(
-                "Insert into additionalauthors set author = ?, biblionumber = ?"
-            );
-
-            $sth->execute( $author, $bibnum );
-
-            $sth->finish;
-        }    # if
-    }
-}    # sub modaddauthor
+      $dbh->prepare("SELECT marcxml FROM biblioitems WHERE biblionumber=? ");
+    $sth->execute($biblionumber);
+    my ($marcxml) = $sth->fetchrow;
+    return $marcxml;
+}
 
-=head2 $errors = REALmodsubject($dbh,$bibnum, $force, @subject);
+=head2 GetAuthorisedValueDesc
 
 =over 4
 
-modify/adds subjects
+my $subfieldvalue =get_authorised_value_desc(
+    $tag, $subf[$i][0],$subf[$i][1], '', $taglib, $category);
+Retrieve the complete description for a given authorised value.
+
+Now takes $category and $value pair too.
+my $auth_value_desc =GetAuthorisedValueDesc(
+    '','', 'DVD' ,'','','CCODE');
 
 =back
 
 =cut
-sub REALmodsubject {
-    my ( $dbh, $bibnum, $force, @subject ) = @_;
-
-    #  my $dbh   = C4Connect;
-    my $count = @subject;
-    my $error="";
-    for ( my $i = 0 ; $i < $count ; $i++ ) {
-        $subject[$i] =~ s/^ //g;
-        $subject[$i] =~ s/ $//g;
-        my $sth =
-          $dbh->prepare(
-"select * from catalogueentry where entrytype = 's' and catalogueentry = ?"
-        );
-        $sth->execute( $subject[$i] );
 
-        if ( my $data = $sth->fetchrow_hashref ) {
+sub GetAuthorisedValueDesc {
+    my ( $tag, $subfield, $value, $framework, $tagslib, $category ) = @_;
+    my $dbh = C4::Context->dbh;
+
+    if (!$category) {
+#---- branch
+        if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "branches" ) {
+            return C4::Branch::GetBranchName($value);
         }
-        else {
-            if ( $force eq $subject[$i] || $force == 1 ) {
 
-                # subject not in aut, chosen to force anway
-                # so insert into cataloguentry so its in auth file
-                my $sth2 =
-                  $dbh->prepare(
-"Insert into catalogueentry (entrytype,catalogueentry) values ('s',?)"
-                );
+#---- itemtypes
+        if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq "itemtypes" ) {
+            return getitemtypeinfo($value)->{description};
+        }
 
-                $sth2->execute( $subject[$i] ) if ( $subject[$i] );
-                $sth2->finish;
-            }
-            else {
-                $error =
-                  "$subject[$i]\n does not exist in the subject authority file";
-                my $sth2 =
-                  $dbh->prepare(
-"Select * from catalogueentry where entrytype = 's' and (catalogueentry like ? or catalogueentry like ? or catalogueentry like ?)"
-                );
-                $sth2->execute( "$subject[$i] %", "% $subject[$i] %",
-                    "% $subject[$i]" );
-                while ( my $data = $sth2->fetchrow_hashref ) {
-                    $error .= "<br>$data->{'catalogueentry'}";
-                }    # while
-                $sth2->finish;
-            }    # else
-        }    # else
-        $sth->finish;
-    }    # else
-    if ($error eq '') {
-        my $sth =
-          $dbh->prepare("Delete from bibliosubject where biblionumber = ?");
-        $sth->execute($bibnum);
-        $sth->finish;
-        $sth =
-          $dbh->prepare(
-            "Insert into bibliosubject (subject,biblionumber) values (?,?)");
-        my $query;
-        foreach $query (@subject) {
-            $sth->execute( $query, $bibnum ) if ( $query && $bibnum );
-        }    # foreach
-        $sth->finish;
-    }    # if
+#---- "true" authorized value
+        $category = $tagslib->{$tag}->{$subfield}->{'authorised_value'}
+    }
 
-    #  $dbh->disconnect;
-    return ($error);
-}    # sub modsubject
+    if ( $category ne "" ) {
+        my $sth =
+            $dbh->prepare(
+                    "SELECT lib FROM authorised_values WHERE category = ? AND authorised_value = ?"
+                    );
+        $sth->execute( $category, $value );
+        my $data = $sth->fetchrow_hashref;
+        return $data->{'lib'};
+    }
+    else {
+        return $value;    # if nothing is found return the original value
+    }
+}
 
-=head2 REALmodbiblioitem($dbh, $biblioitem);
+=head2 GetMarcNotes
 
 =over 4
 
-modify a biblioitem
+$marcnotesarray = GetMarcNotes( $record, $marcflavour );
+Get all notes from the MARC record and returns them in an array.
+The note are stored in differents places depending on MARC flavour
 
 =back
 
 =cut
-sub REALmodbiblioitem {
-    my ( $dbh, $biblioitem ) = @_;
-    my $query;
-
-    my $sth = $dbh->prepare("update biblioitems set number=?,volume=?,                 volumedate=?,           lccn=?,
-                                                                               itemtype=?,                     url=?,                          isbn=?,                         issn=?,
-                                                                               publishercode=?,        publicationyear=?,      classification=?,       dewey=?,
-                                                                               subclass=?,                     illus=?,                        pages=?,                        volumeddesc=?,
-                                                                               notes=?,                        size=?,                         place=?,                        marc=?,
-                                                                               marcxml=?
-                                                       where biblioitemnumber=?");
-       $sth->execute(  $biblioitem->{number},                  $biblioitem->{volume},  $biblioitem->{volumedate},      $biblioitem->{lccn},
-                                       $biblioitem->{itemtype},                $biblioitem->{url},             $biblioitem->{isbn},    $biblioitem->{issn},
-                               $biblioitem->{publishercode},   $biblioitem->{publicationyear}, $biblioitem->{classification},  $biblioitem->{dewey},
-                               $biblioitem->{subclass},                $biblioitem->{illus},           $biblioitem->{pages},   $biblioitem->{volumeddesc},
-                               $biblioitem->{bnotes},                  $biblioitem->{size},            $biblioitem->{place},   $biblioitem->{marc},
-                                       $biblioitem->{marcxml},                 $biblioitem->{biblioitemnumber});
-       my $record = MARC::File::USMARC::decode($biblioitem->{marc});
-       zebra_create($biblioitem->{biblionumber}, $record);
-#      warn "MOD : $biblioitem->{biblioitemnumber} = ".$biblioitem->{marc};
-}    # sub modbibitem
-
-=head2 REALnewbiblioitem($dbh,$biblioitem);
+
+sub GetMarcNotes {
+    my ( $record, $marcflavour ) = @_;
+    my $scope;
+    if ( $marcflavour eq "MARC21" ) {
+        $scope = '5..';
+    }
+    else {    # assume unimarc if not marc21
+        $scope = '3..';
+    }
+    my @marcnotes;
+    my $note = "";
+    my $tag  = "";
+    my $marcnote;
+    foreach my $field ( $record->field($scope) ) {
+        my $value = $field->as_string();
+        if ( $note ne "" ) {
+            $marcnote = { marcnote => $note, };
+            push @marcnotes, $marcnote;
+            $note = $value;
+        }
+        if ( $note ne $value ) {
+            $note = $note . " " . $value;
+        }
+    }
+
+    if ( $note ) {
+        $marcnote = { marcnote => $note };
+        push @marcnotes, $marcnote;    #load last tag into array
+    }
+    return \@marcnotes;
+}    # end GetMarcNotes
+
+=head2 GetMarcSubjects
 
 =over 4
 
-adds a biblioitem ($biblioitem is a hash with the values)
+$marcsubjcts = GetMarcSubjects($record,$marcflavour);
+Get all subjects from the MARC record and returns them in an array.
+The subjects are stored in differents places depending on MARC flavour
 
 =back
 
 =cut
 
-sub REALnewbiblioitem {
-       my ( $dbh, $biblioitem ) = @_;
-
-       $dbh->do("lock tables biblioitems WRITE, biblio WRITE, marc_subfield_structure READ");
-       my $sth = $dbh->prepare("Select max(biblioitemnumber) from biblioitems");
-       my $data;
-       my $biblioitemnumber;
-
-       $sth->execute;
-       $data       = $sth->fetchrow_arrayref;
-       $biblioitemnumber = $$data[0] + 1;
-       
-       # Insert biblioitemnumber in MARC record, we need it to manage items later...
-       my $frameworkcode=MARCfind_frameworkcode($dbh,$biblioitem->{biblionumber});
-       my ($biblioitemnumberfield,$biblioitemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'biblioitems.biblioitemnumber',$frameworkcode);
-       my $record = MARC::File::USMARC::decode($biblioitem->{marc});
-       my $field=$record->field($biblioitemnumberfield);
-       $field->update($biblioitemnumbersubfield => "$biblioitemnumber");
-       $biblioitem->{marc} = $record->as_usmarc();
-       $biblioitem->{marcxml} = $record->as_xml();
-
-       $sth = $dbh->prepare( "insert into biblioitems set
-                                                                       biblioitemnumber = ?,           biblionumber     = ?,
-                                                                       volume           = ?,                   number           = ?,
-                                                                       classification  = ?,                    itemtype         = ?,
-                                                                       url              = ?,                           isbn             = ?,
-                                                                       issn             = ?,                           dewey            = ?,
-                                                                       subclass         = ?,                           publicationyear  = ?,
-                                                                       publishercode    = ?,           volumedate       = ?,
-                                                                       volumeddesc      = ?,           illus            = ?,
-                                                                       pages            = ?,                           notes            = ?,
-                                                                       size             = ?,                           lccn             = ?,
-                                                                       marc             = ?,                           place            = ?,
-                                                                       marcxml          = ?"
-       );
-       $sth->execute(
-               $biblioitemnumber,               $biblioitem->{'biblionumber'},
-               $biblioitem->{'volume'},         $biblioitem->{'number'},
-               $biblioitem->{'classification'}, $biblioitem->{'itemtype'},
-               $biblioitem->{'url'},            $biblioitem->{'isbn'},
-               $biblioitem->{'issn'},           $biblioitem->{'dewey'},
-               $biblioitem->{'subclass'},       $biblioitem->{'publicationyear'},
-               $biblioitem->{'publishercode'},  $biblioitem->{'volumedate'},
-               $biblioitem->{'volumeddesc'},    $biblioitem->{'illus'},
-               $biblioitem->{'pages'},          $biblioitem->{'bnotes'},
-               $biblioitem->{'size'},           $biblioitem->{'lccn'},
-               $biblioitem->{'marc'},           $biblioitem->{'place'},
-               $biblioitem->{marcxml},
-       );
-       $dbh->do("unlock tables");
-       zebra_create($biblioitem->{biblionumber}, $record);
-       return ($biblioitemnumber);
-}
+sub GetMarcSubjects {
+    my ( $record, $marcflavour ) = @_;
+    my ( $mintag, $maxtag );
+    if ( $marcflavour eq "MARC21" ) {
+        $mintag = "600";
+        $maxtag = "699";
+    }
+    else {    # assume unimarc if not marc21
+        $mintag = "600";
+        $maxtag = "611";
+    }
+    
+    my @marcsubjects;
+    my $subject = "";
+    my $subfield = "";
+    my $marcsubject;
+
+    foreach my $field ( $record->field('6..' )) {
+        next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
+        my @subfields_loop;
+        my @subfields = $field->subfields();
+        my $counter = 0;
+        my @link_loop;
+        # if there is an authority link, build the link with an= subfield9
+        my $subfield9 = $field->subfield('9');
+        for my $subject_subfield (@subfields ) {
+            # don't load unimarc subfields 3,4,5
+            next if (($marcflavour eq "UNIMARC") and ($subject_subfield->[0] =~ (3|4|5) ) );
+            my $code = $subject_subfield->[0];
+            my $value = $subject_subfield->[1];
+            my $linkvalue = $value;
+            $linkvalue =~ s/(\(|\))//g;
+            my $operator = " and " unless $counter==0;
+            if ($subfield9) {
+                @link_loop = ({'limit' => 'an' ,link => "$subfield9" });
+            } else {
+                push @link_loop, {'limit' => 'su', link => $linkvalue, operator => $operator };
+            }
+            my $separator = C4::Context->preference("authoritysep") unless $counter==0;
+            # ignore $9
+            my @this_link_loop = @link_loop;
+            push @subfields_loop, {code => $code, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($subject_subfield->[0] == 9 );
+            $counter++;
+        }
+                
+        push @marcsubjects, { MARCSUBJECT_SUBFIELDS_LOOP => \@subfields_loop };
+        
+    }
+        return \@marcsubjects;
+}  #end getMARCsubjects
 
-=head2 REALnewsubtitle($dbh,$bibnum,$subtitle);
+=head2 GetMarcAuthors
 
 =over 4
 
-create a new subtitle
+authors = GetMarcAuthors($record,$marcflavour);
+Get all authors from the MARC record and returns them in an array.
+The authors are stored in differents places depending on MARC flavour
 
 =back
 
 =cut
-sub REALnewsubtitle {
-    my ( $dbh, $bibnum, $subtitle ) = @_;
-    my $sth =
-      $dbh->prepare(
-        "insert into bibliosubtitle set biblionumber = ?, subtitle = ?");
-    $sth->execute( $bibnum, $subtitle ) if $subtitle;
-    $sth->finish;
+
+sub GetMarcAuthors {
+    my ( $record, $marcflavour ) = @_;
+    my ( $mintag, $maxtag );
+    # tagslib useful for UNIMARC author reponsabilities
+    my $tagslib = &GetMarcStructure( 1, '' ); # FIXME : we don't have the framework available, we take the default framework. May be bugguy on some setups, will be usually correct.
+    if ( $marcflavour eq "MARC21" ) {
+        $mintag = "700";
+        $maxtag = "720"; 
+    }
+    elsif ( $marcflavour eq "UNIMARC" ) {    # assume unimarc if not marc21
+        $mintag = "700";
+        $maxtag = "712";
+    }
+    else {
+        return;
+    }
+    my @marcauthors;
+
+    foreach my $field ( $record->fields ) {
+        next unless $field->tag() >= $mintag && $field->tag() <= $maxtag;
+        my @subfields_loop;
+        my @link_loop;
+        my @subfields = $field->subfields();
+        my $count_auth = 0;
+        # if there is an authority link, build the link with Koha-Auth-Number: subfield9
+        my $subfield9 = $field->subfield('9');
+        for my $authors_subfield (@subfields) {
+            # don't load unimarc subfields 3, 5
+            next if ($marcflavour eq 'UNIMARC' and ($authors_subfield->[0] =~ (3|5) ) );
+            my $subfieldcode = $authors_subfield->[0];
+            my $value = $authors_subfield->[1];
+            my $linkvalue = $value;
+            $linkvalue =~ s/(\(|\))//g;
+            my $operator = " and " unless $count_auth==0;
+            # if we have an authority link, use that as the link, otherwise use standard searching
+            if ($subfield9) {
+                @link_loop = ({'limit' => 'Koha-Auth-Number' ,link => "$subfield9" });
+            }
+            else {
+                # reset $linkvalue if UNIMARC author responsibility
+                if ( $marcflavour eq 'UNIMARC' and ($authors_subfield->[0] eq '4')) {
+                    $linkvalue = "(".GetAuthorisedValueDesc( $field->tag(), $authors_subfield->[0], $authors_subfield->[1], '', $tagslib ).")";
+                }
+                push @link_loop, {'limit' => 'au', link => $linkvalue, operator => $operator };
+            }
+            my @this_link_loop = @link_loop;
+            my $separator = C4::Context->preference("authoritysep") unless $count_auth==0;
+            push @subfields_loop, {code => $subfieldcode, value => $value, link_loop => \@this_link_loop, separator => $separator} unless ($authors_subfield->[0] == 9 );
+            $count_auth++;
+        }
+        push @marcauthors, { MARCAUTHOR_SUBFIELDS_LOOP => \@subfields_loop };
+    }
+    return \@marcauthors;
 }
 
-=head2 ($itemnumber,$errors)= REALnewitems($dbh,$item,$barcode);
+=head2 GetMarcUrls
 
 =over 4
 
-create a item. $item is a hash and $barcode the barcode.
+$marcurls = GetMarcUrls($record,$marcflavour);
+Returns arrayref of URLs from MARC data, suitable to pass to tmpl loop.
+Assumes web resources (not uncommon in MARC21 to omit resource type ind) 
 
 =back
 
 =cut
 
-sub REALnewitems {
-    my ( $dbh, $item, $barcode ) = @_;
-
-#      warn "OLDNEWITEMS";
-       
-       $dbh->do('lock tables items WRITE, biblio WRITE,biblioitems WRITE,marc_subfield_structure WRITE');
-    my $sth = $dbh->prepare("Select max(itemnumber) from items");
-    my $data;
-    my $itemnumber;
-    my $error = "";
-    $sth->execute;
-    $data       = $sth->fetchrow_hashref;
-    $itemnumber = $data->{'max(itemnumber)'} + 1;
-
-# FIXME the "notforloan" field seems to be named "loan" in some places. workaround bugfix.
-    if ( $item->{'loan'} ) {
-        $item->{'notforloan'} = $item->{'loan'};
-    }
-
-    # if dateaccessioned is provided, use it. Otherwise, set to NOW()
-    if ( $item->{'dateaccessioned'} ) {
-        $sth = $dbh->prepare( "Insert into items set
-                                                       itemnumber           = ?,                       biblionumber         = ?,
-                                                       multivolumepart      = ?,
-                                                       biblioitemnumber     = ?,                       barcode              = ?,
-                                                       booksellerid         = ?,                       dateaccessioned      = ?,
-                                                       homebranch           = ?,                       holdingbranch        = ?,
-                                                       price                = ?,                       replacementprice     = ?,
-                                                       replacementpricedate = NOW(),           datelastseen            = NOW(),
-                                                       multivolume                     = ?,                    stack                           = ?,
-                                                       itemlost                        = ?,                    wthdrawn                        = ?,
-                                                       paidfor                         = ?,                    itemnotes            = ?,
-                                                       itemcallnumber  =?,                                                     notforloan = ?,
-                                                       location = ?
-                                                       "
-        );
-        $sth->execute(
-                       $itemnumber,                            $item->{'biblionumber'},
-                       $item->{'multivolumepart'},
-                       $item->{'biblioitemnumber'},$item->{barcode},
-                       $item->{'booksellerid'},        $item->{'dateaccessioned'},
-                       $item->{'homebranch'},          $item->{'holdingbranch'},
-                       $item->{'price'},                       $item->{'replacementprice'},
-                       $item->{multivolume},           $item->{stack},
-                       $item->{itemlost},                      $item->{wthdrawn},
-                       $item->{paidfor},                       $item->{'itemnotes'},
-                       $item->{'itemcallnumber'},      $item->{'notforloan'},
-                       $item->{'location'}
-        );
-               if ( defined $sth->errstr ) {
-                       $error .= $sth->errstr;
-               }
+sub GetMarcUrls {
+    my ($record, $marcflavour) = @_;
+    my @marcurls;
+    my $marcurl;
+    for my $field ($record->field('856')) {
+        my $url = $field->subfield('u');
+        my @notes;
+        for my $note ( $field->subfield('z')) {
+            push @notes , {note => $note};
+        }        
+        $marcurl = {  MARCURL => $url,
+                      notes => \@notes,
+                    };
+        if($marcflavour eq 'MARC21') {
+            my $s3 = $field->subfield('3');
+            my $link = $field->subfield('y');
+            $marcurl->{'linktext'} = $link || $s3 || $url ;;
+            $marcurl->{'part'} = $s3 if($link);
+            $marcurl->{'toc'} = 1 if($s3 =~ /^[Tt]able/) ;
+        } else {
+            $marcurl->{'linktext'} = $url;
+        }
+        push @marcurls, $marcurl;    
     }
-    else {
-        $sth = $dbh->prepare( "Insert into items set
-                                                       itemnumber           = ?,                       biblionumber         = ?,
-                                                       multivolumepart      = ?,
-                                                       biblioitemnumber     = ?,                       barcode              = ?,
-                                                       booksellerid         = ?,                       dateaccessioned      = NOW(),
-                                                       homebranch           = ?,                       holdingbranch        = ?,
-                                                       price                = ?,                       replacementprice     = ?,
-                                                       replacementpricedate = NOW(),           datelastseen            = NOW(),
-                                                       multivolume                     = ?,                    stack                           = ?,
-                                                       itemlost                        = ?,                    wthdrawn                        = ?,
-                                                       paidfor                         = ?,                    itemnotes            = ?,
-                                                       itemcallnumber  =?,                                                     notforloan = ?,
-                                                       location = ?
-                                                       "
-        );
-        $sth->execute(
-                       $itemnumber,                            $item->{'biblionumber'},
-                       $item->{'multivolumepart'},
-                       $item->{'biblioitemnumber'},$item->{barcode},
-                       $item->{'booksellerid'},
-                       $item->{'homebranch'},          $item->{'holdingbranch'},
-                       $item->{'price'},                       $item->{'replacementprice'},
-                       $item->{multivolume},           $item->{stack},
-                       $item->{itemlost},                      $item->{wthdrawn},
-                       $item->{paidfor},                       $item->{'itemnotes'},
-                       $item->{'itemcallnumber'},      $item->{'notforloan'},
-                       $item->{'location'}
-        );
-               if ( defined $sth->errstr ) {
-                       $error .= $sth->errstr;
-               }
-    }
-       # item stored, now, deal with the marc part...
-       $sth = $dbh->prepare("select biblioitems.marc,biblio.frameworkcode from biblioitems,biblio 
-                                                       where   biblio.biblionumber=biblioitems.biblionumber and 
-                                                                       biblio.biblionumber=?");
-       $sth->execute($item->{biblionumber});
-    if ( defined $sth->errstr ) {
-        $error .= $sth->errstr;
-    }
-       my ($rawmarc,$frameworkcode) = $sth->fetchrow;
-       warn "ERROR IN REALnewitem, MARC record not found FOR $item->{biblionumber} => $rawmarc <=" unless $rawmarc;
-       my $record = MARC::File::USMARC::decode($rawmarc);
-       # ok, we have the marc record, add item number to the item field (in {marc}, and add the field to the record)
-       my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
-       my $itemrecord = MARC::File::USMARC::decode($item->{marc});
-       my $itemfield = $itemrecord->field($itemnumberfield);
-       $itemfield->add_subfields($itemnumbersubfield => "$itemnumber");
-       $record->insert_grouped_field($itemfield);
-       # save the record into biblioitem
-       $sth=$dbh->prepare("update biblioitems set marc=?,marcxml=? where biblionumber=?");
-       $sth->execute($record->as_usmarc(),$record->as_xml(),$item->{biblionumber});
-    if ( defined $sth->errstr ) {
-        $error .= $sth->errstr;
-    }
-       zebra_create($item->{biblionumber},$record);
-       $dbh->do('unlock tables');
-    return ( $itemnumber, $error );
-}
+    return \@marcurls;
+}  #end GetMarcUrls
 
-=head2 REALmoditem($dbh,$item);
+=head2 GetMarcSeries
 
 =over 4
 
-modify item
+$marcseriesarray = GetMarcSeries($record,$marcflavour);
+Get all series from the MARC record and returns them in an array.
+The series are stored in differents places depending on MARC flavour
 
 =back
 
 =cut
 
-sub REALmoditem {
-    my ( $dbh, $item ) = @_;
-       my $error;
-       $dbh->do('lock tables items WRITE, biblio WRITE,biblioitems WRITE');
-    $item->{'itemnum'} = $item->{'itemnumber'} unless $item->{'itemnum'};
-    my $query = "update items set  barcode=?,itemnotes=?,itemcallnumber=?,notforloan=?,location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?";
-    my @bind = (
-        $item->{'barcode'},                    $item->{'itemnotes'},
-        $item->{'itemcallnumber'},     $item->{'notforloan'},
-        $item->{'location'},           $item->{multivolumepart},
-               $item->{multivolume},           $item->{stack},
-               $item->{wthdrawn},
-    );
-    if ( $item->{'lost'} ne '' ) {
-        $query = "update items set biblioitemnumber=?,barcode=?,itemnotes=?,homebranch=?,
-                                                       itemlost=?,wthdrawn=?,itemcallnumber=?,notforloan=?,
-                                                       location=?,multivolumepart=?,multivolume=?,stack=?,wthdrawn=?";
-        @bind = (
-            $item->{'bibitemnum'},     $item->{'barcode'},
-            $item->{'itemnotes'},          $item->{'homebranch'},
-            $item->{'lost'},           $item->{'wthdrawn'},
-            $item->{'itemcallnumber'}, $item->{'notforloan'},
-            $item->{'location'},               $item->{multivolumepart},
-                       $item->{multivolume},           $item->{stack},
-                       $item->{wthdrawn},
-        );
-               if ($item->{homebranch}) {
-                       $query.=",homebranch=?";
-                       push @bind, $item->{homebranch};
-               }
-               if ($item->{holdingbranch}) {
-                       $query.=",holdingbranch=?";
-                       push @bind, $item->{holdingbranch};
-               }
-    }
-       $query.=" where itemnumber=?";
-       push @bind,$item->{'itemnum'};
-   if ( $item->{'replacement'} ne '' ) {
-        $query =~ s/ where/,replacementprice='$item->{'replacement'}' where/;
+sub GetMarcSeries {
+    my ($record, $marcflavour) = @_;
+    my ($mintag, $maxtag);
+    if ($marcflavour eq "MARC21") {
+        $mintag = "440";
+        $maxtag = "490";
+    } else {           # assume unimarc if not marc21
+        $mintag = "600";
+        $maxtag = "619";
     }
-    my $sth = $dbh->prepare($query);
-    $sth->execute(@bind);
-       
-       # item stored, now, deal with the marc part...
-       $sth = $dbh->prepare("select biblioitems.marc,biblio.frameworkcode from biblioitems,biblio 
-                                                       where   biblio.biblionumber=biblioitems.biblionumber and 
-                                                                       biblio.biblionumber=? and 
-                                                                       biblioitems.biblioitemnumber=?");
-       $sth->execute($item->{biblionumber},$item->{biblioitemnumber});
-    if ( defined $sth->errstr ) {
-        $error .= $sth->errstr;
-    }
-       my ($rawmarc,$frameworkcode) = $sth->fetchrow;
-       warn "ERROR IN REALmoditem, MARC record not found" unless $rawmarc;
-       my $record = MARC::File::USMARC::decode($rawmarc);
-       # ok, we have the marc record, find the previous item record for this itemnumber and delete it
-       my ($itemnumberfield,$itemnumbersubfield) = MARCfind_marc_from_kohafield($dbh,'items.itemnumber',$frameworkcode);
-       # prepare the new item record
-       my $itemrecord = MARC::File::USMARC::decode($item->{marc});
-       my $itemfield = $itemrecord->field($itemnumberfield);
-       $itemfield->add_subfields($itemnumbersubfield => '$itemnumber');
-       # parse all fields fields from the complete record
-       foreach ($record->field($itemnumberfield)) {
-               # when the previous field is found, replace by the new one
-               if ($_->subfield($itemnumbersubfield) == $item->{itemnum}) {
-                       $_->replace_with($itemfield);
-               }
-       }
-#      $record->insert_grouped_field($itemfield);
-       # save the record into biblioitem
-       $sth=$dbh->prepare("update biblioitems set marc=?,marcxml=? where biblionumber=? and biblioitemnumber=?");
-       $sth->execute($record->as_usmarc(),$record->as_xml(),$item->{biblionumber},$item->{biblioitemnumber});
-       zebra_create($item->biblionumber,$record);
-    if ( defined $sth->errstr ) {
-        $error .= $sth->errstr;
-    }
-       $dbh->do('unlock tables');
-
-    #  $dbh->disconnect;
-}
 
-=head2 REALdelitem($dbh,$itemnum);
+    my @marcseries;
+    my $subjct = "";
+    my $subfield = "";
+    my $marcsubjct;
+
+    foreach my $field ($record->field('440'), $record->field('490')) {
+        my @subfields_loop;
+        #my $value = $field->subfield('a');
+        #$marcsubjct = {MARCSUBJCT => $value,};
+        my @subfields = $field->subfields();
+        #warn "subfields:".join " ", @$subfields;
+        my $counter = 0;
+        my @link_loop;
+        for my $series_subfield (@subfields) {
+            my $volume_number;
+            undef $volume_number;
+            # see if this is an instance of a volume
+            if ($series_subfield->[0] eq 'v') {
+                $volume_number=1;
+            }
+
+            my $code = $series_subfield->[0];
+            my $value = $series_subfield->[1];
+            my $linkvalue = $value;
+            $linkvalue =~ s/(\(|\))//g;
+            my $operator = " and " unless $counter==0;
+            push @link_loop, {link => $linkvalue, operator => $operator };
+            my $separator = C4::Context->preference("authoritysep") unless $counter==0;
+            if ($volume_number) {
+            push @subfields_loop, {volumenum => $value};
+            }
+            else {
+            push @subfields_loop, {code => $code, value => $value, link_loop => \@link_loop, separator => $separator, volumenum => $volume_number};
+            }
+            $counter++;
+        }
+        push @marcseries, { MARCSERIES_SUBFIELDS_LOOP => \@subfields_loop };
+        #$marcsubjct = {MARCSUBJCT => $field->as_string(),};
+        #push @marcsubjcts, $marcsubjct;
+        #$subjct = $value;
+
+    }
+    my $marcseriessarray=\@marcseries;
+    return $marcseriessarray;
+}  #end getMARCseriess
+
+=head2 GetFrameworkCode
 
 =over 4
 
-delete item
+    $frameworkcode = GetFrameworkCode( $biblionumber )
 
 =back
 
 =cut
 
-sub REALdelitem {
-    my ( $dbh, $itemnum ) = @_;
+sub GetFrameworkCode {
+    my ( $biblionumber ) = @_;
+    my $dbh = C4::Context->dbh;
+    my $sth = $dbh->prepare("SELECT frameworkcode FROM biblio WHERE biblionumber=?");
+    $sth->execute($biblionumber);
+    my ($frameworkcode) = $sth->fetchrow;
+    return $frameworkcode;
+}
+
+=head2 GetPublisherNameFromIsbn
 
-    #  my $dbh=C4Connect;
-    my $sth = $dbh->prepare("select * from items where itemnumber=?");
-    $sth->execute($itemnum);
-    my $data = $sth->fetchrow_hashref;
-    $sth->finish;
-    my $query = "Insert into deleteditems set ";
-    my @bind  = ();
-    foreach my $temp ( keys %$data ) {
-        $query .= "$temp = ?,";
-        push ( @bind, $data->{$temp} );
+    $name = GetPublishercodeFromIsbn($isbn);
+    if(defined $name){
+        ...
     }
-    $query =~ s/\,$//;
 
-    #  print $query;
-    $sth = $dbh->prepare($query);
-    $sth->execute(@bind);
-    $sth->finish;
-    $sth = $dbh->prepare("Delete from items where itemnumber=?");
-    $sth->execute($itemnum);
-    $sth->finish;
+=cut
 
-    #  $dbh->disconnect;
+sub GetPublisherNameFromIsbn($){
+    my $isbn = shift;
+    $isbn =~ s/[- _]//g;
+    $isbn =~ s/^0*//;
+    my @codes = (split '-', DisplayISBN($isbn));
+    my $code = $codes[0].$codes[1].$codes[2];
+    my $dbh  = C4::Context->dbh;
+    my $query = qq{
+        SELECT distinct publishercode
+        FROM   biblioitems
+        WHERE  isbn LIKE ?
+        AND    publishercode IS NOT NULL
+        LIMIT 1
+    };
+    my $sth = $dbh->prepare($query);
+    $sth->execute("$code%");
+    my $name = $sth->fetchrow;
+    return $name if length $name;
+    return undef;
 }
 
-=head2 REALdelbiblioitem($dbh,$biblioitemnumber);
+=head2 TransformKohaToMarc
 
 =over 4
 
-deletes a biblioitem
-NOTE : not standard sub name. Should be REALdelbiblioitem()
+    $record = TransformKohaToMarc( $hash )
+    This function builds partial MARC::Record from a hash
+    Hash entries can be from biblio or biblioitems.
+    This function is called in acquisition module, to create a basic catalogue entry from user entry
 
 =back
 
 =cut
 
-sub REALdelbiblioitem {
-    my ( $dbh, $biblioitemnumber ) = @_;
+sub TransformKohaToMarc {
 
-    #    my $dbh   = C4Connect;
-    my $sth = $dbh->prepare( "Select * from biblioitems
-where biblioitemnumber = ?"
+    my ( $hash ) = @_;
+    my $dbh = C4::Context->dbh;
+    my $sth =
+    $dbh->prepare(
+        "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
     );
-    my $results;
-
-    $sth->execute($biblioitemnumber);
-
-    if ( $results = $sth->fetchrow_hashref ) {
-        $sth->finish;
-        $sth =
-          $dbh->prepare(
-"Insert into deletedbiblioitems (biblioitemnumber, biblionumber, volume, number, classification, itemtype,
-                                       isbn, issn ,dewey ,subclass ,publicationyear ,publishercode ,volumedate ,volumeddesc ,timestamp ,illus ,
-                                       pages ,notes ,size ,url ,lccn ) values(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)"
-        );
-
-        $sth->execute(
-            $results->{biblioitemnumber}, $results->{biblionumber},
-            $results->{volume},           $results->{number},
-            $results->{classification},   $results->{itemtype},
-            $results->{isbn},             $results->{issn},
-            $results->{dewey},            $results->{subclass},
-            $results->{publicationyear},  $results->{publishercode},
-            $results->{volumedate},       $results->{volumeddesc},
-            $results->{timestamp},        $results->{illus},
-            $results->{pages},            $results->{notes},
-            $results->{size},             $results->{url},
-            $results->{lccn}
-        );
-        my $sth2 =
-          $dbh->prepare("Delete from biblioitems where biblioitemnumber = ?");
-        $sth2->execute($biblioitemnumber);
-        $sth2->finish();
-    }    # if
-    $sth->finish;
-
-    # Now delete all the items attached to the biblioitem
-    $sth = $dbh->prepare("Select * from items where biblioitemnumber = ?");
-    $sth->execute($biblioitemnumber);
-    my @results;
-    while ( my $data = $sth->fetchrow_hashref ) {
-        my $query = "Insert into deleteditems set ";
-        my @bind  = ();
-        foreach my $temp ( keys %$data ) {
-            $query .= "$temp = ?,";
-            push ( @bind, $data->{$temp} );
+    my $record = MARC::Record->new();
+    foreach (keys %{$hash}) {
+        &TransformKohaToMarcOneField( $sth, $record, $_,
+            $hash->{$_}, '' );
         }
-        $query =~ s/\,$//;
-        my $sth2 = $dbh->prepare($query);
-        $sth2->execute(@bind);
-    }    # while
-    $sth->finish;
-    $sth = $dbh->prepare("Delete from items where biblioitemnumber = ?");
-    $sth->execute($biblioitemnumber);
-    $sth->finish();
-
-    #    $dbh->disconnect;
-}    # sub deletebiblioitem
+    return $record;
+}
 
-=head2 REALdelbiblio($dbh,$biblio);
+=head2 TransformKohaToMarcOneField
 
 =over 4
 
-delete a biblio
+    $record = TransformKohaToMarcOneField( $sth, $record, $kohafieldname, $value, $frameworkcode );
 
 =back
 
 =cut
 
-sub REALdelbiblio {
-    my ( $dbh, $biblio ) = @_;
-    my $sth = $dbh->prepare("select * from biblio where biblionumber=?");
-    $sth->execute($biblio);
-    if ( my $data = $sth->fetchrow_hashref ) {
-        $sth->finish;
-        my $query = "Insert into deletedbiblio set ";
-        my @bind  = ();
-        foreach my $temp ( keys %$data ) {
-            $query .= "$temp = ?,";
-            push ( @bind, $data->{$temp} );
-        }
+sub TransformKohaToMarcOneField {
+    my ( $sth, $record, $kohafieldname, $value, $frameworkcode ) = @_;
+    $frameworkcode='' unless $frameworkcode;
+    my $tagfield;
+    my $tagsubfield;
 
-        #replacing the last , by ",?)"
-        $query =~ s/\,$//;
-        $sth = $dbh->prepare($query);
-        $sth->execute(@bind);
-        $sth->finish;
-        $sth = $dbh->prepare("Delete from biblio where biblionumber=?");
-        $sth->execute($biblio);
-        $sth->finish;
+    if ( !defined $sth ) {
+        my $dbh = C4::Context->dbh;
+        $sth = $dbh->prepare(
+            "SELECT tagfield,tagsubfield FROM marc_subfield_structure WHERE frameworkcode=? AND kohafield=?"
+        );
     }
-    $sth->finish;
+    $sth->execute( $frameworkcode, $kohafieldname );
+    if ( ( $tagfield, $tagsubfield ) = $sth->fetchrow ) {
+        my $tag = $record->field($tagfield);
+        if ($tag) {
+            $tag->update( $tagsubfield => $value );
+            $record->delete_field($tag);
+            $record->insert_fields_ordered($tag);
+        }
+        else {
+            $record->add_fields( $tagfield, " ", " ", $tagsubfield => $value );
+        }
+    }
+    return $record;
 }
 
-=head2 $number = itemcount($biblio);
+=head2 TransformHtmlToXml
 
 =over 4
 
-returns the number of items attached to a biblio
+$xml = TransformHtmlToXml( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type )
+
+$auth_type contains :
+- nothing : rebuild a biblio, un UNIMARC the encoding is in 100$a pos 26/27
+- UNIMARCAUTH : rebuild an authority. In UNIMARC, the encoding is in 100$a pos 13/14
+- ITEM : rebuild an item : in UNIMARC, 100$a, it's in the biblio ! (otherwise, we would get 2 100 fields !)
 
 =back
 
 =cut
 
-sub itemcount {
-    my ($biblio) = @_;
-    my $dbh = C4::Context->dbh;
-
-    #  print $query;
-    my $sth = $dbh->prepare("Select count(*) from items where biblionumber=?");
-    $sth->execute($biblio);
-    my $data = $sth->fetchrow_hashref;
-    $sth->finish;
-    return ( $data->{'count(*)'} );
+sub TransformHtmlToXml {
+    my ( $tags, $subfields, $values, $indicator, $ind_tag, $auth_type ) = @_;
+    my $xml = MARC::File::XML::header('UTF-8');
+    $auth_type = C4::Context->preference('marcflavour') unless $auth_type;
+    MARC::File::XML->default_record_format($auth_type);
+    # in UNIMARC, field 100 contains the encoding
+    # check that there is one, otherwise the 
+    # MARC::Record->new_from_xml will fail (and Koha will die)
+    my $unimarc_and_100_exist=0;
+    $unimarc_and_100_exist=1 if $auth_type eq 'ITEM'; # if we rebuild an item, no need of a 100 field
+    my $prevvalue;
+    my $prevtag = -1;
+    my $first   = 1;
+    my $j       = -1;
+    for ( my $i = 0 ; $i <= @$tags ; $i++ ) {
+        if (C4::Context->preference('marcflavour') eq 'UNIMARC' and @$tags[$i] eq "100" and @$subfields[$i] eq "a") {
+            # if we have a 100 field and it's values are not correct, skip them.
+            # if we don't have any valid 100 field, we will create a default one at the end
+            my $enc = substr( @$values[$i], 26, 2 );
+            if ($enc eq '01' or $enc eq '50' or $enc eq '03') {
+                $unimarc_and_100_exist=1;
+            } else {
+                next;
+            }
+        }
+        @$values[$i] =~ s/&/&amp;/g;
+        @$values[$i] =~ s/</&lt;/g;
+        @$values[$i] =~ s/>/&gt;/g;
+        @$values[$i] =~ s/"/&quot;/g;
+        @$values[$i] =~ s/'/&apos;/g;
+#         if ( !utf8::is_utf8( @$values[$i] ) ) {
+#             utf8::decode( @$values[$i] );
+#         }
+        if ( ( @$tags[$i] ne $prevtag ) ) {
+            $j++ unless ( @$tags[$i] eq "" );
+            if ( !$first ) {
+                $xml .= "</datafield>\n";
+                if (   ( @$tags[$i] && @$tags[$i] > 10 )
+                    && ( @$values[$i] ne "" ) )
+                {
+                    my $ind1 = substr( @$indicator[$j], 0, 1 );
+                    my $ind2;
+                    if ( @$indicator[$j] ) {
+                        $ind2 = substr( @$indicator[$j], 1, 1 );
+                    }
+                    else {
+                        warn "Indicator in @$tags[$i] is empty";
+                        $ind2 = " ";
+                    }
+                    $xml .=
+"<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+                    $xml .=
+"<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+                    $first = 0;
+                }
+                else {
+                    $first = 1;
+                }
+            }
+            else {
+                if ( @$values[$i] ne "" ) {
+
+                    # leader
+                    if ( @$tags[$i] eq "000" ) {
+                        $xml .= "<leader>@$values[$i]</leader>\n";
+                        $first = 1;
+
+                        # rest of the fixed fields
+                    }
+                    elsif ( @$tags[$i] < 10 ) {
+                        $xml .=
+"<controlfield tag=\"@$tags[$i]\">@$values[$i]</controlfield>\n";
+                        $first = 1;
+                    }
+                    else {
+                        my $ind1 = substr( @$indicator[$j], 0, 1 );
+                        my $ind2 = substr( @$indicator[$j], 1, 1 );
+                        $xml .=
+"<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+                        $xml .=
+"<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+                        $first = 0;
+                    }
+                }
+            }
+        }
+        else {    # @$tags[$i] eq $prevtag
+            if ( @$values[$i] eq "" ) {
+            }
+            else {
+                if ($first) {
+                    my $ind1 = substr( @$indicator[$j], 0, 1 );
+                    my $ind2 = substr( @$indicator[$j], 1, 1 );
+                    $xml .=
+"<datafield tag=\"@$tags[$i]\" ind1=\"$ind1\" ind2=\"$ind2\">\n";
+                    $first = 0;
+                }
+                $xml .=
+"<subfield code=\"@$subfields[$i]\">@$values[$i]</subfield>\n";
+            }
+        }
+        $prevtag = @$tags[$i];
+    }
+    if (C4::Context->preference('marcflavour') eq 'UNIMARC' and !$unimarc_and_100_exist) {
+#     warn "SETTING 100 for $auth_type";
+        use POSIX qw(strftime);
+        my $string = strftime( "%Y%m%d", localtime(time) );
+        # set 50 to position 26 is biblios, 13 if authorities
+        my $pos=26;
+        $pos=13 if $auth_type eq 'UNIMARCAUTH';
+        $string = sprintf( "%-*s", 35, $string );
+        substr( $string, $pos , 6, "50" );
+        $xml .= "<datafield tag=\"100\" ind1=\"\" ind2=\"\">\n";
+        $xml .= "<subfield code=\"a\">$string</subfield>\n";
+        $xml .= "</datafield>\n";
+    }
+    $xml .= MARC::File::XML::footer();
+    return $xml;
 }
 
-=head2 $biblionumber = newbiblio($biblio);
-
-=over 4
-
-create a biblio. The parameter is a hash
+=head2 TransformHtmlToMarc
 
-=back
+    L<$record> = TransformHtmlToMarc(L<$params>,L<$cgi>)
+    L<$params> is a ref to an array as below:
+    {
+        'tag_010_indicator_531951' ,
+        'tag_010_code_a_531951_145735' ,
+        'tag_010_subfield_a_531951_145735' ,
+        'tag_200_indicator_873510' ,
+        'tag_200_code_a_873510_673465' ,
+        'tag_200_subfield_a_873510_673465' ,
+        'tag_200_code_b_873510_704318' ,
+        'tag_200_subfield_b_873510_704318' ,
+        'tag_200_code_e_873510_280822' ,
+        'tag_200_subfield_e_873510_280822' ,
+        'tag_200_code_f_873510_110730' ,
+        'tag_200_subfield_f_873510_110730' ,
+    }
+    L<$cgi> is the CGI object which containts the value.
+    L<$record> is the MARC::Record object.
 
 =cut
 
-sub newbiblio {
-    my ($biblio) = @_;
-    my $dbh    = C4::Context->dbh;
-    my $bibnum = REALnewbiblio( $dbh, $biblio );
-    # finds new (MARC bibid
-    #  my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$bibnum);
-#     my $record = &MARCkoha2marcBiblio( $dbh, $bibnum );
-#     MARCaddbiblio( $dbh, $record, $bibnum,'' );
-    return ($bibnum);
+sub TransformHtmlToMarc {
+    my $params = shift;
+    my $cgi    = shift;
+    
+    # creating a new record
+    my $record  = MARC::Record->new();
+    my $i=0;
+    my @fields;
+    while ($params->[$i]){ # browse all CGI params
+        my $param = $params->[$i];
+        my $newfield=0;
+        # if we are on biblionumber, store it in the MARC::Record (it may not be in the edited fields)
+        if ($param eq 'biblionumber') {
+            my ( $biblionumbertagfield, $biblionumbertagsubfield ) =
+                &GetMarcFromKohaField( "biblio.biblionumber", '' );
+            if ($biblionumbertagfield < 10) {
+                $newfield = MARC::Field->new(
+                    $biblionumbertagfield,
+                    $cgi->param($param),
+                );
+            } else {
+                $newfield = MARC::Field->new(
+                    $biblionumbertagfield,
+                    '',
+                    '',
+                    "$biblionumbertagsubfield" => $cgi->param($param),
+                );
+            }
+            push @fields,$newfield if($newfield);
+        } 
+        elsif ($param =~ /^tag_(\d*)_indicator_/){ # new field start when having 'input name="..._indicator_..."
+            my $tag  = $1;
+            
+            my $ind1 = substr($cgi->param($param),0,1);
+            my $ind2 = substr($cgi->param($param),1,1);
+            $newfield=0;
+            my $j=$i+1;
+            
+            if($tag < 10){ # no code for theses fields
+    # in MARC editor, 000 contains the leader.
+                if ($tag eq '000' ) {
+                    $record->leader($cgi->param($params->[$j+1])) if length($cgi->param($params->[$j+1]))==24;
+    # between 001 and 009 (included)
+                } else {
+                    $newfield = MARC::Field->new(
+                        $tag,
+                        $cgi->param($params->[$j+1]),
+                    );
+                }
+    # > 009, deal with subfields
+            } else {
+                while($params->[$j] =~ /_code_/){ # browse all it's subfield
+                    my $inner_param = $params->[$j];
+                    if ($newfield){
+                        if($cgi->param($params->[$j+1])){  # only if there is a value (code => value)
+                            $newfield->add_subfields(
+                                $cgi->param($inner_param) => $cgi->param($params->[$j+1])
+                            );
+                        }
+                    } else {
+                        if ( $cgi->param($params->[$j+1]) ) { # creating only if there is a value (code => value)
+                            $newfield = MARC::Field->new(
+                                $tag,
+                                ''.$ind1,
+                                ''.$ind2,
+                                $cgi->param($inner_param) => $cgi->param($params->[$j+1]),
+                            );
+                        }
+                    }
+                    $j+=2;
+                }
+            }
+            push @fields,$newfield if($newfield);
+        }
+        $i++;
+    }
+    
+    $record->append_fields(@fields);
+    return $record;
 }
 
-=head2   $biblionumber = &modbiblio($biblio);
+# cache inverted MARC field map
+our $inverted_field_map;
+
+=head2 TransformMarcToKoha
 
 =over 4
 
-Update a biblio record.
+    $result = TransformMarcToKoha( $dbh, $record, $frameworkcode )
 
-C<$biblio> is a reference-to-hash whose keys are the fields in the
-biblio table in the Koha database. All fields must be present, not
-just the ones you wish to change.
+=back
 
-C<&modbiblio> updates the record defined by
-C<$biblio-E<gt>{biblionumber}> with the values in C<$biblio>.
-
-C<&modbiblio> returns C<$biblio-E<gt>{biblionumber}> whether it was
-successful or not.
-
-=back
+Extract data from a MARC bib record into a hashref representing
+Koha biblio, biblioitems, and items fields. 
 
 =cut
+sub TransformMarcToKoha {
+    my ( $dbh, $record, $frameworkcode, $limit_table ) = @_;
 
-sub modbiblio {
-       my ($biblio) = @_;
-       my $dbh  = C4::Context->dbh;
-       my $biblionumber=REALmodbiblio($dbh,$biblio);
-       my $record = MARCkoha2marcBiblio($dbh,$biblionumber,$biblionumber);
-       # finds new (MARC bibid
-       my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$biblionumber);
-       MARCmodbiblio($dbh,$bibid,$record,"",0);
-       return($biblionumber);
-} # sub modbiblio
-
-=head2   &modsubtitle($biblionumber, $subtitle);
+    my $result;
 
-=over 4
+    unless (defined $inverted_field_map) {
+        $inverted_field_map = _get_inverted_marc_field_map();
+    }
 
-Sets the subtitle of a book.
+    my %tables = ();
+    if ($limit_table eq 'items') {
+        $tables{'items'} = 1;
+    } else {
+        $tables{'items'} = 1;
+        $tables{'biblio'} = 1;
+        $tables{'biblioitems'} = 1;
+    }
 
-C<$biblionumber> is the biblionumber of the book to modify.
+    # traverse through record
+    MARCFIELD: foreach my $field ($record->fields()) {
+        my $tag = $field->tag();
+        next MARCFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag};
+        if ($field->is_control_field()) {
+            my $kohafields = $inverted_field_map->{$frameworkcode}->{$tag}->{list};
+            ENTRY: foreach my $entry (@{ $kohafields }) {
+                my ($subfield, $table, $column) = @{ $entry };
+                next ENTRY unless exists $tables{$table};
+                my $key = _disambiguate($table, $column);
+                if ($result->{$key}) {
+                    unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($field->data() eq "")) {
+                        $result->{$key} .= " | " . $field->data();
+                    }
+                } else {
+                    $result->{$key} = $field->data();
+                }
+            }
+        } else {
+            # deal with subfields
+            MARCSUBFIELD: foreach my $sf ($field->subfields()) {
+                my $code = $sf->[0];
+                next MARCSUBFIELD unless exists $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code};
+                my $value = $sf->[1];
+                SFENTRY: foreach my $entry (@{ $inverted_field_map->{$frameworkcode}->{$tag}->{sfs}->{$code} }) {
+                    my ($table, $column) = @{ $entry };
+                    next SFENTRY unless exists $tables{$table};
+                    my $key = _disambiguate($table, $column);
+                    if ($result->{$key}) {
+                        unless (($key eq "biblionumber" or $key eq "biblioitemnumber") and ($value eq "")) {
+                            $result->{$key} .= " | " . $value;
+                        }
+                    } else {
+                        $result->{$key} = $value;
+                    }
+                }
+            }
+        }
+    }
 
-C<$subtitle> is the new subtitle.
+    # modify copyrightdate to keep only the 1st year found
+    if (exists $result->{'copyrightdate'}) {
+        my $temp = $result->{'copyrightdate'};
+        $temp =~ m/c(\d\d\d\d)/;    # search cYYYY first
+        if ( $1 > 0 ) {
+            $result->{'copyrightdate'} = $1;
+        }
+        else {                      # if no cYYYY, get the 1st date.
+            $temp =~ m/(\d\d\d\d)/;
+            $result->{'copyrightdate'} = $1;
+        }
+    }
 
-=back
+    # modify publicationyear to keep only the 1st year found
+    if (exists $result->{'publicationyear'}) {
+        my $temp = $result->{'publicationyear'};
+        $temp =~ m/c(\d\d\d\d)/;    # search cYYYY first
+        if ( $1 > 0 ) {
+            $result->{'publicationyear'} = $1;
+        }
+        else {                      # if no cYYYY, get the 1st date.
+            $temp =~ m/(\d\d\d\d)/;
+            $result->{'publicationyear'} = $1;
+        }
+    }
 
-=cut
+    return $result;
+}
 
-sub modsubtitle {
-    my ( $bibnum, $subtitle ) = @_;
-    my $dbh = C4::Context->dbh;
-    &REALmodsubtitle( $dbh, $bibnum, $subtitle );
-}    # sub modsubtitle
+sub _get_inverted_marc_field_map {
+    my $field_map = {};
+    my $relations = C4::Context->marcfromkohafield;
+
+    foreach my $frameworkcode (keys %{ $relations }) {
+        foreach my $kohafield (keys %{ $relations->{$frameworkcode} }) {
+            my $tag = $relations->{$frameworkcode}->{$kohafield}->[0];
+            my $subfield = $relations->{$frameworkcode}->{$kohafield}->[1];
+            my ($table, $column) = split /[.]/, $kohafield, 2;
+            push @{ $field_map->{$frameworkcode}->{$tag}->{list} }, [ $subfield, $table, $column ];
+            push @{ $field_map->{$frameworkcode}->{$tag}->{sfs}->{$subfield} }, [ $table, $column ];
+        }
+    }
+    return $field_map;
+}
 
-=head2 &modaddauthor($biblionumber, $author);
+=head2 _disambiguate
 
 =over 4
 
-Replaces all additional authors for the book with biblio number
-C<$biblionumber> with C<$author>. If C<$author> is the empty string,
-C<&modaddauthor> deletes all additional authors.
-
-=back
+$newkey = _disambiguate($table, $field);
 
-=cut
+This is a temporary hack to distinguish between the
+following sets of columns when using TransformMarcToKoha.
 
-sub modaddauthor {
-    my ( $bibnum, @authors ) = @_;
-    my $dbh = C4::Context->dbh;
-    &REALmodaddauthor( $dbh, $bibnum, @authors );
-}    # sub modaddauthor
+items.cn_source & biblioitems.cn_source
+items.cn_sort & biblioitems.cn_sort
 
-=head2 $error = &modsubject($biblionumber, $force, @subjects);
+Columns that are currently NOT distinguished (FIXME
+due to lack of time to fully test) are:
 
-=over 4
+biblio.notes and biblioitems.notes
+biblionumber
+timestamp
+biblioitemnumber
 
-$force - a subject to force
-$error - Error message, or undef if successful.
+FIXME - this is necessary because prefixing each column
+name with the table name would require changing lots
+of code and templates, and exposing more of the DB
+structure than is good to the UI templates, particularly
+since biblio and bibloitems may well merge in a future
+version.  In the future, it would also be good to 
+separate DB access and UI presentation field names
+more.
 
 =back
 
 =cut
 
-sub modsubject {
-    my ( $bibnum, $force, @subject ) = @_;
-    my $dbh = C4::Context->dbh;
-    my $error = &REALmodsubject( $dbh, $bibnum, $force, @subject );
-    if ($error eq ''){
-               # When MARC is off, ensures that the MARC biblio table gets updated with new
-               # subjects, of course, it deletes the biblio in marc, and then recreates.
-               # This check is to ensure that no MARC data exists to lose.
-#              if (C4::Context->preference("MARC") eq '0'){
-#              warn "in modSUBJECT";
-#                      my $MARCRecord = &MARCkoha2marcBiblio($dbh,$bibnum);
-#                      my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber($dbh,$bibnum);
-#                      &MARCmodbiblio($dbh,$bibid, $MARCRecord);
-#              }
-       }
-       return ($error);
-}    # sub modsubject
-
-=head2 modbibitem($biblioitem);
-
-=over 4
-
-modify a biblioitem. The parameter is a hash
-
-=back
-
-=cut
+sub _disambiguate {
+    my ($table, $column) = @_;
+    if ($column eq "cn_sort" or $column eq "cn_source") {
+        return $table . '.' . $column;
+    } else {
+        return $column;
+    }
 
-sub modbibitem {
-    my ($biblioitem) = @_;
-    my $dbh = C4::Context->dbh;
-    &REALmodbiblioitem( $dbh, $biblioitem );
-}    # sub modbibitem
+}
 
-=head2 $biblioitemnumber = newbiblioitem($biblioitem)
+=head2 get_koha_field_from_marc
 
 =over 4
 
-create a biblioitem, the parameter is a hash
+$result->{_disambiguate($table, $field)} = get_koha_field_from_marc($table,$field,$record,$frameworkcode);
+
+Internal function to map data from the MARC record to a specific non-MARC field.
+FIXME: this is meant to replace TransformMarcToKohaOneField after more testing.
 
 =back
 
 =cut
 
-sub newbiblioitem {
-    my ($biblioitem) = @_;
-    my $dbh        = C4::Context->dbh;
-       # add biblio information to the hash
-    my $MARCbiblio = MARCkoha2marcBiblio( $dbh, $biblioitem );
-       $biblioitem->{marc} = $MARCbiblio->as_usmarc();
-    my $bibitemnum = &REALnewbiblioitem( $dbh, $biblioitem );
-    return ($bibitemnum);
-}
+sub get_koha_field_from_marc {
+    my ($koha_table,$koha_column,$record,$frameworkcode) = @_;
+    my ( $tagfield, $subfield ) = GetMarcFromKohaField( $koha_table.'.'.$koha_column, $frameworkcode );  
+    my $kohafield;
+    foreach my $field ( $record->field($tagfield) ) {
+        if ( $field->tag() < 10 ) {
+            if ( $kohafield ) {
+                $kohafield .= " | " . $field->data();
+            }
+            else {
+                $kohafield = $field->data();
+            }
+        }
+        else {
+            if ( $field->subfields ) {
+                my @subfields = $field->subfields();
+                foreach my $subfieldcount ( 0 .. $#subfields ) {
+                    if ( $subfields[$subfieldcount][0] eq $subfield ) {
+                        if ( $kohafield ) {
+                            $kohafield .=
+                              " | " . $subfields[$subfieldcount][1];
+                        }
+                        else {
+                            $kohafield =
+                              $subfields[$subfieldcount][1];
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return $kohafield;
+} 
+
 
-=head2 newsubtitle($biblionumber,$subtitle);
+=head2 TransformMarcToKohaOneField
 
 =over 4
 
-insert a subtitle for $biblionumber biblio
+$result = TransformMarcToKohaOneField( $kohatable, $kohafield, $record, $result, $frameworkcode )
 
 =back
 
 =cut
 
+sub TransformMarcToKohaOneField {
 
-sub newsubtitle {
-    my ( $bibnum, $subtitle ) = @_;
-    my $dbh = C4::Context->dbh;
-    &REALnewsubtitle( $dbh, $bibnum, $subtitle );
+    # FIXME ? if a field has a repeatable subfield that is used in old-db,
+    # only the 1st will be retrieved...
+    my ( $kohatable, $kohafield, $record, $result, $frameworkcode ) = @_;
+    my $res = "";
+    my ( $tagfield, $subfield ) =
+      GetMarcFromKohaField( $kohatable . "." . $kohafield,
+        $frameworkcode );
+    foreach my $field ( $record->field($tagfield) ) {
+        if ( $field->tag() < 10 ) {
+            if ( $result->{$kohafield} ) {
+                $result->{$kohafield} .= " | " . $field->data();
+            }
+            else {
+                $result->{$kohafield} = $field->data();
+            }
+        }
+        else {
+            if ( $field->subfields ) {
+                my @subfields = $field->subfields();
+                foreach my $subfieldcount ( 0 .. $#subfields ) {
+                    if ( $subfields[$subfieldcount][0] eq $subfield ) {
+                        if ( $result->{$kohafield} ) {
+                            $result->{$kohafield} .=
+                              " | " . $subfields[$subfieldcount][1];
+                        }
+                        else {
+                            $result->{$kohafield} =
+                              $subfields[$subfieldcount][1];
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return $result;
 }
 
-=head2 $errors = newitems($item, @barcodes);
+=head1  OTHER FUNCTIONS
+
+=head2 char_decode
 
 =over 4
 
-insert items ($item is a hash)
+my $string = char_decode( $string, $encoding );
+
+converts ISO 5426 coded string to UTF-8
+sloppy code : should be improved in next issue
 
 =back
 
 =cut
 
+sub char_decode {
+    my ( $string, $encoding ) = @_;
+    $_ = $string;
+
+    $encoding = C4::Context->preference("marcflavour") unless $encoding;
+    if ( $encoding eq "UNIMARC" ) {
 
-sub newitems {
-    my ( $item, @barcodes ) = @_;
-    my $dbh = C4::Context->dbh;
-    my $errors;
-    my $itemnumber;
-    my $error;
-    foreach my $barcode (@barcodes) {
-               # add items, one by one for each barcode.
-               my $oneitem=$item;
-               $oneitem->{barcode}= $barcode;
-        my $MARCitem = &MARCkoha2marcItem( $dbh, $oneitem);
-               $oneitem->{marc} = $MARCitem->as_usmarc;
-        ( $itemnumber, $error ) = &REALnewitems( $dbh, $oneitem);
-#         $errors .= $error;
-#         &MARCadditem( $dbh, $MARCitem, $item->{biblionumber} );
-    }
-    return ($errors);
+        #         s/\xe1/Æ/gm;
+        s/\xe2/Ğ/gm;
+        s/\xe9/Ø/gm;
+        s/\xec/ş/gm;
+        s/\xf1/æ/gm;
+        s/\xf3/ğ/gm;
+        s/\xf9/ø/gm;
+        s/\xfb/ß/gm;
+        s/\xc1\x61/à/gm;
+        s/\xc1\x65/è/gm;
+        s/\xc1\x69/ì/gm;
+        s/\xc1\x6f/ò/gm;
+        s/\xc1\x75/ù/gm;
+        s/\xc1\x41/À/gm;
+        s/\xc1\x45/È/gm;
+        s/\xc1\x49/Ì/gm;
+        s/\xc1\x4f/Ò/gm;
+        s/\xc1\x55/Ù/gm;
+        s/\xc2\x41/Á/gm;
+        s/\xc2\x45/É/gm;
+        s/\xc2\x49/Í/gm;
+        s/\xc2\x4f/Ó/gm;
+        s/\xc2\x55/Ú/gm;
+        s/\xc2\x59/İ/gm;
+        s/\xc2\x61/á/gm;
+        s/\xc2\x65/é/gm;
+        s/\xc2\x69/í/gm;
+        s/\xc2\x6f/ó/gm;
+        s/\xc2\x75/ú/gm;
+        s/\xc2\x79/ı/gm;
+        s/\xc3\x41/Â/gm;
+        s/\xc3\x45/Ê/gm;
+        s/\xc3\x49/Î/gm;
+        s/\xc3\x4f/Ô/gm;
+        s/\xc3\x55/Û/gm;
+        s/\xc3\x61/â/gm;
+        s/\xc3\x65/ê/gm;
+        s/\xc3\x69/î/gm;
+        s/\xc3\x6f/ô/gm;
+        s/\xc3\x75/û/gm;
+        s/\xc4\x41/Ã/gm;
+        s/\xc4\x4e/Ñ/gm;
+        s/\xc4\x4f/Õ/gm;
+        s/\xc4\x61/ã/gm;
+        s/\xc4\x6e/ñ/gm;
+        s/\xc4\x6f/õ/gm;
+        s/\xc8\x41/Ä/gm;
+        s/\xc8\x45/Ë/gm;
+        s/\xc8\x49/Ï/gm;
+        s/\xc8\x61/ä/gm;
+        s/\xc8\x65/ë/gm;
+        s/\xc8\x69/ï/gm;
+        s/\xc8\x6F/ö/gm;
+        s/\xc8\x75/ü/gm;
+        s/\xc8\x76/ÿ/gm;
+        s/\xc9\x41/Ä/gm;
+        s/\xc9\x45/Ë/gm;
+        s/\xc9\x49/Ï/gm;
+        s/\xc9\x4f/Ö/gm;
+        s/\xc9\x55/Ü/gm;
+        s/\xc9\x61/ä/gm;
+        s/\xc9\x6f/ö/gm;
+        s/\xc9\x75/ü/gm;
+        s/\xca\x41/Å/gm;
+        s/\xca\x61/å/gm;
+        s/\xd0\x43/Ç/gm;
+        s/\xd0\x63/ç/gm;
+
+        # this handles non-sorting blocks (if implementation requires this)
+        $string = nsb_clean($_);
+    }
+    elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
+        ##MARC-8 to UTF-8
+
+        s/\xe1\x61/à/gm;
+        s/\xe1\x65/è/gm;
+        s/\xe1\x69/ì/gm;
+        s/\xe1\x6f/ò/gm;
+        s/\xe1\x75/ù/gm;
+        s/\xe1\x41/À/gm;
+        s/\xe1\x45/È/gm;
+        s/\xe1\x49/Ì/gm;
+        s/\xe1\x4f/Ò/gm;
+        s/\xe1\x55/Ù/gm;
+        s/\xe2\x41/Á/gm;
+        s/\xe2\x45/É/gm;
+        s/\xe2\x49/Í/gm;
+        s/\xe2\x4f/Ó/gm;
+        s/\xe2\x55/Ú/gm;
+        s/\xe2\x59/İ/gm;
+        s/\xe2\x61/á/gm;
+        s/\xe2\x65/é/gm;
+        s/\xe2\x69/í/gm;
+        s/\xe2\x6f/ó/gm;
+        s/\xe2\x75/ú/gm;
+        s/\xe2\x79/ı/gm;
+        s/\xe3\x41/Â/gm;
+        s/\xe3\x45/Ê/gm;
+        s/\xe3\x49/Î/gm;
+        s/\xe3\x4f/Ô/gm;
+        s/\xe3\x55/Û/gm;
+        s/\xe3\x61/â/gm;
+        s/\xe3\x65/ê/gm;
+        s/\xe3\x69/î/gm;
+        s/\xe3\x6f/ô/gm;
+        s/\xe3\x75/û/gm;
+        s/\xe4\x41/Ã/gm;
+        s/\xe4\x4e/Ñ/gm;
+        s/\xe4\x4f/Õ/gm;
+        s/\xe4\x61/ã/gm;
+        s/\xe4\x6e/ñ/gm;
+        s/\xe4\x6f/õ/gm;
+        s/\xe6\x41/Ă/gm;
+        s/\xe6\x45/Ĕ/gm;
+        s/\xe6\x65/ĕ/gm;
+        s/\xe6\x61/ă/gm;
+        s/\xe8\x45/Ë/gm;
+        s/\xe8\x49/Ï/gm;
+        s/\xe8\x65/ë/gm;
+        s/\xe8\x69/ï/gm;
+        s/\xe8\x76/ÿ/gm;
+        s/\xe9\x41/A/gm;
+        s/\xe9\x4f/O/gm;
+        s/\xe9\x55/U/gm;
+        s/\xe9\x61/a/gm;
+        s/\xe9\x6f/o/gm;
+        s/\xe9\x75/u/gm;
+        s/\xea\x41/A/gm;
+        s/\xea\x61/a/gm;
+
+        #Additional Turkish characters
+        s/\x1b//gm;
+        s/\x1e//gm;
+        s/(\xf0)s/\xc5\x9f/gm;
+        s/(\xf0)S/\xc5\x9e/gm;
+        s/(\xf0)c/ç/gm;
+        s/(\xf0)C/Ç/gm;
+        s/\xe7\x49/\\xc4\xb0/gm;
+        s/(\xe6)G/\xc4\x9e/gm;
+        s/(\xe6)g/ğ\xc4\x9f/gm;
+        s/\xB8/ı/gm;
+        s/\xB9/£/gm;
+        s/(\xe8|\xc8)o/ö/gm;
+        s/(\xe8|\xc8)O/Ö/gm;
+        s/(\xe8|\xc8)u/ü/gm;
+        s/(\xe8|\xc8)U/Ü/gm;
+        s/\xc2\xb8/\xc4\xb1/gm;
+        s/¸/\xc4\xb1/gm;
+
+        # this handles non-sorting blocks (if implementation requires this)
+        $string = nsb_clean($_);
+    }
+    return ($string);
 }
 
-=head2 moditem($item);
+=head2 nsb_clean
 
 =over 4
 
-modify an item ($item is a hash with all item informations)
+my $string = nsb_clean( $string, $encoding );
 
 =back
 
 =cut
 
-
-sub moditem {
-    my ($item) = @_;
-    my $dbh = C4::Context->dbh;
-    &REALmoditem( $dbh, $item );
-    my $MARCitem =
-      &MARCkoha2marcItem( $dbh, $item->{'biblionumber'}, $item->{'itemnum'} );
-    my $bibid =
-      &MARCfind_MARCbibid_from_oldbiblionumber( $dbh, $item->{biblionumber} );
-    &MARCmoditem( $dbh, $MARCitem, $bibid, $item->{itemnum}, 0 );
+sub nsb_clean {
+    my $NSB      = '\x88';    # NSB : begin Non Sorting Block
+    my $NSE      = '\x89';    # NSE : Non Sorting Block end
+                              # handles non sorting blocks
+    my ($string) = @_;
+    $_ = $string;
+    s/$NSB/(/gm;
+    s/[ ]{0,1}$NSE/) /gm;
+    $string = $_;
+    return ($string);
 }
 
-=head2 $error = checkitems($count,@barcodes);
+=head2 PrepareItemrecordDisplay
 
 =over 4
 
-check for each @barcode entry that the barcode is not a duplicate
+PrepareItemrecordDisplay($itemrecord,$bibnum,$itemumber);
+
+Returns a hash with all the fields for Display a given item data in a template
 
 =back
 
 =cut
 
-sub checkitems {
-    my ( $count, @barcodes ) = @_;
+sub PrepareItemrecordDisplay {
+
+    my ( $bibnum, $itemnum ) = @_;
+
     my $dbh = C4::Context->dbh;
-    my $error;
-    my $sth = $dbh->prepare("Select * from items where barcode=?");
-    for ( my $i = 0 ; $i < $count ; $i++ ) {
-        $barcodes[$i] = uc $barcodes[$i];
-        $sth->execute( $barcodes[$i] );
-        if ( my $data = $sth->fetchrow_hashref ) {
-            $error .= " Duplicate Barcode: $barcodes[$i]";
+    my $frameworkcode = &GetFrameworkCode( $bibnum );
+    my ( $itemtagfield, $itemtagsubfield ) =
+      &GetMarcFromKohaField( "items.itemnumber", $frameworkcode );
+    my $tagslib = &GetMarcStructure( 1, $frameworkcode );
+    my $itemrecord = C4::Items::GetMarcItem( $bibnum, $itemnum) if ($itemnum);
+    my @loop_data;
+    my $authorised_values_sth =
+      $dbh->prepare(
+"SELECT authorised_value,lib FROM authorised_values WHERE category=? ORDER BY lib"
+      );
+    foreach my $tag ( sort keys %{$tagslib} ) {
+        my $previous_tag = '';
+        if ( $tag ne '' ) {
+            # loop through each subfield
+            my $cntsubf;
+            foreach my $subfield ( sort keys %{ $tagslib->{$tag} } ) {
+                next if ( subfield_is_koha_internal_p($subfield) );
+                next if ( $tagslib->{$tag}->{$subfield}->{'tab'} ne "10" );
+                my %subfield_data;
+                $subfield_data{tag}           = $tag;
+                $subfield_data{subfield}      = $subfield;
+                $subfield_data{countsubfield} = $cntsubf++;
+                $subfield_data{kohafield}     =
+                  $tagslib->{$tag}->{$subfield}->{'kohafield'};
+
+         #        $subfield_data{marc_lib}=$tagslib->{$tag}->{$subfield}->{lib};
+                $subfield_data{marc_lib} =
+                    "<span id=\"error\" title=\""
+                  . $tagslib->{$tag}->{$subfield}->{lib} . "\">"
+                  . substr( $tagslib->{$tag}->{$subfield}->{lib}, 0, 12 )
+                  . "</span>";
+                $subfield_data{mandatory} =
+                  $tagslib->{$tag}->{$subfield}->{mandatory};
+                $subfield_data{repeatable} =
+                  $tagslib->{$tag}->{$subfield}->{repeatable};
+                $subfield_data{hidden} = "display:none"
+                  if $tagslib->{$tag}->{$subfield}->{hidden};
+                my ( $x, $value );
+                ( $x, $value ) = _find_value( $tag, $subfield, $itemrecord )
+                  if ($itemrecord);
+                $value =~ s/"/&quot;/g;
+
+                # search for itemcallnumber if applicable
+                if ( $tagslib->{$tag}->{$subfield}->{kohafield} eq
+                    'items.itemcallnumber'
+                    && C4::Context->preference('itemcallnumber') )
+                {
+                    my $CNtag =
+                      substr( C4::Context->preference('itemcallnumber'), 0, 3 );
+                    my $CNsubfield =
+                      substr( C4::Context->preference('itemcallnumber'), 3, 1 );
+                    my $temp = $itemrecord->field($CNtag) if ($itemrecord);
+                    if ($temp) {
+                        $value = $temp->subfield($CNsubfield);
+                    }
+                }
+                if ( $tagslib->{$tag}->{$subfield}->{authorised_value} ) {
+                    my @authorised_values;
+                    my %authorised_lib;
+
+                    # builds list, depending on authorised value...
+                    #---- branch
+                    if ( $tagslib->{$tag}->{$subfield}->{'authorised_value'} eq
+                        "branches" )
+                    {
+                        if ( ( C4::Context->preference("IndependantBranches") )
+                            && ( C4::Context->userenv->{flags} != 1 ) )
+                        {
+                            my $sth =
+                              $dbh->prepare(
+                                "SELECT branchcode,branchname FROM branches WHERE branchcode = ? ORDER BY branchname"
+                              );
+                            $sth->execute( C4::Context->userenv->{branch} );
+                            push @authorised_values, ""
+                              unless (
+                                $tagslib->{$tag}->{$subfield}->{mandatory} );
+                            while ( my ( $branchcode, $branchname ) =
+                                $sth->fetchrow_array )
+                            {
+                                push @authorised_values, $branchcode;
+                                $authorised_lib{$branchcode} = $branchname;
+                            }
+                        }
+                        else {
+                            my $sth =
+                              $dbh->prepare(
+                                "SELECT branchcode,branchname FROM branches ORDER BY branchname"
+                              );
+                            $sth->execute;
+                            push @authorised_values, ""
+                              unless (
+                                $tagslib->{$tag}->{$subfield}->{mandatory} );
+                            while ( my ( $branchcode, $branchname ) =
+                                $sth->fetchrow_array )
+                            {
+                                push @authorised_values, $branchcode;
+                                $authorised_lib{$branchcode} = $branchname;
+                            }
+                        }
+
+                        #----- itemtypes
+                    }
+                    elsif ( $tagslib->{$tag}->{$subfield}->{authorised_value} eq
+                        "itemtypes" )
+                    {
+                        my $sth =
+                          $dbh->prepare(
+                            "SELECT itemtype,description FROM itemtypes ORDER BY description"
+                          );
+                        $sth->execute;
+                        push @authorised_values, ""
+                          unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+                        while ( my ( $itemtype, $description ) =
+                            $sth->fetchrow_array )
+                        {
+                            push @authorised_values, $itemtype;
+                            $authorised_lib{$itemtype} = $description;
+                        }
+
+                        #---- "true" authorised value
+                    }
+                    else {
+                        $authorised_values_sth->execute(
+                            $tagslib->{$tag}->{$subfield}->{authorised_value} );
+                        push @authorised_values, ""
+                          unless ( $tagslib->{$tag}->{$subfield}->{mandatory} );
+                        while ( my ( $value, $lib ) =
+                            $authorised_values_sth->fetchrow_array )
+                        {
+                            push @authorised_values, $value;
+                            $authorised_lib{$value} = $lib;
+                        }
+                    }
+                    $subfield_data{marc_value} = CGI::scrolling_list(
+                        -name     => 'field_value',
+                        -values   => \@authorised_values,
+                        -default  => "$value",
+                        -labels   => \%authorised_lib,
+                        -size     => 1,
+                        -tabindex => '',
+                        -multiple => 0,
+                    );
+                }
+                elsif ( $tagslib->{$tag}->{$subfield}->{thesaurus_category} ) {
+                    $subfield_data{marc_value} =
+"<input type=\"text\" name=\"field_value\"  size=47 maxlength=255> <a href=\"javascript:Dopop('cataloguing/thesaurus_popup.pl?category=$tagslib->{$tag}->{$subfield}->{thesaurus_category}&index=',)\">...</a>";
+
+#"
+# COMMENTED OUT because No $i is provided with this API.
+# And thus, no value_builder can be activated.
+# BUT could be thought over.
+#         } elsif ($tagslib->{$tag}->{$subfield}->{'value_builder'}) {
+#             my $plugin="value_builder/".$tagslib->{$tag}->{$subfield}->{'value_builder'};
+#             require $plugin;
+#             my $extended_param = plugin_parameters($dbh,$itemrecord,$tagslib,$i,0);
+#             my ($function_name,$javascript) = plugin_javascript($dbh,$record,$tagslib,$i,0);
+#             $subfield_data{marc_value}="<input type=\"text\" value=\"$value\" name=\"field_value\"  size=47 maxlength=255 DISABLE READONLY OnFocus=\"javascript:Focus$function_name()\" OnBlur=\"javascript:Blur$function_name()\"> <a href=\"javascript:Clic$function_name()\">...</a> $javascript";
+                }
+                else {
+                    $subfield_data{marc_value} =
+"<input type=\"text\" name=\"field_value\" value=\"$value\" size=50 maxlength=255>";
+                }
+                push( @loop_data, \%subfield_data );
+            }
         }
     }
-    $sth->finish;
-    return ($error);
+    my $itemnumber = $itemrecord->subfield( $itemtagfield, $itemtagsubfield )
+      if ( $itemrecord && $itemrecord->field($itemtagfield) );
+    return {
+        'itemtagfield'    => $itemtagfield,
+        'itemtagsubfield' => $itemtagsubfield,
+        'itemnumber'      => $itemnumber,
+        'iteminformation' => \@loop_data
+    };
 }
+#"
 
-=head2 $delitem($itemnum);
+#
+# true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
+# at the same time
+# replaced by a zebraqueue table, that is filled with ModZebra to run.
+# the table is emptied by misc/cronjobs/zebraqueue_start.pl script
+# =head2 ModZebrafiles
+# 
+# &ModZebrafiles( $dbh, $biblionumber, $record, $folder, $server );
+# 
+# =cut
+# 
+# sub ModZebrafiles {
+# 
+#     my ( $dbh, $biblionumber, $record, $folder, $server ) = @_;
+# 
+#     my $op;
+#     my $zebradir =
+#       C4::Context->zebraconfig($server)->{directory} . "/" . $folder . "/";
+#     unless ( opendir( DIR, "$zebradir" ) ) {
+#         warn "$zebradir not found";
+#         return;
+#     }
+#     closedir DIR;
+#     my $filename = $zebradir . $biblionumber;
+# 
+#     if ($record) {
+#         open( OUTPUT, ">", $filename . ".xml" );
+#         print OUTPUT $record;
+#         close OUTPUT;
+#     }
+# }
+
+=head2 ModZebra
 
 =over 4
 
-delete item $itemnum being the item number to delete
+ModZebra( $biblionumber, $op, $server, $newRecord );
 
+    $biblionumber is the biblionumber we want to index
+    $op is specialUpdate or delete, and is used to know what we want to do
+    $server is the server that we want to update
+    $newRecord is the MARC::Record containing the new record. It is usefull only when NoZebra=1, and is used to know what to add to the nozebra database. (the record in mySQL being, if it exist, the previous record, the one just before the modif. We need both : the previous and the new one.
+    
 =back
 
 =cut
 
-sub delitem {
-    my ($itemnum) = @_;
-    my $dbh = C4::Context->dbh;
-    &REALdelitem( $dbh, $itemnum );
-}
+sub ModZebra {
+###Accepts a $server variable thus we can use it for biblios authorities or other zebra dbs
+    my ( $biblionumber, $op, $server, $newRecord ) = @_;
+    my $dbh=C4::Context->dbh;
 
-=head2 deletebiblioitem($biblioitemnumber);
+    # true ModZebra commented until indexdata fixes zebraDB crashes (it seems they occur on multiple updates
+    # at the same time
+    # replaced by a zebraqueue table, that is filled with ModZebra to run.
+    # the table is emptied by misc/cronjobs/zebraqueue_start.pl script
 
-=over 4
+    if (C4::Context->preference("NoZebra")) {
+        # lock the nozebra table : we will read index lines, update them in Perl process
+        # and write everything in 1 transaction.
+        # lock the table to avoid someone else overwriting what we are doing
+        $dbh->do('LOCK TABLES nozebra WRITE,biblio WRITE,biblioitems WRITE, systempreferences WRITE, auth_types WRITE, auth_header WRITE');
+        my %result; # the result hash that will be builded by deletion / add, and written on mySQL at the end, to improve speed
+        my $record;
+        if ($server eq 'biblioserver') {
+            $record= GetMarcBiblio($biblionumber);
+        } else {
+            $record= C4::AuthoritiesMarc::GetAuthority($biblionumber);
+        }
+        if ($op eq 'specialUpdate') {
+            # OK, we have to add or update the record
+            # 1st delete (virtually, in indexes), if record actually exists
+            if ($record) { 
+                %result = _DelBiblioNoZebra($biblionumber,$record,$server);
+            }
+            # ... add the record
+            %result=_AddBiblioNoZebra($biblionumber,$newRecord, $server, %result);
+        } else {
+            # it's a deletion, delete the record...
+            # warn "DELETE the record $biblionumber on $server".$record->as_formatted;
+            %result=_DelBiblioNoZebra($biblionumber,$record,$server);
+        }
+        # ok, now update the database...
+        my $sth = $dbh->prepare("UPDATE nozebra SET biblionumbers=? WHERE server=? AND indexname=? AND value=?");
+        foreach my $key (keys %result) {
+            foreach my $index (keys %{$result{$key}}) {
+                $sth->execute($result{$key}->{$index}, $server, $key, $index);
+            }
+        }
+        $dbh->do('UNLOCK TABLES');
+
+    } else {
+        #
+        # we use zebra, just fill zebraqueue table
+        #
+        my $sth=$dbh->prepare("INSERT INTO zebraqueue  (biblio_auth_number,server,operation) VALUES(?,?,?)");
+        $sth->execute($biblionumber,$server,$op);
+        $sth->finish;
+    }
+}
 
-delete the biblioitem $biblioitemnumber
+=head2 GetNoZebraIndexes
 
-=back
+    %indexes = GetNoZebraIndexes;
+    
+    return the data from NoZebraIndexes syspref.
 
 =cut
 
-sub deletebiblioitem {
-    my ($biblioitemnumber) = @_;
-    my $dbh = C4::Context->dbh;
-    &REALdelbiblioitem( $dbh, $biblioitemnumber );
-}    # sub deletebiblioitem
+sub GetNoZebraIndexes {
+    my $index = C4::Context->preference('NoZebraIndexes');
+    my %indexes;
+    foreach my $line (split /('|"),/,$index) {
+        $line =~ /(.*)=>(.*)/;
+        my $index = substr($1,1); # get the index, don't forget to remove initial ' or "
+        my $fields = $2;
+        $index =~ s/'|"|\s//g;
 
-=head2 delbiblio($biblionumber)
 
-=over 4
+        $fields =~ s/'|"|\s//g;
+        $indexes{$index}=$fields;
+    }
+    return %indexes;
+}
 
-delete biblio $biblionumber
+=head1 INTERNAL FUNCTIONS
 
-=back
+=head2 _DelBiblioNoZebra($biblionumber,$record,$server);
+
+    function to delete a biblio in NoZebra indexes
+    This function does NOT delete anything in database : it reads all the indexes entries
+    that have to be deleted & delete them in the hash
+    The SQL part is done either :
+    - after the Add if we are modifying a biblio (delete + add again)
+    - immediatly after this sub if we are doing a true deletion.
+    $server can be 'biblioserver' or 'authorityserver' : it indexes biblios or authorities (in the same table, $server being part of the table itself
 
 =cut
 
-sub delbiblio {
-    my ($biblio) = @_;
+
+sub _DelBiblioNoZebra {
+    my ($biblionumber, $record, $server)=@_;
+    
+    # Get the indexes
     my $dbh = C4::Context->dbh;
-    &REALdelbiblio( $dbh, $biblio );
-    my $bibid = &MARCfind_MARCbibid_from_oldbiblionumber( $dbh, $biblio );
-    &MARCdelbiblio( $dbh, $bibid, 0 );
+    # Get the indexes
+    my %index;
+    my $title;
+    if ($server eq 'biblioserver') {
+        %index=GetNoZebraIndexes;
+        # get title of the record (to store the 10 first letters with the index)
+        my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
+        $title = lc($record->subfield($titletag,$titlesubfield));
+    } else {
+        # for authorities, the "title" is the $a mainentry
+        my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield(152,'b'));
+        warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
+        $title = $record->subfield($authref->{auth_tag_to_report},'a');
+        $index{'mainmainentry'}= $authref->{'auth_tag_to_report'}.'a';
+        $index{'mainentry'}    = $authref->{'auth_tag_to_report'}.'*';
+        $index{'auth_type'}    = '152b';
+    }
+    
+    my %result;
+    # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
+    $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
+    # limit to 10 char, should be enough, and limit the DB size
+    $title = substr($title,0,10);
+    #parse each field
+    my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
+    foreach my $field ($record->fields()) {
+        #parse each subfield
+        next if $field->tag <10;
+        foreach my $subfield ($field->subfields()) {
+            my $tag = $field->tag();
+            my $subfieldcode = $subfield->[0];
+            my $indexed=0;
+            # check each index to see if the subfield is stored somewhere
+            # otherwise, store it in __RAW__ index
+            foreach my $key (keys %index) {
+#                 warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
+                if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
+                    $indexed=1;
+                    my $line= lc $subfield->[1];
+                    # remove meaningless value in the field...
+                    $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
+                    # ... and split in words
+                    foreach (split / /,$line) {
+                        next unless $_; # skip  empty values (multiple spaces)
+                        # if the entry is already here, do nothing, the biblionumber has already be removed
+                        unless ($result{$key}->{$_} =~ /$biblionumber,$title\-(\d);/) {
+                            # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
+                            $sth2->execute($server,$key,$_);
+                            my $existing_biblionumbers = $sth2->fetchrow;
+                            # it exists
+                            if ($existing_biblionumbers) {
+#                                 warn " existing for $key $_: $existing_biblionumbers";
+                                $result{$key}->{$_} =$existing_biblionumbers;
+                                $result{$key}->{$_} =~ s/$biblionumber,$title\-(\d);//;
+                            }
+                        }
+                    }
+                }
+            }
+            # the subfield is not indexed, store it in __RAW__ index anyway
+            unless ($indexed) {
+                my $line= lc $subfield->[1];
+                $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
+                # ... and split in words
+                foreach (split / /,$line) {
+                    next unless $_; # skip  empty values (multiple spaces)
+                    # if the entry is already here, do nothing, the biblionumber has already be removed
+                    unless ($result{'__RAW__'}->{$_} =~ /$biblionumber,$title\-(\d);/) {
+                        # get the index value if it exist in the nozebra table and remove the entry, otherwise, do nothing
+                        $sth2->execute($server,'__RAW__',$_);
+                        my $existing_biblionumbers = $sth2->fetchrow;
+                        # it exists
+                        if ($existing_biblionumbers) {
+                            $result{'__RAW__'}->{$_} =$existing_biblionumbers;
+                            $result{'__RAW__'}->{$_} =~ s/$biblionumber,$title\-(\d);//;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return %result;
 }
 
-=head2 ($count,@results) = getbiblio($biblionumber);
-
-=over 4
+=head2 _AddBiblioNoZebra($biblionumber, $record, $server, %result);
 
-return an array with hash of biblios.
-
-FIXME : biblionumber being the primary key, this sub will always return only 1 result, API should be modified...
-
-=back
+    function to add a biblio in NoZebra indexes
 
 =cut
 
-sub getbiblio {
-    my ($biblionumber) = @_;
+sub _AddBiblioNoZebra {
+    my ($biblionumber, $record, $server, %result)=@_;
     my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare("Select * from biblio where biblionumber = ?");
+    # Get the indexes
+    my %index;
+    my $title;
+    if ($server eq 'biblioserver') {
+        %index=GetNoZebraIndexes;
+        # get title of the record (to store the 10 first letters with the index)
+        my ($titletag,$titlesubfield) = GetMarcFromKohaField('biblio.title');
+        $title = lc($record->subfield($titletag,$titlesubfield));
+    } else {
+        # warn "server : $server";
+        # for authorities, the "title" is the $a mainentry
+        my $authref = C4::AuthoritiesMarc::GetAuthType($record->subfield(152,'b'));
+        warn "ERROR : authtype undefined for ".$record->as_formatted unless $authref;
+        $title = $record->subfield($authref->{auth_tag_to_report},'a');
+        $index{'mainmainentry'} = $authref->{auth_tag_to_report}.'a';
+        $index{'mainentry'}     = $authref->{auth_tag_to_report}.'*';
+        $index{'auth_type'}     = '152b';
+    }
 
-    # || die "Cannot prepare $query\n" . $dbh->errstr;
-    my $count = 0;
-    my @results;
+    # remove blancks comma (that could cause problem when decoding the string for CQL retrieval) and regexp specific values
+    $title =~ s/ |,|;|\[|\]|\(|\)|\*|-|'|=//g;
+    # limit to 10 char, should be enough, and limit the DB size
+    $title = substr($title,0,10);
+    #parse each field
+    my $sth2=$dbh->prepare('SELECT biblionumbers FROM nozebra WHERE server=? AND indexname=? AND value=?');
+    foreach my $field ($record->fields()) {
+        #parse each subfield
+        next if $field->tag <10;
+        foreach my $subfield ($field->subfields()) {
+            my $tag = $field->tag();
+            my $subfieldcode = $subfield->[0];
+            my $indexed=0;
+            # check each index to see if the subfield is stored somewhere
+            # otherwise, store it in __RAW__ index
+            foreach my $key (keys %index) {
+#                 warn "examining $key index : ".$index{$key}." for $tag $subfieldcode";
+                if ($index{$key} =~ /$tag\*/ or $index{$key} =~ /$tag$subfieldcode/) {
+                    $indexed=1;
+                    my $line= lc $subfield->[1];
+                    # remove meaningless value in the field...
+                    $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
+                    # ... and split in words
+                    foreach (split / /,$line) {
+                        next unless $_; # skip  empty values (multiple spaces)
+                        # if the entry is already here, improve weight
+#                         warn "managing $_";
+                        if ($result{$key}->{"$_"} =~ /$biblionumber,$title\-(\d);/) {
+                            my $weight=$1+1;
+                            $result{$key}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
+                            $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
+                        } else {
+                            # get the value if it exist in the nozebra table, otherwise, create it
+                            $sth2->execute($server,$key,$_);
+                            my $existing_biblionumbers = $sth2->fetchrow;
+                            # it exists
+                            if ($existing_biblionumbers) {
+                                $result{$key}->{"$_"} =$existing_biblionumbers;
+                                my $weight=$1+1;
+                                $result{$key}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
+                                $result{$key}->{"$_"} .= "$biblionumber,$title-$weight;";
+                            # create a new ligne for this entry
+                            } else {
+#                             warn "INSERT : $server / $key / $_";
+                                $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).', indexname='.$dbh->quote($key).',value='.$dbh->quote($_));
+                                $result{$key}->{"$_"}.="$biblionumber,$title-1;";
+                            }
+                        }
+                    }
+                }
+            }
+            # the subfield is not indexed, store it in __RAW__ index anyway
+            unless ($indexed) {
+                my $line= lc $subfield->[1];
+                $line =~ s/-|\.|\?|,|;|!|'|\(|\)|\[|\]|{|}|"|<|>|&|\+|\*|\/|=|:/ /g;
+                # ... and split in words
+                foreach (split / /,$line) {
+                    next unless $_; # skip  empty values (multiple spaces)
+                    # if the entry is already here, improve weight
+                    if ($result{'__RAW__'}->{"$_"} =~ /$biblionumber,$title\-(\d);/) {
+                        my $weight=$1+1;
+                        $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
+                        $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
+                    } else {
+                        # get the value if it exist in the nozebra table, otherwise, create it
+                        $sth2->execute($server,'__RAW__',$_);
+                        my $existing_biblionumbers = $sth2->fetchrow;
+                        # it exists
+                        if ($existing_biblionumbers) {
+                            $result{'__RAW__'}->{"$_"} =$existing_biblionumbers;
+                            my $weight=$1+1;
+                            $result{'__RAW__'}->{"$_"} =~ s/$biblionumber,$title\-(\d);//;
+                            $result{'__RAW__'}->{"$_"} .= "$biblionumber,$title-$weight;";
+                        # create a new ligne for this entry
+                        } else {
+                            $dbh->do('INSERT INTO nozebra SET server='.$dbh->quote($server).',  indexname="__RAW__",value='.$dbh->quote($_));
+                            $result{'__RAW__'}->{"$_"}.="$biblionumber,$title-1;";
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return %result;
+}
 
-    $sth->execute($biblionumber);
 
-    # || die "Cannot execute $query\n" . $sth->errstr;
-    while ( my $data = $sth->fetchrow_hashref ) {
-        $results[$count] = $data;
-        $count++;
-    }    # while
+=head2 _find_value
 
-    $sth->finish;
-    return ( $count, @results );
-}    # sub getbiblio
+=over 4
 
-=item bibdata
+($indicators, $value) = _find_value($tag, $subfield, $record,$encoding);
 
-  $data = &bibdata($biblionumber, $type);
+Find the given $subfield in the given $tag in the given
+MARC::Record $record.  If the subfield is found, returns
+the (indicators, value) pair; otherwise, (undef, undef) is
+returned.
 
-Returns information about the book with the given biblionumber.
+PROPOSITION :
+Such a function is used in addbiblio AND additem and serial-edit and maybe could be used in Authorities.
+I suggest we export it from this module.
 
-C<$type> is ignored.
-
-C<&bibdata> returns a reference-to-hash. The keys are the fields in
-the C<biblio>, C<biblioitems>, and C<bibliosubtitle> tables in the
-Koha database.
+=back
 
-In addition, C<$data-E<gt>{subject}> is the list of the book's
-subjects, separated by C<" , "> (space, comma, space).
+=cut
 
-If there are multiple biblioitems with the given biblionumber, only
-the first one is considered.
+sub _find_value {
+    my ( $tagfield, $insubfield, $record, $encoding ) = @_;
+    my @result;
+    my $indicator;
+    if ( $tagfield < 10 ) {
+        if ( $record->field($tagfield) ) {
+            push @result, $record->field($tagfield)->data();
+        }
+        else {
+            push @result, "";
+        }
+    }
+    else {
+        foreach my $field ( $record->field($tagfield) ) {
+            my @subfields = $field->subfields();
+            foreach my $subfield (@subfields) {
+                if ( @$subfield[0] eq $insubfield ) {
+                    push @result, @$subfield[1];
+                    $indicator = $field->indicator(1) . $field->indicator(2);
+                }
+            }
+        }
+    }
+    return ( $indicator, @result );
+}
 
-=cut
-#'
-sub bibdata {
-       my ($bibnum, $type) = @_;
-       my $dbh   = C4::Context->dbh;
-       my $sth   = $dbh->prepare("Select *, biblioitems.notes AS bnotes, biblio.notes
-                                                               from biblio 
-                                                               left join biblioitems on biblioitems.biblionumber = biblio.biblionumber
-                                                               left join bibliosubtitle on
-                                                               biblio.biblionumber = bibliosubtitle.biblionumber
-                                                               left join itemtypes on biblioitems.itemtype=itemtypes.itemtype
-                                                               where biblio.biblionumber = ?
-                                                               ");
-       $sth->execute($bibnum);
-       my $data;
-       $data  = $sth->fetchrow_hashref;
-       $sth->finish;
-       # handle management of repeated subtitle
-       $sth   = $dbh->prepare("Select * from bibliosubtitle where biblionumber = ?");
-       $sth->execute($bibnum);
-       my @subtitles;
-       while (my $dat = $sth->fetchrow_hashref){
-               my %line;
-               $line{subtitle} = $dat->{subtitle};
-               push @subtitles, \%line;
-       } # while
-       $data->{subtitles} = \@subtitles;
-       $sth->finish;
-       $sth   = $dbh->prepare("Select * from bibliosubject where biblionumber = ?");
-       $sth->execute($bibnum);
-       my @subjects;
-       while (my $dat = $sth->fetchrow_hashref){
-               my %line;
-               $line{subject} = $dat->{'subject'};
-               push @subjects, \%line;
-       } # while
-       $data->{subjects} = \@subjects;
-       $sth->finish;
-       $sth   = $dbh->prepare("Select * from additionalauthors where biblionumber = ?");
-       $sth->execute($bibnum);
-       while (my $dat = $sth->fetchrow_hashref){
-               $data->{'additionalauthors'} .= "$dat->{'author'} - ";
-       } # while
-       chop $data->{'additionalauthors'};
-       chop $data->{'additionalauthors'};
-       chop $data->{'additionalauthors'};
-       $sth->finish;
-       return($data);
-} # sub bibdata
-
-=head2 ($count,@results) = getbiblioitem($biblioitemnumber);
+=head2 _koha_marc_update_bib_ids
 
 =over 4
 
-return an array with hash of biblioitemss.
+_koha_marc_update_bib_ids($record, $frameworkcode, $biblionumber, $biblioitemnumber);
 
-FIXME : biblioitemnumber being unique, this sub will always return only 1 result, API should be modified...
+Internal function to add or update biblionumber and biblioitemnumber to
+the MARC XML.
 
 =back
 
 =cut
 
-sub getbiblioitem {
-    my ($biblioitemnum) = @_;
-    my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare( "Select * from biblioitems where
-biblioitemnumber = ?"
-    );
-    my $count = 0;
-    my @results;
-
-    $sth->execute($biblioitemnum);
-
-    while ( my $data = $sth->fetchrow_hashref ) {
-        $results[$count] = $data;
-        $count++;
-    }    # while
-
-    $sth->finish;
-    return ( $count, @results );
-}    # sub getbiblioitem
+sub _koha_marc_update_bib_ids {
+    my ($record, $frameworkcode, $biblionumber, $biblioitemnumber) = @_;
 
-=head2 ($count,@results) = getbiblioitembybiblionumber($biblionumber);
+    # we must add bibnum and bibitemnum in MARC::Record...
+    # we build the new field with biblionumber and biblioitemnumber
+    # we drop the original field
+    # we add the new builded field.
+    my ($biblio_tag, $biblio_subfield ) = GetMarcFromKohaField("biblio.biblionumber",$frameworkcode);
+    my ($biblioitem_tag, $biblioitem_subfield ) = GetMarcFromKohaField("biblioitems.biblioitemnumber",$frameworkcode);
 
-=over 4
-
-return an array with hash of biblioitems for the given biblionumber.
-
-=back
+    if ($biblio_tag != $biblioitem_tag) {
+        # biblionumber & biblioitemnumber are in different fields
 
-=cut
-
-sub getbiblioitembybiblionumber {
-    my ($biblionumber) = @_;
-    my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare("Select * from biblioitems where biblionumber = ?");
-    my $count = 0;
-    my @results;
+        # deal with biblionumber
+        my ($new_field, $old_field);
+        if ($biblio_tag < 10) {
+            $new_field = MARC::Field->new( $biblio_tag, $biblionumber );
+        } else {
+            $new_field =
+              MARC::Field->new( $biblio_tag, '', '',
+                "$biblio_subfield" => $biblionumber );
+        }
 
-    $sth->execute($biblionumber);
+        # drop old field and create new one...
+        $old_field = $record->field($biblio_tag);
+        $record->delete_field($old_field);
+        $record->append_fields($new_field);
 
-    while ( my $data = $sth->fetchrow_hashref ) {
-        $results[$count] = $data;
-        $count++;
-    }    # while
+        # deal with biblioitemnumber
+        if ($biblioitem_tag < 10) {
+            $new_field = MARC::Field->new( $biblioitem_tag, $biblioitemnumber, );
+        } else {
+            $new_field =
+              MARC::Field->new( $biblioitem_tag, '', '',
+                "$biblioitem_subfield" => $biblioitemnumber, );
+        }
+        # drop old field and create new one...
+        $old_field = $record->field($biblioitem_tag);
+        $record->delete_field($old_field);
+        $record->insert_fields_ordered($new_field);
+
+    } else {
+        # biblionumber & biblioitemnumber are in the same field (can't be <10 as fields <10 have only 1 value)
+        my $new_field = MARC::Field->new(
+            $biblio_tag, '', '',
+            "$biblio_subfield" => $biblionumber,
+            "$biblioitem_subfield" => $biblioitemnumber
+        );
 
-    $sth->finish;
-    return ( $count, @results );
-}    # sub
+        # drop old field and create new one...
+        my $old_field = $record->field($biblio_tag);
+        $record->delete_field($old_field);
+        $record->insert_fields_ordered($new_field);
+    }
+}
 
-=head2 ($count,@results) = getitemsbybiblioitem($biblionumber);
+=head2 _koha_add_biblio
 
 =over 4
 
-returns an array with hash of items
+my ($biblionumber,$error) = _koha_add_biblio($dbh,$biblioitem);
+
+Internal function to add a biblio ($biblio is a hash with the values)
 
 =back
 
 =cut
 
-sub getitemsbybiblioitem {
-    my ($biblioitemnum) = @_;
-    my $dbh = C4::Context->dbh;
-    my $sth = $dbh->prepare( "Select * from items, biblio where
-biblio.biblionumber = items.biblionumber and biblioitemnumber
-= ?"
-    );
-
-    # || die "Cannot prepare $query\n" . $dbh->errstr;
-    my $count = 0;
-    my @results;
-
-    $sth->execute($biblioitemnum);
+sub _koha_add_biblio {
+    my ( $dbh, $biblio, $frameworkcode ) = @_;
 
-    # || die "Cannot execute $query\n" . $sth->errstr;
-    while ( my $data = $sth->fetchrow_hashref ) {
-        $results[$count] = $data;
-        $count++;
-    }    # while
-
-    $sth->finish;
-    return ( $count, @results );
-}    # sub getitemsbybiblioitem
-
-=item ItemInfo
-
-  @results = &ItemInfo($env, $biblionumber, $type);
+    my $error;
 
-Returns information about books with the given biblionumber.
+    # set the series flag
+    my $serial = 0;
+    if ( $biblio->{'seriestitle'} ) { $serial = 1 };
+
+    my $query = 
+        "INSERT INTO biblio
+        SET frameworkcode = ?,
+            author = ?,
+            title = ?,
+            unititle =?,
+            notes = ?,
+            serial = ?,
+            seriestitle = ?,
+            copyrightdate = ?,
+            datecreated=NOW(),
+            abstract = ?
+        ";
+    my $sth = $dbh->prepare($query);
+    $sth->execute(
+        $frameworkcode,
+        $biblio->{'author'},
+        $biblio->{'title'},
+        $biblio->{'unititle'},
+        $biblio->{'notes'},
+        $serial,
+        $biblio->{'seriestitle'},
+        $biblio->{'copyrightdate'},
+        $biblio->{'abstract'}
+    );
 
-C<$type> may be either C<intra> or anything else. If it is not set to
-C<intra>, then the search will exclude lost, very overdue, and
-withdrawn items.
+    my $biblionumber = $dbh->{'mysql_insertid'};
+    if ( $dbh->errstr ) {
+        $error.="ERROR in _koha_add_biblio $query".$dbh->errstr;
+        warn $error;
+    }
 
-C<$env> is ignored.
+    $sth->finish();
+    #warn "LEAVING _koha_add_biblio: ".$biblionumber."\n";
+    return ($biblionumber,$error);
+}
 
-C<&ItemInfo> returns a list of references-to-hash. Each element
-contains a number of keys. Most of them are table items from the
-C<biblio>, C<biblioitems>, C<items>, and C<itemtypes> tables in the
-Koha database. Other keys include:
+=head2 _koha_modify_biblio
 
 =over 4
 
-=item C<$data-E<gt>{branchname}>
+my ($biblionumber,$error) == _koha_modify_biblio($dbh,$biblio,$frameworkcode);
 
-The name (not the code) of the branch to which the book belongs.
+Internal function for updating the biblio table
 
-=item C<$data-E<gt>{datelastseen}>
-
-This is simply C<items.datelastseen>, except that while the date is
-stored in YYYY-MM-DD format in the database, here it is converted to
-DD/MM/YYYY format. A NULL date is returned as C<//>.
+=back
 
-=item C<$data-E<gt>{datedue}>
+=cut
 
-=item C<$data-E<gt>{class}>
+sub _koha_modify_biblio {
+    my ( $dbh, $biblio, $frameworkcode ) = @_;
+    my $error;
 
-This is the concatenation of C<biblioitems.classification>, the book's
-Dewey code, and C<biblioitems.subclass>.
+    my $query = "
+        UPDATE biblio
+        SET    frameworkcode = ?,
+               author = ?,
+               title = ?,
+               unititle = ?,
+               notes = ?,
+               serial = ?,
+               seriestitle = ?,
+               copyrightdate = ?,
+               abstract = ?
+        WHERE  biblionumber = ?
+        "
+    ;
+    my $sth = $dbh->prepare($query);
+    
+    $sth->execute(
+        $frameworkcode,
+        $biblio->{'author'},
+        $biblio->{'title'},
+        $biblio->{'unititle'},
+        $biblio->{'notes'},
+        $biblio->{'serial'},
+        $biblio->{'seriestitle'},
+        $biblio->{'copyrightdate'},
+        $biblio->{'abstract'},
+        $biblio->{'biblionumber'}
+    ) if $biblio->{'biblionumber'};
+
+    if ( $dbh->errstr || !$biblio->{'biblionumber'} ) {
+        $error.="ERROR in _koha_modify_biblio $query".$dbh->errstr;
+        warn $error;
+    }
+    return ( $biblio->{'biblionumber'},$error );
+}
 
-=item C<$data-E<gt>{ocount}>
+=head2 _koha_modify_biblioitem_nonmarc
 
-I think this is the number of copies of the book available.
+=over 4
 
-=item C<$data-E<gt>{order}>
+my ($biblioitemnumber,$error) = _koha_modify_biblioitem_nonmarc( $dbh, $biblioitem );
 
-If this is set, it is set to C<One Order>.
+Updates biblioitems row except for marc and marcxml, which should be changed
+via ModBiblioMarc
 
 =back
 
 =cut
-#'
-sub ItemInfo {
-       my ($env,$biblionumber,$type) = @_;
-       my $dbh   = C4::Context->dbh;
-       my $query = "SELECT *,items.notforloan as itemnotforloan FROM items, biblio, biblioitems 
-                                       left join itemtypes on biblioitems.itemtype = itemtypes.itemtype
-                                       WHERE items.biblionumber = ?
-                                       AND biblioitems.biblioitemnumber = items.biblioitemnumber
-                                       AND biblio.biblionumber = items.biblionumber";
-       $query .= " order by items.dateaccessioned desc";
-       my $sth=$dbh->prepare($query);
-       $sth->execute($biblionumber);
-       my $i=0;
-       my @results;
-       while (my $data=$sth->fetchrow_hashref){
-               my $datedue = '';
-               my $isth=$dbh->prepare("Select issues.*,borrowers.cardnumber from issues,borrowers where itemnumber = ? and returndate is null and issues.borrowernumber=borrowers.borrowernumber");
-               $isth->execute($data->{'itemnumber'});
-               if (my $idata=$isth->fetchrow_hashref){
-               $data->{borrowernumber} = $idata->{borrowernumber};
-               $data->{cardnumber} = $idata->{cardnumber};
-               $datedue = format_date($idata->{'date_due'});
-               }
-               if ($datedue eq ''){
-                       my ($restype,$reserves)=C4::Reserves2::CheckReserves($data->{'itemnumber'});
-                       if ($restype) {
-                               $datedue=$restype;
-                       }
-               }
-               $isth->finish;
-       #get branch information.....
-               my $bsth=$dbh->prepare("SELECT * FROM branches WHERE branchcode = ?");
-               $bsth->execute($data->{'holdingbranch'});
-               if (my $bdata=$bsth->fetchrow_hashref){
-                       $data->{'branchname'} = $bdata->{'branchname'};
-               }
-               my $date=format_date($data->{'datelastseen'});
-               $data->{'datelastseen'}=$date;
-               $data->{'datedue'}=$datedue;
-       # get notforloan complete status if applicable
-               my $sthnflstatus = $dbh->prepare('select authorised_value from marc_subfield_structure where kohafield="items.notforloan"');
-               $sthnflstatus->execute;
-               my ($authorised_valuecode) = $sthnflstatus->fetchrow;
-               if ($authorised_valuecode) {
-                       $sthnflstatus = $dbh->prepare("select lib from authorised_values where category=? and authorised_value=?");
-                       $sthnflstatus->execute($authorised_valuecode,$data->{itemnotforloan});
-                       my ($lib) = $sthnflstatus->fetchrow;
-                       $data->{notforloan} = $lib;
-               }
-               $results[$i]=$data;
-               $i++;
-       }
-       $sth->finish;
-       return(@results);
-}
 
-=item bibitems
-
-  ($count, @results) = &bibitems($biblionumber);
-
-Given the biblionumber for a book, C<&bibitems> looks up that book's
-biblioitems (different publications of the same book, the audio book
-and film versions, etc.).
+sub _koha_modify_biblioitem_nonmarc {
+    my ( $dbh, $biblioitem ) = @_;
+    my $error;
 
-C<$count> is the number of elements in C<@results>.
+    # re-calculate the cn_sort, it may have changed
+    my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
+
+    my $query = 
+    "UPDATE biblioitems 
+    SET biblionumber    = ?,
+        volume          = ?,
+        number          = ?,
+        itemtype        = ?,
+        isbn            = ?,
+        issn            = ?,
+        publicationyear = ?,
+        publishercode   = ?,
+        volumedate      = ?,
+        volumedesc      = ?,
+        collectiontitle = ?,
+        collectionissn  = ?,
+        collectionvolume= ?,
+        editionstatement= ?,
+        editionresponsibility = ?,
+        illus           = ?,
+        pages           = ?,
+        notes           = ?,
+        size            = ?,
+        place           = ?,
+        lccn            = ?,
+        url             = ?,
+        cn_source       = ?,
+        cn_class        = ?,
+        cn_item         = ?,
+        cn_suffix       = ?,
+        cn_sort         = ?,
+        totalissues     = ?
+        where biblioitemnumber = ?
+        ";
+    my $sth = $dbh->prepare($query);
+    $sth->execute(
+        $biblioitem->{'biblionumber'},
+        $biblioitem->{'volume'},
+        $biblioitem->{'number'},
+        $biblioitem->{'itemtype'},
+        $biblioitem->{'isbn'},
+        $biblioitem->{'issn'},
+        $biblioitem->{'publicationyear'},
+        $biblioitem->{'publishercode'},
+        $biblioitem->{'volumedate'},
+        $biblioitem->{'volumedesc'},
+        $biblioitem->{'collectiontitle'},
+        $biblioitem->{'collectionissn'},
+        $biblioitem->{'collectionvolume'},
+        $biblioitem->{'editionstatement'},
+        $biblioitem->{'editionresponsibility'},
+        $biblioitem->{'illus'},
+        $biblioitem->{'pages'},
+        $biblioitem->{'bnotes'},
+        $biblioitem->{'size'},
+        $biblioitem->{'place'},
+        $biblioitem->{'lccn'},
+        $biblioitem->{'url'},
+        $biblioitem->{'biblioitems.cn_source'},
+        $biblioitem->{'cn_class'},
+        $biblioitem->{'cn_item'},
+        $biblioitem->{'cn_suffix'},
+        $cn_sort,
+        $biblioitem->{'totalissues'},
+        $biblioitem->{'biblioitemnumber'}
+    );
+    if ( $dbh->errstr ) {
+        $error.="ERROR in _koha_modify_biblioitem_nonmarc $query".$dbh->errstr;
+        warn $error;
+    }
+    return ($biblioitem->{'biblioitemnumber'},$error);
+}
 
-C<@results> is an array of references-to-hash; the keys are the fields
-of the C<biblioitems> and C<itemtypes> tables of the Koha database. In
-addition, C<itemlost> indicates the availability of the item: if it is
-"2", then all copies of the item are long overdue; if it is "1", then
-all copies are lost; otherwise, there is at least one copy available.
-
-=cut
-#'
-sub bibitems {
-    my ($bibnum) = @_;
-    my $dbh   = C4::Context->dbh;
-    my $sth   = $dbh->prepare("SELECT biblioitems.*,
-                        itemtypes.*,
-                        MIN(items.itemlost)        as itemlost,
-                        MIN(items.dateaccessioned) as dateaccessioned
-                          FROM biblioitems, itemtypes, items
-                         WHERE biblioitems.biblionumber     = ?
-                           AND biblioitems.itemtype         = itemtypes.itemtype
-                           AND biblioitems.biblioitemnumber = items.biblioitemnumber
-                      GROUP BY items.biblioitemnumber");
-    my $count = 0;
-    my @results;
-    $sth->execute($bibnum);
-    while (my $data = $sth->fetchrow_hashref) {
-        $results[$count] = $data;
-        $count++;
-    } # while
-    $sth->finish;
-    return($count, @results);
-} # sub bibitems
+=head2 _koha_add_biblioitem
 
+=over 4
 
-=item bibitemdata
+my ($biblioitemnumber,$error) = _koha_add_biblioitem( $dbh, $biblioitem );
 
-  $itemdata = &bibitemdata($biblioitemnumber);
+Internal function to add a biblioitem
 
-Looks up the biblioitem with the given biblioitemnumber. Returns a
-reference-to-hash. The keys are the fields from the C<biblio>,
-C<biblioitems>, and C<itemtypes> tables in the Koha database, except
-that C<biblioitems.notes> is given as C<$itemdata-E<gt>{bnotes}>.
+=back
 
 =cut
-#'
-sub bibitemdata {
-    my ($bibitem) = @_;
-    my $dbh   = C4::Context->dbh;
-    my $sth   = $dbh->prepare("Select *,biblioitems.notes as bnotes from biblio, biblioitems,itemtypes where biblio.biblionumber = biblioitems.biblionumber and biblioitemnumber = ? and biblioitems.itemtype = itemtypes.itemtype");
-    my $data;
-
-    $sth->execute($bibitem);
 
-    $data = $sth->fetchrow_hashref;
+sub _koha_add_biblioitem {
+    my ( $dbh, $biblioitem ) = @_;
+    my $error;
 
-    $sth->finish;
-    return($data);
-} # sub bibitemdata
+    my ($cn_sort) = GetClassSort($biblioitem->{'biblioitems.cn_source'}, $biblioitem->{'cn_class'}, $biblioitem->{'cn_item'} );
+    my $query =
+    "INSERT INTO biblioitems SET
+        biblionumber    = ?,
+        volume          = ?,
+        number          = ?,
+        itemtype        = ?,
+        isbn            = ?,
+        issn            = ?,
+        publicationyear = ?,
+        publishercode   = ?,
+        volumedate      = ?,
+        volumedesc      = ?,
+        collectiontitle = ?,
+        collectionissn  = ?,
+        collectionvolume= ?,
+        editionstatement= ?,
+        editionresponsibility = ?,
+        illus           = ?,
+        pages           = ?,
+        notes           = ?,
+        size            = ?,
+        place           = ?,
+        lccn            = ?,
+        marc            = ?,
+        url             = ?,
+        cn_source       = ?,
+        cn_class        = ?,
+        cn_item         = ?,
+        cn_suffix       = ?,
+        cn_sort         = ?,
+        totalissues     = ?
+        ";
+    my $sth = $dbh->prepare($query);
+    $sth->execute(
+        $biblioitem->{'biblionumber'},
+        $biblioitem->{'volume'},
+        $biblioitem->{'number'},
+        $biblioitem->{'itemtype'},
+        $biblioitem->{'isbn'},
+        $biblioitem->{'issn'},
+        $biblioitem->{'publicationyear'},
+        $biblioitem->{'publishercode'},
+        $biblioitem->{'volumedate'},
+        $biblioitem->{'volumedesc'},
+        $biblioitem->{'collectiontitle'},
+        $biblioitem->{'collectionissn'},
+        $biblioitem->{'collectionvolume'},
+        $biblioitem->{'editionstatement'},
+        $biblioitem->{'editionresponsibility'},
+        $biblioitem->{'illus'},
+        $biblioitem->{'pages'},
+        $biblioitem->{'bnotes'},
+        $biblioitem->{'size'},
+        $biblioitem->{'place'},
+        $biblioitem->{'lccn'},
+        $biblioitem->{'marc'},
+        $biblioitem->{'url'},
+        $biblioitem->{'biblioitems.cn_source'},
+        $biblioitem->{'cn_class'},
+        $biblioitem->{'cn_item'},
+        $biblioitem->{'cn_suffix'},
+        $cn_sort,
+        $biblioitem->{'totalissues'}
+    );
+    my $bibitemnum = $dbh->{'mysql_insertid'};
+    if ( $dbh->errstr ) {
+        $error.="ERROR in _koha_add_biblioitem $query".$dbh->errstr;
+        warn $error;
+    }
+    $sth->finish();
+    return ($bibitemnum,$error);
+}
 
+=head2 _koha_delete_biblio
 
-=item getbibliofromitemnumber
+=over 4
 
-  $item = &getbibliofromitemnumber($env, $dbh, $itemnumber);
+$error = _koha_delete_biblio($dbh,$biblionumber);
 
-Looks up the item with the given itemnumber.
+Internal sub for deleting from biblio table -- also saves to deletedbiblio
 
-C<$env> and C<$dbh> are ignored.
+C<$dbh> - the database handle
+C<$biblionumber> - the biblionumber of the biblio to be deleted
 
-C<&itemnodata> returns a reference-to-hash whose keys are the fields
-from the C<biblio>, C<biblioitems>, and C<items> tables in the Koha
-database.
+=back
 
 =cut
-#'
-sub getbibliofromitemnumber {
-  my ($env,$dbh,$itemnumber) = @_;
-  $dbh = C4::Context->dbh;
-  my $sth=$dbh->prepare("Select * from biblio,items,biblioitems
-    where items.itemnumber = ?
-    and biblio.biblionumber = items.biblionumber
-    and biblioitems.biblioitemnumber = items.biblioitemnumber");
-#  print $query;
-  $sth->execute($itemnumber);
-  my $data=$sth->fetchrow_hashref;
-  $sth->finish;
-  return($data);
-}
 
-=item barcodes
+# FIXME: add error handling
 
-  @barcodes = &barcodes($biblioitemnumber);
+sub _koha_delete_biblio {
+    my ( $dbh, $biblionumber ) = @_;
 
-Given a biblioitemnumber, looks up the corresponding items.
+    # get all the data for this biblio
+    my $sth = $dbh->prepare("SELECT * FROM biblio WHERE biblionumber=?");
+    $sth->execute($biblionumber);
 
-Returns an array of references-to-hash; the keys are C<barcode> and
-C<itemlost>.
+    if ( my $data = $sth->fetchrow_hashref ) {
 
-The returned items include very overdue items, but not lost ones.
+        # save the record in deletedbiblio
+        # find the fields to save
+        my $query = "INSERT INTO deletedbiblio SET ";
+        my @bind  = ();
+        foreach my $temp ( keys %$data ) {
+            $query .= "$temp = ?,";
+            push( @bind, $data->{$temp} );
+        }
 
-=cut
-#'
-sub barcodes{
-    #called from request.pl
-    my ($biblioitemnumber)=@_;
-    my $dbh = C4::Context->dbh;
-    my $sth=$dbh->prepare("SELECT barcode, itemlost, holdingbranch FROM items
-                           WHERE biblioitemnumber = ?
-                             AND (wthdrawn <> 1 OR wthdrawn IS NULL)");
-    $sth->execute($biblioitemnumber);
-    my @barcodes;
-    my $i=0;
-    while (my $data=$sth->fetchrow_hashref){
-       $barcodes[$i]=$data;
-       $i++;
+        # replace the last , by ",?)"
+        $query =~ s/\,$//;
+        my $bkup_sth = $dbh->prepare($query);
+        $bkup_sth->execute(@bind);
+        $bkup_sth->finish;
+
+        # delete the biblio
+        my $del_sth = $dbh->prepare("DELETE FROM biblio WHERE biblionumber=?");
+        $del_sth->execute($biblionumber);
+        $del_sth->finish;
     }
     $sth->finish;
-    return(@barcodes);
-}
-
-
-=item itemdata
-
-  $item = &itemdata($barcode);
-
-Looks up the item with the given barcode, and returns a
-reference-to-hash containing information about that item. The keys of
-the hash are the fields from the C<items> and C<biblioitems> tables in
-the Koha database.
-
-=cut
-#'
-sub get_item_from_barcode {
-  my ($barcode)=@_;
-  my $dbh = C4::Context->dbh;
-  my $sth=$dbh->prepare("Select * from items,biblioitems where barcode=?
-  and items.biblioitemnumber=biblioitems.biblioitemnumber");
-  $sth->execute($barcode);
-  my $data=$sth->fetchrow_hashref;
-  $sth->finish;
-  return($data);
+    return undef;
 }
 
+=head2 _koha_delete_biblioitems
 
-=item itemissues
-
-  @issues = &itemissues($biblioitemnumber, $biblio);
-
-Looks up information about who has borrowed the bookZ<>(s) with the
-given biblioitemnumber.
+=over 4
 
-C<$biblio> is ignored.
+$error = _koha_delete_biblioitems($dbh,$biblioitemnumber);
 
-C<&itemissues> returns an array of references-to-hash. The keys
-include the fields from the C<items> table in the Koha database.
-Additional keys include:
+Internal sub for deleting from biblioitems table -- also saves to deletedbiblioitems
 
-=over 4
+C<$dbh> - the database handle
+C<$biblionumber> - the biblioitemnumber of the biblioitem to be deleted
 
-=item C<date_due>
-
-If the item is currently on loan, this gives the due date.
+=back
 
-If the item is not on loan, then this is either "Available" or
-"Cancelled", if the item has been withdrawn.
+=cut
 
-=item C<card>
+# FIXME: add error handling
 
-If the item is currently on loan, this gives the card number of the
-patron who currently has the item.
+sub _koha_delete_biblioitems {
+    my ( $dbh, $biblioitemnumber ) = @_;
 
-=item C<timestamp0>, C<timestamp1>, C<timestamp2>
+    # get all the data for this biblioitem
+    my $sth =
+      $dbh->prepare("SELECT * FROM biblioitems WHERE biblioitemnumber=?");
+    $sth->execute($biblioitemnumber);
 
-These give the timestamp for the last three times the item was
-borrowed.
+    if ( my $data = $sth->fetchrow_hashref ) {
 
-=item C<card0>, C<card1>, C<card2>
+        # save the record in deletedbiblioitems
+        # find the fields to save
+        my $query = "INSERT INTO deletedbiblioitems SET ";
+        my @bind  = ();
+        foreach my $temp ( keys %$data ) {
+            $query .= "$temp = ?,";
+            push( @bind, $data->{$temp} );
+        }
 
-The card number of the last three patrons who borrowed this item.
+        # replace the last , by ",?)"
+        $query =~ s/\,$//;
+        my $bkup_sth = $dbh->prepare($query);
+        $bkup_sth->execute(@bind);
+        $bkup_sth->finish;
+
+        # delete the biblioitem
+        my $del_sth =
+          $dbh->prepare("DELETE FROM biblioitems WHERE biblioitemnumber=?");
+        $del_sth->execute($biblioitemnumber);
+        $del_sth->finish;
+    }
+    $sth->finish;
+    return undef;
+}
 
-=item C<borrower0>, C<borrower1>, C<borrower2>
+=head1 UNEXPORTED FUNCTIONS
 
-The borrower number of the last three patrons who borrowed this item.
+=head2 ModBiblioMarc
 
-=back
+    &ModBiblioMarc($newrec,$biblionumber,$frameworkcode);
+    
+    Add MARC data for a biblio to koha 
+    
+    Function exported, but should NOT be used, unless you really know what you're doing
 
 =cut
-#'
-sub itemissues {
-    my ($bibitem, $biblio)=@_;
-    my $dbh   = C4::Context->dbh;
-    # FIXME - If this function die()s, the script will abort, and the
-    # user won't get anything; depending on how far the script has
-    # gotten, the user might get a blank page. It would be much better
-    # to at least print an error message. The easiest way to do this
-    # is to set $SIG{__DIE__}.
-    my $sth   = $dbh->prepare("Select * from items where
-items.biblioitemnumber = ?")
-      || die $dbh->errstr;
-    my $i     = 0;
-    my @results;
 
-    $sth->execute($bibitem)
-      || die $sth->errstr;
-
-    while (my $data = $sth->fetchrow_hashref) {
-        # Find out who currently has this item.
-        # FIXME - Wouldn't it be better to do this as a left join of
-        # some sort? Currently, this code assumes that if
-        # fetchrow_hashref() fails, then the book is on the shelf.
-        # fetchrow_hashref() can fail for any number of reasons (e.g.,
-        # database server crash), not just because no items match the
-        # search criteria.
-        my $sth2   = $dbh->prepare("select * from issues,borrowers
-where itemnumber = ?
-and returndate is NULL
-and issues.borrowernumber = borrowers.borrowernumber");
-
-        $sth2->execute($data->{'itemnumber'});
-        if (my $data2 = $sth2->fetchrow_hashref) {
-            $data->{'date_due'} = $data2->{'date_due'};
-            $data->{'card'}     = $data2->{'cardnumber'};
-           $data->{'borrower'}     = $data2->{'borrowernumber'};
-        } else {
-            if ($data->{'wthdrawn'} eq '1') {
-                $data->{'date_due'} = 'Cancelled';
-            } else {
-                $data->{'date_due'} = 'Available';
-            } # else
-        } # else
-
-        $sth2->finish;
-
-        # Find the last 3 people who borrowed this item.
-        $sth2 = $dbh->prepare("select * from issues, borrowers
-                                               where itemnumber = ?
-                                                                       and issues.borrowernumber = borrowers.borrowernumber
-                                                                       and returndate is not NULL
-                                                                       order by returndate desc,timestamp desc") || die $dbh->errstr;
-        $sth2->execute($data->{'itemnumber'}) || die $sth2->errstr;
-        for (my $i2 = 0; $i2 < 2; $i2++) { # FIXME : error if there is less than 3 pple borrowing this item
-            if (my $data2 = $sth2->fetchrow_hashref) {
-                $data->{"timestamp$i2"} = $data2->{'timestamp'};
-                $data->{"card$i2"}      = $data2->{'cardnumber'};
-                $data->{"borrower$i2"}  = $data2->{'borrowernumber'};
-            } # if
-        } # for
-
-        $sth2->finish;
-        $results[$i] = $data;
-        $i++;
+sub ModBiblioMarc {
+    
+# pass the MARC::Record to this function, and it will create the records in the marc field
+    my ( $record, $biblionumber, $frameworkcode ) = @_;
+    my $dbh = C4::Context->dbh;
+    my @fields = $record->fields();
+    if ( !$frameworkcode ) {
+        $frameworkcode = "";
     }
+    my $sth =
+      $dbh->prepare("UPDATE biblio SET frameworkcode=? WHERE biblionumber=?");
+    $sth->execute( $frameworkcode, $biblionumber );
+    $sth->finish;
+    my $encoding = C4::Context->preference("marcflavour");
 
+    # deal with UNIMARC field 100 (encoding) : create it if needed & set encoding to unicode
+    if ( $encoding eq "UNIMARC" ) {
+        my $string;
+        if ( length($record->subfield( 100, "a" )) == 35 ) {
+            $string = $record->subfield( 100, "a" );
+            my $f100 = $record->field(100);
+            $record->delete_field($f100);
+        }
+        else {
+            $string = POSIX::strftime( "%Y%m%d", localtime );
+            $string =~ s/\-//g;
+            $string = sprintf( "%-*s", 35, $string );
+        }
+        substr( $string, 22, 6, "frey50" );
+        unless ( $record->subfield( 100, "a" ) ) {
+            $record->insert_grouped_field(
+                MARC::Field->new( 100, "", "", "a" => $string ) );
+        }
+    }
+    ModZebra($biblionumber,"specialUpdate","biblioserver",$record);
+    $sth =
+      $dbh->prepare(
+        "UPDATE biblioitems SET marc=?,marcxml=? WHERE biblionumber=?");
+    $sth->execute( $record->as_usmarc(), $record->as_xml_record($encoding),
+        $biblionumber );
     $sth->finish;
-    return(@results);
+    return $biblionumber;
 }
 
-=item getsubject
+=head2 z3950_extended_services
 
-  ($count, $subjects) = &getsubject($biblionumber);
+z3950_extended_services($serviceType,$serviceOptions,$record);
 
-Looks up the subjects of the book with the given biblionumber. Returns
-a two-element list. C<$subjects> is a reference-to-array, where each
-element is a subject of the book, and C<$count> is the number of
-elements in C<$subjects>.
+    z3950_extended_services is used to handle all interactions with Zebra's extended serices package, which is employed to perform all management of the MARC data stored in Zebra.
 
-=cut
-#'
-sub getsubject {
-  my ($bibnum)=@_;
-  my $dbh = C4::Context->dbh;
-  my $sth=$dbh->prepare("Select * from bibliosubject where biblionumber=?");
-  $sth->execute($bibnum);
-  my @results;
-  my $i=0;
-  while (my $data=$sth->fetchrow_hashref){
-    $results[$i]=$data;
-    $i++;
-  }
-  $sth->finish;
-  return($i,\@results);
-}
+C<$serviceType> one of: itemorder,create,drop,commit,update,xmlupdate
 
-=item getaddauthor
+C<$serviceOptions> a has of key/value pairs. For instance, if service_type is 'update', $service_options should contain:
 
-  ($count, $authors) = &getaddauthor($biblionumber);
+    action => update action, one of specialUpdate, recordInsert, recordReplace, recordDelete, elementUpdate.
 
-Looks up the additional authors for the book with the given
-biblionumber.
+and maybe
 
-Returns a two-element list. C<$authors> is a reference-to-array, where
-each element is an additional author, and C<$count> is the number of
-elements in C<$authors>.
+    recordidOpaque => Opaque Record ID (user supplied) or recordidNumber => Record ID number (system number).
+    syntax => the record syntax (transfer syntax)
+    databaseName = Database from connection object
 
-=cut
-#'
-sub getaddauthor {
-  my ($bibnum)=@_;
-  my $dbh = C4::Context->dbh;
-  my $sth=$dbh->prepare("Select * from additionalauthors where biblionumber=?");
-  $sth->execute($bibnum);
-  my @results;
-  my $i=0;
-  while (my $data=$sth->fetchrow_hashref){
-    $results[$i]=$data;
-    $i++;
-  }
-  $sth->finish;
-  return($i,\@results);
-}
+    To set serviceOptions, call set_service_options($serviceType)
 
+C<$record> the record, if one is needed for the service type
 
-=item getsubtitle
-
-  ($count, $subtitles) = &getsubtitle($biblionumber);
-
-Looks up the subtitles for the book with the given biblionumber.
-
-Returns a two-element list. C<$subtitles> is a reference-to-array,
-where each element is a subtitle, and C<$count> is the number of
-elements in C<$subtitles>.
+    A record should be in XML. You can convert it to XML from MARC by running it through marc2xml().
 
 =cut
-#'
-sub getsubtitle {
-  my ($bibnum)=@_;
-  my $dbh = C4::Context->dbh;
-  my $sth=$dbh->prepare("Select * from bibliosubtitle where biblionumber=?");
-  $sth->execute($bibnum);
-  my @results;
-  my $i=0;
-  while (my $data=$sth->fetchrow_hashref){
-    $results[$i]=$data;
-    $i++;
-  }
-  $sth->finish;
-  return($i,\@results);
-}
 
+sub z3950_extended_services {
+    my ( $server, $serviceType, $action, $serviceOptions ) = @_;
 
-=item getwebsites
+    # get our connection object
+    my $Zconn = C4::Context->Zconn( $server, 0, 1 );
 
-  ($count, @websites) = &getwebsites($biblionumber);
+    # create a new package object
+    my $Zpackage = $Zconn->package();
 
-Looks up the web sites pertaining to the book with the given
-biblionumber.
+    # set our options
+    $Zpackage->option( action => $action );
 
-C<$count> is the number of elements in C<@websites>.
+    if ( $serviceOptions->{'databaseName'} ) {
+        $Zpackage->option( databaseName => $serviceOptions->{'databaseName'} );
+    }
+    if ( $serviceOptions->{'recordIdNumber'} ) {
+        $Zpackage->option(
+            recordIdNumber => $serviceOptions->{'recordIdNumber'} );
+    }
+    if ( $serviceOptions->{'recordIdOpaque'} ) {
+        $Zpackage->option(
+            recordIdOpaque => $serviceOptions->{'recordIdOpaque'} );
+    }
 
-C<@websites> is an array of references-to-hash; the keys are the
-fields from the C<websites> table in the Koha database.
+ # this is an ILL request (Zebra doesn't support it, but Koha could eventually)
+ #if ($serviceType eq 'itemorder') {
+ #   $Zpackage->option('contact-name' => $serviceOptions->{'contact-name'});
+ #   $Zpackage->option('contact-phone' => $serviceOptions->{'contact-phone'});
+ #   $Zpackage->option('contact-email' => $serviceOptions->{'contact-email'});
+ #   $Zpackage->option('itemorder-item' => $serviceOptions->{'itemorder-item'});
+ #}
 
-=cut
-#FIXME : could maybe be deleted. Otherwise, would be better in a Websites.pm package
-#(with add / modify / delete subs)
+    if ( $serviceOptions->{record} ) {
+        $Zpackage->option( record => $serviceOptions->{record} );
 
-sub getwebsites {
-    my ($biblionumber) = @_;
-    my $dbh   = C4::Context->dbh;
-    my $sth   = $dbh->prepare("Select * from websites where biblionumber = ?");
-    my $count = 0;
-    my @results;
+        # can be xml or marc
+        if ( $serviceOptions->{'syntax'} ) {
+            $Zpackage->option( syntax => $serviceOptions->{'syntax'} );
+        }
+    }
 
-    $sth->execute($biblionumber);
-    while (my $data = $sth->fetchrow_hashref) {
-        # FIXME - The URL scheme shouldn't be stripped off, at least
-        # not here, since it's part of the URL, and will be useful in
-        # constructing a link to the site. If you don't want the user
-        # to see the "http://" part, strip that off when building the
-        # HTML code.
-        $data->{'url'} =~ s/^http:\/\///;      # FIXME - Leaning toothpick
-                                               # syndrome
-        $results[$count] = $data;
-       $count++;
-    } # while
+    # send the request, handle any exception encountered
+    eval { $Zpackage->send($serviceType) };
+    if ( $@ && $@->isa("ZOOM::Exception") ) {
+        return "error:  " . $@->code() . " " . $@->message() . "\n";
+    }
 
-    $sth->finish;
-    return($count, @results);
-} # sub getwebsites
+    # free up package resources
+    $Zpackage->destroy();
+}
 
-=item getwebbiblioitems
+=head2 set_service_options
 
-  ($count, @results) = &getwebbiblioitems($biblionumber);
+my $serviceOptions = set_service_options($serviceType);
 
-Given a book's biblionumber, looks up the web versions of the book
-(biblioitems with itemtype C<WEB>).
+C<$serviceType> itemorder,create,drop,commit,update,xmlupdate
 
-C<$count> is the number of items in C<@results>. C<@results> is an
-array of references-to-hash; the keys are the items from the
-C<biblioitems> table of the Koha database.
+Currently, we only support 'create', 'commit', and 'update'. 'drop' support will be added as soon as Zebra supports it.
 
 =cut
-#'
-sub getwebbiblioitems {
-    my ($biblionumber) = @_;
-    my $dbh   = C4::Context->dbh;
-    my $sth   = $dbh->prepare("Select * from biblioitems where biblionumber = ?
-and itemtype = 'WEB'");
-    my $count = 0;
-    my @results;
-
-    $sth->execute($biblionumber);
-    while (my $data = $sth->fetchrow_hashref) {
-        $data->{'url'} =~ s/^http:\/\///;
-        $results[$count] = $data;
-        $count++;
-    } # while
 
-    $sth->finish;
-    return($count, @results);
-} # sub getwebbiblioitems
+sub set_service_options {
+    my ($serviceType) = @_;
+    my $serviceOptions;
 
-sub char_decode {
+# FIXME: This needs to be an OID ... if we ever need 'syntax' this sub will need to change
+#   $serviceOptions->{ 'syntax' } = ''; #zebra doesn't support syntaxes other than xml
 
-    # converts ISO 5426 coded string to ISO 8859-1
-    # sloppy code : should be improved in next issue
-    my ( $string, $encoding ) = @_;
-    $_ = $string;
+    if ( $serviceType eq 'commit' ) {
 
-    #  $encoding = C4::Context->preference("marcflavour") unless $encoding;
-    if ( $encoding eq "UNIMARC" ) {
-#         s/\xe1/Æ/gm;
-        s/\xe2/Ð/gm;
-        s/\xe9/Ø/gm;
-        s/\xec/þ/gm;
-        s/\xf1/æ/gm;
-        s/\xf3/ð/gm;
-        s/\xf9/ø/gm;
-        s/\xfb/ß/gm;
-        s/\xc1\x61/à/gm;
-        s/\xc1\x65/è/gm;
-        s/\xc1\x69/ì/gm;
-        s/\xc1\x6f/ò/gm;
-        s/\xc1\x75/ù/gm;
-        s/\xc1\x41/À/gm;
-        s/\xc1\x45/È/gm;
-        s/\xc1\x49/Ì/gm;
-        s/\xc1\x4f/Ò/gm;
-        s/\xc1\x55/Ù/gm;
-        s/\xc2\x41/Á/gm;
-        s/\xc2\x45/É/gm;
-        s/\xc2\x49/Í/gm;
-        s/\xc2\x4f/Ó/gm;
-        s/\xc2\x55/Ú/gm;
-        s/\xc2\x59/Ý/gm;
-        s/\xc2\x61/á/gm;
-        s/\xc2\x65/é/gm;
-        s/\xc2\x69/í/gm;
-        s/\xc2\x6f/ó/gm;
-        s/\xc2\x75/ú/gm;
-        s/\xc2\x79/ý/gm;
-        s/\xc3\x41/Â/gm;
-        s/\xc3\x45/Ê/gm;
-        s/\xc3\x49/Î/gm;
-        s/\xc3\x4f/Ô/gm;
-        s/\xc3\x55/Û/gm;
-        s/\xc3\x61/â/gm;
-        s/\xc3\x65/ê/gm;
-        s/\xc3\x69/î/gm;
-        s/\xc3\x6f/ô/gm;
-        s/\xc3\x75/û/gm;
-        s/\xc4\x41/Ã/gm;
-        s/\xc4\x4e/Ñ/gm;
-        s/\xc4\x4f/Õ/gm;
-        s/\xc4\x61/ã/gm;
-        s/\xc4\x6e/ñ/gm;
-        s/\xc4\x6f/õ/gm;
-        s/\xc8\x41/Ä/gm;
-        s/\xc8\x45/Ë/gm;
-        s/\xc8\x49/Ï/gm;
-        s/\xc8\x61/ä/gm;
-        s/\xc8\x65/ë/gm;
-        s/\xc8\x69/ï/gm;
-        s/\xc8\x6F/ö/gm;
-        s/\xc8\x75/ü/gm;
-        s/\xc8\x76/ÿ/gm;
-        s/\xc9\x41/Ä/gm;
-        s/\xc9\x45/Ë/gm;
-        s/\xc9\x49/Ï/gm;
-        s/\xc9\x4f/Ö/gm;
-        s/\xc9\x55/Ü/gm;
-        s/\xc9\x61/ä/gm;
-        s/\xc9\x6f/ö/gm;
-        s/\xc9\x75/ü/gm;
-        s/\xca\x41/Å/gm;
-        s/\xca\x61/å/gm;
-        s/\xd0\x43/Ç/gm;
-        s/\xd0\x63/ç/gm;
+        # nothing to do
+    }
+    if ( $serviceType eq 'create' ) {
 
-        # this handles non-sorting blocks (if implementation requires this)
-        $string = nsb_clean($_);
+        # nothing to do
     }
-    elsif ( $encoding eq "USMARC" || $encoding eq "MARC21" ) {
-        if (/[\xc1-\xff]/) {
-            s/\xe1\x61/à/gm;
-            s/\xe1\x65/è/gm;
-            s/\xe1\x69/ì/gm;
-            s/\xe1\x6f/ò/gm;
-            s/\xe1\x75/ù/gm;
-            s/\xe1\x41/À/gm;
-            s/\xe1\x45/È/gm;
-            s/\xe1\x49/Ì/gm;
-            s/\xe1\x4f/Ò/gm;
-            s/\xe1\x55/Ù/gm;
-            s/\xe2\x41/Á/gm;
-            s/\xe2\x45/É/gm;
-            s/\xe2\x49/Í/gm;
-            s/\xe2\x4f/Ó/gm;
-            s/\xe2\x55/Ú/gm;
-            s/\xe2\x59/Ý/gm;
-            s/\xe2\x61/á/gm;
-            s/\xe2\x65/é/gm;
-            s/\xe2\x69/í/gm;
-            s/\xe2\x6f/ó/gm;
-            s/\xe2\x75/ú/gm;
-            s/\xe2\x79/ý/gm;
-            s/\xe3\x41/Â/gm;
-            s/\xe3\x45/Ê/gm;
-            s/\xe3\x49/Î/gm;
-            s/\xe3\x4f/Ô/gm;
-            s/\xe3\x55/Û/gm;
-            s/\xe3\x61/â/gm;
-            s/\xe3\x65/ê/gm;
-            s/\xe3\x69/î/gm;
-            s/\xe3\x6f/ô/gm;
-            s/\xe3\x75/û/gm;
-            s/\xe4\x41/Ã/gm;
-            s/\xe4\x4e/Ñ/gm;
-            s/\xe4\x4f/Õ/gm;
-            s/\xe4\x61/ã/gm;
-            s/\xe4\x6e/ñ/gm;
-            s/\xe4\x6f/õ/gm;
-            s/\xe8\x45/Ë/gm;
-            s/\xe8\x49/Ï/gm;
-            s/\xe8\x65/ë/gm;
-            s/\xe8\x69/ï/gm;
-            s/\xe8\x76/ÿ/gm;
-            s/\xe9\x41/Ä/gm;
-            s/\xe9\x4f/Ö/gm;
-            s/\xe9\x55/Ü/gm;
-            s/\xe9\x61/ä/gm;
-            s/\xe9\x6f/ö/gm;
-            s/\xe9\x75/ü/gm;
-            s/\xea\x41/Å/gm;
-            s/\xea\x61/å/gm;
-
-            # this handles non-sorting blocks (if implementation requires this)
-            $string = nsb_clean($_);
-        }
+    if ( $serviceType eq 'drop' ) {
+        die "ERROR: 'drop' not currently supported (by Zebra)";
     }
-    return ($string);
-}
-
-sub nsb_clean {
-    my $NSB = '\x88';    # NSB : begin Non Sorting Block
-    my $NSE = '\x89';    # NSE : Non Sorting Block end
-                         # handles non sorting blocks
-    my ($string) = @_;
-    $_ = $string;
-    s/$NSB/(/gm;
-    s/[ ]{0,1}$NSE/) /gm;
-    $string = $_;
-    return ($string);
-}
-
-sub FindDuplicate {
-       my ($record)=@_;
-       my $dbh = C4::Context->dbh;
-       my $result = MARCmarc2koha($dbh,$record,'');
-       my $sth;
-       my ($biblionumber,$bibid,$title);
-       # search duplicate on ISBN, easy and fast...
-       if ($result->{isbn}) {
-               $sth = $dbh->prepare("select biblio.biblionumber,bibid,title from biblio,biblioitems,marc_biblio where biblio.biblionumber=biblioitems.biblionumber and marc_biblio.biblionumber=biblioitems.biblionumber and isbn=?");
-               $sth->execute($result->{'isbn'});
-               ($biblionumber,$bibid,$title) = $sth->fetchrow;
-               return $biblionumber,$bibid,$title if ($biblionumber);
-       }
-       # a more complex search : build a request for SearchMarc::catalogsearch()
-       my (@tags, @and_or, @excluding, @operator, @value, $offset,$length);
-       # search on biblio.title
-       my ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblio.title","");
-       if ($record->field($tag)) {
-               if ($record->field($tag)->subfields($subfield)) {
-                       push @tags, "'".$tag.$subfield."'";
-                       push @and_or, "and";
-                       push @excluding, "";
-                       push @operator, "contains";
-                       push @value, $record->field($tag)->subfield($subfield);
-#                      warn "for title, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
-               }
-       }
-       # ... and on biblio.author
-       ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblio.author","");
-       if ($record->field($tag)) {
-               if ($record->field($tag)->subfields($subfield)) {
-                       push @tags, "'".$tag.$subfield."'";
-                       push @and_or, "and";
-                       push @excluding, "";
-                       push @operator, "contains";
-                       push @value, $record->field($tag)->subfield($subfield);
-#                      warn "for author, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
-               }
-       }
-       # ... and on publicationyear.
-       ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.publicationyear","");
-       if ($record->field($tag)) {
-               if ($record->field($tag)->subfields($subfield)) {
-                       push @tags, "'".$tag.$subfield."'";
-                       push @and_or, "and";
-                       push @excluding, "";
-                       push @operator, "=";
-                       push @value, $record->field($tag)->subfield($subfield);
-#                      warn "for publicationyear, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
-               }
-       }
-       # ... and on size.
-       ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.size","");
-       if ($record->field($tag)) {
-               if ($record->field($tag)->subfields($subfield)) {
-                       push @tags, "'".$tag.$subfield."'";
-                       push @and_or, "and";
-                       push @excluding, "";
-                       push @operator, "=";
-                       push @value, $record->field($tag)->subfield($subfield);
-#                      warn "for size, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
-               }
-       }
-       # ... and on publisher.
-       ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.publishercode","");
-       if ($record->field($tag)) {
-               if ($record->field($tag)->subfields($subfield)) {
-                       push @tags, "'".$tag.$subfield."'";
-                       push @and_or, "and";
-                       push @excluding, "";
-                       push @operator, "=";
-                       push @value, $record->field($tag)->subfield($subfield);
-#                      warn "for publishercode, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
-               }
-       }
-       # ... and on volume.
-       ($tag,$subfield) = MARCfind_marc_from_kohafield($dbh,"biblioitems.volume","");
-       if ($record->field($tag)) {
-               if ($record->field($tag)->subfields($subfield)) {
-                       push @tags, "'".$tag.$subfield."'";
-                       push @and_or, "and";
-                       push @excluding, "";
-                       push @operator, "=";
-                       push @value, $record->field($tag)->subfield($subfield);
-#                      warn "for volume, I add $tag / $subfield".$record->field($tag)->subfield($subfield);
-               }
-       }
-
-       my ($finalresult,$nbresult) = C4::SearchMarc::catalogsearch($dbh,\@tags,\@and_or,\@excluding,\@operator,\@value,0,10);
-       # there is at least 1 result => return the 1st one
-       if ($nbresult) {
-#              warn "$nbresult => ".@$finalresult[0]->{biblionumber},@$finalresult[0]->{bibid},@$finalresult[0]->{title};
-               return @$finalresult[0]->{biblionumber},@$finalresult[0]->{bibid},@$finalresult[0]->{title};
-       }
-       # no result, returns nothing
-       return;
-}
-
-sub DisplayISBN {
-       my ($isbn)=@_;
-       my $seg1;
-       if(substr($isbn, 0, 1) <=7) {
-               $seg1 = substr($isbn, 0, 1);
-       } elsif(substr($isbn, 0, 2) <= 94) {
-               $seg1 = substr($isbn, 0, 2);
-       } elsif(substr($isbn, 0, 3) <= 995) {
-               $seg1 = substr($isbn, 0, 3);
-       } elsif(substr($isbn, 0, 4) <= 9989) {
-               $seg1 = substr($isbn, 0, 4);
-       } else {
-               $seg1 = substr($isbn, 0, 5);
-       }
-       my $x = substr($isbn, length($seg1));
-       my $seg2;
-       if(substr($x, 0, 2) <= 19) {
-#              if(sTmp2 < 10) sTmp2 = "0" sTmp2;
-               $seg2 = substr($x, 0, 2);
-       } elsif(substr($x, 0, 3) <= 699) {
-               $seg2 = substr($x, 0, 3);
-       } elsif(substr($x, 0, 4) <= 8399) {
-               $seg2 = substr($x, 0, 4);
-       } elsif(substr($x, 0, 5) <= 89999) {
-               $seg2 = substr($x, 0, 5);
-       } elsif(substr($x, 0, 6) <= 9499999) {
-               $seg2 = substr($x, 0, 6);
-       } else {
-               $seg2 = substr($x, 0, 7);
-       }
-       my $seg3=substr($x,length($seg2));
-       $seg3=substr($seg3,0,length($seg3)-1) ;
-       my $seg4 = substr($x, -1, 1);
-       return "$seg1-$seg2-$seg3-$seg4";
+    return $serviceOptions;
 }
 
+1;
 
-END { }    # module clean-up code here (global destructor)
-
-=back
+__END__
 
 =head1 AUTHOR
 
@@ -2904,115 +3140,6 @@ Koha Developement team <info@koha.org>
 
 Paul POULAIN paul.poulain@free.fr
 
-=cut
+Joshua Ferraro jmf@liblime.com
 
-# $Id$
-# $Log$
-# Revision 1.137  2006/02/13 16:34:26  tipaul
-# fixing some warnings (perl -w should be quiet)
-#
-# Revision 1.136  2006/01/10 17:01:29  tipaul
-# adding a XMLgetbiblio in Biblio.pm (1st draft, to use with zebra)
-#
-# Revision 1.135  2006/01/06 16:39:37  tipaul
-# synch'ing head and rel_2_2 (from 2.2.5, including npl templates)
-# Seems not to break too many things, but i'm probably wrong here.
-# at least, new features/bugfixes from 2.2.5 are here (tested on some features on my head local copy)
-#
-# - removing useless directories (koha-html and koha-plucene)
-#
-# Revision 1.134  2006/01/04 15:54:55  tipaul
-# utf8 is a : go for beta test in HEAD.
-# some explanations :
-# - updater/updatedatabase => will transform all tables in innoDB (not related to utf8, just to warn you) AND collate them in utf8 / utf8_general_ci. The SQL command is : ALTER TABLE tablename DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci.
-# - *-top.inc will show the pages in utf8
-# - THE HARD THING : for me, mysql-client and mysql-server were set up to communicate in iso8859-1, whatever the mysql collation ! Thus, pages were improperly shown, as datas were transmitted in iso8859-1 format ! After a full day of investigation, someone on usenet pointed "set NAMES 'utf8'" to explain that I wanted utf8. I could put this in my.cnf, but if I do that, ALL databases will "speak" in utf8, that's not what we want. Thus, I added a line in Context.pm : everytime a DB handle is opened, the communication is set to utf8.
-# - using marcxml field and no more the iso2709 raw marc biblioitems.marc field.
-#
-# Revision 1.133  2005/12/12 14:25:51  thd
-#
-#
-# Reverse array filled with elements from repeated subfields
-# to avoid last to first concatenation of elements in Koha DB.-
-#
-# Revision 1.132  2005-10-26 09:12:33  tipaul
-# big commit, still breaking things...
-#
-# * synch with rel_2_2. Probably the last non manual synch, as rel_2_2 should not be modified deeply.
-# * code cleaning (cleaning warnings from perl -w) continued
-#
-# Revision 1.131  2005/09/22 10:01:45  tipaul
-# see mail on koha-devel : code cleaning on Search.pm + normalizing API + use of biblionumber everywhere (instead of bn, biblio, ...)
-#
-# Revision 1.130  2005/09/02 14:34:14  tipaul
-# continuing the work to move to zebra. Begin of work for MARC=OFF support.
-# IMPORTANT NOTE : the MARCkoha2marc sub API has been modified. Instead of biblionumber & biblioitemnumber, it now gets a hash.
-# The sub is used only in Biblio.pm, so the API change should be harmless (except for me, but i'm aware ;-) )
-#
-# Revision 1.129  2005/08/12 13:50:31  tipaul
-# removing useless sub declarations
-#
-# Revision 1.128  2005/08/11 16:12:47  tipaul
-# Playing with the zebra...
-#
-# * go to koha cvs home directory
-# * in misc/zebra there is a unimarc directory. I suggest that marc21 libraries create a marc21 directory
-# * put your zebra.cfg files here & create your database.
-# * from koha cvs home directory, ln -s misc/zebra/marc21 zebra (I mean create a symbolic link to YOUR zebra directory)
-# * now, everytime you add/modify a biblio/item your zebra DB is updated correctly.
-#
-# NOTE :
-# * this uses a system call in perl. CPU consumming, but we are waiting for indexdata Perl/zoom
-# * deletion still not work
-# * UNIMARC zebra config files are provided in misc/zebra/unimarc directory. The most important line being :
-# in zebra.cfg :
-# recordId: (bib1,Local-number)
-# storeKeys:1
-#
-# in .abs file :
-# elm 090            Local-number            -
-# elm 090/?          Local-number            -
-# elm 090/?/9        Local-number            !:w
-#
-# (090$9 being the field mapped to biblio.biblionumber in Koha)
-#
-# Revision 1.127  2005/08/11 14:37:32  tipaul
-# * POD documenting
-# * removing useless subs
-# * removing some subs that are also elsewhere
-# * renaming all OLDxxx subs to REALxxx subs (should not change anything, as OLDxxx, as well as REAL, are supposed to be for Biblio.pm internal use only)
-#
-# Revision 1.126  2005/08/11 09:13:28  tipaul
-# just removing useless subs (a lot !!!) for code cleaning
-#
-# Revision 1.125  2005/08/11 09:00:07  tipaul
-# Ok guys, this time, it seems that item add and modif begin working as expected...
-# Still a lot of bugs to fix, of course
-#
-# Revision 1.124  2005/08/10 10:21:15  tipaul
-# continuing the road to zebra :
-# - the biblio add begins to work.
-# - the biblio modif begins to work.
-#
-# (still without doing anything on zebra)
-# (no new change in updatedatabase)
-#
-# Revision 1.123  2005/08/09 14:10:28  tipaul
-# 1st commit to go to zebra.
-# don't update your cvs if you want to have a working head...
-#
-# this commit contains :
-# * updater/updatedatabase : get rid with marc_* tables, but DON'T remove them. As a lot of things uses them, it would not be a good idea for instance to drop them. If you really want to play, you can rename them to test head without them but being still able to reintroduce them...
-# * Biblio.pm : modify MARCgetbiblio to find the raw marc record in biblioitems.marc field, not from marc_subfield_table, modify MARCfindframeworkcode to find frameworkcode in biblio.frameworkcode, modify some other subs to use biblio.biblionumber & get rid of bibid.
-# * other files : get rid of bibid and use biblionumber instead.
-#
-# What is broken :
-# * does not do anything on zebra yet.
-# * if you rename marc_subfield_table, you can't search anymore.
-# * you can view a biblio & bibliodetails, go to MARC editor, but NOT save any modif.
-# * don't try to add a biblio, it would add data poorly... (don't try to delete either, it may work, but that would be a surprise ;-) )
-#
-# IMPORTANT NOTE : you need MARC::XML package (http://search.cpan.org/~esummers/MARC-XML-0.7/lib/MARC/File/XML.pm), that requires a recent version of MARC::Record
-# Updatedatabase stores the iso2709 data in biblioitems.marc field & an xml version in biblioitems.marcxml Not sure we will keep it when releasing the stable version, but I think it's a good idea to have something readable in sql, at least for development stage.
-
-# tipaul cutted previous commit notes
+=cut