// $Id: gbs_hsu.js,v 1.18 2008-11-28 11:49:03 uhahn Exp $

// ask GoogleSearch for isXn or PPN
// hint: PPN did not return any result yet

/* Einfuegung der div in zzgbv.asc _nach_ den Titelangaben:
Alternativen: "unterm Strich" oder rechts von den Titelangaben in der Tabelle oder besser: Styles

Ab Version (1.5) ist keine dieser Aenderungen am Picalayout 
mehr erforderlich.
Die div Tags werden per JS/DOM eingefuegt.

Ein Bookmarklet tuts auch:
javascript:var s=document.createElement("script");s.setAttribute("type", "text/javascript");s.setAttribute("src","http://hsu-bibliothek.de/GoogleBS/gbs_hsu.js");document.documentElement.firstChild.appendChild(s);void 1

<TR><TD align="left" valign="top"><TABLE
            summary="layout" width="100%"
            cellpadding="0" cellspacing="0" border="0"><%
        include(TITLE_PRESENTATION)>
    </TABLE>     <div class="GBSdata" id="GBSdata"></div>
</TD>
</TR>

zweite Tabellenspalte neben Titeldaten: (springt zu sehr hin und her)
<TR><TD align="left" valign="top"><TABLE
            summary="layout" width="100%"
            cellpadding="0" cellspacing="0" border="0"><%
        include(TITLE_PRESENTATION)>
    </TABLE>
</TD>
<td class="GBScol">   <div class="GBSdata" id="GBSdata"></div></td>
    </TR>

*/
var thisisxn;
var PicaLabelTab; // found out: this is a Pica single item view

// Pica Variablen
var presLabels=new Array('preslabel','rec_lable'); // welche gibts noch?
var blacksites=new Array('books.google.com','amazon.de','amazon.com'); // no action here @TODO move to user prefs
var preslabelClass="init";
var presvalueClass='presvalue';

// localization?
var prevtab={'full':'Volltext',
   			'partial':'Volltextauszug',
   			'noview':''};


//if(document.body) // IE has no defined "document" here, sorry
//	gbscall(document); // starting here
gbscall();

function gbscall(){
for(var i in presLabels){
	var tmptab=labelTab(presLabels[i]);
	if(tmptab){
		preslabelClass=presLabels[i];
		PicaLabelTab=tmptab;
		break;
}}

if(blacklisted()) return; // no action on sites matching blacksites[]
thisisxn=getIsxnsFromElement(document.documentElement.lastChild);
if(thisisxn.length){ // do NOTHING if no isxn found
    loadStyle("http://ub.hsu-hh.de/GBS/gbs.css");
    appendDiv('GBSdata');
    search();
//	ganalyze();
}}


/**
	@void track activity in Google Analytics
	@TODO testing..
*/
function ganalyze(){
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
    var scriptElement = document.createElement("script");
    scriptElement.setAttribute("id", "gnalyze");
    scriptElement.setAttribute("src",gaJsHost + "google-analytics.com/ga.js");
    scriptElement.setAttribute("type", "text/javascript");
    document.documentElement.firstChild.appendChild(scriptElement);

var pageTracker = _gat._getTracker("UA-4596773-2");
pageTracker._initData();
pageTracker._trackPageview();
}


