//////////////////////////////////////////////////////////////////////////////////
var browser = "";
var appletid = "ProgrammingApplet";
//////////////////////////////////////////////////////////////////////////////////
function isdefined(variable)
{
  return (typeof(window[variable]) == 'undefined')? false : true;
}
function mwInsertProgrammingWikiEditButtonCall() {
	var toolbar = document.getElementById('toolbar');
	if (!toolbar) { return false; }

	var textbox = document.getElementById('wpTextbox1');
	if (!textbox) { return false; }

	// Don't generate buttons for browsers which don't fully
	// support it.
	if (!(document.selection && document.selection.createRange)
		&& textbox.selectionStart === null) {
		return false;
	}

	var image = document.createElement("img");
	image.width = 23;
	image.height = 22;
	image.className = "mw-toolbar-editbutton";
	image.src = "http://michael-hielscher.de/wiki/images/Button_pwiki.png";
	image.border = 0;
	image.alt = "Programming Wiki Toolbar einblenden";
	image.title = "Programming Wiki Toolbar einblenden";
	image.style.cursor = "pointer";
  	image.onclick = function() {
		var pw = document.getElementById('ProgrammingWikiToolbar');
		if (!pw) { return false; }	
		pw.style.display = "block";
		return false;
	};
	toolbar.appendChild(image);
	return true;
}
function mwInsertProgrammingWikiEditButton() {
       window.setTimeout("mwInsertProgrammingWikiEditButtonCall()", 500) 
}
if(!wgProgrammingWikiToolbarAlwaysOn)
    hookEvent("load", mwInsertProgrammingWikiEditButton);
//////////////////////////////////////////////////////////////////////////////////
// Helper
//////////////////////////////////////////////////////////////////////////////////
/**
* Cross-Browser Ereignis-Registrar v.
* Scott Andrew
*/
function addLoadEvent(obj, f, useCaption)
{
  if (obj.addEventListener) {
    obj.addEventListener("load", f, useCaption);
    return true;
  } else if (obj.attachEvent) {
    var retVal = obj.attachEvent("onload", f);
    return retVal;
  } else {
    return false;
  }
}
//////////////////////////////////////////////////////////////////////////////////

function GetParam (name){
  var Params = (window.location.search.substring(1)).split("&");
  for (i = 0; i < Params.length; i++){
    var p = Params[i].split("=");
    if(p[0] == name) return unescape(p[1].replace(/\+/g,' '));
  }
  return '';
}
//////////////////////////////////////////////////////////////////////////////////
var AppletIsNowLoaded = false;
function lockButtonsUntilAppletLoaded() {
  if(AppletIsNowLoaded) return;
  var x = document.getElementById(appletid);
  if (typeof(x) == "undefined"){ window.setTimeout("lockButtonsUntilAppletLoaded();", 500); return; }
  try {
   if(x.isActive()) {
	AppletIsNowLoaded = true;
	turnOnButtons();
   }else{
        window.setTimeout("lockButtonsUntilAppletLoaded();", 500);
   }
  }
  catch(e) { window.setTimeout("lockButtonsUntilAppletLoaded();", 500); }
}
//////////////////////////////////////////////////////////////////////////////////
function browsercheck() {
	if(document.getElementById(appletid)!=null) {
		if(navigator.appName=="Opera")
		{
			browser = "Opera";
			alert("Opera isnt supported by the Programming-Wiki-System. Please use FireFox or IE instead");
		}
		if(navigator.userAgent.toLowerCase().indexOf('chrome') > -1){

		}
		if(browser != "") {
			var areas = document.getElementsByTagName('textarea');
			for(var i=0; i<areas.length; i++) {
				var cname = areas.item(i).className;
				if(cname.search("codepress")>-1)
				{
					areas.item(i).className = "";
					areas.item(i).removeAttribute("class");
					//areas.item(i).style.resize="none";
				}
			}
			turnOnButtons();
		}
	}else setTimeout("browsercheck()",1000);
}
//////////////////////////////////////////////////////////////////////////////////
function javaTest() {
//	if(!navigator.javaEnabled())
//		alert("You have to activate java within your browser");
}
//////////////////////////////////////////////////////////////////////////////////
var langg = "";   //Die ausgewählte Sprache
//////////////////////////////////////////////////////////////////////////////////
function languageMarker(lang){ 
  langg = lang;
  return;
}
//////////////////////////////////////////////////////////////////////////////////
function createHTMLRequest() {   
  var req = null;
      try{
            req = new XMLHttpRequest();
        }
        catch (e){
            try{
                req = new ActiveXObject("Msxml2.XMLHTTP");
            } 
            catch (e){
                try{
                    req = new ActiveXObject("Microsoft.XMLHTTP");
                } 
                catch (failed) {
                    req = null;
                }
            }  
        }
        if (req == null) {
              alert("Error creating request object!");
              return null;
        }
        return req;
 }
