// ==UserScript==
// @name        XISBN LibraryLookup - UIUC Library
// @namespace   http://userscripts.org/people/4764
// @description Check availability in UIUC Voyager Catalog
// @include     http://*.amazon.*
// @include     http://*.chapters.indigo.ca/*
// @include     http://*.powells.com/*
// @include     http://*allconsuming.net/item/view/*
// ==/UserScript==

// Copied from Waterloo Public Library script - thanks dude.

// This script was inspired by Jon Udell's userscript of similar functionality
// that he posted in his 'Further adventures in lightweight service
// composition' post of 30 January, 2006
// (http://weblog.infoworld.com/udell/2006/01/30.html).
//
// I've modified the code in the following ways:
// - it's more understandable to me - your mileage may vary, but I found the
//   background DOM modification and associated event a little confusing
// - it works against the Waterloo Public Library instead of the Keene
//   libraries
// - it only hits XISBN if the original ISBN doesn't appear in the library
// - if no versions of the book are found in the library, that fact is noted
//   on the Amazon page
//
// The latest version of this script is always available at
// http://userscripts.org/scripts/show/3393
//
// Updates:
//
// 2006.03.09, later on
// - added All Consuming
//
// 2006.03.09
// - fixed broken ISBN detection on Powells
//
// 2006.03.08
// - Added builtin support for Powells web pages (a US bookseller)
// - Fixed up some logs. A little.
//
// 2006.03.05
// - split 'source page' (formerly Amazon site) functionality into separate objects
//   and added builtin support for Chapters web pages (a Canadian bookseller)

