//
// Utilities for publications list.
//
// Contact/licensing details on http://publicationslist.org
//
// Copyright (c) 2007 Textensor Limited (www.textensor.com)
//
//

var noexport = false;

function getReq() {
  var req;  if (window.XMLHttpRequest) {    req = new XMLHttpRequest();  }
  else {    req = new ActiveXObject("Microsoft.XMLHTTP");  }  return req;
}

function fetchURL(url) {
  var req = getReq();    
  req.open("GET", url, false);  
  req.send(null);  
  var ret = req.responseText;
  return ret;  
}

function postURL(url, args) { 
  var req = getReq();    
  req.open("POST", url, false);  
  req.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
  req.send(args);  
  var ret = req.responseText;
  return ret;  
}

 function findRef(refid) {
   for (var i=0; i<publist.length; i++) {
     if (publist[i].refid == refid) {
       return publist[i];
     }
   }
 }

 function removeRef(refid) {
   for (var i=0; i<publist.length; i++) {
     if (publist[i].refid == refid) {
       publist.splice(i,1);
       return true;
     }
   }
   return false;
 }

function maybeDelete(refid) {
  var ref = findRef(refid);
  var txt = ref.author +" (" + ref.year+") "+ ref.title;

  if (window.confirm("Really delete reference: \n"+txt+"?")) {
    document.location = "deleteRef.php?u="+userid+"&refid="+refid;
  }
}


 function exportSelected(format) {
   var txt = "";
   for (el in selectedById) {
     if (selectedById[el]) {
       if (txt != "") { txt += ","; }
       txt += el;
     }
   }  

   //  alert("txt is "+txt);
   var ret = postURL("exportRef.php?refid=export&fmt="+format+"&u="+userid, "ids="+txt);
   if (ret.substring(0,5) == "OK - ") {
     // alert("Got back "+ret);
     window.open(ret.substring(4), "_blank");
   }
   else {
     alert("Problem exporting : "+ret);
   }   
 }

 
 function deleteSelected() {
   if (window.confirm("Delete "+selectedCount+" highlighted entries?")) {
     // Get a list of selected entries.
     
     var txt = "";
     for (el in selectedById) {
       if (selectedById[el]) {
	 if (txt != "") { txt += ","; }
	 txt += el;
	 removeRef(el);
       }
     }
     
     selectedById = new Object();
     
     //  alert("Highlighted entries are "+txt);
     var ret = postURL("deleteSelected.php", "ids="+txt);
     display();
     countSelected();
     updateTags();
     updateAuthors();

     updateStatus(prevexp, prevvalid, prevpublink, false);

     alert(ret);
     //     document.location = "deleteRecent.php?u="+userid;
   }
 }
 
 

function importSelected() {
  if (window.confirm("Import "+selectedCount+" highlighted entries?")) {
     var txt = "";
     for (el in selectedById) {
       if (selectedById[el]) {
	 if (txt != "") { txt += ","; }
	 txt += el;
       }
     }
     
     var ret = postURL("importSelected.php", "ids="+txt);
     alert(ret);

   }
 }
 


 // array by refid
 var expandedRefs = new Array();
 
 function toggleRef(i) {
   if (expandedRefs[publist[i].refid]) {
     collapseRef(i);
   }
   else {
     expandRef(i);
   }
 }

 function expandRef(i) {
   var div = document.getElementById("list"+i);
   var txt = getRefHtml(i, publist[i], true, publist[i].userid);
   var d2 = document.createElement('div');
   d2.innerHTML = txt;
   removeChildren(div);
   div.appendChild(d2);

   expandedRefs[publist[i].refid] = true;

   //var editdiv = document.getElementById("editref"+i);
   //if (editdiv) editdiv.style.visibility = "visible";


   /*
   if (document.all) { 
	 div.style.minWidth = "0px";
	 div.style.border = "1px solid red";	 
	 var td = document.getElementById("td-"+i);
	 td.innerHTML = td.innerHTML;
   }
   */
   //forceRepaint();
 }

 function collapseRef(i) {
   var div = document.getElementById("list"+i);
   var txt = getRefHtml(i, publist[i], false, publist[i].userid);
   var d2 = document.createElement('div');
   d2.innerHTML = txt;
   removeChildren(div);
   div.appendChild(d2);
   expandedRefs[publist[i].refid] = false;
   // var editdiv = document.getElementById("editref"+i);
   // if (editdiv) editdiv.style.visibility = "hidden";

   /*
   if (document.all) { 
	 div.style.minWidth = "0px";
	 div.style.border = "1px solid blue";	 
	 var td = document.getElementById("td-"+i);
	 td.innerHTML = td.innerHTML; 
   }
   */
   //   forceRepaint();
 }