//////////////////////////////////////////////////////////////////////////////////
//Entweder den Code der textarea oder des von codepress erzeugten zugehörigen iframes ermitteln
//////////////////////////////////////////////////////////////////////////////////
function trim (str){
  return str.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
}

function getCode(id){              
  if(id.search("_cp")==-1) id+="_cp";

  var org = "";
  eval('if (isdefined("code_box_'+id+'")) org=code_box_'+id);
  var text = "";

  if(document.getElementById(id)){
    var textarea=document.getElementById(id);
    var iframe=textarea.previousSibling;
    text = iframe.getCode();
  }else {
    id = id.replace("_cp", "");
    var textarea = document.getElementById(id);
    text = textarea.value;
  }
  text = text.replace(/&nbsp;/g," ");
  text = text.replace(new RegExp(String.fromCharCode(160), "g"), " "); 

  return text;
}
//////////////////////////////////////////////////////////////////////////////////
// Speichert den aktuellen Codeboxinhalt in der Datenbank ab
//////////////////////////////////////////////////////////////////////////////////
function saveCode(id){              
  if(id.search("_cp")==-1)
    id+="_cp";

  var org = "";
  eval('if (isdefined("code_box_'+id+'")) org=code_box_'+id);
  var text = getCode(id);
  var t = text;  
  org = trim(org.replace(/&#10;/g,"\n"));  
//  if(text == html_entity_decode(org)) return;  
  
  tex = text.replace(/\+/g, "__#PLUS#__");
  org = org.replace(/\+/g, "__#PLUS#__");
  org = org.replace(/&nbsp;/g, " ");
  //org = org.replace(/\\/g, "\\\\");
  //tex = tex.replace(/\\/g, "\\\\");
  tex = htmlentities(tex);
  tex = tex.replace(/&nbsp;/g," ");
  tex = tex.replace(new RegExp(String.fromCharCode(160), "g"), " "); 
  org = org.replace(new RegExp(String.fromCharCode(160), "g"), " "); 
//  tex = tex.replace(new RegExp(String.fromCharCode(13), "g"),"");

  var username = wgUserName;
  var view = GetParam('view');
  if(view != '') username = view;
  if(username == null) return;

  var elementid = "";
  eval('if (isdefined("code_box_'+id+'id")) elementid=code_box_'+id+'id');

  var otyp = sajax_request_type;
  sajax_request_type = "POST";
  sajax_do_call( 'pw_saveCodeAJAX', [wgPageName,elementid,username,org,tex], null );
  sajax_request_type = otyp;
}

//////////////////////////////////////////////////////////////////////////////////
function saveCheck(constraint,success){              
 var i = 1;
 var r = 0;
 var b = 0;
 for (i = 1; i <=2000; i++){
  if(document.getElementById('check_box_'+i+'_btn')){
   if(document.getElementById('check_box_'+i).className == 'ims_BadSmilie') b++;
   if(document.getElementById('check_box_'+i).className == 'ims_GoodSmilie') r++;
  }else break;
 }
 var maxchecks = i-1;
 var username = wgUserName;
 var view = GetParam('view');
 if(view != '') username = view;
 if(username == null) return;

  var otyp = sajax_request_type;
  sajax_request_type = "POST";
  sajax_do_call( 'pw_saveCheckAJAX', [wgPageName,username,r,b,maxchecks], null);
  sajax_request_type = otyp;
}
//////////////////////////////////////////////////////////////////////////////////
var RunResultID;

function CancelRunProc(){
  try{document.getElementById(appletid).cancel(); }catch(err){}
  turnOnButtons();
}


//////////////////////////////////////////////////////////////////////////////////
function runProcCallback(res){    

    if(document.getElementById(RunResultID+"_cp")){

       eval(RunResultID+".setCode(res)");
    }else {
       var textarea = document.getElementById(RunResultID);
       textarea.value = res;
    }
    turnOnButtons();
}
function runProc(previousCode,callID,resultID,LastCodeBoxID){
  if(langg!=""){
    turnOffButtons();     //Währen einer evaluation werden die buttons deaktiviert
    var call=getCode(callID);  //Der Aufruf
    saveCode(callID);

    var result = document.getElementById(resultID); //Das Ergebnisfenster
    //if(langg != 'Scheme' ){
    //previousCode = getAllCode();
    //}
    if(langg == 'Pascal' ){
     call = "BEGIN "+call+" END.";
    }
    if(langg == 'XPath2' || langg == 'XSLT')   previousCode = getCode(LastCodeBoxID);

    RunResultID = resultID;
    RunCode(previousCode,call,'runProcCallback');
  }
}
/////////////////////////////////////////////////////////////////////////////////
var CurrentConstraint = "";
function CheckConstraintCallback(res){
  var result = document.getElementById(RunResultID); //Das Ergebnisfenster
  var success = false;
  success = (res.indexOf('check_box_result::->true')>= 0);
  if (success){
     result.className = 'ims_GoodSmilie'; 
     document.getElementById(RunResultID+'_out').innerHTML = '<b><font color=green>Prima, deine Lösung scheint zu stimmen.</font></b>';
     saveCheck(CurrentConstraint,true);
  }else{
     result.className = 'ims_BadSmilie';
     document.getElementById(RunResultID+'_out').innerHTML = '<b><font color=red>Leider noch nicht richtig, versuch es erneut.</font></b>';
     saveCheck(CurrentConstraint,false);
  }
  turnOnButtons();
}

// Achtung es wird immer die ganze Seite evaluiert um einen Check durchzuführen
// bei Sprachen wie Scheme kann das zu Nebeneffekten führen!

function CheckConstraint(constraint,resultID,previousCode){
  if(langg!=""){
	turnOffButtons();     //Währen einer evaluation werden die buttons deaktiviert
    RunResultID = resultID; 
    var call = "";
    constraint = constraint.replace(String.fromCharCode(160),' '); // &nbsp; bug

    //previousCode = getAllCode();

    if(langg == 'Javascript') call = 'function check_box_result(){'+constraint+'} if (check_box_result()) "check_box_result::->true"; else "check_box_result::->false";';
    if(langg == 'Java') call = 'boolean check_box_result(){'+constraint+'} System.out.println("check_box_result::->"+check_box_result());';
    if(langg == 'Scheme') call = '(define check_box_result (lambda () (begin '+constraint+' ))) (if (check_box_result) "check_box_result::->true" "check_box_result::->false")';
    if(langg == 'Pascal') call = "function check_box_result:boolean; \r\nbegin "+constraint+" end;\r\n" + "BEGIN \r\n if (check_box_result) then write('check_box_result::->true') else write('check_box_result::->false');\r\nEND.";
 
    if(call == ''){
     alert('Die Sprache '+langg+' unterstützt derzeit keine Check-Elemente.');
     return;
    }

    CurrentConstraint = constraint;     
    RunCode(previousCode,call,'CheckConstraintCallback');
  }
}
/////////////////////////////////////////////////////////////////////////////////
var pw_executingCode = "";
var pw_executingCall = "";
var pw_executingCallback = null;
var pw_executingCount = 0;
var pw_executingElements = new Array();

function RegExpEscape (text) {
  var specials = [
      '/', '.', '*', '+', '?', '|',
      '(', ')', '[', ']', '{', '}', '\\'
  ];
  var r = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
  return text.replace(r, '\\$1');
}

function codeLoadedAJAX(r){
  var s = r.responseText;
  var a = s.split("|");
  var page = a[0];
  var eID  = a[1];
  a.shift();
  a.shift();
  var code = html_entity_decode(a.join("|"));
  findSubPagePattern(code);
  var r = new RegExp("\\[\\["+RegExpEscape (page)+"\\|"+RegExpEscape (eID)+"\\]\\]", 'g');
  pw_executingCode = pw_executingCode.replace(r,code);
  pw_executingCall = pw_executingCall.replace(r,code);

  pw_executingCount++;
  checkForAllDataLoaded();
}
function addToExecutingElements(o) {
  for(var i=0; i < pw_executingElements.length; i++){
      var x = pw_executingElements[i];
      if(o.page == x.page && o.eID == x.eID) { return; }
  }
  pw_executingElements.push(o);
  sajax_do_call( 'pw_getCodeAJAX', [o.page,o.eID], codeLoadedAJAX );
}

function ExecuteCodeRun() {
  if(document.getElementById(appletid) && document.getElementById(appletid).isActive()){
   try{  
    
    var res = document.getElementById(appletid).eval(pw_executingCode, pw_executingCall, pw_executingCallback, 30000);
   }catch(err){ eval(callback+'("")'); alert("Applet wurde noch nicht geladen. Lade die Seite neu und warte zunächst etwas!"); return ""; }
   return res;
  } 
}
function checkForAllDataLoaded() {
  if(pw_executingCount == pw_executingElements.length) ExecuteCodeRun();
}

function findSubPagePattern(s){
  var pattern2=/\[\[([^\|\]]+)\|([^\]]+)\]\]/;
  var pattern =/\[\[([^\|\]]+)\|([^\]]+)\]\]/g;
  
  var a = s.match(pattern);
  if(a != null)
  for(var i = 0; i < a.length; i++) {
    var s2 = a[i];
    var b = s2.match(pattern2);
    var o = new Object();
    o.page = b[1];
    o.eID = b[2];
    addToExecutingElements(o);
  }
}
function RunCode(code,call,callback){
  canvas_clearTurtles(); // delete old Turtles
  GlobalCanvasHintSeen = false;

  pw_executingElements = new Array();
  pw_executingCode = code;
  pw_executingCall = call;
  r = Math.floor(Math.random()*1000000);
  pw_executingCallback = callback;
  pw_executingCount = 0;

  findSubPagePattern(code);
  findSubPagePattern(call);

  checkForAllDataLoaded();
  return "";
}
//////////////////////////////////////////////////////////////////////////////////
function collectPriviousCode(){     //den code einer Run-Umgebung (s.o.) sammeln und der globalen Variable code ablegen
 var code="";
 var args = collectPriviousCode.arguments;
 if (args == null) return code;
 for(var i=0; i<args.length; i++){
  code += getCode(args[i]);
  saveCode(args[i]);  
 }
 return code;
}
//////////////////////////////////////////////////////////////////////////////////
function getAllCode() {
	var code="";
	var elems = document.getElementsByTagName('textarea');
	for(var i=0; i<elems.length; i++) {
		if(elems[i].id.search(langg)>-1 && elems[i].id.search('Call')==-1 && elems[i].id.search('Run')==-1) {
			var c = getCode(elems[i].id) + "\n";
                     code = code + c;		
			saveCode(elems[i].id);  
		}
	}
	return code;
}