/**
	@bool are we on a blacklisted URL?
	@TODO maintain blacklist with user prefs
*/
function blacklisted(){
for(i=0;i<blacksites.length;i++){ // ?? for(i in blacksites) fails on Worldcat ??
	if(0 <= document.URL.search(blacksites[i])) return true;	
	}
return false;	
}

  /**
   * This function is the call-back function for the JSON scripts which 
   * executes a Google book search response.
   *
   * @param {JSON} booksInfo is the JSON object pulled from the Google Book Search service.
   */
  function listEntries(booksInfo) {
//alert('listEntries called back');
    // Clear any old data to prepare to display the Loading... message.
    var div = document.getElementById('GBSdata');
    if (div.firstChild) div.removeChild(div.firstChild);
  
    var mainDiv = document.createElement("div");
    var gbslogosmall=document.createElement('img');
    	gbslogosmall.title="Rezensionen, Kommentare, Volltext, Bezugsquellen bei Google Books";
    	gbslogosmall.src="http://books.google.com/intl/de/googlebooks/google_booksearch.gif";
		gbslogosmall.className="gbslogosmall";
//    	gbslogosmall.style.border="0";  // set in class now
//    	gbslogosmall.style.width='100%';
    var gbslogo=gbslogosmall.cloneNode(true);
		gbslogo.src="http://books.google.com/intl/de/images/books_sm.gif";

//if(!booksInfo || "({})" == booksInfo.toSource()){
if(!booksInfo){
//alert("no booksInfo from google" );
		// request a shadow from amazon: see http://aaugh.com/imageabuse.html
    	gbslogo.src="http://images.amazon.com/images/P/"+ thisisxn[0] + ".01._PC1,1,1,1__.jpg";
		gbslogo.title=null;
       	var thumbnailDiv = document.createElement("div");
       	thumbnailDiv.style.display='none';
       	thumbnailDiv.className = "thumbnail";
       	div.appendChild(thumbnailDiv);
		thumbnailDiv.appendChild(gbslogo);
		thumbnailDiv.style.display='block';
 	return;
}

	for (i in booksInfo) {
     // Create a DIV for each book
       var book = booksInfo[i];
       var thumbnailDiv = document.createElement("div");
       thumbnailDiv.className = "thumbnail";
     	thumbnailDiv.style.display='none';
  
     // Add a link to each book's information page
        var a = document.createElement("a");
        a.href = book.info_url;
//        a.innerHTML = "Google Books" ;
		a.appendChild(gbslogo);
        a.target='_blank';
 
     // Display a thumbnail of the book's cover
		if(book.thumbnail_url){
//        var img = document.createElement("img");
//        img.src = book.thumbnail_url;    
//        a.appendChild(img);
		gbslogo.src=book.thumbnail_url; // just replace the logo with the thumbnail
        }else{ // get it from Amazon
        gbslogo.src="http://images.amazon.com/images/P/"+ thisisxn[0] + ".01._PC1,1,1,1__.jpg";
//alert("refhead: "+prefs.getIntPref("sendRefererHeader"));
//    	gbslogo.src="http://hsb.ub.hsu-hh.de/imagetest/"+ thisisxn[0] + ".jpg";
        }
        thumbnailDiv.appendChild(a);
        thumbnailDiv.style.display='block';
  
     // is there a preview available?
  	if(!PicaLabelTab){ // PICA gets the link embedded
        var p = document.createElement("p");
		if('noview'!=book.preview){        
		var atx = document.createElement("a");
	    atx.href = book.preview_url;
 		atx.appendChild(document.createTextNode(prevtab[book.preview]));
 		p.className=preslabelClass;
	    atx.target='_blank';
	    p.appendChild(atx);
		}
  
     thumbnailDiv.appendChild(p);
	}

// prepare additional Pica Attributes
// only when PICA Elements found
if(PicaLabelTab && !document.getElementById('GBSlines')){ // only once :-)
var ai = document.createElement("a");
		ai.id='GBSlines';
	    ai.href = book.info_url;
var ailogo=gbslogosmall.cloneNode(true);
//	    ailogo.style.width="10em";
 		ai.appendChild(ailogo);
	    ai.target='_blank';
addOpcTitleLine("Link:",ai)

if('noview'!=book.preview){        
	var ad = document.createElement("a");
	    ad.href = book.preview_url;
	var adlogo=gbslogosmall.cloneNode(true);
//	    adlogo.style.width="10em";
 		ad.appendChild(adlogo);
	    ad.target='_blank';
addOpcTitleLine(prevtab[book.preview] + ":",ad)
}
}
     mainDiv.appendChild(thumbnailDiv);
	break; // hier ist _ein_ Treffer immer ausreichend, da der Katalog genau einen liefert
    }
    
    div.appendChild(mainDiv);
  
  }
  
  /**
   *
   * @param {DOM object} query The form element containing the
   *                     input parameters "isbns"
   */
  function search(query) {
    // Clear any old data to prepare to display the Loading... message.
    var div = document.getElementById('GBSdata');
    if (div.firstChild) div.removeChild(div.firstChild);
  
    // Show a "Loading..." indicator.
    var p = document.createElement('p');
    p.appendChild(document.createTextNode('Loading...'));
    div.appendChild(p);
    // Delete any previous Google Book Search JSON queries.
    var jsonScript = document.getElementById("jsonScript");
    if (jsonScript) {
      jsonScript.parentNode.removeChild(jsonScript);
      }
        
    // Add a script element with the src as the user's Google Book Search query. 
    // JSON output is specified by including the alt=json-in-script argument
    // and the callback function is also specified as a URI argument.
    var scriptElement = document.createElement("script");
    scriptElement.setAttribute("id", "jsonScript");
    scriptElement.setAttribute("src",
        "http://books.google.com/books?bibkeys=" 
//        + escape(query.isbns.value) 
		+ isXns2BibKeys()
        + "&jscmd=viewapi&callback=listEntries");
    scriptElement.setAttribute("type", "text/javascript");
    // make the request to Google Book Search
    document.documentElement.firstChild.appendChild(scriptElement);

    }


