var xmlHttp

// Standard routines

function GetXmlHttpObject() {
  var xmlHttp = null;

  try {
    // Firefox, Opera 8.0+, Safari
    xmlHttp = new XMLHttpRequest();
  }
  catch (e){
    //Internet Explorer
    try {
      xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) {
      xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
  }
  return xmlHttp;

}

/* Clear down input fields eg login, search ***********/

function clearInput(input){
  if (input.defaultValue == input.value) {
    input.value = '';
  }
}

/* Suckerfish menuing fix *****************************/ 

startList = function() {
  var i = 0;
  if (document.all&&document.getElementById) {
      navRoot = document.getElementById("dmenu");
      for (i=0; i<navRoot.childNodes.length; i++) {
	 node = navRoot.childNodes[i];
	 if (node.nodeName=="LI") {
	    node.onmouseover=function() {
		this.className+=" over";
            }
	    node.onmouseout=function() {
		this.className=this.className.replace(" over", "");
	    }
	 }
      }
   }
}

/* homepage style for swapping text in a definition list ***************/

function switch_text (mylink) {

  $$('#homepagedl dd').each (function (dds) {
    $(dds).hide();
  });

  $$('a.dthover').each (function (selected) {
    $(selected).removeClassName('dthover');
  }); 

  $(mylink).addClassName('dthover');

  var dt = mylink.parentNode;

  /* NB nextSibling will only work if there is NO whitespace
   * between the elements 
   */ 
  var dd = dt.nextSibling;
  dd.style.display = 'block';
}


function lastFive (resourcecategoryid) {
  new Ajax.Request ("page_ajax.php",{
    method: 'get',
    parameters: 'q=last5&xhr=1&resourcecategoryid=' + resourcecategoryid,
    onSuccess: function (xhrResponse) {
	$('last5').update (xhrResponse.responseText);	

    },
    onFailure: function(xhrResponse) {
	$('last5').update (getTemplate ('500.html'));		
    }
});
return (false);

}




/****  COPY to clipboard function seemless in IE 
       needs manual intervention in MOZ            ************/ 

function getPageEventCoords(evt) {
  
  var posx = 0;
  var posy = 0;
     
  var evt = (evt) ? evt : event;

  if (evt.pageX || evt.pageY) 	{
    posx = evt.pageX;
    posy = evt.pageY;
  } else if (evt.clientX || evt.clientY) {
    posx = evt.clientX + document.body.scrollLeft
      + document.documentElement.scrollLeft;
    posy = evt.clientY + document.body.scrollTop
      + document.documentElement.scrollTop;
  }

  return {left:posx, top:posy};
}

function copy_to_clipboard (e,id,text) {  

   if(window.clipboardData) {  
     window.clipboardData.setData('text',text);  
   } else {  

     // clear out any currently openned windows
     if ((popped = document.getElementById("copyLink")) != null) {
       popped.parentNode.removeChild(popped);
     }

     var popup = document.createElement("div");
     var inner = document.createElement("div");

     // name them so that we can apply styles
     popup.setAttribute("id","copyLink");
     inner.setAttribute("id","inner");

     inner.innerHTML = getTemplate ("discussion_link_snippet.html");

     popup.appendChild(inner);       

     var mousePosition =  getPageEventCoords(e);

     popup.style.position = "Absolute";
     popup.style.top      = (mousePosition.top + 10) + 'px';
     popup.style.left     = (mousePosition.left - 420) + 'px' ;

     var bodyRef = document.getElementsByTagName("body").item(0);
     bodyRef.appendChild(popup);

  
     $('linkto').value = text;

     // and focus on the first field
     document.forms['linksnippet'].elements['linkto'].focus ();
     document.forms['linksnippet'].elements['linkto'].select ();
   }
}

/* fix the background of png files for IE6 
 * Takes a css class name or anything else that 
 * can be returned by prototype's $$ operator
 */

function pingFix (cname) {
  if (navigator.userAgent.indexOf("MSIE") != -1) {
    var version = parseFloat(navigator.appVersion.split('MSIE')[1]);

    if ((version >= 5.5) && (version < 7)) {
      $$(cname).each(function(poElement){
  
       // if IE5.5+ on win32, then display PNGs with AlphaImageLoader
       var cBGImg = poElement.currentStyle.backgroundImage;
       var cImage = cBGImg.substring(cBGImg.indexOf('"') + 1, cBGImg.lastIndexOf('"'));
				
       poElement.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + cImage + "', sizingMethod='scale')";
       poElement.style.backgroundImage = "none"; } );
    }
  }
}


// User

function userSuggestions(str) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="base_ajax.php";
  url = url + "?q=userSuggestions;lastname=" + str;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	document.getElementById("whatever goes here").innerHTML = xmlHttp.responseText; 
      }
    }
  }
 

 xmlHttp.send(null);
}


/************************************
 * Organisation
 * 
 ************************************/

function organisationSuggestions(str) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="base_ajax.php";
  url = url + "?q=organisationSuggestions;organisationname=" + str;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	document.getElementById("whatever goes here").innerHTML = xmlHttp.responseText; 
      }
    }
  }
 

 xmlHttp.send(null);
}



