Index: millennium.admin.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/millennium/Attic/millennium.admin.inc,v
retrieving revision 1.1.2.4
diff -u -r1.1.2.4 millennium.admin.inc
--- millennium.admin.inc	21 Oct 2009 21:47:18 -0000	1.1.2.4
+++ millennium.admin.inc	22 Oct 2009 23:04:03 -0000
@@ -13,7 +13,7 @@
   $chart_prefix = "http://chart.apis.google.com/chart?cht=ls&chm=o,FF9900,0,-1,5.0&chs=200x100&chdlp=b&chma=10,10,10,10&chd=t:";
   #&chf=bg,s,EFEFEF
 
-  $s[t("Total items imported")] = db_result(db_query("SELECT count(id) FROM {millennium_node_opacitem}"));
+  $s[t("Total items imported")] = db_result(db_query("SELECT count(id) FROM {millennium_node_bib}"));
 
   // Autocrawl
   $s[t("Crawl activated?")] = ( variable_get('millennium_crawl_flag', 0)? t('yes') : t('no'));
@@ -37,7 +37,7 @@
   $s[t('Queue: items pending')] = db_result(db_query("SELECT count(id) FROM {millennium_import_queue}"));
 
   // Import activity per day
-  $result = db_query_range("SELECT count(*) as n, date(created) as day FROM {millennium_node_opacitem} GROUP BY day ORDER BY day DESC", 0, 10);
+  $result = db_query_range("SELECT count(*) as n, date(created) as day FROM {millennium_node_bib} GROUP BY day ORDER BY day DESC", 0, 10);
   $import_history = "<table><tr><th>Date<th>Nodes created\n";
   $chd = array();
   $chd_min = 9999;
@@ -306,7 +306,7 @@
  * Callback for drupal_get_form that shows admin options for manually queueing items.
  */
 function millennium_admin_queue() {
-  $tot_items = db_result(db_query("SELECT count(item_recnum) FROM {millennium_node_opacitem}"));
+  $tot_items = db_result(db_query("SELECT count(*) FROM {millennium_node_bib} WHERE base_url = '%s'", millennium_get_real_baseurl() ));
   $form['source'] = array(
     '#type' => 'radios',
     '#title' => t("Items to import"),
@@ -346,8 +346,8 @@
     );
   $form['list']['queue'] = array(
     '#type' => 'textarea',
-    '#title' => t('Item record numbers to queue for import (one per line)'),
-    '#description' => t('Record numbers are written like this: i123456, i123456x. You can get item numbers from Millennium Client\'s "Create Lists". NOTE: Bibliographic record numbers are NOT allowed.'),
+    '#title' => t('Record numbers to queue for import (one per line)'),
+    '#description' => t('Record numbers are written like this: b123456, i123456x. You can get bibliographic or item record numbers from Millennium Client\'s "Create Lists".'),
     '#default_value' => '',
   );
   $form['range'] = array(
@@ -363,7 +363,7 @@
   );
   $form['range']["end"] = array(
     '#type' => 'textfield',
-    '#default_value' => variable_get('millennium_range_form_end', '100001'),
+    '#default_value' => variable_get('millennium_range_form_end', '100010'),
     '#size' => 7,
     '#title' => t('Ending item number'),
   );
@@ -410,29 +410,27 @@
         form_set_error($element, t("Must be equal or higher than 10000"));
       }
     }
-    if ($form_state["values"]["end"] <= $form_state["values"]["start"]) {
-      form_set_error("end", t("Ending number must be higher than starting number."));
+    if ($form_state["values"]["end"] < $form_state["values"]["start"]) {
+      form_set_error("end", t("Ending number must be higher or equal than starting number."));
     }
   }
 
   if ($form_state["values"]["source"] == "list") {
     if (trim($form_state['values']['queue']) == "") {
-      form_set_error("queue", t("You must enter at least one item number in the list."));
+      form_set_error("queue", t("You must enter at least one record number (e.g.: b123456x, i123456x) in the list."));
       return;
     }
     $lines = explode("\n", $form_state['values']['queue']);
     $errors = array();
     foreach ($lines as $line) {
       $recnum = trim($line);
-      if ($recnum == "") {
-        continue;
-      }
-      if (!preg_match('/^i[0-9]+x*$/i', $recnum)) {
-        $errors[] = $line;
+      if ($recnum) {
+        $recnum = drupal_substr($recnum, 0, drupal_strlen($recnum)-1);
+        $item_recnums[$recnum] = $recnum;
       }
     }
     if ($errors) {
-      form_set_error("queue", t("These are not Millennium item record numbers:") . theme('item_list', $errors), "error");
+      form_set_error("queue", t("These are not Millennium record numbers:") . theme('item_list', $errors), "error");
     }
   }
 }