function publish() {
  // alert("about to publish");
  var el = document.getElementById("publistdiv");
  var txt = el.innerHTML; 

  var pubform = document.getElementById("pubformid");
  var publisthtml = document.getElementById("publisthtml");
  //  alert("got "+pubform+" and "+publisthtml);
  publisthtml.value = txt;

  //  alert("sending stuff "+txt);
  pubform.submit();
  
  // alert("Posting "+txt);
}

 function isChecked(i) {
   var check = document.getElementById("check"+i);
   if (check && check.checked) {
     return true;
   }
   return false;
 }

 function toggleChecked(i, nocount) {
   var refdiv = document.getElementById("refdiv"+i);
   var editdiv = document.getElementById("editref"+i);

   var checked = isChecked(i);
   if (checked) {
     refdiv.className = "refdiv selref";
	// if (editdiv) editdiv.style.visibility = "visible";
   }
   else {
     refdiv.className = "refdiv";
	// if (editdiv) editdiv.style.visibility = "hidden";
   }
   var refid = publist[i].refid;

   selectedById[refid] = checked;

   if (nocount) {} else {
     countSelected();
   }

   //   alert("Repainting");
   forceRepaint();
 }
 
 var selectedCount = 0;

 var countByTag = false;
 var allTags = new Array();
 
 function updateTags() {
   countByTag = new Object();
   allTags = new Array();
   allTags[0] = "(no tag)";
   countByTag[allTags[0]] = 0;
   for (var i=0; i<publist.length; i++) {
     var ref = publist[i];
     var tags = ref.tags;
     if (tags) {
       var list = splitTags(tags); // tags.split(",");
       for (var j=0; j<list.length; j++) {
	 var tag = trim(list[j]);  
	 if (tag) {
	   if (!countByTag[tag]) { 
	     allTags[allTags.length] = tag; 
	     countByTag[tag] = 0;
	   }
	   countByTag[tag]++;
	 }
       }
     }
     else {
       countByTag["(no tag)"] ++;
     }
   }

   // Sort the tag list.
   allTags.sort(function(a,b) { 
		  if (a=="(no tag)") { return -1; }
		  if (a.toLowerCase() < b.toLowerCase()) { return -1; }
		  if (a.toLowerCase() > b.toLowerCase()) { return 1; }
		  return 0;
		});
   
   // Update the list.
   var el = document.getElementById("tagslist");
   if (el) {
     var txt = "";
     if (allTags.length > 1) {
       el.style.display="block";
       txt += "<b>All Tags:</b> &nbsp;";
       for (var i=1; i<allTags.length; i++) {
	 var tag = allTags[i];
	 if (tag != "") {
	   var count = countByTag[tag];
	   var cstr = (count==1) ? "" : "&nbsp;("+count+")";
	   var htag = tag.replace(" ", "&nbsp;");
	   if (i!=1) { txt += ",&nbsp;&nbsp; "; }
	   txt += "<a class='atag' href='javascript:showTags("+i+")'>"+htag+"</a>"+cstr+"";
	 }
       }
       var div = document.createElement("div");
       //div.style.fontSize = "70%";
       div.innerHTML = txt;
       removeChildren(el);
       el.appendChild(div);
     }
     else {
       el.style.display="none";
     }
   }
 }

 // Version with string
 function showTag(str) {
   selectByTag(str);
 }
 function showTags(i) {
   selectByTag(allTags[i]);
 }
 function showAuthor(str) {
   selectByAuthor(str);
 }
 function showAuthors(i) {
   selectByAuthor(allAuthors[i]);
 }

 var countByAuthor = new Object();

 function lastName(a) {
   var i = a.lastIndexOf(" ");

   // Check for Joe van Bloggs - last name van Bloggs, 
   return a.substr(i);
 }


 // Form: "F Howell"
 function normaliseAuthorObj(aobj) {
   var first = aobj.first;
   var last = aobj.last;
   if (first.length > 1) { first = first.charAt(0); }
   if (first) { return first + " " + last; }
   return last;
 }

 function normaliseAuthor(a) {
   var words = a.split(" ");
   var first = "";

   var last = "";
   if (words.length > 0) { last = words[words.length -1]; }
   if (words.length > 1) { first = words[0].charAt(0); }
   if (words.length > 2) { 
     // Check for van, de, le
     var mid = words[words.length-2];
     if (mid != "" && mid == mid.toLowerCase()) {
       last = mid+" "+last;
       first = words[0].charAt(0); 
     }
   }

   if (first) { return first + " " + last; }
   return last;
 }

 function updateAuthors() {
   countByAuthor = new Object();
   allAuthors = new Array();
   //   allAuthors[0] = "(no author)";
   //countByAuthor[allAuthors[0]] = 0;
   for (var i=0; i<publist.length; i++) {
     var ref = publist[i];
     var authors = ref.author;
     if (authors) {
	   
	   var list = authorStringToArray(authors);

       for (var j=0; j<list.length; j++) {
		 var obj = list[j];
		 
		 // Normalise to A Other 
		 var author = normaliseAuthorObj(obj);
		 if (author) {
		   if (!countByAuthor[author]) { 
			 allAuthors[allAuthors.length] = author; 
			 countByAuthor[author] = 0;
		   }
		   countByAuthor[author]++;
		 }
       }
     }
   }

   // Sort the author list.
   allAuthors.sort(function(a,b) { 
		  var la = lastName(a).toLowerCase();
		  var lb = lastName(b).toLowerCase();
		  if (la < lb) { return -1; }
		  if (la > lb) { return 1; }
		  return (a > b);
		});
   
   // Update the list.
   var el = document.getElementById("authorslist");
   var txt = "";
   if (allAuthors.length > 0) {
     el.style.display = "block";
     txt += "<h4>Authors</h4>";
     for (var i=0; i<allAuthors.length; i++) {
       var author = allAuthors[i];
       if (author != "") {
		 var count = countByAuthor[author];
		 var cstr = (count==1) ? "" : "&nbsp;("+count+")";
		 var hauthor = author.replace(" ", "&nbsp;");
		 if (i!=0) { txt += ",&nbsp;&nbsp; "; }
		 txt += "<a class='aauthor' href='javascript:showAuthors("+i+")'>"+hauthor+"</a>"+cstr+"";
       }
     }
     var div = document.createElement("div");
	 //     div.style.fontSize = "70%";
     div.innerHTML = txt;
     removeChildren(el);
     el.appendChild(div);
   }
   else {
     el.style.display = "none";
   }
 }


 function countSelected() {
   if ((editmode != "indexsel") && (editmode != "edit" || readonly)) { return; }
   selectedCount = 0;
   for (var i=0; i<publist.length; i++) {
     var checked = isChecked(i);
     if (checked) {
       selectedCount ++;
     }
   }

   var el = document.getElementById('selectops');
   if (selectedCount == 0) {
     // Hide the delete /export box.     
     el.style.display = "none";
   }
   else {
     // Show the delete /export box.
     el.style.display = "block";

     //     alert("Recounting - got "+selectedCount);
     var selcountid = document.getElementById('selcountid');
     var txt =  ""+selectedCount+" item";
     if (selectedCount>1) { txt+="s"; }
     selcountid.innerHTML = txt;
   }
 }

 function selectAll() {
   for (var i=0; i<publist.length; i++) {
     var check = document.getElementById("check"+i);
     if (check && !check.checked) {
       check.checked = true;
       toggleChecked(i, true);
     }
   }
   countSelected();
 }

 function selectNone() {
   for (var i=0; i<publist.length; i++) {
     var check = document.getElementById("check"+i);
     if (check && check.checked) {
       check.checked = false;
       toggleChecked(i, true);
     }
   }
   countSelected();
 }

 function selectByTag(tag) {
   var lctag = tag.toLowerCase();
   selectNone();

   var firstnum = -1;
   for (var i=0; i<publist.length; i++) {
     var ref = publist[i];
     var tags = trim(ref.tags.toLowerCase());
     var match = false;
     if (lctag == "(no tag)" && tags == "") {
       match = true;
     }
     else if (tags.indexOf(lctag) != -1) {
       var list = splitTags(tags);
       for (var j=0; j<list.length; j++) {
	 if (lctag == trim(list[j])) {
	   match = true;
	 }
       }
     }
     if (match) { 
       if (firstnum==-1) firstnum = i;
       var check = document.getElementById("check"+i);
       if (check) {
	 check.checked = true;
       }
       toggleChecked(i, true);
     }
   }
   countSelected();
   if (firstnum != -1) {	
	 jumpAnchor("#refno"+(firstnum));
   }
 }

 function selectByAuthor(author) {
   var lastauthor = lastName(author.toLowerCase());
   var nauthor = normaliseAuthor(author);

   selectNone();

   var firstnum = -1;
   for (var i=0; i<publist.length; i++) {
     var ref = publist[i];
     var authors = ref.author;
     if (authors) {
       var lauthors = authors.toLowerCase();
       var match = false;

       if (lauthors.indexOf(lastauthor) != -1) {
		 var list = authorStringToArray(authors);

		 for (var j=0; j<list.length; j++) {	 
		   if (nauthor == normaliseAuthorObj(list[j])) {
			 match = true;
		   }
		 }
       }
       if (match) { 
		 if (firstnum==-1) firstnum = i;
		 var check = document.getElementById("check"+i);
		 if (check) {
		   check.checked = true;
		 }
		 toggleChecked(i, true);
       }
     }
   }
   countSelected();
   //   alert("Done sel by author "+author);
   if (firstnum != -1) {
	 jumpAnchor("#refno"+(firstnum));
   }
 }