function getSelectedOrganisation(text, li) {

  /* do I need a not null check? */
 
  var organisationid = li.id;

  /* get the organisation object and then populate the remaining fields */
  /* include the name field because this will be populated with a partial address */

  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="base_ajax.php";
  url = url + "?q=getOrganisation;organisationid=" + organisationid;
  url = url + ";sid=" + Math.random();
  xmlHttp.open("GET",url,true);

  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	var json = xmlHttp.responseText;

	if (json.length) {
	  var options = eval ( "(" + json + ")" );
    
	  // populate with json data
	  for (var fieldname in options) {
	    if ($(fieldname) != null) {
	      $(fieldname).value = options [fieldname];
	    }
	  }
	}
      }
    }
  }


  xmlHttp.send(null);

}



/************************************
 * Folder and File
 * 
 ************************************/

function filetypeAoH(str) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="folder_ajax.php";
  url = url + "?q=filetypeAoH;filename=" + str;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	setOptions ('DOMfiletypeid',xmlHttp.responseText);
      }
    }
  }
 

 xmlHttp.send(null);
}


function foldercontentsAoH(rid,order,sort) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="folder_ajax.php";
  url = url + '?q=foldercontentsAoH;resourceid=' + rid + ';order=' + order + ';sort=' + sort;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
		document.getElementById("r"+rid).innerHTML = xmlHttp.responseText; 
	//	document.getElementById("foldercontents"+rid).innerHTML = xmlHttp.responseText; 
      }
    }
  }
 
  xmlHttp.send(null);
}




/************************************
 * Pageinfo
 * 
 ************************************/

function showPageinfoTeamAoH(accountid,resourceid) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="page_ajax.php";
  url = url + '?q=showPageinfoTeamAoH;resourceid=' + resourceid + ';accountid=' + accountid;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	document.getElementById("pi"+accountid).innerHTML = xmlHttp.responseText; 
      }
    }
  }
 
  xmlHttp.send(null);
}

function hidePageinfoTeamAoH(accountid,resourceid) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="page_ajax.php";
  url = url + '?q=hidePageinfoTeamAoH;resourceid=' + resourceid + ';accountid=' + accountid;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	document.getElementById("pi"+accountid).innerHTML = xmlHttp.responseText; 
      }
    }
  }

  xmlHttp.send(null);
}



/************************************
 * Poll functions
 * 
 ************************************/

function pollResponse(form) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var answers = form.answerid;
  var resourceid = form.resourceid.value;

  /* check that one answer has been selected and 
   * return it's value OR false
   */
  var isValidRadio = function(options) {
   for (var i = 0; i < options.length; i++) {
      if (options[i].checked) {
	return options[i].value;
      }
    }
    return false;
  };

  var answerid = isValidRadio (answers); 
  
  if (answerid != false) {
    var url="poll_ajax.php";
    url = url + '?q=pollResponse;resourceid=' + resourceid + ';answerid=' + answerid;
    url = url + ";sid=" + Math.random();

    xmlHttp.open("GET",url,true);
    xmlHttp.send(null);
    xmlHttp.onreadystatechange = function() {
      if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
	if (xmlHttp.status==200) {
	  // We want to replace the entire div not just it's content
	  var poll = $("r" + resourceid);
	  var parent = poll.parentNode;
	  var newdiv = document.createElement('div');

	  newdiv.innerHTML = xmlHttp.responseText;
	  parent.replaceChild(newdiv,poll);
	}
      }   
    }
  }
}



/************************************
 * Gallery functions
 * 
 ************************************/

function refreshGallery(resourceid,index,mode) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="gallery_ajax.php";
  url = url + '?q=refreshGallery;resourceid=' + resourceid + ';index=' + index + ';mode' + mode;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	// We want to replace the entire div not just it's content

	//var gallery = document.getElementById("r" + resourceid);
	var gallery = $("r" + resourceid);
        var parent = gallery.parentNode;
	var newdiv = document.createElement('div');

        newdiv.innerHTML = xmlHttp.responseText;
    
        parent.replaceChild(newdiv,gallery);
      }
    }
  }

  xmlHttp.send(null);
}


function getSlides (resourceid) {
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="gallery_ajax.php";
  url = url + '?q=getSlides;resourceid=' + resourceid ;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,false);
  xmlHttp.send(null); // this blocks as request is synchronous

  if (xmlHttp.status==200) {
    return xmlHttp.responseText; 
  } 

  xmlHttp.send(null);
}

/***************************************************
 * slideShow Class 
 * Hacked about implementation of an example at
 * http://www.icommunicate.co.uk/ (itself based on
 * one from http://www.tomdoyletalk.com/)
 * Changed to source data differently, add pause and rewind
 * Don't bother with the fade transition 
 * We also deal with broken implementations of IE
 * and added a thumbnail mode. 
 */