@@ -462,12 +460,15 @@
         $queued = 0;
         foreach ($lines as $line) {
           $recnum = trim($line);
-          if (!preg_match('/^i[0-9]+x*$/i', $recnum)) {
-            drupal_set_message("Ignoring '$recnum': not a Millennium item record number", "error");
+          if ($recnum == "") {
+            continue;
+          }
+          if (!preg_match('/^[bi][0-9]{4-8}+x*$/i', $recnum)) {
+            drupal_set_message("Ignoring '$recnum': not a Millennium record number", "error");
           }
           else {
             $recnum = drupal_substr($recnum, 0, drupal_strlen($recnum)-1);
-            $ok = db_query("INSERT INTO {millennium_import_queue} (item_recnum, priority, force_update) VALUES ('%s', %d, %d)",
+            $ok = db_query("INSERT INTO {millennium_import_queue} (recnum, priority, force_update) VALUES ('%s', %d, %d)",
               $recnum,
               $form_state['values']['priority'],
               $form_state['values']['force_update']);
@@ -481,8 +482,8 @@
         // Import from range
         $start = $form_state["values"]["start"];
         $end = $form_state["values"]["end"];
-        for ($num = $start; $num < $end; $num++) {
-          $ok = db_query("INSERT INTO {millennium_import_queue} (item_recnum, priority, force_update) VALUES ('%s', %d, %d)",
+        for ($num = $start; $num <= $end; $num++) {
+          $ok = db_query("INSERT INTO {millennium_import_queue} (recnum, priority, force_update) VALUES ('%s', %d, %d)",
             "i" . $num,
             $form_state['values']['priority'],
             $form_state['values']['force_update']);
@@ -493,9 +494,9 @@
       }
       
       if ($form_state["values"]["source"] == "existing") {
-        $result = db_query("SELECT item_recnum FROM {millennium_node_opacitem}");
+        $result = db_query("SELECT bib_recnum FROM {millennium_node_bib} WHERE base_url = '%s'", millennium_get_real_baseurl());
         while ($data = db_fetch_object($result)) {
-          $ok = db_query("INSERT INTO {millennium_import_queue} (item_recnum, priority, force_update) VALUES ('%s', %d, %d)",
+          $ok = db_query("INSERT INTO {millennium_import_queue} (recnum, priority, force_update) VALUES ('%s', %d, %d)",
             $data->item_recnum,
             $form_state['values']['priority'],
             $form_state['values']['force_update']
@@ -518,10 +519,7 @@
         $queued = 0;
         foreach ($lines as $line) {
           $recnum = trim($line);
-          if (!preg_match('/^i[0-9]+x*$/i', $recnum)) {
-            drupal_set_message("Ignoring '$recnum': not a Millennium item record number", "error");
-          }
-          else {
+          if ($recnum) {
             $recnum = drupal_substr($recnum, 0, drupal_strlen($recnum)-1);
             $item_recnums[$recnum] = $recnum;
           }
@@ -532,15 +530,15 @@
         // Import from range
         $start = $form_state["values"]["start"];
         $end = $form_state["values"]["end"];
-        for ($num = $start; $num < $end; $num++) {
+        for ($num = $start; $num <= $end; $num++) {
           $item_recnums["i{$num}"] = "i{$num}";
         }
       }
       
       if ($form_state["values"]["source"] == "existing") {
-        $result = db_query("SELECT item_recnum FROM {millennium_node_opacitem}");
+        $result = db_query("SELECT bib_recnum FROM {millennium_node_bib} WHERE base_url = '%s'", millennium_get_real_baseurl());
         while ($data = db_fetch_object($result)) {
-          $item_recnums[$data->item_recnum] = $data->item_recnum;
+          $item_recnums[$data->bib_recnum] = $data->bib_recnum;
         }
       }
 
Index: millennium.cron.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/millennium/Attic/millennium.cron.inc,v
retrieving revision 1.1.2.4
diff -u -r1.1.2.4 millennium.cron.inc
--- millennium.cron.inc	21 Oct 2009 21:47:18 -0000	1.1.2.4
+++ millennium.cron.inc	22 Oct 2009 22:54:46 -0000
@@ -51,33 +51,33 @@
   );
   foreach ($queue_jobs as $priority => $limit) {
     // Get items to import from DB
-    $handle = db_query("SELECT id, item_recnum, force_update FROM {millennium_import_queue} WHERE priority=%d LIMIT {$limit}", $priority);
+    $handle = db_query("SELECT id, recnum, force_update FROM {millennium_import_queue} WHERE priority=%d LIMIT {$limit}", $priority);
     $stop = $tot_imported + $limit;
-    $item_recnums = array();
+    $recnums = array();
     while ($data = db_fetch_object($handle)) {
-      $item_recnums[] = $data->item_recnum;
-      $force_update[$data->item_recnum] = $data->force_update;
-      $queue_id[$data->item_recnum] = $data->id;
+      $recnums[] = $data->recnum;
+      $force_update[$data->recnum] = $data->force_update;
+      $queue_id[$data->recnum] = $data->id;
     }
-    $tot_attempted += sizeof($item_recnums);
+    $tot_attempted += sizeof($recnums);
     // Chunk array into groups of 50 (maximum number allowed by bookcart)
-    $item_recnums_chunks = array_chunk($item_recnums, 50);
-    foreach ($item_recnums_chunks as $item_recnums_chunk) {
-      $fetched = millennium_fetch_records_via_bookcart($item_recnums_chunk);
+    $recnums_chunks = array_chunk($recnums, 50);
+    foreach ($recnums_chunks as $recnums_chunk) {
+      $fetched = millennium_fetch_records_via_bookcart($recnums_chunk);
 
       // Remove not-found items from queue
-      foreach ($fetched['not_found'] as $item_recnum) {
-        db_query("DELETE FROM {millennium_import_queue} where id=%d", $queue_id[$item_recnum]);
+      foreach ($fetched['not_found'] as $recnum) {
+        db_query("DELETE FROM {millennium_import_queue} where id=%d", $queue_id[$recnum]);
         $tot_notfound++;
-        $import_errors[] = array("recnum" => $item_recnum, "error" => 'Not found');
+        $import_errors[] = array("recnum" => $recnum, "error" => 'Not found');
       }
 
       // Import successful fetches only
       foreach ($fetched['found'] as $data) {
-        db_query("DELETE FROM {millennium_import_queue} where id=%d", $queue_id[$data['item_recnum']]);
+        db_query("DELETE FROM {millennium_import_queue} where id=%d", $queue_id[$data['recnum']]);
         $result = millennium_import_update_item(
-          $data['item_recnum'],
-          $force_update[$data['item_recnum']],
+          $data['recnum'],         // TODO: Trying to do recnum but maybe not really an item...
+          $force_update[$data['recnum']],
           $data['marc'],
           $data['bib_recnum']
         );
@@ -88,10 +88,10 @@
           $tot_fail++;
           watchdog("Millennium",
             "Queue #@id: Failed to import node: item #@recnum, error: @error",
-            array("@id" => $ids[$data['item_recnum']], "@recnum" => $data['item_recnum'], "@error" => $result["error"])
+            array("@id" => $ids[$data['recnum']], "@recnum" => $data['recnum'], "@error" => $result["error"])
           );
           // Build a list of errors
-          $import_errors[] = array("recnum" => $data['item_recnum'], "error" => $result["error"]);
+          $import_errors[] = array("recnum" => $data['recnum'], "error" => $result["error"]);
         }
 
         if ($tot_imported > $stop || $tot_imported > $max_to_import) {
@@ -99,7 +99,7 @@
         }
 
       }
-    } // foreach ($item_recnums_chunks as $item_recnums_chunk)
+    } // foreach ($recnums_chunks as $recnums_chunk)
   }
 
   // Send errors via email
@@ -124,6 +124,7 @@
   if ($will_auto_crawl) {
 
     // AUTO CRAWL ================================================================
+    // TODO: Use bib instead of items
     $rollover_limit = intval($default_end + ($default_end - $default_start)*.05);
     $item_recnums = array();
     for ($num = $beginning_rec_num; $num < $beginning_rec_num + $max_to_import; $num++) {
Index: millennium.import.inc
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/millennium/Attic/millennium.import.inc,v
retrieving revision 1.1.2.5
diff -u -r1.1.2.5 millennium.import.inc
--- millennium.import.inc	21 Oct 2009 21:47:18 -0000	1.1.2.5
+++ millennium.import.inc	22 Oct 2009 23:09:32 -0000
@@ -3,9 +3,9 @@
 
 /**
  * Gets a sequential number of records obeying PHP's max_execution_time setting.
- * @param array $item_recnums Array of item numbers to fetch.
+ * @param array $recnums Array of item or bib numbers to fetch.
  */
-function millennium_mass_fetch($item_recnums) {
+function millennium_mass_fetch($recnums) {
   $max_records_for_bookcart = 50; // This seems to be the limit for WebOPACs, do not change =)
 
   if (ini_get('max_execution_time')<20) {
@@ -16,7 +16,7 @@
   $max_time = ini_get('max_execution_time') * 0.75;
 
   // Chunk array into groups of $max_records_for_bookcart
-  $chunks = array_chunk($item_recnums, $max_records_for_bookcart);
+  $chunks = array_chunk($recnums, $max_records_for_bookcart);
   $results = array('found' => array(), 'not_found' => array());
   foreach ($chunks as $chunk) {
     $result = millennium_fetch_records_via_bookcart($chunk);
@@ -35,10 +35,10 @@
 /**
  * Gets item information (bib number & MARC record) using the III's book cart.
  * Recieves an array of item numbers and returns an array of found item data including bib number and MARC keyed by item number, and an unkeyed array of not found items.
- * @param array $item_recnums An unkeyed array of item numbers = array('i100000', 'i100002', ...)
+ * @param array $recnums An unkeyed array of item or bib numbers = array('i123456', 'b123456', ...)
  * @param bool $complete_holdings A flag that specifies if an extra request should be done if the holdings table is incomplete.
  */
-function millennium_fetch_records_via_bookcart($item_recnums, $complete_holdings = true) {
+function millennium_fetch_records_via_bookcart($recnums, $complete_holdings = true) {
   static $headers = array();
 
   // Start timer to measure average performance
@@ -70,9 +70,9 @@
   }
 
   // Issue N requests to add items to the bookcart, 25 records at a time
-  $chunks = array_chunk($item_recnums, 25);
+  $chunks = array_chunk($recnums, 25);
   foreach ($chunks as $chunk) {
-    // Add items from $item_recnums array to the cart
+    // Add items from $recnums array to the cart
     $path = '/search?/X&searchscope=0&SORT=D/X&searchscope=0&SORT=D&SUBKEY=/1%2C7175%2C7175%2CE/2browse';
     $post = "jumpref=X&save=" . implode("&save=", $chunk) . "&save_func=save_marked";
     $result = drupal_http_request("{$baseurl}{$path}", $headers, 'POST', $post);
@@ -85,7 +85,7 @@
   $path = "/search/?/++export/1,-1,-1,B/export";
   $result = drupal_http_request("{$baseurl}{$path}", $headers, 'GET');
   $ok = preg_match_all(
-    '/name="save" value="(b[0-9]+)".*?browseEntryData.*?record=(i[0-9]+)/si',
+    '/name="save" value="(b[0-9]+)".*?browseEntryData.*?record=([bi][0-9]+)/si',
     $result->data,
     $matches,
     PREG_SET_ORDER
@@ -94,22 +94,25 @@
   #return;
 
   // Start off assuming no items have been found
-  foreach ($item_recnums as $num) {
+  foreach ($recnums as $num) {
     $not_found_items[$num] = $num;
   }
-  // Store each found item's item <=> bib relationship
+
   $found_items = array();
   foreach ($matches as $match) {
     $found_bib_recnum = $match[1];
-    $found_item_recnum = $match[2];
+    $found_recnum = $match[2];
     // Remove found items off $not_found_items list
-    unset($not_found_items[$found_item_recnum]);
-    $found_items[$found_item_recnum] = array(
-      'item_recnum' => $found_item_recnum,
+    unset($not_found_items[$found_recnum]);
+    $found_items[$found_recnum] = array(
       'bib_recnum' => $found_bib_recnum
     );
+    // If supplied recnum is an item record, store item <=> bib relationship
+    if (substr($found_recnum, 0, 1) == "i") {
+      $found_items[$found_recnum]['item_recnum'] = $found_recnum;
+    }
   }
-  #dpm($item_to_bib);
+  #dpm($found_items);
 
   // Get MARC for all!
   $path = "/search/?/++export/1%2C-1%2C-1%2CB/export/";
@@ -126,15 +129,15 @@
   #dpm($matches);
   // Assign marc to item numbers
   $index = 0;
-  foreach ($found_items as $item => $dummy) {
-    $found_items[$item]['marc'] = $matches[$index][1];
+  foreach ($found_items as $recnum => $dummy) {
+    $found_items[$recnum]['marc'] = $matches[$index][1];
 
     // Add holdings information; determine if an extra request is needed
-    $this_bib_recnum = $found_items[$item]['bib_recnum'];
+    $this_bib_recnum = $found_items[$recnum]['bib_recnum'];
     if ($matches[$index][3] != "" && $complete_holdings == true) {
-      $found_items[$item]['holdings'] = millennium_get_holdings_info($this_bib_recnum);
+      $found_items[$recnum]['holdings'] = millennium_get_holdings_info($this_bib_recnum);
     } else {
-      $found_items[$item]['holdings'] = millennium_get_holdings_info($this_bib_recnum, $matches[$index][2]);
+      $found_items[$recnum]['holdings'] = millennium_get_holdings_info($this_bib_recnum, $matches[$index][2]);
     }
     $index++;
   }
@@ -154,23 +157,34 @@
 
   // Read timer.
   $elapsed = round(timer_read("millennium_fetch_records_via_bookcart") / 1000, 3);
-  #drupal_set_message("Tried to fetch:" . sizeof($item_recnums) . ". Found: " . sizeof($found_items) . ". Elapsed time: {$elapsed}s");
+  #drupal_set_message("Tried to fetch:" . sizeof($recnums) . ". Found: " . sizeof($found_items) . ". Elapsed time: {$elapsed}s");
 
   // Return results
   $results = array('found' => $found_items, 'not_found' => $not_found_items);
-  #dpm($results);
+  dpm($results);
 
   return $results;
 
   /* $results = array(
       'found' => array(
-        'i100001' => array(
-          'item_recnum' => 'i100001',
+        'b100001' => array(
+          'bib_recnum' => 'b100001',
+          'marc' => 'LEADER 00000cam 2200000 a 4500 001 tec042...
+          'holdings' => '...'
+        ),
+        'i222222' => array(
+          'item_recnum' => 'i222222',
           'bib_recnum' => 'b426763',
           'marc' => 'LEADER 00000cam 2200000 a 4500 001 tec042...
+          'holdings' => array(
+            0 => array(
+              'location' => 'MTY 4to. Piso',
+              'classnumber' => 'QH541.15.B56 E95 2009',
+              'classvolume' => '',
+              'status' => 'CATALOGACION',
+            ),
+          ),
         ),
-        'i100003' => array(...)
-        [...]
       ),
       'not_found' => array('i100000', 'i100005', [...])
     );
Index: millennium.install
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/millennium/millennium.install,v
retrieving revision 1.1.2.5.2.1.2.2
diff -u -r1.1.2.5.2.1.2.2 millennium.install
--- millennium.install	28 Nov 2008 23:10:02 -0000	1.1.2.5.2.1.2.2
+++ millennium.install	22 Oct 2009 22:51:45 -0000
@@ -14,7 +14,7 @@
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
-      'item_recnum' => array(
+      'recnum' => array(
         // 'description' => t('TODO'),
         'type' => 'char',
         'length' => 15,
@@ -41,7 +41,7 @@
     'primary key' => array('id'),
   );
 
-  $schema['millennium_node_opacitem'] = array(
+  $schema['millennium_node_bib'] = array(
     // 'description' => t('TODO'),
     'fields' => array(
       'id' => array(
@@ -56,36 +56,79 @@
         'unsigned' => TRUE,
         'not null' => TRUE,
       ),
-      'item_recnum' => array(
+      'bib_recnum' => array(
         // 'description' => t('TODO'),
         'type' => 'char',
         'length' => 15,
         'not null' => TRUE,
       ),
+      'updated' => array(
+        // 'description' => t('TODO'),
+        'type' => 'datetime',
+        'not null' => TRUE,
+      ),
+      'created' => array(
+        // 'description' => t('TODO'),
+        'type' => 'datetime',
+        'not null' => TRUE,
+      ),
+      'biblio_data' => array(
+        // 'description' => t('TODO'),
+        'type' => 'text',
+        'not null' => TRUE,
+      ),
+      'base_url' => array(
+        // 'description' => t('TODO'),
+        'type' => 'char',
+        'length' => 80,
+        'not null' => TRUE,
+      ),
+    ),
+    'indexes' => array(
+      'id_2' => array('bib_recnum', 'base_url'),
+      'nid' => array('nid'),
+    ),
+    'unique keys' => array(
+      'id' => array('id'),
+    ),
+    'primary key' => array('id'),
+  );
+  
+  $schema['millennium_bib_item'] = array(
+    // 'description' => t('TODO'),
+    'fields' => array(
+      'id' => array(
+        // 'description' => t('TODO'),
+        'type' => 'serial',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
+      'nid' => array(
+        // 'description' => t('TODO'),
+        'type' => 'int',
+        'unsigned' => TRUE,
+        'not null' => TRUE,
+      ),
       'bib_recnum' => array(
         // 'description' => t('TODO'),
         'type' => 'char',
         'length' => 15,
         'not null' => TRUE,
       ),
-      'item_updated' => array(
+      'item_recnum' => array(
         // 'description' => t('TODO'),
-        'type' => 'datetime',
+        'type' => 'char',
+        'length' => 15,
         'not null' => TRUE,
       ),
-      'created' => array(
+      'updated' => array(
         // 'description' => t('TODO'),
         'type' => 'datetime',
         'not null' => TRUE,
       ),
-      'bib_updated' => array(
+      'created' => array(
         // 'description' => t('TODO'),
         'type' => 'datetime',
-        'not null' => FALSE,
-      ),
-      'biblio_data' => array(
-        // 'description' => t('TODO'),
-        'type' => 'text',
         'not null' => TRUE,
       ),
       'base_url' => array(
@@ -96,9 +139,9 @@
       ),
     ),
     'indexes' => array(
-      'id_2' => array('id', 'nid', 'item_recnum', 'item_updated'),
+      'id_3' => array('item_recnum', 'base_url'),
+      'id_2' => array('bib_recnum', 'base_url'),
       'nid' => array('nid'),
-      'bib_recnum' => array('bib_recnum'),
     ),
     'unique keys' => array(
       'id' => array('id'),
Index: millennium.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/millennium/millennium.module,v
retrieving revision 1.13.2.33.2.2.2.34
diff -u -r1.13.2.33.2.2.2.34 millennium.module
--- millennium.module	22 Oct 2009 19:48:20 -0000	1.13.2.33.2.2.2.34
+++ millennium.module	22 Oct 2009 23:14:16 -0000
@@ -138,7 +138,6 @@
     'type' => MENU_CALLBACK,
     'access callback' => true
   );
-  // TODO this should only show up in certain nodes!! See http://drupal.org/node/218692
   $items['node/%node/millennium'] = array(
     'title' => 'Millennium Tools',
     'page callback' => 'millennium_node_tools' ,
@@ -148,7 +147,6 @@
     'weight' => 10,
     'type' => MENU_LOCAL_TASK,
   );
-  // TODO this should only show up in certain nodes!! See http://drupal.org/node/218692
   $items['node/%node/marc'] = array(
     'title' => 'MARC display',
     'page callback' => 'millennium_node_marc' ,
@@ -198,7 +196,7 @@
  * Callback function from hook_menu to determine if millennium tools tab should be shown
  */
 function millennium_tools_tab_access($node) {
-  if ($item_recnum = millennium_item_recnum_from_node($node->nid) && user_access("administer millennium")) {
+  if ($item_recnum = millennium_bib_recnum_from_node($node->nid) && user_access("administer millennium")) {
     return true;
   }
   return false;
@@ -208,54 +206,52 @@
  * Callback function from hook_menu that shows import and conversion information for node $nid
  */
 function millennium_node_tools($node) {
-  $item_recnum = millennium_item_recnum_from_node($node->nid);
-  if (! $item_recnum) {
+  $bib_recnum = millennium_bib_recnum_from_node($node->nid);
+  if (! $bib_recnum) {
     drupal_set_message(t('This node (!nid) does not have any Millennium record number associated with it.', array('!nid' => $node->nid)));
     drupal_goto('node/'. $node->nid);
   }
 
   // Show record info
-  $result = db_query("SELECT * from {millennium_node_opacitem} WHERE nid=%d", $node->nid);
-  $data = db_fetch_object($result);
+  $data = db_fetch_object(db_query("SELECT * from {millennium_node_bib} WHERE nid = %d", $node->nid));
 
   $output = "<h2>". t("Import history") . "</h2>";
 
-  $bib_recnum = millennium_bib_recnum_from_node($node->nid);
   $items[] = t("WebOPAC: !link", array("!link" => l($data->base_url, $data->base_url)));
   $items[] = t("Bibliographic record #: !link", array("!link" => l($bib_recnum, millennium_permalink($bib_recnum))));
-  $items[] = t("Item record #: !link", array("!link" => l($item_recnum, millennium_permalink($item_recnum))));
+  #TODO: $items[] = t("Item records: !link", array("!link" => l($bib_recnum, millennium_permalink($item_recnum))));
   $items[] = t("Node first import date: @date", array("@date" => $data->created));
-  $items[] = t("Node last update date: @date", array("@date" => $data->item_updated));
+  $items[] = t("Node last update date: @date", array("@date" => $data->updated));
   $items[] = l(t('Click here to reimport this node'), 'millennium/reimport/'. $node->nid);
   $output .= theme('item_list', $items);
 
   $output .= "<p></p>";
   $output .= "<h2>". t('MARC record and conversion') ."</h2>";
-  $output .= _millennium_show_conversion($item_recnum, $node->millennium_biblio_data["marc"]);
+  $output .= _millennium_show_conversion($recnum, $node->millennium_biblio_data["marc"]);
   return $output;
 }
 
 /**
  * Diagnostics to show conversion of MARC into fields for node object
  */
-function _millennium_show_conversion($item_recnum, $marc = false) {
+function _millennium_show_conversion($recnum, $marc = false) {
   $output = "";
 
   if ($marc === false) {
     // Get bib number from item recnum
-    $result = millennium_fetch_recordpage($item_recnum);
+    $result = millennium_fetch_recordpage($recnum);
     $record_html = $result->data;
-    $ok = preg_match('/\/record=(b[0-9]+)/si', $record_html, $matches);
-    $bib_recnum = $matches[1];
-    $marc = millennium_fetch_marc($bib_recnum);
-    $output .= t("Item record = @item, Bib recnum = @bib", array("@item" => $item_recnum, "@bib" => $bib_recnum));
+    #$ok = preg_match('/\/record=(b[0-9]+)/si', $record_html, $matches);
+    #$bib_recnum = $matches[1];
+    $marc = millennium_fetch_marc($recnum);
+    $output .= t("Bib recnum = @bib", array("@bib" => $recnum));
   }
 
   $output .= "<h3>" .t('MARC record') ."</h3>";
   $output .= t('This MARC record was just fetched from the WebOPAC.');
   $output .= "<pre class='millennium marc'>$marc</pre>";
 
-  $tmp_node = millennium_marc_to_nodeobject($item_recnum, $marc);
+  $tmp_node = millennium_marc_to_nodeobject($marc, $recnum);
 
   $output .= "<h3>" .t('Conversion results') ."</h3>";
 
@@ -287,18 +283,18 @@
 }
 
 /**
- * Callback function from hook_menu that reimports a node using its stored item number in table millennium_node_opacitem
+ * Callback function from hook_menu that reimports a node using its previously stored bib data
  */
 function millennium_node_reimport($nid) {
-  $item_recnum = millennium_item_recnum_from_node($nid);
-  if (! $item_recnum) {
+  $bib_recnum = millennium_bib_recnum_from_node($nid);
+  if (! $bib_recnum) {
     drupal_set_message(t('This node does not have any Millennium record number associated with it.'));
     drupal_goto('node/'. $nid);
   }
-  $result = millennium_import_update_item($item_recnum, true); #true == force update
+  #TODO: Use bib_recnum # $result = millennium_import_update_item($item_recnum, true); #true == force update
 
   if ($result["success"] !== false) {
-    drupal_set_message("Node reimported from Millennium item #$item_recnum.");
+    drupal_set_message("TODO: Node reimported from Millennium item #$item_recnum.");
   }
   else {
     drupal_set_message("Failed to reimport from Millennium: ". $result["error"]);
@@ -331,7 +327,22 @@
  * @param bool $force_update (Optional) States if an existing node for that item record number should be updated.
  * @param string $marc_text (Optional) A MARC record to import from.
  */
-function millennium_import_update_item($item_recnum, $force_update = true, $marc_text = null, $bib_recnum = null) {
+function millennium_import_update_item($recnum, $force_update = true, $marc_text = null, $bib_recnum = null) {
+  #drupal_set_message("millennium_import_update_item($item_recnum, $force_update, $marc_text, $bib_recnum)");
+  
+  // Sort out what type of record the first argument is
+  if (substr($recnum, 0, 1) == "i") {
+    $item_recnum = $recnum;
+    if ($bib_recnum == null) {
+      // Try the database
+      $bib_recnum = db_result(db_query("SELECT bib_recnum FROM {millennium_node_bib} WHERE item_recnum='%s' AND base_url = '%s'", $recnum, millennium_get_real_baseurl()));
+      if (!$bib_recnum) {
+        $bib_recnum = null;
+      }
+    }
+  }
+  // TODO TODO TODO! OJO AQUI ME QUEDE::: hay que manejar la baja para los casos: $recnum es item, bibliografico
+  
   // Assume item exists when marc_text is given.
   $item_exists = true;
   if ($marc_text == null) {
@@ -355,7 +366,7 @@
   // Record exists.
   // Had we already imported this item record?
   $import_history = db_fetch_object(db_query(
-    "SELECT * FROM {millennium_node_opacitem} WHERE item_recnum='%s' AND base_url = '%s'", 
+    "SELECT * FROM {millennium_bib_item} WHERE item_recnum='%s' AND base_url = '%s'", 
     $item_recnum, 
     millennium_get_real_baseurl()
     ));
@@ -368,7 +379,7 @@
     if ($force_update == false) {
       // TODO: What do we update with any changes to the item record? 
       // From xrecord: Use ICODEs? LOCATION? OUT DATE? YTDCIRC? TOTCIRC?
-      // From imported history: Expiry time? (millennium_node_opacitem.item_updated)
+      // From imported history: Expiry time? (millennium_bib_item.updated)
       return array(
         "success" => true,
         "error" => t("This item #@item_number had already been imported under nid @nid", array("@item_number" => $item_recnum, "@nid" => $import_history->nid))
@@ -387,52 +398,68 @@
       $bib_recnum = $matches[1];
     }
   }
-  return millennium_update_bibrecord($bib_recnum, $item_recnum, $force_update, $marc_text);
+  #drupal_set_message("About to call: millennium_import_update_item($item_recnum, $force_update, $marc_text, $bib_recnum)");
+  return millennium_import_record($bib_recnum, $item_recnum, $force_update, $marc_text);
 }
 
 /**
- * Imports a parent bibliographic record for an item record.
- * Requires the item and bibliographic record number to be known.
- * Optionally, if the full marc record is passed, it is used directly and will not be fetched
- * from the webpac.
+ * Imports a bibliographic record into a node from a given bib_recnum, updating existing nodes if stale,
+ * and links the nodes, bib records and item record together.
+ * Requires the bibliographic record number to be known.
+ * Optionally, if the full marc record is passed, it is used directly instead of being fetched
+ * from the WebOPAC.
  *
- * @param bib_recnum Millennium bibliographic record number
- * @param item_recnum An item record number for the record
- * @param force_update Forces the record to be updated if it already exists
- * @param marc_text The full marc record in plain text (same format as the webpac marc view)
+ * @param string $bib_recnum Required. Millennium bibliographic record number.
+ * @param string $item_recnum Optional. An item record number for this bibliographic record.
+ * @param boolean $force_update Optional. If true, forces the node to be updated when it already exists.
+ * @param string $marc_text The full marc record in plain text (same format as the WebOPAC marc view)
  */
-function millennium_update_bibrecord($bib_recnum, $item_recnum, $force_update = true, $marc_text = null) {
-  static $xml_disabled = FALSE;
-
-  $bib_import_history = db_fetch_object(db_query("SELECT * FROM {millennium_node_opacitem} WHERE bib_recnum='%s' AND base_url = '%s'", $bib_recnum,millennium_get_real_baseurl()));
+function millennium_import_record($bib_recnum, $item_recnum = false, $force_update = false, $marc_text = null) {
+  static $xml_disabled = false;
+  
+  $bib_import_history = db_fetch_object(db_query("SELECT * FROM {millennium_node_bib} WHERE bib_recnum='%s' AND base_url = '%s'", $bib_recnum, millennium_get_real_baseurl()));
 
   // Has this bib record been imported before?
-  if (! $bib_import_history) {
-    // It hasn't! Make nodeobject from the MARC record, import resulting nodeobject, then add taxonomy
-
-    // Make nodeobject from the MARC record
-    $nodeobject = millennium_item_to_nodeobject($bib_recnum, $item_recnum, $marc_text);
-
-    if ($nodeobject->success === false) {
-      #drupal_set_message("millennium_update_bibrecord(): millennium_item_to_nodeobject() returned error ". $result["error"]);
-      return array("success" => false, "error" => $nodeobject->error);
+  if (! $bib_import_history->nid) {
+    #drupal_set_message("bib $bib_recnum not imported before");
+    // It hasn't!
+    // We want a node == one bib record for each opac (determined by baseurl).
+    // Make nodeobject from the MARC record, import resulting nodeobject
+    $new_node = millennium_record_to_nodeobject($bib_recnum, $marc_text);
+    if ($new_node->success === false) {
+      #drupal_set_message("millennium_import_record(): millennium_record_to_nodeobject() returned error ". $result["error"]);
+      return array("success" => false, "error" => $new_node->error);
     }
-
-    #$nodeobject = $result[0];
-    #$marc_parsed = $result[1];
-
     // Add the new node
-    millennium_node_add($nodeobject, $item_recnum, $bib_recnum);
-
-    // Add taxonomy to new node
-    #millennium_add_taxonomy_to_node($nodeobject, $marc_parsed);
-
-    return array("success" => true, "node" => $nodeobject);
+    $saved_node = millennium_node_add($new_node, $item_recnum, $bib_recnum);
+    
+    #dpm($saved_node);
+        
+    // Add node-bib relationship 
+    $record = array('nid' => $saved_node->nid, 'bib_recnum' => $bib_recnum,
+      'biblio_data' => serialize($saved_node->millennium_biblio_data),
+      'updated' => date("Y-m-d H:i:s"), 'created' => date("Y-m-d H:i:s"), 'base_url' => millennium_get_real_baseurl());
+    $result = drupal_write_record('millennium_node_bib', $record);
+    if (!$result) {
+      drupal_set_message("millennium_import_record drupal_write_record('millennium_node_bib') returned false");
+      dpm($record);
+    }
+    
+    // Is this related to an item?
+    if ($item_recnum) {
+      $record = array('nid' => $saved_node->nid, 'bib_recnum' => $bib_recnum, 'item_recnum' => $item_recnum, 
+        'updated' => date("Y-m-d H:i:s"), 'created' => date("Y-m-d H:i:s"), 'base_url' => millennium_get_real_baseurl());
+      $result = drupal_write_record('millennium_bib_item', $record);
+      if (!$result) {
+        drupal_set_message("millennium_import_record drupal_write_record('millennium_bib_item') returned false");
+        dpm($record);
+      } 
+    }
+    return array("success" => true, "node" => $saved_node);
   }
   else {
-    // There is an existing node for this item's parent bibrecord
-
-    // Check if there is need to update this record.
+    // There is an existing node for this bib record
+    // Check if there is need to update the node.
     /*
     if ($force_update == false) {
       $result = millennium_fetch_recordpage($bib_import_history->bib_recnum, "xml");
@@ -469,23 +496,49 @@
     }
     */
 
-    // Is this newer than the existing bib record found for this item?
-    if ($force_update == true || $bib_lastupdate > substr($bib_import_history->bib_updated, 0, 10)) {
-
-      // Millennium newer than imported, re-create a nodeobject from the MARC record
-      $nodeobject = millennium_item_to_nodeobject($bib_import_history->bib_recnum, $item_recnum, $marc_text);
-      if ($nodeobject->success === false) {
-        #drupal_set_message("millennium_update_bibrecord(): millennium_item_to_nodeobject() returned error ". $result["error"]);
-        return array("success" => false, "error" => $nodeobject->error);
+    // Determine if record is stale
+    $stale_record_age = (3600*24*30); // 30 days
+    $is_stale = (time() > (strtotime($bib_import_history->updated) + $stale_record_age));
+
+    if ($force_update == true || $is_stale) {
+      // Re-create a nodeobject from the MARC record
+      $new_node = millennium_record_to_nodeobject($bib_import_history->bib_recnum, $marc_text);
+      if ($new_node->success === false) {
+        #drupal_set_message("millennium_import_record(): millennium_record_to_nodeobject() returned error ". $result["error"]);
+        return array("success" => false, "error" => $new_node->error);
       }
 
-      // insert existing node's nid into nodeobject and save node
-      $nodeobject->nid = $bib_import_history->nid;
+      // insert existing node's nid into new_node and save node
+      $new_node->nid = $bib_import_history->nid;
       
       // Update
-      millennium_node_update($nodeobject, $item_recnum, $bib_recnum);
-
-      return array("success" => true, "node" => $nodeobject);
+      millennium_node_update($new_node);
+      
+      // Update the node-bib relationship 
+      $record = array('nid' => $bib_import_history->nid, 'bib_recnum' => $bib_recnum, 
+        'updated' => date("Y-m-d H:i:s"), 'base_url' => millennium_get_real_baseurl());
+      // Update millennium_node_bib using key 'nid'
+      $result = drupal_write_record('millennium_node_bib', $record, array('nid'));
+      if (!$result) {
+        drupal_set_message("drupal_write_record('millennium_node_bib') returned false");
+        dpm($record);
+      }
+      
+      // Is this related to an item?
+      if ($item_recnum) {
+        // Check if this record existed before.
+        if (db_result(db_query("SELECT count(*) FROM {millennium_bib_item} WHERE nid = '%d' AND item_recnum='%s' AND base_url = '%s'", $bib_import_history->nid, $item_recnum, millennium_get_real_baseurl()))) {
+          $record = array('nid' => $new_node->nid, 'bib_recnum' => $bib_recnum, 'item_recnum' => $item_recnum, 
+            'updated' => date("Y-m-d H:i:s"), 'created' => date("Y-m-d H:i:s"), 'base_url' => millennium_get_real_baseurl());
+          // Insert/update millennium_node_bib using key 'nid'
+          $result = drupal_write_record('millennium_bib_item', $record);
+          if (!$result) {
+            drupal_set_message("drupal_write_record('millennium_bib_item') returned false");
+            dpm($record);
+          }
+        }
+      }
+      return array("success" => true, "node" => $new_node);
     } else {
       // TODO: Use Success?
       return array("success" => true, "error" => "Item belongs to existing bib item ". $bib_import_history->bib_recnum ." in node ". $bib_import_history->nid);
@@ -500,13 +553,13 @@
  */
 function millennium_handle_deleted_item($item_recnum) {
   // Get bibrecord number and erase any existing node-item relationships
-  $data = db_fetch_object(db_query("SELECT nid, bib_recnum FROM {millennium_node_opacitem} WHERE item_recnum='%s' AND base_url='%s'", $item_recnum, millennium_get_real_baseurl()));
+  $data = db_fetch_object(db_query("SELECT nid, bib_recnum FROM {millennium_bib_item} WHERE item_recnum='%s' AND base_url='%s'", $item_recnum, millennium_get_real_baseurl()));
 
   if ($data->bib_recnum) {
-    db_query("DELETE FROM {millennium_node_opacitem} WHERE item_recnum='%s' AND base_url = '%s'", $item_recnum, millennium_get_real_baseurl());
+    db_query("DELETE FROM {millennium_bib_item} WHERE item_recnum='%s' AND base_url = '%s'", $item_recnum, millennium_get_real_baseurl());
     watchdog("Millennium", "Deleted node-item relationship for node @nid and item #@item.", array("@item" => $item_recnum, "@nid" => $data->nid));
     // Delete the node if no items remain for same bibrecord
-    $count = db_result(db_query("SELECT count(*) FROM {millennium_node_opacitem} where bib_recnum='%s' AND base_url ='%s'", $data->bib_recnum, millennium_get_real_baseurl()));
+    $count = db_result(db_query("SELECT count(*) FROM {millennium_bib_item} where bib_recnum='%s' AND base_url ='%s'", $data->bib_recnum, millennium_get_real_baseurl()));
     if ($count == 0) {
       node_delete($data->nid);
       watchdog("Millennium", "Deleted node @nid because item #@item was deleted, and there were no remaining imported nodes for bib record #@bib.",
@@ -518,25 +571,25 @@
 
 /**
  * Fetches information for a Millennium record and returns a populated nodeobject
- * @param bib_recnum Millennium record number (b123456) to fetch
+ * @param recnum Millennium record number (b123456, i123456) to fetch
  * @param string $marc_text An optional MARC record to import from.
  */
-function millennium_item_to_nodeobject($bib_recnum, $item_recnum, $marc_text = null) {
+function millennium_record_to_nodeobject($recnum, $marc_text = null) {
   $result = new stdClass();
   if ($marc_text == null) {
-    $marc_text = millennium_fetch_marc($bib_recnum);
+    $marc_text = millennium_fetch_marc($recnum);
     if (!$marc_text) {
       $result->success = FALSE;
-      $result->error = "Could not fetch MARC for $item_recnum";
+      $result->error = "Could not fetch MARC for $recnum";
       return $result;
     }
   }
 
   //Create a nodeobject from parsed MARC
-  $nodeobject = millennium_marc_to_nodeobject($item_recnum, $marc_text);
+  $nodeobject = millennium_marc_to_nodeobject($marc_text, $recnum);
   if (!$nodeobject) {
     $result->success = false;
-    $result->error = "Could not create node object from parsed MARC for $item_recnum";
+    $result->error = "Could not create node object from parsed MARC for $recnum";
     return $result;
   }
 
@@ -592,32 +645,44 @@
 /**
  * Returns a URL for a certain item record view in Millennium
  */
-function millennium_permalink($item_recnum, $mode = 'plain') {
+function millennium_permalink($recnum, $mode = 'plain') {
   $baseurl = millennium_get_real_baseurl();
   if ($baseurl == false) {
     return false;
   }
+  // Determine if record is for an item or bib
+  $recnum_type = substr($recnum, 0, 1);
+
   switch ($mode) {
     case "plain":
-      $url = "{$baseurl}/record={$item_recnum}&searchscope=0";
+      $url = "{$baseurl}/record={$recnum}&searchscope=0";
       # TODO check if this one is better:
       #$url = "{$baseurl}/search*eng/?searchtype=.&searcharg={$item_recnum}&searchscope=0";
       break;
     case "xml":
-      $url = "{$baseurl}/xrecord={$item_recnum}&searchscope=0";
-      break;
-    case "hold":
-      $bib_recnum = db_result(db_query("SELECT bib_recnum FROM {millennium_node_opacitem} WHERE item_recnum='%s' AND base_url = '%s'", $item_recnum, millennium_get_real_baseurl()));
-      $url = "{$baseurl}/search*eng?/.{$item_recnum}/.{$bib_recnum}/1%2C1%2C1%2CB/request~{$bib_recnum}";
+      $url = "{$baseurl}/xrecord={$recnum}&searchscope=0";
       break;
     case "marc":
-      $url = "{$baseurl}/search*eng?/.{$item_recnum}/.{$item_recnum}/1,1,1,B/marc~{$item_recnum}";
-      break;
+    case "hold":
     case "items":
-      $bib_recnum = db_result(db_query("SELECT bib_recnum FROM {millennium_node_opacitem} WHERE item_recnum='%s' AND base_url = '%s'", $item_recnum, millennium_get_real_baseurl()));
-      $num = drupal_substr($item_recnum, 1); // e.g.: 123456
-      $url = $baseurl ."/search*eng?/.{$item_recnum}/.{$bib_recnum}/1,1,1,B/holdings~{$num}&FF=&1,0,";
-      break;
+      if ($recnum_type == "i") {
+        $bib_recnum = db_result(db_query("SELECT bib_recnum FROM {millennium_node_bib} WHERE item_recnum='%s' AND base_url = '%s'", $recnum, millennium_get_real_baseurl()));
+        $item_recnum = $recnum;
+      } else {
+        $bib_recnum = $item_recnum = $recnum;
+      }
+      switch($mode) {
+        case "items":
+          $url = "{$baseurl}/search*eng?/.{$item_recnum}/.{$bib_recnum}/1%2C1%2C1%2CB/request~{$bib_recnum}";
+          break;
+        case "marc":
+          $url = "{$baseurl}/search*eng?/.{$item_recnum}/.{$item_recnum}/1,1,1,B/marc~{$item_recnum}";
+          break;
+        case "items":
+          $num = drupal_substr($item_recnum, 1); // e.g.: 123456
+          $url = $baseurl ."/search*eng?/.{$item_recnum}/.{$bib_recnum}/1,1,1,B/holdings~{$num}&FF=&1,0,";
+          break;
+      }
   }
   #drupal_set_message("millennium_permalink($item_recnum, $mode): url: $url");
   return $url;
@@ -663,15 +728,15 @@
 
 /**
  * Takes a parsed marc record array and generates a nodeobject with type 'biblio'
- * @param item_recnum Millennium record number (i123456) that contains this MARC
+ * @param bib_recnum Millennium record number (b123456) that contains this MARC
  * @param marc_text MARC record (plaintext)
  */
-function millennium_marc_to_nodeobject($item_recnum, $marc_text) {
+function millennium_marc_to_nodeobject($marc_text, $recnum = false) {
   global $_millennium_field_labels;
 
   $marc = millennium_parse_marc($marc_text);
   if (! $marc) {
-    #return array("success" => false, "error" => "Could not parse MARC for $item_recnum");
+    #return array("success" => false, "error" => "Could not parse MARC for $bib_recnum");
     return false;
   }
 
@@ -680,8 +745,8 @@
   // LCC
   $lcc = millennium_getFieldPlain($marc, "05...");
   // If no LCC, try to get from items
-  if (trim($lcc) == "") {
-    $holdings = millennium_get_holdings_info($item_recnum);
+  if (trim($lcc) == "" && $recnum) {
+    $holdings = millennium_get_holdings_info($bib_recnum);
     // Look for first "classnumber" in items
     if (is_array($holdings)) {
       foreach ($holdings as $holding) {
@@ -887,9 +952,9 @@
   }
 
   // Others
-  $biblio["item_recnum"] = $item_recnum;
+  #$biblio["bib_recnum"] = $bib_recnum;
   $biblio["imprint"] = $biblio["imprint_place"] ." ". $biblio["imprint_name"] ." ". $biblio["imprint_date"];
-  $biblio["url"] = l(t('Link to original record'), millennium_permalink($item_recnum, "plain"));
+  $biblio["url"] = l(t('Link to original record'), millennium_permalink($bib_recnum, "plain"));
   $biblio["marc"] = $marc_text;
 
   // Clean up (almost) every $biblio[] value
@@ -940,7 +1005,7 @@
     "biblio_call_number" => $biblio["lcc"],
     "biblio_lang" => $biblio["lang"],
     "biblio_url" => $biblio["url"],
-    "biblio_custom7" => $biblio["item_recnum"],
+    "biblio_custom7" => $biblio["bib_recnum"],
     */
   );
 
@@ -1012,33 +1077,23 @@
 }
 
 /**
- * Saves a node object to the database and associates it with the Millennium record # that originated it.
+ * Saves a node object to the database
  */
 function millennium_node_add($node, $item_recnum, $bib_recnum) {
   $base_url = millennium_get_real_baseurl();
   $node = node_submit($node);
   node_save($node);
-  $nid = $node->nid;
-
-  // Add relationship to millennium_node_opacitem table
-  $result = db_query("INSERT INTO {millennium_node_opacitem} (nid, item_recnum, bib_recnum, item_updated, created, bib_updated, biblio_data, base_url) VALUES (%d, '%s', '%s', now(), now(), now(), '%s', '%s')",
-      $node->nid,
-      $item_recnum,
-      $bib_recnum,
-      serialize($node->millennium_biblio_data),
-      $base_url
-  );
   return $node;
 }
 
 /**
  * Updates an existing node object imported from a Millennium record
  */
-function millennium_node_update(&$node, $item_recnum, $bib_recnum) {
+function millennium_node_update(&$node) {
   
-  // If no node->nid, get it from recnum
+  // If no node->nid, get it from bib_recnum
   if (empty($node->nid)) {
-    $node->nid = db_result(db_query("SELECT nid FROM {millennium_node_opacitem} WHERE item_recnum = '%s' AND base_url = '%s'", $item_recnum, millennium_get_real_baseurl())); 
+    return false;
   }
   
   // Clear node cache
@@ -1052,23 +1107,7 @@
   
   // Store node in MySQL
   node_save($node);
-
-  // Add or update relationship to millennium_node_opacitem table
-  $result = db_fetch_object(db_query("SELECT * from {millennium_node_opacitem} WHERE item_recnum = '%s' AND bib_recnum= '%s' AND base_url = '%s'", $item_recnum, $bib_recnum, millennium_get_real_baseurl()));
-  if ($result->item_recnum) {
-    $result = db_query("UPDATE {millennium_node_opacitem} SET bib_updated = NOW(), biblio_data='%s' WHERE bib_recnum='%s'",
-      serialize($node->millennium_biblio_data),
-      $bib_recnum);
-  } else {
-    // Add relationship to millennium_node_opacitem table
-    $result = db_query("INSERT INTO {millennium_node_opacitem} (nid, item_recnum, bib_recnum, item_updated, created, bib_updated, biblio_data, base_url) VALUES (%d, '%s', '%s', NOW(), NOW(), NOW(), '%s', '%s')",
-        $node->nid,
-        $item_recnum,
-        $bib_recnum,
-        serialize($node->millennium_biblio_data),
-        millennium_get_real_baseurl()
-    );
-  }
+  
   return $node;
 }
 
@@ -1443,8 +1482,8 @@
 function millennium_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
   static $googleapi_js_included = false;
 
-  $item_recnum = millennium_item_recnum_from_node($node->nid);
-  if (! $item_recnum) {
+  $bib_recnum = millennium_bib_recnum_from_node($node->nid);
+  if (! $bib_recnum) {
     return;
   }
   switch ($op) {
@@ -1470,7 +1509,8 @@
       */
       break;
     case 'delete':
-      db_query("DELETE FROM {millennium_node_opacitem} WHERE nid = %d", $node->nid);
+      db_query("DELETE FROM {millennium_node_bib} WHERE nid = %d", $node->nid);
+      db_query("DELETE FROM {millennium_bib_item} WHERE nid = %d", $node->nid);
       break;
 
     case 'rss item':
@@ -1624,12 +1664,12 @@
   //    http://example.com/search?/.i[item rec num]/.b[bib rec num]/1%2C1%2C1%2CB/request%7Eb[bib rec num]
   // Another example:
   //    http://example.com/search~S16?/.i[item rec num]/.b[bib rec num]/1%2C1%2C1%2CB/request~b2405160
-  $item_recnum = millennium_item_recnum_from_node($nid);
-  if (! $item_recnum) {
+  $bib_recnum = millennium_bib_recnum_from_node($nid);
+  if (! $bib_recnum) {
     return;
   }
 
-  $hold_url = millennium_permalink($item_recnum, "hold");
+  $hold_url = millennium_permalink($bib_recnum, "hold");
   $links["millennium_holds"] = array(
     'title' => t('Place hold or request delivery'),
     'href' => $hold_url,
@@ -1754,13 +1794,14 @@
  * Return the item record number for node
  * @param nid node id
  */
+ /*
 function millennium_item_recnum_from_node($nid) {
   static $cache;
   if (isset($cache[$nid])) {
     return $cache[$nid];
   }
   else {
-    $recnum = db_result(db_query("SELECT item_recnum FROM {millennium_node_opacitem} WHERE nid=%d", $nid));
+    $recnum = db_result(db_query("SELECT item_recnum FROM {millennium_bib_item} WHERE nid=%d", $nid));
     if ($recnum) {
       $cache[$nid] = $recnum;
       return $recnum;
@@ -1770,6 +1811,7 @@
     }
   }
 }
+*/
 
 /**
  * Return the bib record number for node
@@ -1781,7 +1823,7 @@
     return $cache[$nid];
   }
   else {
-    $recnum = db_result(db_query("SELECT bib_recnum FROM {millennium_node_opacitem} WHERE nid=%d", $nid));
+    $recnum = db_result(db_query("SELECT bib_recnum FROM {millennium_node_bib} WHERE nid=%d", $nid));
     if ($recnum) {
       $cache[$nid] = $recnum;
       return $recnum;
@@ -1841,7 +1883,7 @@
       }
       $mil_page = $page ? "page" : "teaser";
 
-      $item_recnum = millennium_item_recnum_from_node($nid);
+      $bib_recnum = millennium_bib_recnum_from_node($nid);
       drupal_add_js("var millenniumModulePath = ". drupal_to_js(drupal_get_path('module', 'millennium')) .";", 'inline');
       drupal_add_js("var millenniumLoadingText = ". drupal_to_js(t('Loading...')) .";", 'inline');
       drupal_add_js("var millenniumLocale = ". drupal_to_js($mil_locale) .";", 'inline');
@@ -1850,7 +1892,7 @@
       $baseurl = millennium_get_real_baseurl();
       if ($baseurl) {
         $output .= "<div class='millennium holdings load' id='nid-$nid'>";
-        $output .= l( $msg, millennium_permalink($item_recnum));
+        $output .= l( $msg, millennium_permalink($bib_recnum));
         $output .= "</div>";
       }
       break;
@@ -1861,9 +1903,9 @@
       break;
 
     case "recordlink":
-      $item_recnum = millennium_item_recnum_from_node($nid);
+      $bib_recnum = millennium_bib_recnum_from_node($nid);
       $baseurl = millennium_get_real_baseurl();
-      $record_link = l( $msg, millennium_permalink($item_recnum));
+      $record_link = l( $msg, millennium_permalink($bib_recnum));
       $output .= "<div class='millennium holdings'>". $record_link ."</div>";
       break;
   }
@@ -2739,8 +2781,8 @@
     $output = unserialize($cache->data);
   }
   else {
-    $item_recnum = millennium_item_recnum_from_node($nid);
-    $holdings = millennium_get_holdings_info($item_recnum);
+    $bib_recnum = millennium_bib_recnum_from_node($nid);
+    $holdings = millennium_get_holdings_info($bib_recnum);
     $output = theme('millennium_holdings', $nid, $holdings, $page);
     cache_set($cid, serialize($output), 'cache', time() + 900); // 15 minutes
   }
@@ -2809,7 +2851,7 @@
     return $cache[$nid];
   }
   $data = false;
-  $result = db_result(db_query("SELECT biblio_data FROM {millennium_node_opacitem} WHERE nid = %d", $nid));
+  $result = db_result(db_query("SELECT biblio_data FROM {millennium_node_bib} WHERE nid = %d", $nid));
   if ($result) {
     $data = unserialize($result);
   }
@@ -2837,15 +2879,15 @@
 function millennium_token_values($type, $object = NULL) {
   switch ($type) {
     case 'node':
-      $item_recnum = millennium_item_recnum_from_node($object->nid);
-      if (! $item_recnum) {
+      $bib_recnum = millennium_bib_recnum_from_node($object->nid);
+      if (! $bib_recnum) {
         break;
       }
       $bib_recnum = millennium_bib_recnum_from_node($object->nid);
       $biblio_data = millennium_get_biblio_data($object->nid);
       $year = intval($biblio_data["imprint_date"]);
       $values['millennium-year']    = check_plain($year);
-      $values['millennium-item-recnum']    = check_plain($item_recnum);
+      #TODO: How to handle several values? # $values['millennium-item-recnum']    = check_plain($item_recnum);
       $values['millennium-bib-recnum']     = check_plain($bib_recnum);
       $values['millennium-authors'] = check_plain($biblio_data["authors"]);
       $values['millennium-type']    = check_plain($biblio_data["type"]);
Index: millennium_auth.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/millennium/millennium_auth.module,v
retrieving revision 1.1.2.5
diff -u -r1.1.2.5 millennium_auth.module
--- millennium_auth.module	17 Apr 2009 16:04:37 -0000	1.1.2.5
+++ millennium_auth.module	22 Oct 2009 22:01:35 -0000
@@ -160,7 +160,7 @@
   }
   foreach($items as $item) {
     // Has record been imported into Drupal?
-    $nid = db_result(db_query("SELECT nid FROM {millennium_node_opacitem} where item_recnum='%s'", $item["item_recnum"]));
+    $nid = db_result(db_query("SELECT nid FROM {millennium_bib_item} where item_recnum='%s' AND base_url = '%s'", $item["item_recnum"], millennium_get_real_baseurl()));
     if ($nid) {
       $link = l($item["title"], "node/$nid");
     }