// Jump to anchor on same page
function jumpAnchor(a) {
  var oldloc = "" + document.location;
  var hpos = oldloc.indexOf("#");
  if (hpos != -1) {
	oldloc = oldloc.substring(0, hpos);
  }
  document.location = oldloc + a;
}

 function hideHighlight(i) {
   var refdiv = document.getElementById("refdiv"+i);
   refdiv.className = "refdiv";
 }

 function showHighlight(i) {
   var refdiv = document.getElementById("refdiv"+i);
   //   var check = document.getElementById("check"+i);
   if (isChecked(i)) {
     refdiv.className = "refdiv selref";
   }
   else {
     refdiv.className = "refdiv";
   }
 }


// Get reference for given user.
function getRefHtml(i, ref, expanded, user) {
   txt = "";

   // format : 123 or a.n.other-123
   var fullid = ref.refid;
   
   if (!user) {
     user = userid;
   }

   /*
   else {
     // Full id: includes user.
     fullid = user +"-"+ref.refid;
   }
   */   

   var sty = (editmode=='preview') ? "display:none" : "";

   var selected = selectedById[fullid];
   var seltxt = selected ? " checked='1' " : "";

   var chksty = ((editmode=="edit" && !readonly) || editmode=="indexsel") ? "" : "display:none";

   txt = "<input style='float: right; border:none; "+chksty+"' id='check"+i+"' type='checkbox' "+seltxt+" onclick='toggleChecked("+i+", false)'>";



   // Add an expand / collapse control.
   //txt += "<div style='float:left; margin-left:-2em; margin-top: -0.3em; z-index:100'>";
   txt += "<div style='float:left;'>";
   if (!expanded) {
	 txt += "<a href='javascript:expandRef("+i+")' title='Show details'><img src='"+rootpath+"laf/triangle-sml.png' /></a>";
   }
   else {
     txt += "<a href='javascript:collapseRef("+i+")' title='Hide details'><img src='"+rootpath+"laf/triangle-sml-down.png'/></a>";
   }
   txt += "</div>";

   // white border gets around Safari layout bug.
   txt += "<a name='refno"+i+"' style='position:relative; top: -80px'></a><a name='refid"+fullid+"' style='position:relative; top: -80px'></a><div id='refdiv"+i+"' style='border:1px solid white; margin-left:2em;'";
   
   if (selected) {
     txt += " class='refdiv selref'>";
   }
   else {
     txt += " class='refdiv'>";
   }

   if (!readonly) {
	 var vis = "visibility:hidden;";
	 if (true || expanded) {
	   vis = "visibility:visible;";
	 }
	 
	 txt += "<div id='editref"+i+"' class='flright' style='float:right; "+vis+" padding-left:3em; "+sty+"'><a title='Edit reference' href='editRef.php?refid="+ref.refid+"'><img alt='edit' src=\""+rootpath+"edit-sml.png\"/></a>&nbsp;&nbsp;<a href='javascript:maybeDelete("+ref.refid+")' title='Delete reference'><img alt='delete' src=\""+rootpath+"delete-sml.png\"/></a>&nbsp;&nbsp;</div>";
   }
   
 
   if (ref.doi || ref.urllink || ref.pdflink || ref.attachment || ref.pubmed) {
   }
   else {
     if (!readonly) { 
       var sty = (editmode=='preview') ? "display:none" : "";

       txt += "<div id='addlink"+i+"' style='padding-left : 12px; float:right; "+sty+"'><a title='No full text link yet - add it now' style='color:red; text-decoration:none;' href='editRef.php?refid="+ref.refid+"#fulltext'> <img alt='clip' src=\""+rootpath+"clip-col-sml.png\"/> </a></div>";
     }
   }

   txt += refToHtml(ref.articletype, ref, expanded, user, rootpath, i);


   // Add the duplicate tags for index.
   var key = getPaperKey(ref);
   if (key && bypaperkey) {
     var ulist = bypaperkey[key];
     if (ulist) {
       if (ulist.length > 1) {
	 txt += " <span class='dup'>[";
	 var first = true;
	 for (var k=0; k<ulist.length; k++) {
	   var duser = ulist[k];
	   if (duser != user) {
	     if (!first) { txt += ", "; } else { txt += "also in "; }
	     txt += duser+"'s list";
	     first = false;
	   }
	 }
	 if (first) {
	   txt += "duplicate entry";
	 }
	 txt += "]</span> ";
       }
     }
   } 


   if (expanded && !noexport) {
     var refid = publist[i].refid;
     txt += "<div style='clear:right; float:right; padding:1em; font-size:8pt;'>";
     txt += "<a target='_blank' href='"+rootpath+"php/exportRef.php?u="+user+"&refid="+refid+"&fmt=bibtex'>bibtex</a> | ";
     txt += "<a target='_blank' href='"+rootpath+"php/exportRef.php?u="+user+"&refid="+refid+"&fmt=endnote'>endnote</a> | ";
     txt += "<a target='_blank' href='"+rootpath+"php/exportRef.php?u="+user+"&refid="+refid+"&fmt=ris'>procite (RIS)</a> | ";
     txt += "<a target='_blank' href='"+rootpath+"php/exportRef.php?u="+user+"&refid="+refid+"&fmt=isi'>ISI</a> | ";
     txt += "<a target='_blank' href='"+rootpath+"php/exportRef.php?u="+user+"&refid="+refid+"&fmt=xml'>XML</a> ";
     txt += "</div><div style='clear:right'></div>\n";
   }   

   txt += "</div>"; // refdiv

   return txt;
 }