/**
 *	Append an new DIV at the very end of the body
 *
 *	@param {DOM Object Id name} the created object gets this Id - doubles are not suppressed
 */
function appendDiv(id){ // letztes Elem im Body: gilt nicht nur für Pica
	if(document.getElementById(id)) return; // bitte nur einmal..
	var newdiv=document.createElement('div');
	newdiv.id=id;	

//	getOPCtitab().parentNode.appendChild(newdiv); // wuerde nur Pica Kataloge erweitern
//	document.documentElement.lastChild.appendChild(newdiv); // IE klemmt hier
	document.getElementsByTagName('body')[0].appendChild(newdiv); // nur fuer IE
}

// obsolete:
// finde die TABLE OPCtitab (die im GBV Layout keine Id hat)
// @TODO fix to match GBV XML 
function getOPCtitab(){
var labeltab=labelTab(preslabelClass); // labeltab now finds the innermost table / tbody
if(labeltab)
	return labeltab.parentNode.parentNode.parentNode.parentNode.parentNode;

return null;
}

/**
 finde das Tabellenenelement, an dem die PICA preslabel haengen (keine id noetig)
 @param {tdclass} class name of the current label class en vogue 
 (hint: a list of recognized label
 
  class names is maintained in Array presLabels[])
*/
function labelTab(tdclass){
var labeltds=new Array();
var alltds=document.getElementsByTagName('td');
for(t in alltds){ 
	if(tdclass==alltds[t].className){ 
		labeltds=labeltds.concat(alltds[t]);
	}
}
//alert(labeltds.length + " labeltds found");

if(labeltds.length){
var node=labeltds[0];
	while(node=node.parentNode){ // ist root.parentNode == null?
		if(('TBODY'==node.nodeName.toUpperCase()) || ('TABLE'==node.nodeName.toUpperCase())){
			return node;
	}}
return null;	
}}

/**
 erweitere die Titelanzeige in einem PicaOPC

 @param {label name} label:value pair which is appended to the currently displayed Pica labels
 @param{DOM Object} the value currently has to be prepared as a DOM Object
*/
function addOpcTitleLine(label,dataEl){ 
var labeltab=PicaLabelTab; // set before as found on page
if(!labeltab) return; // wo sind wir? 
var labelEl=document.createTextNode(label);

// @TODO flexible DOM Object / Text handling
//var dataEl=document.createTextNode(data);

var newrow=document.createElement('tr');
	newrow.appendChild(document.createElement('td'));
	newrow.lastChild.className=preslabelClass;
	newrow.lastChild.style.valign="top";
	newrow.lastChild.appendChild(labelEl);
	newrow.appendChild(document.createElement('td'));
	newrow.lastChild.className=presvalueClass;
	newrow.lastChild.style.valign="bottom";
	newrow.lastChild.appendChild(dataEl);

labeltab.appendChild(newrow);
    }

/**
	isxns now taken from variable (may be an Array..)
*/
function isXns2BibKeys(){   // does not depend on bibtip div tags
var isxns, ppn;

return FormatBibkeys(thisisxn.toString());
}
    
/**
	prepare the Google Book Search query parameter 
	@param{isxns} a string of isXn Numbers, possibly comma-separated
	@param{ppn} a ppn number (string or number) 
*/    
function FormatBibkeys(isxns,ppn){
var keys=new Array();

	if(isxns){
		var str=isxns.replace(/-{1}/g,"");
			str=str.match(/\b[0-9Xx]{10}\b|\b[0-9xX]{13}\b/g);  // 8-digit ISBNs not supported by Bibkeys
			
	 	if(str) keys[keys.length]='ISBN:' + str;
	 }
	if(ppn){
	keys[keys.length]='OCLC:' + ppn;
	 }
//alert(keys.join(','));	
return escape(keys);
}

/**
	load URL as a new stylesheet into the HEAD of the current Document
	@param{url} URL of type text/css or..
*/
function loadStyle(url){
var newsty = document.createElement('link');
newsty.setAttribute('type','text/css');
newsty.setAttribute('rel','stylesheet');
document.getElementsByTagName('head')[0].appendChild(newsty);
newsty.setAttribute('href',url);
}



///////////////////////////////  as found in bibtip-prepare