/////////////////////////////////////////////////////////////////////////////////
function displayBreakingPanel(){
  var pan = document.getElementById('BreakingPanel');
  if (pan) {
   if (pan.goingtodisplay == 1)
    pan.style.display = 'block';
  }
}
function turnOffButtons(){
  buttons = document.getElementsByTagName('button');
  for(nr in buttons){
     var b = buttons[nr];
     b.disabled = 'disabled';
  }
  var pan = document.getElementById('BreakingPanel');
  if (pan) pan.goingtodisplay = 1;
  window.setTimeout('displayBreakingPanel();',1000);
}
/////////////////////////////////////////////////////////////////////////////////
function turnOnButtons(){
  buttons = document.getElementsByTagName('button');
  for(var i = 0;i<buttons.length;i++){
      var b = buttons[i];
      b.removeAttribute('disabled');
  }
  var pan = document.getElementById('BreakingPanel');
  if (pan) pan.style.display = 'none';
  if (pan) pan.goingtodisplay = 0;
}

/////////////////////////////////////////////////////////////////////////////////
function checkAllCheckboxes (){
 var r = true;
 for (var i = 1; i <=2000; i++){
  if(document.getElementById('check_box_'+i+'_btn') == null) break;
     document.getElementById('check_box_'+i+'_btn').click();
  r = r && document.getElementById('check_box_'+i).className == 'ims_GoodSmilie';
 }
 if (r == true){
   document.getElementById('check_all_check').className = 'ims_GoodSmilie'; 
   document.getElementById('check_all_check_out').innerHTML = '<b><font color=green>Alle Lösungen scheinen richtig zu sein.</font></b>';
 }else{
   document.getElementById('check_all_check').className = 'ims_BadSmilie';
   document.getElementById('check_all_check_out').innerHTML = '<b><font color=red>Lösungen sind fehlerhaft!</font></b>';
 }
}
/////////////////////////////////////////////////////////////////////////////////
var GlobalCanvasHintSeen = false;
var GlobalCanvasStack = "";
var UseGlobalCanvasStack = false;
function canvas_noticeUserThatThisCanvasNotExist(CanvasID){
  if (GlobalCanvasHintSeen) return;
  GlobalCanvasHintSeen = true;
  alert('Der Canvas'+CanvasID+' exesitert nicht!');
}
/////////////////////////////////////////////////////////////////////////////////
// Canvas Object for JavaScript
/////////////////////////////////////////////////////////////////////////////////
function Canvas(id){
 this.ID = id;
 this.clear = function(){
  canvas_clear(this.ID);
 }
 this.clearRect = function(x1,y1,x2,y2){
  canvas_clearRect(this.ID,x1,y1,x2,y2);
 }
 this.drawImage = function (x,y,w,h,URL){
  canvas_drawimage(this.ID,x,y,w,h,URL)
 }
 this.line= function(x1,y1,x2,y2){
  canvas_line(this.ID,x1,y1,x2,y2);
 }
 this.rect= function(x1,y1,x2,y2){
  canvas_rect(this.ID,x1,y1,x2,y2);
 }
 this.fillRect= function(x1,y1,x2,y2){
  canvas_fillrect(this.ID,x1,y1,x2,y2);
 }
 this.triangle = function(x1,y1,x2,y2,x3,y3){
  canvas_triangle(this.ID,x1,y1,x2,y2,x3,y3);
 }
 this.text= function(x,y,Text,size){
  canvas_text(this.ID,x,y,Text,size);
 }
 this.ellipse= function(x,y,r){
  canvas_ellipse(this.ID,x,y,r);
 }
 this.setWidth = function(w){
  canvas_setwidth(this.ID,w);
 }
 this.setColor= function(c){
  canvas_setcolor(this.ID,c);
 }
 this.setRGBColor= function(r,g,b){
  canvas_setRGBcolor(this.ID,r,g,b);
 }
}
/////////////////////////////////////////////////////////////////////////////////
// Turtle Object for JavaScript
/////////////////////////////////////////////////////////////////////////////////
var globalTurtleID = 0;
function Turtle (id){
 this.ID = globalTurtleID++;
 this.CanvasID = id;
 this.penWidthValue = 1;
 this.colorR = 0;
 this.colorG = 0;
 this.colorB = 0;
 this.isVisible = true;
 this.isPenDown = true;
 this.angle = 0.0;
 this.x = 100.0;
 this.y = 100.0;

 this.clone = function (){
  var t = new Turtle(this.CanvasID);
  t.penWidthValue = this.penWidthValue;
  t.colorR = this.colorR;
  t.colorG = this.colorG;
  t.colorB = this.colorB;
  t.isVisible = this.isVisible;
  t.isPenDown = this.isPenDown;
  t.angle = this.angle;
  t.x = this.x;
  t.y = this.y;
  if(this.isVisible) t.show();
  return t;
 }

 this.show = function (){
  this.isVisible = true;
  canvas_setTurtle(this.CanvasID,this.ID,this.x,this.y,this.angle);
 }
 this.hide = function(){
  this.isVisible = false;
  canvas_delTurtle(this.ID);
 }
 this.setAngleTo = function(t){
	var yOffset = (t.y - this.y);
	var xOffset = (t.x - this.x);
	var r = Math.sqrt(xOffset * xOffset + yOffset * yOffset);
	var a = 0;
	if (yOffset > 0)
	{
		a = Math.asin(yOffset / r);
		if (xOffset < 0)
			a = Math.PI - a;
	}
	else if (xOffset < 0)
		a = Math.PI + Math.atan(yOffset / xOffset);
	else
		a = Math.PI*2 - Math.acos(xOffset / r);
	this.angle = (a / Math.PI * 180)+90;
	while (this.angle < 0) this.angle += 360;
	while (this.angle >= 360) this.angle -= 360;  
	if(this.isVisible) this.show();
 } 
 this.home = function(){
  this.move(300.0,100.0);
 }
 this.move = function(tx,ty){
  this.x = tx; this.y = ty;
  if(this.isVisible) this.show();
 }
 this.forward = function(n){
	var oldx = this.x;
	var oldy = this.y;
       this.x += Math.cos(((this.angle - 90) * Math.PI/180)) * n;
	this.y += Math.sin(((this.angle - 90) * Math.PI/180)) * n;
	if (this.isVisible) this.show();
	if (!this.isPenDown) return;
	canvas_setRGBcolor(this.CanvasID,this.colorR,this.colorG,this.colorB);
	canvas_setwidth(this.CanvasID, this.penWidthValue); 
	canvas_line(this.CanvasID, oldx, oldy, this.x, this.y);
 }
 this.backward = function(n){
	this.forward (-n);
 }
 this.right = function(a){
	this.angle += a;
	while(this.angle < 0) this.angle += 360;
	if(this.isVisible) this.show();
 }
 this.left = function(a){
	this.right(-a);
 }
 this.penUp = function (){
	this.isPenDown = false;
 }
 this.penDown = function (){
	this.isPenDown = true;
 }
 this.penErase = function (){
	this.penColor (255,255,255);
 }
 this.penColor = function(r,g,b){
	this.colorR = r; this.colorG = g; this.colorB = b;
 }
 this.penWidth = function(w){
	this.penWidthValue = w;
 }
 this.setAngle = function(a){
	this.angle = a;
	if(this.isVisible) this.show();
 }
}