/* --- other display modes not used.

 function displayOrigOrder(div) {
   for (var i=0; i<publist.length; i++) {
     var ref = publist[i];
     var el = document.createElement("div");
     el.className = "publication";
     el.id = "list"+i;
     
     txt = getRefHtml(i, ref, false);
     el.innerHTML = txt;
     div.appendChild(el);
   }   
 }

 function displayByYear(div) {
   var byyear = new Object();
   var keys = new Array();
   for (var i=0; i<publist.length; i++) {
     var ref = publist[i];
     var year = "- no year specified -";

     if (ref.year) {
       year = ref.year; // could get 1st 4 chars
     }
     else {
       //  alert("strange year "+ref.year);
     }
     
     if (!byyear[year]) {
       byyear[year] = new Array();
       keys[keys.length] = year;
       // alert("got a year "+year + " keys length "+keys.length);
     }
     byyear[year][byyear[year].length] = i;         
   }
   keys.sort();


   for (var y = keys.length-1; y>=0; y--) {
     var el = document.createElement("h2");
     el.className='yeartitle';
     div.appendChild(el);
     var year = keys[y];    
     el.innerHTML = year;
     //alert("Got year "+year);
     var subdiv = document.createElement("div");
     subdiv.className = 'yearindent';
     div.appendChild(subdiv);

     for (var i=0; i<byyear[year].length; i++) {
       var el = document.createElement("div");
       el.className = "publication";
       var pli = byyear[year][i];
       var ref = publist[ pli ];
       el.id = "list"+pli;
       txt = getRefHtml(pli, ref, false);
       el.innerHTML = txt;
       subdiv.appendChild(el);
     }
   }      
 }

*/