var slideShow = Class.create ({
  initialize: function (argv) {
      this.resourceid   	= argv.resourceid ? argv.resourceid : '';
      this.wait 		= argv.wait ? argv.wait : 4000;
      this.duration 		= argv.duration ? argv.duration : 1;
      this.start 		= argv.start ? argv.start : 0;
      this.i		        = argv.i ? argv.i : 0;
      this.slides               = eval(getSlides (this.resourceid));
      this.image                = 'r' + this.resourceid + '_image';
      this.caption              = 'r' + this.resourceid + '_caption';
      this.counter              = 'r' + this.resourceid + '_counter';
      this.startBtn             = 'r' + this.resourceid + '_startBtn';
      this.pauseBtn             = 'r' + this.resourceid + '_pauseBtn';
      this.thumbBtn             = 'r' + this.resourceid + '_thumbBtn';
      this.slideBtn             = 'r' + this.resourceid + '_slideBtn';
      this.nextBtn              = 'r' + this.resourceid + '_nextBtn';
      this.prevBtn              = 'r' + this.resourceid + '_prevBtn';
      this.rewindBtn            = 'r' + this.resourceid + '_rewindBtn';

      this.interval             = 0;

      /* We hide both buttons with CCS style then display the 
       * one that isn't the default in this case the thumbnail button.
       */

      $(this.thumbBtn).show();
    },
      
  thumbnail: function () {
      clearInterval(this.interval);				
      $(this.thumbBtn).hide();
      $(this.slideBtn).show();
      $(this.startBtn).show();
      $(this.pauseBtn).hide();

      if ($(this.image) != null && $(this.image).hasChildNodes()) {
	while ($(this.image).firstChild) {
	  $(this.image).removeChild($(this.image).firstChild);
	}
      }

      for (var i = 0; i < this.slides.length; i++) {
	var thumbnail = document.createElement ('div');
	thumbnail.setAttribute ('className', 'thumbnail');
	thumbnail.setAttribute ('class',     'thumbnail');

	var link = document.createElement ('a');
	link.setAttribute ('href', '/images/' + this.slides[i].resourceid + '/' + this.slides[i].size);
	
	if (navigator.userAgent.indexOf("MSIE") != -1) {
	  /* .... and because you can't use setAttribute with events in IE
	   * .... and because you can't set a variable in a paramter!
	   */
	  link.setAttribute ('title', i);
	  var func = 'gallery_r' + this.resourceid + '.display (this.title);';

	  link.onclick = function () {
	    eval (func);
	    return false; 
	    };
	} else {
	  link.setAttribute ('onclick','gallery_r' + this.resourceid + 
			     '.display ('+ i +');return false;');
	}
	
	var img = document.createElement ('img');
	img.setAttribute ('src', '/images/' + this.slides[i].resourceid + '/0');
	img.setAttribute ('alt', this.slides[i].resourcedesc); 
	img.setAttribute ('className', 'thumbimg');
	img.setAttribute ('class',     'thumbimg');

	link.appendChild (img);
	thumbnail.appendChild (link);
	$(this.image).appendChild (thumbnail);
	
	/* tidy up the gallery 
	 * and make sure that the caption height doesn't change
	 * so that the gallery height doesn't change
	 */
	$(this.caption).innerHTML = '&nbsp;';
	$(this.counter).innerHTML = this.slides.length + ' of ' +  this.slides.length;

      }
   },

  play: function () {
     $(this.startBtn).hide();
     $(this.pauseBtn).show();

     if (++this.i == this.slides.length) {
	this.i = 0;
      }
      
      this.display ();
   },

  pause: function () {
      clearInterval(this.interval);				
      $(this.startBtn).show();
      $(this.pauseBtn).hide();
    },
    
  rewind: function () {
      clearInterval(this.interval);				
      $(this.startBtn).show();
      $(this.pauseBtn).hide();
 
      this.i = 0;
      this.display ();
    },

  next: function () {
      clearInterval(this.interval);
      $(this.startBtn).show();
      $(this.pauseBtn).hide();

      if (++this.i >= this.slides.length) {
	this.i = 0;
      }
      
      this.display ();
   },   

  previous: function () {
      clearInterval(this.interval);				
      $(this.startBtn).show();
      $(this.pauseBtn).hide();

      if (--this.i < 0) {
	this.i = this.slides.length - 1;
      }

      this.display();
    },

  display: function (slide) {
      this.i = slide === undefined ? this.i :  parseInt(slide);  	
      $(this.thumbBtn).show();
      $(this.slideBtn).hide();
  
      var num = this.i + 1; 
      var imageStr = '';
     
      if (this.slides[this.i].url != null) {
	imageStr = '<a href="' + this.slides[this.i].url + '" target="_blank"><img class="photo" src="/images/' + this.slides[this.i].resourceid + '/' + this.slides[this.i].size + '" alt="' + this.slides[this.i].resourcedesc + '" /></a>';
      } else {
	imageStr = '<a href="/images/' + this.slides[this.i].resourceid + '/4" target="_blank">' + '<img class="photo" src="/images/' + this.slides[this.i].resourceid + '/' + this.slides[this.i].size + '" alt="' + this.slides[this.i].resourcedesc + '" /></a>';
      }
      
      $(this.caption).innerHTML = this.slides[this.i].resourcedesc;
      $(this.image).innerHTML = imageStr;
      $(this.counter).innerHTML = num  + ' of ' +  this.slides.length;
      $(this.image).hide();
     
     if (navigator.userAgent.indexOf("MSIE") != -1) {
       // who'd have thunk IE couldn't handle this!
       $(this.image).show ();
     }else{
       $(this.image).appear ({duration: this.duration });
     }
    },

   startShow: function () {
      this.interval = setInterval(this.play.bind(this),this.wait);
      $(this.startBtn).hide();
      $(this.pauseBtn).show();
    }
  
  });