/////////////////////////////////////////////////////////////////////////////////
function canvas_clear(CanvasID){
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.clearRect(0, 0, 10000, 10000);
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_clearRect(CanvasID,x1,y1,x2,y2){
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.globalCompositeOperation = "source-over";
    canvas.clearRect(x1+0.5,y1+0.5,x2+0.5,y2+0.5);
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_clearTurtles(){
  CanvasTurtles = new Object();
  CanvasTurtles.length = 0;
  CanvasTurtles.ids  = new Array();
}

function canvas_delTurtle(Turtle){
  CanvasTurtles["t_"+Turtle] = null;
  canvas_drawTurtles();
}

function canvas_setTurtle(CanvasID,Turtle,x,y,angle){    
  CanvasTurtles["t_"+Turtle] = new Object(); 
  CanvasTurtles["t_"+Turtle].x = x;
  CanvasTurtles["t_"+Turtle].y = y;
  CanvasTurtles["t_"+Turtle].CanvasID = CanvasID;
  CanvasTurtles["t_"+Turtle].angle = angle;
//  alert("Set:"+Turtle+" "+angle);
  var isThere = false;
  for (var i = 0; i < CanvasTurtles.ids.length; i++) {
   if (CanvasTurtles.ids[i] == "t_"+Turtle) isThere = true;
  }
  if(!isThere) CanvasTurtles.ids.push("t_"+Turtle);
  canvas_drawTurtles();
}

function canvas_drawTurtles(){
  for (var i = 0; i < 100; i++) {
   var overlay = document.getElementById('canvas_overlay' + i);
   if (overlay && overlay.getContext){ 
    over = overlay.getContext('2d');
    over.clearRect(0,0,overlay.width,overlay.height); // clear canvas
   }
  }

  for (var i = 0; i < CanvasTurtles.ids.length; i++) {
  var id = CanvasTurtles.ids[i];
  if(CanvasTurtles[id] == null) continue;
  var x = CanvasTurtles[id].x;
  var y = CanvasTurtles[id].y;
  var angle = CanvasTurtles[id].angle;
  var CanvasID = CanvasTurtles[id].CanvasID;
  var overlay = document.getElementById('canvas_overlay' + CanvasID);
  if (overlay && overlay.getContext){ 
    over = overlay.getContext('2d');        
    over.save();
    over.translate(x+0.5,y+0.5);
    var a = (angle) * Math.PI / 180.0;
    over.rotate(a);
    over.drawImage(turtleImage,-15,-18);
    over.restore();
  }}
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_drawimage(CanvasID,x,y,w,h,URL){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_drawimage("+CanvasID+","+x+","+y+","+w+","+h+",'"+URL+"');";
    return;
  }
  GlobalCanvasStack = "";
  UseGlobalCanvasStack = true; 
  var img = new Image();   
  img.onload = function(){
    UseGlobalCanvasStack = false;
    var canvas = document.getElementById('canvas' + CanvasID);
    if (canvas && canvas.getContext){ 
     canvas = canvas.getContext('2d');
//    alert(img.width+" "+img.height + " "+img.src+" "+img.complete);
     if(w == 0 && h == 0)     
       canvas.drawImage(img ,x,y); else     
       canvas.drawImage(img ,x,y,w,h); 
    }
    eval(GlobalCanvasStack); 
  } 
  img.src = URL; 
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_line(CanvasID,x1,y1,x2,y2){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_line("+CanvasID+","+x1+","+y1+","+x2+","+y2+");";    
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.lineJoin = 'round';
    canvas.lineCap = 'round';
    canvas.beginPath();
    canvas.moveTo(x1+0.5,y1+0.5);
    canvas.lineTo(x2+0.5,y2+0.5);
    canvas.stroke();
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_text(CanvasID,x,y,Text,size){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_text("+CanvasID+","+x+","+y+",'"+Text+"',"+size+");";
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    CanvasTextFunctions.enable(canvas);
    canvas.drawText("sans",size,x,y,Text);
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_triangle(CanvasID,x1,y1,x2,y2,x3,y3){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_triangle("+CanvasID+","+x1+","+y1+","+x2+","+y2+","+x3+","+y3+");";
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.lineJoin = 'round';
    canvas.lineCap = 'round';
    canvas.beginPath();
    canvas.moveTo(x1+0.5,y1+0.5);
    canvas.lineTo(x2+0.5,y2+0.5);
    canvas.lineTo(x3+0.5,y3+0.5);
    canvas.fill();
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_rect(CanvasID,x1,y1,x2,y2){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_rect("+CanvasID+","+x1+","+y1+","+x2+","+y2+");";
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.strokeRect(x1+0.5,y1+0.5,x2+0.5,y2+0.5);
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_fillrect(CanvasID,x1,y1,x2,y2){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_fillrect("+CanvasID+","+x1+","+y1+","+x2+","+y2+");";
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.fillRect(x1+0.5,y1+0.5,x2+0.5,y2+0.5);
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_ellipse(CanvasID,x,y,r){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_ellipse("+CanvasID+","+x+","+y+","+r+");";
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.beginPath();
    canvas.arc(x+0.5,y+0.5,r,0,Math.PI*2,true);
    canvas.stroke();
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_setwidth(CanvasID,w){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_setwidth("+CanvasID+","+w+");";
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.lineWidth = w;
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_setcolor(CanvasID,c){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_setcolor("+CanvasID+","+c+");";
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.fillStyle = c;
    canvas.strokeStyle = c;
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
function canvas_setRGBcolor(CanvasID,r,g,b){
  if (UseGlobalCanvasStack) {
    GlobalCanvasStack += "canvas_setRGBcolor("+CanvasID+","+r+","+g+","+b+");";
    return;
  }
  var canvas = document.getElementById('canvas' + CanvasID);
  if (canvas && canvas.getContext){ 
    canvas = canvas.getContext('2d');
    canvas.fillStyle = 'rgba(' + r + ',' + g + ',' + b +',1)';
    canvas.strokeStyle = 'rgba(' + r + ',' + g + ',' + b +',1)';
  }else canvas_noticeUserThatThisCanvasNotExist(CanvasID);
}
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
// {{{ get_html_translation_table
function get_html_translation_table(table, quote_style) {
    var entities = {}, histogram = {}, decimal = 0, symbol = '';
    var constMappingTable = {}, constMappingQuoteStyle = {};
    var useTable = {}, useQuoteStyle = {};
    
    useTable      = (table ? table.toUpperCase() : 'HTML_SPECIALCHARS');
    useQuoteStyle = (quote_style ? quote_style.toUpperCase() : 'ENT_COMPAT');
    
    // Translate arguments
    constMappingTable[0]      = 'HTML_SPECIALCHARS';
    constMappingTable[1]      = 'HTML_ENTITIES';
    constMappingQuoteStyle[0] = 'ENT_NOQUOTES';
    constMappingQuoteStyle[2] = 'ENT_COMPAT';
    constMappingQuoteStyle[3] = 'ENT_QUOTES';
    
    // Map numbers to strings for compatibilty with PHP constants
    if (!isNaN(useTable)) {
        useTable = constMappingTable[useTable];
    }
    if (!isNaN(useQuoteStyle)) {
        useQuoteStyle = constMappingQuoteStyle[useQuoteStyle];
    }
    
    if (useTable == 'HTML_SPECIALCHARS') {
        // ascii decimals for better compatibility
        entities['60'] = '&lt;';
        entities['62'] = '&gt;';
        entities['38'] = '&amp;';
    } else if (useTable == 'HTML_ENTITIES') {
        // ascii decimals for better compatibility
	    entities['38'] = '&amp;';
	    entities['60'] = '&lt;';
	    entities['62'] = '&gt;';
	    entities['160'] = '&nbsp;';
	    entities['161'] = '&iexcl;';
	    entities['162'] = '&cent;';
	    entities['163'] = '&pound;';
	    entities['164'] = '&curren;';
	    entities['165'] = '&yen;';
	    entities['166'] = '&brvbar;';
	    entities['167'] = '&sect;';
	    entities['168'] = '&uml;';
	    entities['169'] = '&copy;';
	    entities['170'] = '&ordf;';
	    entities['171'] = '&laquo;';
	    entities['172'] = '&not;';
	    entities['173'] = '&shy;';
	    entities['174'] = '&reg;';
	    entities['175'] = '&macr;';
	    entities['176'] = '&deg;';
	    entities['177'] = '&plusmn;';
	    entities['178'] = '&sup2;';
	    entities['179'] = '&sup3;';
	    entities['180'] = '&acute;';
	    entities['181'] = '&micro;';
	    entities['182'] = '&para;';
	    entities['183'] = '&middot;';
	    entities['184'] = '&cedil;';
	    entities['185'] = '&sup1;';
	    entities['186'] = '&ordm;';
	    entities['187'] = '&raquo;';
	    entities['188'] = '&frac14;';
	    entities['189'] = '&frac12;';
	    entities['190'] = '&frac34;';
	    entities['191'] = '&iquest;';
	    entities['192'] = '&Agrave;';
	    entities['193'] = '&Aacute;';
	    entities['194'] = '&Acirc;';
	    entities['195'] = '&Atilde;';
	    entities['196'] = '&Auml;';
	    entities['197'] = '&Aring;';
	    entities['198'] = '&AElig;';
	    entities['199'] = '&Ccedil;';
	    entities['200'] = '&Egrave;';
	    entities['201'] = '&Eacute;';
	    entities['202'] = '&Ecirc;';
	    entities['203'] = '&Euml;';
	    entities['204'] = '&Igrave;';
	    entities['205'] = '&Iacute;';
	    entities['206'] = '&Icirc;';
	    entities['207'] = '&Iuml;';
	    entities['208'] = '&ETH;';
	    entities['209'] = '&Ntilde;';
	    entities['210'] = '&Ograve;';
	    entities['211'] = '&Oacute;';
	    entities['212'] = '&Ocirc;';
	    entities['213'] = '&Otilde;';
	    entities['214'] = '&Ouml;';
	    entities['215'] = '&times;';
	    entities['216'] = '&Oslash;';
	    entities['217'] = '&Ugrave;';
	    entities['218'] = '&Uacute;';
	    entities['219'] = '&Ucirc;';
	    entities['220'] = '&Uuml;';
	    entities['221'] = '&Yacute;';
	    entities['222'] = '&THORN;';
	    entities['223'] = '&szlig;';
	    entities['224'] = '&agrave;';
	    entities['225'] = '&aacute;';
	    entities['226'] = '&acirc;';
	    entities['227'] = '&atilde;';
	    entities['228'] = '&auml;';
	    entities['229'] = '&aring;';
	    entities['230'] = '&aelig;';
	    entities['231'] = '&ccedil;';
	    entities['232'] = '&egrave;';
	    entities['233'] = '&eacute;';
	    entities['234'] = '&ecirc;';
	    entities['235'] = '&euml;';
	    entities['236'] = '&igrave;';
	    entities['237'] = '&iacute;';
	    entities['238'] = '&icirc;';
	    entities['239'] = '&iuml;';
	    entities['240'] = '&eth;';
	    entities['241'] = '&ntilde;';
	    entities['242'] = '&ograve;';
	    entities['243'] = '&oacute;';
	    entities['244'] = '&ocirc;';
	    entities['245'] = '&otilde;';
	    entities['246'] = '&ouml;';
	    entities['247'] = '&divide;';
	    entities['248'] = '&oslash;';
	    entities['249'] = '&ugrave;';
	    entities['250'] = '&uacute;';
	    entities['251'] = '&ucirc;';
	    entities['252'] = '&uuml;';
	    entities['253'] = '&yacute;';
	    entities['254'] = '&thorn;';
	    entities['255'] = '&yuml;';
    } else {
        throw Error("Table: "+useTable+' not supported');
        return false;
    }
    
    if (useQuoteStyle != 'ENT_NOQUOTES') {
        entities['34'] = '&quot;';
    }
    
    if (useQuoteStyle == 'ENT_QUOTES') {
        entities['39'] = '&#039;';
    }
    
    // ascii decimals to real symbols
    for (decimal in entities) {
        symbol = String.fromCharCode(decimal)
        histogram[symbol] = entities[decimal];
    }
    
    return histogram;
}// }}}

// {{{ html_entity_decode
function html_entity_decode( string, quote_style ) {
    // Convert all HTML entities to their applicable characters
    var histogram = {}, symbol = '', tmp_str = '', i = 0;
    tmp_str = string.toString();
    
    if (false === (histogram = get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }
    
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(entity).join(symbol);
    }
    
    return tmp_str;
}// }}}

// {{{ htmlentities
function htmlentities (string, quote_style) {
    // Convert all applicable characters to HTML entities
    var histogram = {}, symbol = '', tmp_str = '', i = 0;
    tmp_str = string.toString();
    
    if (false === (histogram = get_html_translation_table('HTML_ENTITIES', quote_style))) {
        return false;
    }
    
    for (symbol in histogram) {
        entity = histogram[symbol];
        tmp_str = tmp_str.split(symbol).join(entity);
    }
    
    return tmp_str;
}// }}}