// Get a key for a paper.
function getPaperKey(ref) {
  var ret = "";
  ret += trim(ref.year)+"-";
   
  // Try for volume * pages match...
  if (ref.volume && ref.pages) { 
	if (ref.volume) {
	  ret += trim(ref.volume)+"-";
	}
	if (ref.number) {
	  ret += trim(ref.number)+"-";
	}
	if (ref.pages) {
	  ret += trim(ref.pages)+"-";
	}
  }
  else {
	if (ref.author) {
	  var list = authorStringToArray(ref.author.toUpperCase());
	  for (var j=0; j<list.length; j++) {
		var obj = list[j];
		var astr = normaliseAuthorObj(obj);
		if (astr) {
		  ret += astr.toLowerCase()+"-";
		}
	  }
	}

	if (ref.title) {
	  // Remove '-' characters....
	  var t2 = ref.title;
	  if (t2.indexOf("-")!=-1) {
		t2 = t2.replace("-", " ");		
	  }
	  ret += trim(t2).toLowerCase()+"-";
	}
	else if (ref.booktitle) {
	  ret += trim(ref.booktitle).toLowerCase()+"-";
	}
	if (ref.journal) {
	  ret += trim(ref.journal).toLowerCase()+"-";
	}
  }

  return ret;
}

// paper key -> list of users.
var bypaperkey = false;



// Global vars for callback.
// var worklist = false;
// var workstart = 0;
var batchsize = 10;
var workdelay = 10;

function displaycb() {
  if (worklist) {
    //  alert("Doing ref "+workstart+" to "+(workstart + batchsize));
    for (var k=workstart; k<worklist.length && k < workstart+batchsize; k++) {
      var work = worklist[k];
      var pli = work["pli"];
      var ref = work["ref"];
      var el = work["el"];
      var user = work["user"];
      var key = work["key"];
      var txt = getRefHtml(pli, ref, false, user);
    
      el.innerHTML = txt;
    }

    workstart += batchsize;
    if (workstart < worklist.length) {
      setTimeout(displaycb, workdelay);
    }
    else {
      worklist = false;
      countSelected(); // update it...
    }
  }
}

 function displayByType(div) {
   displayRangeByType(div, 0, publist.length, true);
 }