function growImage (resourceid,direction,factor) {
  resourceid = resourceid === undefined ? null   : resourceid;
  direction  = direction  === undefined ? 'grow' : direction;
  factor     = factor     === undefined ? 1.2    : factor;

  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="gallery_ajax.php";
  url = url + "?q=growImage;resourceid=" + resourceid + ";direction=" + direction + ";factor=" + factor;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	var dim = eval ("(" + xmlHttp.responseText + ")");
	var image   = "r" + resourceid + "_image";
	var caption = "r" + resourceid + "_caption";
	
	if ($(image) !== null && dim.height !== undefined 
	    && dim.width !== undefined) {
	  $(image).setAttribute ('height',dim.height); 
	  $(image).setAttribute ('width',dim.width); 
	  $(caption) !== null && $(caption).setAttribute ('width',dim.width);
	} 
      }
    }
  } 
  xmlHttp.send(null);
}

/************************************
 * Discussion system 
 *
 ***********************************/


function addDiscussion () {
  new Ajax.Request ("discussion_ajax.php",{
    method: 'post',
    parameters: 'q=addDiscussion&xhr=1&' + get_params('discussion'),
    onSuccess: function (xhrResponse) {
	var parent;

	if ($F('parentid') != 1) {
	  parent = $($F('parentid'));

	} else {

	  parent = $('structure');
	}

	popup = $('addDiscussion');
	popup.parentNode.removeChild (popup);

	var newChild = document.createElement ('DIV');
	newChild.innerHTML = xhrResponse.responseText;
	
	// NB this is not alphabetical
	//insertAlphabetical (newChild,parent); 
	//newChild.focus ();
	insertAfter (newChild,parent); 
    },
    on406: function(xhrResponse) {
	
	$('addDiscussion').innerHTML = xhrResponse.responseText;
	
	if ($F('typeid') == 'r' || $F('typeid') == 's') {
	  showmoderate = $('showmoderate');
	  showstatus = $('showstatus');
	  showmoderate.parentNode.removeChild(showmoderate);
	  showstatus.parentNode.removeChild(showstatus);
	}	
		
    },
    onFailure: function(xhrResponse) {
      $('addDiscussion').innerHTML = getTemplate ('500.html');		
    }
});
return (false);

}


function displayDiscussionInput (typeid,level,root,parentid) {
  typeid   = typeid   === undefined ? 'r'  : typeid;
  level    = level    === undefined ? 0    : level;
  root     = root     === undefined ? 1    : root;
  parentid = parentid === undefined ? root : parentid;

  
  // clear out any currently openned windows
  if ((popped = document.getElementById("addDiscussion")) != null) {
    popped.parentNode.removeChild(popped);
  }
  
  var currentPosition = getElementPosition(typeid+parentid);

  // create the divs for the popup
  var popup = document.createElement("div");
  var inner = document.createElement("div");

  // name them so that we can apply styles
  popup.setAttribute("id","addDiscussion");
  inner.setAttribute("id","inner");

  inner.innerHTML = getTemplate ("discussion_snippet.html");

  popup.appendChild(inner);       
  popup.style.position = "Absolute";
  popup.style.top      = (currentPosition.top - 32) + 'px';
  popup.style.left     = (currentPosition.left + 32) + 'px' ;

  var bodyRef = document.getElementsByTagName("body").item(0);
  bodyRef.appendChild(popup);

  // set the values we know XXXXXXX do I want to pass this out to another 
  // function via an associative array 
  
  $('typeid').value = typeid;
  $('root').value = root;
  $('parentid').value = parentid;
  $('level').value = level;


  // we display different versions
  if ($('status_o') != null) {
    $('status_o').checked = true;
  }

  if ($('no') != null) {
    $('no').checked = true;
  }


  // which bits don't we want to see
  if (typeid == 'r' || typeid == 's') {
    var showmoderate = $("showmoderate");
    var showstatus = $("showstatus");
    showmoderate.parentNode.removeChild(showmoderate);
    showstatus.parentNode.removeChild(showstatus);
  }

  // and focus on the first field
  document.forms['discussion'].elements['resourcename'].focus ();

}

/* monitor changes in a textarea and change size dynamically */

function textareaHeight (text_area) {
  text_area.style.height =
    text_area.scrollHeight - ((isIE())?0:2) + "px";
}


function discussionGetEditSnippet (id) {

  var messagediv = 'p' + id + '_content'; 
  var txtarea = 'p' + id + '_message'; 
  var height = $(messagediv).offsetHeight; 
  var width  = $(messagediv).offsetWidth; 
  
  new Ajax.Request ("discussion_ajax.php",{
    method: 'post',
    parameters: 'q=discussionGetEditSnippet&xhr=1&dpostingid=' + id + '&' + get_params ('editMessage'),
    onSuccess: function (xhrResponse) {
        $(messagediv).innerHTML = xhrResponse.responseText;
	$(txtarea).style.height = height + 'px';
        $(txtarea).style.width = width + 'px';
	$(txtarea).style.overflow = 'auto';
    },
    on406: function(xhrResponse) {
	$(messagediv).innerHTML = xhrResponse.responseText;
	$(txtarea).style.height = height + 'px';
        $(txtarea).style.width = width + 'px';
  	$(txtarea).style.overflow = 'auto';
   },
     onFailure: function(xhrResponse) {
      return getTemplate ('500.html');		
    }
  });

  return (false);
}