(
   function()
   {
      var libraryQueryPrefix = 'http://library.ilcso.illinois.edu/uiu'+'/cgi-bin/Pwebrecon.cgi?SAB1=';
      var libraryQuerySuffix = '&BOOL1=all%20of%20these&FLD1=ISBN%20(ISBN)&DB=local&CNT=25';
      var libraryName = 'UIUC';
      var libraryAvailability = /.*(Available|Recently|Process).*/;
      var libraryDueBack = /c.*Due.*(\d{2}\-\d{2}\-\d{2})/;
      var libraryOnHoldShelf = /.*(Missing|Lost).*/;

      var xisbnQuery = 'http://labs.oclc.org/xisbn/';

      var isbnREplain = /(\d{7,9}[\d|Xx])/g;
      var isbnREdelimited = /[^\d](\d{7,9}[\dXx])[^\dXx]/;


      var extraIsbns = [];

      // Figure out which site the source page comes from to add a new one,
      // make a new block like the "chapters" and "amazon" variables below,
      // and extend the "if...else..." block at the bottom of this function.
      function whichSiteIsThis()
      {
         var chapters =
            {
               getIsbn: function()
               {
                  isbnLinkNode = document.evaluate
                     (
                        "//td[@class='itempage_itemdetails']/a",
                        document,
                        null,
                        XPathResult.FIRST_ORDERED_NODE_TYPE, null
                        ).singleNodeValue;
                  if ( isbnLinkNode )
                  {
                     isbn = isbnLinkNode.firstChild.nodeValue;
                  }
                  return isbn;
               },

               getOriginalTitle: function()
               {
                  var origTitle = document.evaluate
                     (
                        "//div[@class='itempage_itemtitle']/b",
                        document,
                        null,
                        XPathResult.FIRST_ORDERED_NODE_TYPE, null
                        ).singleNodeValue;
                  return origTitle;
               }
            }

         var allconsuming =
            {
               getIsbn: function()
               {
                  isbnLinkNode = document.evaluate
                     (
                        "//div[@class='item-details']/h3/a[2]/@href",
                        document,
                        null,
                        XPathResult.FIRST_ORDERED_NODE_TYPE, null
                        ).singleNodeValue;
                  if ( isbnLinkNode )
                  {
                     isbn = isbnLinkNode.firstChild.nodeValue.match(isbnREdelimited)[1];
                  }
                  return isbn;
               },

               getOriginalTitle: function()
               {
                  var origTitle = document.evaluate
                     (
                        "//div[@class='item-details']/h1[@class='item-title']",
                        document,
                        null,
                        XPathResult.FIRST_ORDERED_NODE_TYPE, null
                        ).singleNodeValue;
                  return origTitle;
               }
            }

         var amazon =
            {
               getIsbn: function()
               {
                  try
                  {
                     return location.href.match(isbnREdelimited)[1];
                  }
                  catch ( e )
                  {
                     return null;
                  }
               },

               getOriginalTitle: function()
               {
                  var origTitle = document.evaluate
                     (
                        "//b[@class='sans']",
                        document,
                        null,
                        XPathResult.FIRST_ORDERED_NODE_TYPE, null
                        ).singleNodeValue;
                  return origTitle;
               }
            }

         var powells =
            {
               getIsbn: function()
               {
                  try
                  {
                     return location.href.match(isbnREdelimited)[1];
                  }
                  catch ( e )
                  {
                     return null;
                  }
               },

               getOriginalTitle: function()
               {
                  var origTitle = document.evaluate
                     (
                        "//h1[@class='title']",
                        document,
                        null,
                        XPathResult.FIRST_ORDERED_NODE_TYPE, null
                        ).singleNodeValue;
                  return origTitle;
               }
            }

         // figure out what site we're looking at
         if ( location.href.match(/chapters/) )
         {
            return chapters;
         }
         else if ( location.href.match(/allconsuming/) )
         {
            return allconsuming;
         }
         else if ( location.href.match(/powells/) )
         {
            GM_log('powells');
            return powells;
         }
         else
         {
            // Amazon's pretty popular - make it the default
            return amazon;
         }
      }

      var libraryLookup =
         {
            insertLink: function(isbn, hrefTitle, aLabel, due)
            {
               var title = origTitle.firstChild.nodeValue;
               var newTitle = document.createElement('b');
               newTitle.setAttribute('class','sans');
               var titleText = document.createTextNode(title);
               newTitle.appendChild(titleText);
               var sp = document.createTextNode(' ');
               var link = document.createElement('a');
               link.setAttribute ( 'title', link );
               link.setAttribute('href', libraryQueryPrefix + isbn + libraryQuerySuffix);
               var label = document.createTextNode( aLabel );
               link.appendChild(label);

               var div = origTitle.parentNode;
               if ( div )
               {
                  div.insertBefore(newTitle, origTitle);
                  div.insertBefore(sp, origTitle);
                  div.insertBefore(link, origTitle);
                  div.removeChild(origTitle);
               }
            },

            // Look up the alternate isbns for this one.  Store the results in
            // libraryLookup.extraIsbns and start looking them up.
            xisbn: function(isbn)
            {
               GM_xmlhttpRequest
                  (
                  {
                    method:  'GET',
                                url:     xisbnQuery + isbn,
                                onload:  function(results)
                                {
                                   page = results.responseText;
                                   extraIsbns = page.match(isbnREplain);

                                   // the first ISBN is always the search
                                   // term, so no need to look again - pop it
                                   extraIsbns.shift();

                                   GM_log('extra Isbns = ' + extraIsbns);
                                   libraryLookup.keepLooking();
                                }
                     }
                     );
            },

            // Get the results of a lookup - mark up the page and return true
            // if there's a hit, otherwise return false.
            processLookup: function(isbn, results)
            {
               page = results.responseText;
               if ( libraryAvailability.test(page) )
               {
                  libraryLookup.insertLink
                     (
                        isbn,
                        "On the shelf now!",
                        "Hey! It's available in the " +
                        libraryName + " Library!"
                        );
               }
               else if ( libraryDueBack.test(page) )
               {
                  var due = page.match(libraryDueBack)[1]
                     libraryLookup.insertLink
                     (
                        isbn,
                        "Due back " + due,
                        "Due back at the " + libraryName +
                        " Library on " + due
                        );
               }
               else if ( libraryOnHoldShelf.test(page) )
               {
                  libraryLookup.insertLink
                     (
                        isbn,
                        "Missing",
                        "Missing or lost at the " + libraryName + " Library"
                        );
               }
               else
               {
                  GM_log('couldn\'t find ' + isbn + ' at the ' + libraryName);
                  return false;
               }

               GM_log('found ' + isbn + ' - no more looking');
               return true;
            },

            // Lookup ISBNs from the libraryLookup.extraIsbns list. If there
            // aren't any extra ISBNs left, give up in disgust. Otherwise, try
            // the first ISBN. If it doesn't work out, call keepLooking again.
            keepLooking: function()
            {
               GM_log('keepLooking: extraIsbns.length = ' + extraIsbns.length);
               if ( 0 == extraIsbns.length )
               {
                  libraryLookup.insertLink
                     (
                        isbn,
                        "Isn't there",
                        "isn't at the " + libraryName + " Library"
                        );
                  return;
               }

               var isbn = extraIsbns.shift();
               GM_log('next ISBN = '  + isbn);

               // look up the next book
               GM_xmlhttpRequest
                  (
                  {
                    method:  'GET',
                                url:     libraryQueryPrefix + isbn + libraryQuerySuffix,
                                onload:  function(results)
                                {
                                   var found = libraryLookup.processLookup(isbn, results);
                                   if ( ! found )
                                   {
                                      libraryLookup.keepLooking();
                                   }
                                }
                    }
                     )
            },

            // Look up an original ISBN - if this fails, fall back to the
            // alternate ISBNs provided by xisbn
            lookupBook: function(isbn)
            {
               GM_xmlhttpRequest
                  (
                  {

                    method:  'GET',
                                url:     libraryQueryPrefix + isbn + libraryQuerySuffix,
                                onload:  function(results)
                                {
                                   var found = libraryLookup.processLookup(isbn, results);
                                   if ( ! found )
                                   {
                                      libraryLookup.xisbn(isbn);
                                   }
                                }
                    }
                     )
                  },
         } // end of libraryLookup


      var theSite = whichSiteIsThis();
      var isbn = theSite.getIsbn();
      if ( isbn )
      {
         GM_log('found isbn = "' + isbn + '" on source page');
      }
      else
      {
         return;
      }

      var origTitle = theSite.getOriginalTitle();
      if ( ! origTitle )
      {
         GM_log("couldn't find the original title");
         return;
      }

      libraryLookup.lookupBook(isbn);
   }
)();