// Display a range of pubs from publist
function displayRangeByType(div, startpli, endpli, doreset) {
   var bytype = new Object();
   var keys = new Array();
   
   if (doreset || (typeof(worklist) == "undefined") || worklist === false) {
	 worklist = new Array();
	 workstart = 0;
   }
   
   // Order of sections.   
   var inits = ["article", "book", "inbook", "inproceedings"];
   for (var i=0; i<inits.length; i++) {
     var dtype = getDisplayType(inits[i]);
     keys[i] = dtype;
     bytype[dtype] = new Array();
   }
   keys[0] = getDisplayType("article");
   keys[1] = getDisplayType("book");
   keys[2] = getDisplayType("inbook");
   keys[3] = getDisplayType("inproceedings");

   for (var i=startpli; i<endpli; i++) {
     var ref = publist[i];
     var atype = "misc";

     if (ref.articletype) {
       atype = ref.articletype;
     }
     var dtype = getDisplayType(atype);
     if (atype == "misc" && ref.sectionheading) {
       dtype = ref.sectionheading;
     }
     
     if (!bytype[dtype]) {
       bytype[dtype] = new Array();
       keys[keys.length] = dtype;
     }
     bytype[dtype][bytype[dtype].length] = i;         
   }
  
   // Main table for pubs.
   var tbl = document.createElement("table");
   tbl.style.width = "95%"; // 100% no good for IE
   tbl.style.tableLayout = "fixed";
   div.appendChild(tbl);
   
   var tr = tbl.insertRow(-1);
   var td = tr.insertCell(-1);
   td.style.width='40px';
   var td = tr.insertCell(-1);

   // Start vertical label after 6 publications and continue for 4.
   var typerepeat = 6;
   var typespace  = 4; 

   for (var t = 0; t<keys.length; t++) {
     var el = document.createElement("h2");
     el.className='yeartitle';
     var dtype = keys[t];    

	 // Article type.

     if (bytype[dtype].length > 0) {
	   var tr  = tbl.insertRow(-1);
	   var td = tr.insertCell(-1);
	   td.colSpan = "2";
	   //td.style.width="auto";
       el.innerHTML = dtype;
       td.appendChild(el);

	   	   	   
	   var tr = tbl.insertRow(-1);
	   var td = tr.insertCell(-1);
       td.style.width="100px";
       var subdiv = document.createElement("div");
       subdiv.className = 'yearindent';
       td.appendChild(subdiv);
       
       var ret = sortWithinByYear(bytype[dtype]);
       
       var prevy = "";

       var typeidx = 0; // counter for vert label

       for (var i=0; i<ret.length; i++) {
		 var el = document.createElement("div");
		 el.className = "publication";
		 var pli = ret[i];
		 var ref = publist[ pli ];
		 el.id = "list"+pli;
		 var txt = "";
		 
		 typeidx ++;
		 if (typeidx == typerepeat && i < ret.length - typespace) {
		   // Add a vertical 'journal articles' label
		   var tr = tbl.insertRow(-1);
		   var td = tr.insertCell(-1);
		   var vdiv = document.createElement("div");
		   vdiv.style.position = "relative";
		   vdiv.style.height = "0px";
		   td.appendChild(vdiv);
		   var img = imagesByType[ref.articletype];
		   // alert(img);
		   vdiv.innerHTML = "<div style='position : absolute; left:-50px; z-index : 0'><img class='ja' title='"+dtype+"' src='"+rootpath+img+"'/></div>";
		   
		   typeidx = -typespace;
		 }
		

		 var tr = tbl.insertRow(-1);
		 var td = tr.insertCell(-1);

         if (ref.year != prevy) {
             var ydiv = document.createElement("div");
		     ydiv.className = "yearsep";
		     ydiv.innerHTML = ref.year;		   
		     td.appendChild(ydiv);			 
		     td.style.verticalAlign="top";
             prevy = ref.year;
         }

		 var td = tr.insertCell(-1);
		 td.appendChild(el);
		 td.id = "td-"+pli;
		 
		 var workuser = userid;
		 if (ref.userid) {
		   workuser = ref.userid;
		 }

		 worklist[worklist.length] = {"pli":pli, "ref":ref, "subdiv":subdiv, "el":el, "user":workuser};
       }
     }
   } 
     
   // Draw the refs on callback.
   displaycb();
   // setTimeout(displaycb, workdelay);
 }


 // Sort within an indexed array by fld.
 function sortWithinByYear(ary) {
   var ret = new Array();
   for (var i=0; i<ary.length; i++) {
     ret[i] = ary[i];
   }
   
   ret.sort(function(a,b) { 
	      var y1 = publist[a].year;
	      var y2 = publist[b].year;
	      if (y1 > y2) { return -1; }
	      if (y1 < y2) { return 1; }
	      return 0;
	    });
   return ret;
 }

var displayMode = "type";