function discussionMakeEditable (id) {

  if ($(id) == null) {
    return;
  }
  var message = $(id); 

  // get the dimensions of the original for the overlay size. 
  var height = message.offsetHeight; 
  var width =  message.offsetWidth; 

  // get the original text
  var txt =  message.innerHTML;
  var wrapper = document.createElement ('div');
  var snippet = getTemplate ('discussionEditSnippet.html');


  snippet = snippet.replace (/\:\:\{\$dpostingid\}\:\:/g,id);
  snippet = snippet.replace (/\:\:\{\$message\}\:\:/g,txt);

  wrapper.innerHTML = snippet;

  // parent is the posting
  var parent =  message.parentNode;
  
  try {
    parent.replaceChild(wrapper,message);
  } catch (err) {
    alert (err.message);
  }
}

function getTemplate (filename) {
  filename = filename === undefined ? '404.html' : filename;
  
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="page_ajax.php";
  url = url + '?q=getTemplate;filename=' + filename;
  url = url + ";sid=" + Math.random();

  // use false to wait on the return

  xmlHttp.open("GET",url,false);
  xmlHttp.send(null); // this blocks as request is synchronous
  if (xmlHttp.status==200) {
    return xmlHttp.responseText; 
  }

  xmlHttp.send(null);

}

function closePopup (popupID) {
  try{
    var popup = document.getElementById(popupID);//.style.display = "none";
    popup.parentNode.removeChild(popup);
  } catch(e) {
    alert ("No popup object open");
  }
}


function toggleLock(obj,resourceid) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="discussion_ajax.php";
  url = url + '?q=toggleLock;resourceid=' + resourceid;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	if (obj.className == 'discussionlocklink') {
	  obj.className = 'discussionunlocklink'
	}else{
	  obj.className = 'discussionlocklink'
	}
      }
    }
  }
 
  xmlHttp.send(null);
}

function togglePin(obj,resourceid) { 
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="discussion_ajax.php";
  url = url + '?q=togglePin;resourceid=' + resourceid;
  url = url + ";sid=" + Math.random();

  xmlHttp.open("GET",url,true);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	if (obj.className == 'discussionpinlink') {
	  obj.className = 'discussionunpinlink'
	}else{
	  obj.className = 'discussionpinlink'
	}
      }
    }
  }
 
  xmlHttp.send(null);
}

function setSelRange(inputEl, selStart, selEnd) { 
  if (inputEl.setSelectionRange) { 
    inputEl.focus(); 
    inputEl.setSelectionRange(selStart, selEnd); 
  } else if (inputEl.createTextRange) { 
    var range = inputEl.createTextRange(); 
    range.collapse(true); 
    range.moveEnd('character', selEnd); 
    range.moveStart('character', selStart); 
    range.select(); 
  } 
}



/** resource editing functions
 *
 */