function getIsxnsFromElement(element) // Citavi Picker macht sich an den ISxN zu schaffen..
{
	if(!element)return null; // prevent from breaking
	var results = new Array();
	var numbers=new Array();
	
  if(element.nodeType==3){
    // text node
    str = element.data.replace(/-{1}/g,"");
    //results = str.match(/\b[0-9Xx]{10}\b|\b[0-9xX]{13}\b|\b[0-9Xx]{8}\b/g)
    // issn rausgenommen, da signatur auch 8 stellig
    numbers = str.match(/\b[0-9Xx]{10}\b|\b[0-9xX]{13}\b/g);

	if(numbers)
    for(i=0;i<numbers.length;i++){
    	curr=canon_isbn(numbers[i]);
    	if(is_isbn_checksum_valid(curr)) results=results.concat(curr); // drop non-isXn
	}
    return results;
  }
  else 
  //if (element.nodeName != 'DIV') 
  	{
    // element node
    var children=element.childNodes;
    var numChildren=children.length;
    for(var i=0;i<children.length;i++){
        results_tmp = getIsxnsFromElement(children[i]);
        if (results_tmp) {
            results = results.concat(results_tmp);
        }
    }
  }

  return results;
}

function getStringFromElement(element)
{
  var results = "";

  if(element.nodeType==3){ // text node
    str = element.data.replace(/@/g,""); // the @ in a title marks the first word of index relevance
    return str;
  }
  else 
  	//if (element.nodeName != 'DIV') 
  	{ // element node
    var children=element.childNodes 
    for(var i=0;i<children.length;i++){
        results_tmp = getStringFromElement(children[i]);
        if (results_tmp) {
            results = results.concat(results_tmp);
        }
    }
  }
  return results;
}



/**********************************************************************
taken from:
      JavaScript Validation for the "Recommend Book" Form

	    	    	by John Walker
			 October MMI

*/

/*  CANON_ISBN  --  Convert ISBN to canonical form, deleting
                    punctuation and converting any letters to
                    upper case.  Note that many forms of invalid
                    ISBNs will be passed by this code; use
                    is_ISBN_valid to check a canonical value.  */

function canon_isbn(s)
{
    var cs = s.toUpperCase(), n, ch, ocs = "";
    for (n = 0; n < cs.length; n++) {
        ch = cs.charAt(n);
        if ((ch >= '0' && (ch <= '9')) || ((ch >= 'A') && (ch <= 'Z'))) {
            ocs += ch;
        }
    }
    return ocs;
}

/*  IS_ISBN_13_CHECKSUM_VALID  --  Compute and check ISBN-13 checksum, given
                            	   ISBN-13 in canonical form.  The ISBN-13
				   checksum is computed by multiplying the
				   12 digits by alternating factors of 1 and
				   3, summing the products, then subtracting
				   the sum modulo 10 from 10.  */


function is_isbn_13_checksum_valid(s)
{
    var checksum = 0, n, v, c, f = 1;

    if (s.length != 13) {
//      dump("ISBN-13 err", "Bad length");
        return false;
    }
    for (n = 0; n < s.length; n++) {
        c = s.charAt(n);
        if ((c >= '0') && (c <= '9')) {
            v = c - '0';
        } else {
//          dump("ISBN-13 err", "Invalid character");
        }
        checksum += f * v;
	f = (f + 2) & 3;
    }
    checksum %= 10;

    return (checksum == 0);
}

/*  IS_ISBN_CHECKSUM_VALID  --  Compute and check ISBN checksum, given
                                ISBN in canonical form.  */


function is_isbn_checksum_valid(s)
{
    var checksum = 0, n, v, c;

    if (s.length == 13) {
    	return is_isbn_13_checksum_valid(s);
    }

    if (s.length != 10) {
//      dump("ISBN err", "Bad length");
        return false;
    }
    for (n = 0; n < s.length; n++) {
        c = s.charAt(n);
        if ((c >= '0') && (c <= '9')) {
            v = c - '0';
        } else if (c == 'X') {
            if (n != 9) {
//              dump("ISBN err", "X not last character");
                return false;
            }
            v = 10;
        } else {
//          dump("ISBN err", "Invalid character");
        }
        checksum += (10 - n) * v;
    }
    checksum %= 11;
    return (checksum == 0);
}

/*  TRIM  -- Trim leading and trailing blanks from a string.  */

function trim(s)
{
    var first, last, fnb = false;

    for (n = 0; n < s.length; n++) {
        if (s.charAt(n) != ' ') {
            if (!fnb) {
                first = n;
                fnb = true;
            }
            last = n;
        }
    }
    if (fnb) {
        return(s.substring(first, last + 1));
    } else {
        return "";
    }
}