function authorInfo() {
    var txt = '';
	if (mode == "publish") { return ""; } // Don't display help info
    txt += '<h2>About you</h2>';
    txt += "<p><i>The 'Author details' section lets you add your work address, home page and ";
	txt += "other biographical information."; 
    txt += '</i></p>';
    return txt;
}


// Filter a publications list by tag.
// Returns a shorter list with only the matching elements.
function filterByTag(plist, mtag) {
  var ret = new Array();
  for (var i=0; i<plist.length; i++) {
	var el = plist[i];

	// Do the tags match?
	var t = el["tags"];
	var l = splitTags(t);
	var found = false;

	for (var j=0; j<l.length && !found; j++) {
	  var tag = trim(l[j]);  
	  if (tag) {
		if (tag.toLowerCase() == mtag.toLowerCase()) {
		  found = true;
		}
	  }
	}
	if (found) {
	  ret[ret.length] = el;
	}
  }
  return ret;
}


function display() {
    var div = document.getElementById('publistdiv');
    if (div) {
      removeChildren(div);
    }

    var txt = '';
    if (!publist || publist.length==0) {
      txt = "&nbsp;";      
      if (!readonly) {

	var firstname = trim(details["firstname"]);
	var lastname = trim(details["lastname"]);
	var lookup = firstname+"_"+lastname;
    txt = '<h2>Your publications</h2>';
	txt += "<div id='clickhelpid'><br/><p><i>";
	txt += "Click the '<b>Add a paper</b>' button above to enter details for your publications ";
	txt += "or import citation information from Bibtex, Endnote, Reference Manager, PubMed ";
	txt += "and other formats.";
	
	txt += "<br/><br/>You can also search the author index for <a target='_blank' href='"+rootpath+"php/authors.php?a="+lookup+"'>"+firstname+" "+lastname+"</a> to check if your co-authors have already added some of your publications for you to add to your list.";

	txt += "<br/><br/><h4>PubMed users</h4>Biomedical researchers can <a href='pubmed.php'>lookup publications on PubMed using the integrated search page</a> and import selected papers. See also the 'pubmed' link in the top right.";

	txt += "</p></div>";
      }
	  else {
		if (!publist) {
		  txt = "<b>Publications list not available</b>";
		}
	  }
      var el = document.createElement("div");
      el.innerHTML = txt;
      div.appendChild(el);
    }
    else {
      if (displayMode=="type") {
	displayByType(div);
      }
      else {
	displayByYear(div);
      }
    }
}

 function updateControls(mode) {
   var el = document.getElementById("controlsid");
   var txt  = "";
   var div = document.createElement("div");
   txt = "Arrange by ";
   if (mode != "date") {
     txt += "<a class='control' href='javascript:setDateMode()'>date</a> |  ";
   }   
   else {
     txt += "<b>date</b> |  ";
   }

   if (mode != "type") {
     txt += "<a class='control' href='javascript:setTypeMode()'>article type</a> | ";
   }   
   else {
     txt += "<b>article type</b>  ";
   }

   if (mode != "both") {
     txt += "<a class='control' href='javascript:setBothMode()'>type and date</a> ";
   }   
   else {
     txt += "<b>type and date</b>  ";
   }

   div.innerHTML = txt;
   removeChildren(el);
   el.appendChild(div);
 }

 function setDateMode() {
   displayMode = "date";
   updateControls(displayMode);
   display();
 }

 function setBothMode() {
   displayMode = "both";
   updateControls(displayMode);
   display();
 }

 function setTypeMode() {
   displayMode = "type";
   updateControls(displayMode);
   display();
 }

function setDetailField(field) {
  if (details[field]) {
    var el = document.getElementById(field+'id');
    if (el) {
	  var txt = details[field];

	  /* Nastiness because IE innerhtml is broken */
	  txt = txt.replace(/\n/g, "<br/>"); 
	  txt = txt.replace(/\r/g, ""); 

	  el.innerHTML = txt;
    }
    else {
      alert(field+" not found");
    }
  }
}


 var editmode = "edit";

 // toggle display of edit controls.
 function toggleEdits(mode) {
   document.getElementById('editlinksid').style.display=mode;
   document.getElementById('selectid').style.display=mode;
   var clickhelp = document.getElementById('clickhelpid');
   if (clickhelp) { clickhelp.style.display=mode; }

   for (var i=0; i<publist.length; i++) {
	 // Don't hide edit controls
	 //     document.getElementById('editref'+i).style.display=mode;
     var lel = document.getElementById('addlink'+i);
     if (lel) { lel.style.display=mode; }
     var cel = document.getElementById('check'+i);
     if (cel) { cel.style.display=mode; }

     if (mode=='block') { showHighlight(i); } else { hideHighlight(i); }
   }   
 }

 function edit() {
   editmode = "edit";
   editControls();
   toggleEdits("block");
   countSelected();
 }

 function preview() {
   editmode = "preview";
   document.getElementById("selectops").style.display="none";
   editControls();
   selectedById = new Object(); // zap selections.
   toggleEdits("none");
 }

 function editControls() {
   return;
   if (ownpage) {
     var el = document.getElementById('editbuttons');
     removeChildren(el);
     var div = document.createElement("div");
     var txt = "";
     if (editmode == "edit") {
       txt = "<div class='selbutton'>Edit</div>&nbsp;&nbsp;<a class='unselbutton' href='javascript:preview()'>Preview</a>&nbsp;&nbsp;<a class='unselbutton' target='_blank' href='publist.php?u="+userid+"&m=publish'>Publish</a>";
     }
     else if (editmode == "preview") {
       txt = "<a class='unselbutton' href='javascript:edit()'>Edit</a>&nbsp;&nbsp;<div class='selbutton'>Preview</div>&nbsp;&nbsp;<a class='unselbutton'  target='_blank' href='publist.php?u="+userid+"&m=publish'>Publish</a>";
     }
     div.innerHTML = txt;
     el.appendChild(div);
   }
 }