function getEditable (resourceid) {

  /* 1. Get the insertion_point snippet and cache it for regex replacement
   *    we don't want to do the round trip more times than needed but we do 
   *    want to get the correct language version
   * 2. Get the anchor divs
   * 3. Write the anchors out separately
   * 4. Toggle the edit/live button
   */

  // 1
  var insertionPoint = getTemplate ('insertion_point_snippet.html');

  // 2
  var anchors = getElementsByRegExpId(/^anchor\d+$/,undefined,'div');


  // 3
  for (var i=0; i < anchors.length; i++) {
    { 
      var anchorDIV = anchors[i];
      matches = anchorDIV.getAttribute('id').match(/anchor(\d+)/);
      anchor = matches[1];

      var divs = getElementsByRegExpId(/^r\d+$/,anchorDIV,'div');

      var item = 1;
      for (var j=0; j < divs.length; j++) {

	var child = divs[j];
        var iptemplate = insertionPoint;

	// parent is the anchor
	var parent = child.parentNode;

	// fill out the insertion template.
	var iPoint = document.createElement("div");
	iptemplate = iptemplate.replace (/id="pai"/g,'id="p'+ resourceid + 'a' + anchor + 'i' + item + '"'); 
	iptemplate = iptemplate.replace (/parentid=/g,'parentid=' + resourceid); 
	iptemplate = iptemplate.replace (/anchor=/g,'anchor=' + anchor); 
	iptemplate = iptemplate.replace (/item=/g,'item=' + item); 
	iptemplate = iptemplate.replace (/displayAddable\(\,\,\)/g,'displayAddable('+ resourceid + ',' + anchor + ',' + item + ')'); 
	iptemplate = iptemplate.replace (/displayClipboard\(\,\,\)/g,'displayClipboard('+ resourceid + ',' + anchor + ',' + item + ')'); 
	
	iPoint.innerHTML = iptemplate;
 
	parent.insertBefore (iPoint,child);

	var newchild = makeEditable(child.cloneNode(true),resourceid);
	
	try {
	  parent.replaceChild(newchild,child);
	} catch (err) {
	  alert (err.message);
	}

	item++;
      }
      
      // add the trailing insertion point

      var lastip = document.createElement('div');
      var iptemplate = insertionPoint;

      iptemplate = iptemplate.replace (/id="pai"/g,'id="p'+ resourceid + 'a' + anchor + 'i' + item + '"'); 
      iptemplate = iptemplate.replace (/parentid=/g,'parentid=' + resourceid); 
      iptemplate = iptemplate.replace (/anchor=/g,'anchor=' + anchor); 
      iptemplate = iptemplate.replace (/item=/g,'item=' + item); 
      iptemplate = iptemplate.replace (/displayAddable\(\,\,\)/g,'displayAddable('+ resourceid + ',' + anchor + ',' + item + ')'); 
      iptemplate = iptemplate.replace (/displayClipboard\(\,\,\)/g,'displayClipboard('+ resourceid + ',' + anchor + ',' + item + ')'); 

      lastip.innerHTML = iptemplate;

      anchorDIV.appendChild (lastip);
    }
  }

  // 4
  var editlink = document.getElementById ('editmode');

  try {
    editlink.innerHTML = '<a href="change_display_mode.php?resourceid=' + resourceid  + ';mode=live" accesskey="T" onclick="unwrap(' + resourceid + ');return false;"><img src="/icons/live.gif" alt="switch to normal view accesskey ALT+T" height="16" width="16" />Normal view</a>';
  } catch (err) {
  }

  // 5 Display the resource widget

  $$('div.editblock').each (function (div) {
    new Draggable (div, {revert: true, ghosting: true});
  });

  $$('div.additem').each (function (div) {
    Droppables.add(div, { 
      accept: 'draggable',
      hoverclass: 'hover',
      onDrop: function() { div.highlight(); }
    });
  });

  displayAddable ();


}


function makeEditable (resource,resourceid) { 

  // construct the wrapper
  var wrapper = document.createElement("div");
  wrapper.setAttribute ("id","editblock" + resourceid);
  wrapper.setAttribute ("class","editblock");

  var handle = document.createElement("div");
  handle.setAttribute ("id", "editimage");
 
  var link =  document.createElement("a");
  link.setAttribute ("class","editlink");
  link.href = "#";
  link.setAttribute ('onclick','editResource(' + resourceid +');return false;'); 

  var image = document.createElement("img");
  image.setAttribute ("class","editlinkimage");
  image.src = '/icons/edit.gif';
  image.alt = 'Edit properties';

  link.appendChild (image);
  handle.appendChild (link);

  wrapper.appendChild (resource);
  wrapper.appendChild (handle); 
 

  return wrapper;
}


// get the insertion point template to cache

function getInsertionSnippet () {
  xmlHttp=GetXmlHttpObject();

  if (xmlHttp == null) {
   return;
  }

  var url="page_ajax.php";
  url = url + '?q=getInsertionPointSnippet';
  url = url + ";sid=" + Math.random();

  // use false to wait on the return

  xmlHttp.open("GET",url,false);
  xmlHttp.onreadystatechange = function() {
    if (xmlHttp.readyState==4 || xmlHttp.readyState == "complete") {
      if (xmlHttp.status==200) {
	return xmlHttp.responseText;
      }
    }
  }

  xmlHttp.send(null);

}

function unwrap (resourceid) {

  if ($('addResource') != null) {
    $('addResource').remove ();
  }

  var divs = getElementsByRegExpId(/^editblock\d+$/,undefined,'div');
 
  for (var i = 0; i < divs.length; i++) {
    var child = divs[i];

    var parent = child.parentNode;
    var inner = child.firstChild;
    parent.replaceChild (inner,child)
  }

  // clean up the tail ends
  var tails = getElementsByRegExpId(/^p\d+a\d+i\d+$/,undefined,'div');

  for (var i = 0; i < tails.length; i++) {
    var child = tails[i];
    var parent = child.parentNode;
    parent.removeChild (child);
  }

  // toggle the live/edit mode link
  var livelink = document.getElementById ('editmode');

  try {
    livelink.innerHTML = '<a href="change_display_mode.php?resourceid=' + resourceid + ';mode=edit" accesskey="T" onclick="getEditable(' + resourceid + ');return false;"><img src="/icons/edit.gif" alt="switch to edit mode accesskey ALT+T" height="16" width="16" />Edit mode</a>';
  } catch (err) {
  }
}