function displayDetails() {
  if (details) {
    setDetailField("address");
    setDetailField("firstname");
    setDetailField("lastname");
    //    setDetailField("middlename");
    setDetailField("biosketch");

    if (! details.biosketch || details.biosketch.length < 2) {
        var el = document.getElementById("biosketchid");
        el.innerHTML = authorInfo();
    }


    if (details.email) {
      document.getElementById('emailid').innerHTML="<table><tr><td><img src='"+rootpath+"email-sml.png'/></td><td> "+details.email + "</td></tr></table>";
    }
    if (details.website) {
      document.getElementById('websiteid').innerHTML="<table><tr><td><img src='"+rootpath+"web-sml.png'/></td><td><a href='"+details.website+"'>"+trimWS(details.website)+"</a> </td></tr></table>";
    }
  }
}

 function trimWS(txt) {
     if (txt.indexOf("http://") == 0) {
         txt = txt.substr(7);
     }
     return txt;
 }



 var selectedById = new Object();


// For publish.php
function sendlink(a) {
  var ael = document.getElementById("auth"+a);
  if (ael) {
    var aname = ael.title;
   
    var ael = document.getElementById("coinvite");
    ael.style.display="block";
      
    var n1 = document.getElementById("invitename");
    var n2 = document.getElementById("invitename2");
    var ta = document.getElementById("invitetxt");
    var em = document.getElementById("inviteemail");
    //      var il = document.getElementById("invitelink");
    var ia = document.getElementById("invitea");
    spanInnerHtml(n1, aname);
    spanInnerHtml(n2, aname);


    ta.style.width = "100%";

    ta.value = "Loading your co-publications with "+aname+" ...";      
    em.value = "";      
    var fullname = details.firstname + " "+ details.lastname;
    ia.value = a;
      
    setTimeout("sendlinkcb("+a+")", 100);
  }
}

function sendlinkcb(a) {
  var ael = document.getElementById("auth"+a);
  if (ael) {
    var aname = ael.title;
   
    var txt = postURL("sendLink.php", "n="+encodeURIComponent(aname));
    
    if (txt.substring(0,3) != "ERR") {
      var ael = document.getElementById("coinvite");
      ael.style.display="block";
      
      var n1 = document.getElementById("invitename");
      var n2 = document.getElementById("invitename2");
      var ta = document.getElementById("invitetxt");
      var em = document.getElementById("inviteemail");
      //      var il = document.getElementById("invitelink");
      var ia = document.getElementById("invitea");
      spanInnerHtml(n1, aname);
      spanInnerHtml(n2, aname);
      ta.value = "";
      ta.value = txt;      
      ta.style.width = "100%";
      em.value = "";      
      var fullname = details.firstname + " "+ details.lastname;
      ia.value = a;
      
      //      il.href = "mailto:?subject=" + encodeURIComponent("[publicationslist.org] "+fullname+" has added some of your co-publications")+"&body=" + encodeURIComponent(txt);
    }
    else {
      alert(txt);
    }
  }
}

function closeinvite() {
  var bel = document.getElementById("coinvite");
  bel.style.display="none";  
}

function sendemaillink() {  
  var email = document.getElementById("inviteemail").value;
  var a = document.getElementById("invitea").value;
  var ael = document.getElementById("auth"+a);
  if (ael) {
    var aname = ael.title;
   
    //    window.prompt("Enter "+aname+"'s email address\nto send them a link to your publications list", "");
    if (email) {
      // Call a PHP to send a message.
      var ret = postURL("sendLink.php", "e="+encodeURIComponent(email)+"&n="+encodeURIComponent(aname));
      alert(ret); // "OK - Sent a link to "+email + " "+ret);
      ael.style.color = "#a0a0a0";

      closeinvite();
      
    }
  }
}