function displayAddable (parentid,anchor,item) {
  parentid = parentid === undefined ? 1 : parentid;
  anchor   = anchor   === undefined ? 1 : anchor;
  item     = item     === undefined ? 1 : item;
  
  // clear out any currently openned windows
  if ($('addResource') != null) {
    $('addResource').remove ();
  }
  
  //  var currentPosition = getElementPosition ('p' + parentid + 'a' + anchor + 'i' + item);
  
  var currentPosition = {left: 120, top: 120};


  // XXXXXXXX BUST var pos = $('p' + parentid + 'a' + anchor + 'i' + item);
  // XXXXXXXX BUST var currentPosition = pos.positionedOffset();

  // create the divs for the popup
  //  var popup = document.createElement("div");
  //  var inner = document.createElement("div");
  var popup = new Element ('div',{'id': 'addResource'});
  var inner = new Element ('div',{'id' : 'inner'});


  iptemplate = getTemplate ("addResource_snippet.html"); 

  iptemplate = iptemplate.replace (/parentid=/g,'parentid=' + parentid); 
  iptemplate = iptemplate.replace (/anchor=/g,'anchor=' + anchor); 
  iptemplate = iptemplate.replace (/item=/g,'item=' + item); 

  inner.update (iptemplate);

  popup.appendChild (inner);       
  popup.style.position = "Absolute";
  popup.style.top      = (currentPosition.top - 32) + 'px';
  popup.style.left     = (currentPosition.left + 32) + 'px' ;


  var bodyRef = document.getElementsByTagName("body").item(0);
  bodyRef.appendChild(popup);

  $('snippet').select('a').each (function (a) {
    new Draggable (a, {revert: true, ghosting: true});
  });

  // and focus on the first field
  //$('snippet').focus ();
}


/* utility functions */

function reveal (link,divID) {
  if(divID != null) {
    var pos = getElementPosition(link);
  
    $(divID).style.position = "Absolute";
    $(divID).style.top      = (pos.top - 11) + 'px';
    $(divID).style.left     = (pos.left - 145) + 'px' ;
    $(divID).show ();
  }
}

function conceal (divID) {
  if(divID != null) {
    $(divID).hide ();
  }  
}


/**
 * Curtesy of Ajax the Definitive Guide ...
 * Uses Prototype library
 * This function, get_params, takes the id of a form in a page and
 * parses out all form elements, creating a parameter string to be
 * used in an Ajax call.
 *
 * @param {String} p_formId The id of the form to parse elements from.
 * @return Returns the parameter string containing all of the form
 * elements and their values.
 * @type String
 */

function get_params(p_formId) {

  if ($(p_formId) == null)
    {
      return false;
    }


  var params = '';
  var selects = $(p_formId).getElementsByTagName('select');
  
  /*
   * Loop through any <select> elements in the form and get their
   * values
   */
  
  for (var i = 0, il = selects.length; i < il; i++)
    params += ((params.length > 0) ? '&' : '') + selects[i].id + '=' + selects[i].value;
  
  var inputs = $(p_formId).getElementsByTagName('input');
  
  /*
   * Loop through any <input> elements in the form and get their
   * values
   */

  for (var i = 0, il = inputs.length; i < il; i++) {
    var type = inputs[i].getAttribute('type');
    
    /*
     * Is this <input> element of type text, password, hidden,
     * or checkbox?
     */

    if (type == 'text' || type == 'password' || type == 'hidden' || (type == 'checkbox' && inputs[i].checked))
       params += ((params.length > 0) ? '&' : '') + inputs[i].id + '=' + inputs[i].value;

    /* Is this <input> element of type radio? */
    if ((type == 'radio' && inputs[i].checked))
      params += ((params.length > 0) ? '&' : '') + inputs[i].name + '=' + inputs[i].value;
  }
  
  var textareas = $(p_formId).getElementsByTagName('textarea');
  
  /*
   * Loop through any <textarea> elements in the form and get their
   * values
   */

  for (var i = 0, il = textareas.length; i < il; i++) {
    params += ((params.length > 0) ? '&' : '') + textareas[i].name + '=' + textareas[i].value;
  }
  return (params);
}

/**
 * XXXXXXXXXXXXXX Prototype example JUST HERE for demo purposes 

 * This function, myForm_onclick, makes an Ajax request to the server
 * and changes the /pageContentContainer/ <div> element to the
 * /responseText/ sent by the server.
 *
 * @return Returns false so that the form will not submit in the
 *  normal XHTML fashion.
 * @type Boolean
 * @see Ajax#Request
 */

function myForm_onclick() {
  new Ajax.Request('example_14-7.php', {
    method: 'post',
       parameters: 'xhr=1&' + get_params('myForm'),
       onSuccess: function(xhrResponse) {
       $('pageContentContainer').innerHTML = xhrResponse.responseText;
    },
     onFailure: function(xhrResponse) {
       $('pageContentContainer').innerHTML = xhrResponse.responseText;
     }
  });
  return (false);
}





function getElementsByRegExpId(p_regexp, p_element, p_tagName) {
  p_element = p_element === undefined ? document : p_element;
  p_tagName = p_tagName === undefined ? '*' : p_tagName;

  var v_return = [];
  var v_inc = 0;

  for (var v_i = 0, v_il = p_element.getElementsByTagName(p_tagName).length; v_i < v_il; v_i++) {
     if (p_element.getElementsByTagName(p_tagName).item(v_i).id && 
        p_element.getElementsByTagName(p_tagName).item(v_i).id.match(p_regexp)) {
   	v_return[v_inc] = p_element.getElementsByTagName(p_tagName).item(v_i);
  	v_inc++;
     }
   }
 return v_return;
}


function printDOM (node) {
  domstr = domstr + node.nodeType +" " + node.nodeName + " " +node.nodeValue + "\n";
  if (node.hasChildNodes()) {
    for (var i=0;i<node.childNodes.length;i++) {
	printDOM (node.childNodes.item(i));
    }
  }
}

function getElementPosition (element) {
  var trail = document.getElementById(element);
  var offsetLeft = 0;
  var offsetTop = 0;

  while (trail) {
    offsetLeft += trail.offsetLeft;
    offsetTop  += trail.offsetTop;
    trail = trail.offsetParent;
  }

  if (navigator.userAgent.indexOf("Mac") != -1 &&
      typeof document.body.leftMargin != "undefined") {
    offsetLeft += document.body.leftMargin;
    offsetTop += document.body.topMargin;
  }

  return {left:offsetLeft, top:offsetTop};

}


function insertAfter (elem, before) {
  // Takes two objects
  // If the parent's lastchild is the before element append to parent
  // else before element has siblings so put it before the next sibling

  var parent = before.parentNode;

  if (parent.lastchild == before) {
    parent.appendChild(elem);
  } else {
    parent.insertBefore (elem, before.nextSibling);
  }
}

/*********************************************************
 *
 * setOptions (str ElementId, str JSON)
 *
 * generalised method for populating a list with an array 
 * of JSON hashes 
 * Can support any attributes but MUST include at least  
 * a name and value 
 *
 * NB
 * It would be nice to use a boolean for selected BUT
 * we use the same library function for generating the data
 * and it needs to produce the selected attribute as is for 
 * fallback pruposes on the non-javascript rendering of
 * this data.
 *
 *********************************************************/

function setOptions (id,json) {
  if (json == undefined || id == undefined){
    return;
  }

  var options = eval (json);

  select = document.getElementById(id);
  
  if (select !== undefined && json.length) {
    
    // clear existing children
    if(select.hasChildNodes()) {
      while(select.firstChild) {
	select.removeChild(select.firstChild);
      }
    }
     
    // populate with new nodes
    for (var i = 0; i < options.length; i++) {
      var opt = document.createElement ('option');
      
      for (var prop in options[i]) {
	if (prop === 'name') {
	  opt.appendChild (document.createTextNode (options[i].name));
	} else if (prop === 'selected') {
	  if (options[i].selected !== '')
	    opt.setAttribute ('selected',options[i].selected);	  
	} else {
	  // and any other attributes
	  opt.setAttribute (prop,options[i][prop]);
	}
      }

      select.appendChild (opt);
    }
  }
}

/*
function setListItems (id,json) {
  if (json == undefined || id == undefined){
    return;
  }

  var lis = eval (json);
  var ul  = $(id);

  if (ul !== null && json.length) {
    // clear existing children
    if(ul.hasChildNodes()) {
      while(ul.firstChild) {
	ul.removeChild($(id).firstChild);
      }
    }

 
    // populate with new nodes
    for (var i = 0; i < lis.length; i++) {
      var li = document.createElement ('li');
      ul.appendChild (document.createTextNode (lis[i]));
      
    }
  }
}

*/

/*********************************************************
 *
 * setTableRows (str ElementId, str JSON)
 *
 * takes a JSON array of hashes and transforms it into a 
 * series of table rows.
 * Supports the following properties:
 * tr: class
 * td: class, headers, title
 * a:  class, href, target
 *
 *********************************************************/

function setTableRows (id,json){

  if (json == undefined || id == undefined){
    return;
  }
  
  var rows = eval (json);
  
  var tbody = document.getElementById (id);
  
  if (tbody != undefined && json.length) {
    
    // clear existing children
    if(tbody.hasChildNodes()) {
      while(tbody.firstChild) {
	tbody.removeChild(tbody.firstChild);
      }
    }
     
    // populate with new nodes
    for (var i = 0; i < rows.length; i++) {
      var row = document.createElement ('tr');
      // set class for the row, if any

      // and because IE is completely braindead
      rows[i].classname != undefined && row.setAttribute ('className', rows[i].classname);
      rows[i].classname != undefined && row.setAttribute ('class',     rows[i].classname);
    
      var cells = rows[i].cells; 

      for (var j = 0; j < cells.length ; j++) {
	var cell = document.createElement ('td');

	// ditto above. I spent 5 hours sorting this out.  Thanks Bill your browser stinks! 
	cells[j].classname != undefined && cell.setAttribute ('class',     cells[j].classname);
	cells[j].classname != undefined && cell.setAttribute ('className', cells[j].classname);
	cells[j].headers   != undefined && cell.setAttribute ('headers',   cells[j].headers);
	cells[j].title     != undefined && cell.setAttribute ('title',     cells[j].title);

	var data = document.createTextNode (cells[j].data);

	if (cells [j].href != null) {
	  var link = document.createElement ('a');
	  cells[j].title  != undefined  && link.setAttribute ('title',  cells[j].title);
	  cells[j].href   != undefined  && link.setAttribute ('href',   cells[j].href);
	  cells[j].target != undefined  && link.setAttribute ('target', cells[j].target);
	  link.appendChild (data);
	  cell.appendChild (link);
	} else {
	  cell.appendChild (data);
	}

	row.appendChild (cell);
      }

      tbody.appendChild (row);
    }
  }
}

