/* JavaScript Wappen-Interpreter v2.2
 *   ©   2003 by Hans Peter Schneider
 *           mail@hans-p-schneider.de
 * ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 * Methode zur Interpretation des Wappencodes und Anzeige des daraus resultierenden Wappens
 *
 * Die Methode ‹Wappen(code, breite, höhe, url)› zeigt das im Wappencode ‹code› übergebene und verschlüsselte Wappen
 *	auf einer Fläche mit den Seitenlängen ‹breite› und ‹höhe› in Pixeln an. ‹breite› und ‹höhe› müssen 20 oder größer 
 *	sein, sonst gibt die Methode einen leeren String zurück.
 *	Erzeugt wird der zur Anzeige nötige HTML-Code und zurückgegeben. Fügt man diesen in ein positioniertes
 *	Element ein, so beinhaltet dieses Element das Wappen und zeigt es an. Ist der Code leer, so wird ein leeres
 *	Wappen angezeigt. Ist der Code fehlerhaft, so wird ein Wappen mit der Aufschrift "Code-Fehler!" angezeigt.
 *	Die Methode erlaubt zwar eine rechteckige Wappendarstellung, optimal ist aber eine quadratische. Beste 
 *	Darstellungen erhält man in den beiden im Fundus gespeicherten Größen 96×96px² und 360×360px².
 *	
 *	- Beispiel 1: <div id="wappen"> ... <div>
 *		    <script ... >  ... document.getElementById("wappen").innerHTML = Wappen(meinCode, 120, 120, "../ws"); ...
 *		    </script>
 *
 *	- Beispiel 2: <div> ...
 *		      <script ... > ... document.write(Wappen(meinCode, 54, 54, "ws")); ... </script>
 *		    </div>
 *
 *	- Beispiel 3: <div onClick="this.innerHTML = Wappen(meinCode, 210, 210, ""); return true;"> ...
 *		    </div>
 *
 *	Der dazu nötige Fundus an Bildern muss sich sortiert im Ordner ‹url› befinden. Der Fundus besteht aus den zwei 
 *	Ordnern /pics/ (kleine Bilder, Wappengröße 96×96px² und kleiner) und /rcs/ (große Bilder, Wappengröße über
 *	 96×96px²), beide mit einer identischen Unterstruktur. Der Ordner /pics/ kann noch eine Reihe .gifs und die 
 *	Ordner /ordnung/ und /docu/ mehr enthalten, wenn er gleichzeitig für die Wappenschmiede zuständig ist.
 + ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 | Doku des Wappencodes
 |	Ein Wappen baut sich von unten nach oben auf. Jede Farbschicht hat ihren eigenen Code. Diese werden durch · getrennt
 |	(ASCII+ <ALT+250>, ISO <ALT+0813>) und der ganze Code wird wiederum von · eingerahmt:  ·LayerCode1·LayerCode2·LayerCode3·
 |	Die Zahl der Layers ist nicht beschränkt; ein NullCode ist zulässig und besteht nur aus einem ·, dieser erzeugt ein leeres Wappen.
 |	Jeder LayerCode ist ein String und beginnt mit der Kennung des Typs:
 |		G = Grundfarbe,  T = Teilung,  H = Heroldstück,  W = Wappentier,  F = kleine Figuren-Anordnung,  U = URL eines Bildes
 |	Danach folgen die Parameter:
 |		Grundfarbe G:	B×H	pics: 96×96px², rcs: 360×360px²
 |			Farbe (1 Zeichen: b = blau, d = gold, f = Feh, g = grün, h = Hermelin, k = Kürsch, r = rot, s = schwarz, w = weiß)
 |		Teilung T:		B×H	pics: 96×96px², rcs: 360×360px²
 |			Art der Teilung (2 Zeichen: zwischen 01 und 30)	
 |			Farbe (1 Zeichen: bdfghkrsw s.o.)
 |		Heroldsstück H:	B×H	pics: 96×96px², rcs: 360×360px²
 |			Art der Heroldsstücks (2 Zeichen: zwischen 01 und 30)	
 |			Farbe (1 Zeichen: bdfghkrsw s.o.)
 |		Wappentier W:	B×H	pics: 80×88px², rcs: 300×330px²
 |			Art des Wappentiers (2 Zeichen: zwischen 01 und 20)
 |			Farbe des Tiers (1 Zeichen: bdgrsw s.o.)
 |		[	Farbe der Bewehrung (1 Zeichen: bdgrsw s.o.), default: wie Farbe des Tiers		]
 |		[	Vergrößerung* (1 Zeichen: zwischen 0 und 9, Faktor = (9+n)/(27-n) ), default: n = 8
 |		: [	Ausrichtung* (1 Zeichen: zwischen 0 und 8,	0 = links oben,    1 = mitte oben,   2 = rechts oben,
 |		: :		default: 4 (Zentrum)			3 = links mitte,  4 = Zentrum,      5 = rechts mitte,
 |		_-							6 = links unten,  7 = mitte unten,  8 = rechts unten ) ] ]
 |		Figuren F:		B×H	pics: 60×60px²	rcs:200×200px² 
 |			Art der Figur	(2 Zeichen: zwischen 01 und 35)
 |			Farbe der Figur (1 Zeichen: bdgrsw s.o.)
 |			System der Anordnung (1 Zeichen: zwischen 0 und 8,	0 = Kreis mit Figur oben	1 = Kreis mit Lücke oben
 |											2 = 30° Anordnung ·.·.·.·	3 = 30° Anordnung .·.·.·.
 |											4 = 45° Anordnung ·.·.·.·	4 = 45° Anordnung .·.·.·.
 |											6 = 60° Anordnung ·.·.·.·	7 = 60° Anordnung .·.·.·.
 |											8 = 90° Anordnung ::::: )
 |			Größe der Anordnung (2 Zeichen zwischen 01 und 99)
 |		[	Vergrößerung (1 Zeichen: zwischen 0 und 9,	Faktor = (n+3)/8 der Berührungsbreite
 |		:		default: n = 3	(Standardbreite)	Faktor = (n+3)/6 der Standardbreite )
 |		: [	Indikator-Bitset im Basis-32-Format (1 bis 6 Zeichen 0..9a..v, 5 Bits pro Zeichen, nur die Figuren der
 |		: :		Anordnung mit gesetzten Bits werden angezeigt, für die anderen bleibt eine Lücke. Höchstens 30 Bits sind 
 |		: :		setzbar; Figuren jenseits der ersten 30 werden nicht angezeigt**, wenn mindestens ein Bit gesetzt ist.
 |		_-		Ist kein Bit gesetzt, werden alle Figuren auch jenseits des 30. gezeigt.  )  default: 0 (alle Figuren gezeigt) ] ]
 |		Bildadresse* U:	80×80px² < B×H < 400×400px²
 |			URL/Pfad/Dateiname des Bildes (1 und mehr Zeichen)
 |
 |	*(Nicht in der Wappenschmiede implementiert, wird aber interpretiert bei Code-Eingabe per Hand.)
 |	**(In der Wappenschmiede können nicht mehr als 30 Figuren in einem Layer erzeugt werden.)
 |	in [ ... ] gesetzte Parameter sind optional.
 |
 |	Alle Codezeichen folgen unmittelbar aufeinander, Separatoren, Leerzeichen und Umbrüche sind nicht erlaubt.
 |	Kann ein Code-Teil nicht interpretiert werden, wird ein Wappenschild mit der Aufschrift "Code-Fehler!" angezeigt.
 |	Beispiel:
 |				·Gd·W01rs·H04g·F13d405216o·
 |	Beschreibung:
 |		Auf goldenem Grund ein roter, schwarz bewehrter Adler, überdeckt von einem grünen, mit fünf goldenen Kugeln
 |		belegten Schrägbalken.
 |
 ********************************************************************************************************************************************/

// kleine Hilfsfunktionen

	function round(fl) {
	  return Math.floor(fl+0.5);
	}; // round
	
	var z32 = "0123456789abcdefghijklmnopqrstuv";
	
	function parseInt32(str) {	// Basis-32-Umrechnung string -> integer
	  var i = 0;
	  var z = 0;
	  var n = 0;
	  while ((z > -1) && (i < 6) && (i < str.length)) {
	    z = z32.indexOf(str.substring(i, i+1));
	    n = n*32 + z;
	    i++;
	  };
	  return n;
	}; // parseInt32
	
	function toString32(n, s) {	// Basis-32-Umrechnung integer -> string [auf s Stellen mit führenden Nullen]
	  str = "";
	  while (n > 0) {
	    i = n % 32;
	    str = z32.substring(i, i+1)+str;
	    n = n >> 5;
	  };
	  if (str == "") str = "0";
	  if (s) {
	    while (str.length < s) {
	      str = "0"+str;
	    }; // while
	  }; // if
	  return str;
	};

// Konstanten, die den Bereich für die kleinen Figuren definieren (Anteil der Seitenlängen). Bloß nichts verändern!

	var subDir = new Array();
	  subDir["G"] = "farben/";
	  subDir["T"] = "teilungen/";
	  subDir["H"] = "herolds/";
	  subDir["W"] = "wtiere/";
	  subDir["F"] = "figuren/";

	var xf = 0.1444;		// Abstand vom linken Rand
	var yf = 0.0639;		// Abstand vom oberen Rand
	var wf = 0.8333;		// Breite
	var hf = 0.8722;		// Höhe
	var bf = 0.9167;		// Höhe bis in den Bogenfuß

	var pi = 3.1417;		// Pi
	var w1h = 0.5;		// cos 60°
	var w2h = 0.7071;	// cos 45°
	var w3h = 0.8660;	// cos 30°

	var prm = new Array();	// zur internen Verwendung
	  prm.url = "";				// Quellverzeichnis
	  prm.dir = "";				// Bildverzeichnus
	  prm.typ = "·";				// Layer-Typ
	  prm.src1 = "";				// erstes Bild
	  prm.src2 = "";				// zweites bild
	  prm.sys = 0;				// Anordnung
	  prm.mgn = 0;				// Vergrößerung
	  prm.sde = 4;				// Zahl
	  prm.bits = 0;				// Indikator
	  prm.evt = "";				// Events
	  prm.nme = "";				// Namensrumpf
	  prm.anz = 0;				// Rückgabewert: Anzahl der Positionen in der Anordnung
	  prm.act = 0;				// Rückgabewert: Anzahl der aktiven Figuren in der Anordnung
	  
	function parseSubCode(scode) {	// Parser für einen LayerCode, setzt die Werte von prm
	  if (scode.length > 1) {
	    prm.typ = scode.substring(0,1);
	    if ("THWF".indexOf(prm.typ) >= 0) {
	      if (scode.length < 4) {  prm.typ = "#"; 
	      } else {
	        prm.src1 = scode.substring(1,4) + ".gif";
	        if (prm.src1.substring(0,1) == "0")  prm.src1 = prm.src1.substring(1,prm.src1.length);
	      };
	    };
	    switch (prm.typ) {
	      case "G":	prm.src1 = scode.substring(1,2) + ".gif";
	      case "T":
	      case "H":	break;
	      case "U":	prm.src1 = scode.substring(1, scode.length);
			break;
	      case "W":	prm.src2 = "";	prm.mgn = 8;	prm.sys = 4;
			if (scode.length > 4) {
			  var hlp = scode.substring(4,5);
			  if ("rgbdsw".indexOf(hlp) > -1) {
			    prm.src2 = scode.substring(1, 3) + scode.substring(4, 5) + ".gif";
			    if (prm.src2.substring(0,1) == "0")  prm.src2 = prm.src2.substring(1,prm.src2.length);
			    var i = 1;
			  } else {
			    var i = 0;
			  };
			};
			if (scode.length > 4+i)   prm.mgn = parseInt(scode.substring(4+i, 5+i));
			if (scode.length > 5+i)   prm.sys = parseInt(scode.substring(5+i, 6+i))%9;
			break;
	      case "F":	if (scode.length > 6) {
			  prm.sys = parseInt(scode.substring(4, 5));
			  prm.sde = parseInt(scode.substring(5, 7), 10);
			  prm.mgn = 3;	prm.bits = 0;
			  if (scode.length > 7)   prm.mgn = parseInt(scode.substring(7, 8));
			  if (scode.length > 8)   prm.bits = parseInt32(scode.substring(8, scode.length));
			  break;
			};
	      default:	prm.typ = "#";
	    }; // switch
	  } else {		prm.typ = "#";
	  }; // if
	  return prm.typ;
	};
  
	function newOrd(wpix, hpix, zidx, edit) {
			// Zeichnet die gewählte Verteilung in das angegebene Rechteck, 
			//  unten durch einen einbeschriebenen Halbkreis begrenzt, aus den Daten von prm mit prm.typ = "F"
	  var ordStr = "";
	  var bts = prm.bits;
	  var px = wpix*xf;		var py = hpix*yf;		// Rechteck
	  var wd = wpix*wf;		var ht = hpix*hf;		var bt = hpix*bf;
	  var cx = px + wd/2;		var cy = py+ht/2;		
	  var xy = ht/wd;		var hw = hpix/wpix;
	  var nx = prm.sde;		var alle = prm.bits;
	  var mg = (prm.mgn+3.)/8.;		// Vergrößerungsfaktor für die Darstellung der kleinen Figuren
	  var addition = "";
	  prm.anz = 0;
	  prm.act = 0;
	  if ((wpix < 20) || (hpix < 20)) nx = 0;
	  if (nx > 0) {
	    if (prm.sys < 2) {	// -------------- Kreis ------------------------------------------------------- 
	      var sz = (pi*wd)/(nx+pi);			// normierte Größe
	      var cr = (wd-sz)/2;			// Radius des Kreises
	      var iz = sz*mg/2;			// Offset vom Mittelpunkt der Figur
	      var size = round(sz*mg);			// Seitenlänge der Figur
	      if (size > 60) {	prm.dir = "rcs/";
	      } else {	prm.dir = "pics/";
	      };
	      if (prm.sys == 1) {	rd = sz/2;	// Halbe Größe als Radiant-Offset
	      } else {		rd = 0.0;
	      };
	      var tr;  var tx;  var ty;  			// Zwischenergebnisse
	      var xofs = 0;	var yofs = 0;		// Pixelkoordinaten
	      for (var i = 0; i < nx; i++) {
	        if ((alle == 0) || (bts % 2 == 1) || (edit == true)) {
	          if (nx == 1) {
	            tx = cx;            ty = cx;
	          } else {
	            tr = (i*sz + rd)/cr;				// Radiant
	            tx = cx - (Math.sin(tr)*cr);		// x-Position
	            ty = cy - (Math.cos(tr)*cr*hw);	// y-Position
	          };
	          xofs = round(tx-iz);
	          yofs = round(ty-iz);
		  addition = "";
		  if (prm.evt != "") {
		    addition = " "+prm.evt;
		  };
		  if (prm.nme != "") {
		    addition = addition+" name='"+prm.nme+i+"'";
		  };
		  if ((bts % 2 == 1)||(alle == 0)) {
	            ordStr = ordStr + "<img src='"+prm.url+prm.dir+subDir[prm.typ]+prm.src1+"' width='"+size+"' height='"+size+"' style='position:absolute; left:"+xofs+"px; top:"+yofs+"px; zIndex:"+zidx+";'"+addition+">\n";
		    prm.act++;
		  } else {
	            ordStr = ordStr + "<img src='"+prm.url+prm.dir+subDir[prm.typ]+"passiv.gif' width='"+size+"' height='"+size+"' style='position:absolute; left:"+xofs+"px; top:"+yofs+"px; zIndex:"+zidx+";'"+addition+">\n";
		  };
		};
		prm.anz++;
	        bts = bts >> 1;	
	      }; // while
	    } else {		//----------- kein Kreis -------------------------------------------------
	      switch (prm.sys) {
	        case 2: 					// 30° Gitter 
	        case 3:   var sx = wd/((nx-1)*w3h + 1);
		        var sy = sx*hw;
		        var dx = sx*w3h;	var dy = 2.*sy*w1h;
		        var iy = sy*w1h;
		        break; 
	        case 4:  					// 45° Gitter
	        case 5:   var sx = wd/((nx-1)*w2h + 1);
		        var sy = sx*xy;
		        var dx = sx*w2h;	var dy = 2.*sy*w2h;
		        var iy = sy*w2h;
		        break;
	        case 6:  					// 60° Gitter
	        case 7:   var sx = wd/((nx-1)*w1h + 1);
		        var sy = sx*hw;
		        var dx = sx*w1h;	var dy = 2.*sy*w3h;
		        var iy = sy*w3h;
		        break; 
	        default:    					// 90° Gitter
		        var sx = wd/nx;	var sy = sx*xy;
		        var dx = sx;		var dy = sy;
		        var iy = 0.;
		        break; 
	      }; // switch
	      var ny = Math.floor((bt-sy)/dy) +1;
	      if (prm.sys < 8) {
	        var no = Math.floor((bt-sy)/iy);
	        var oy =(ht - sy - no*iy)/2;
	        if (oy < 0.)   oy = 0.;
	      } else {
	        var oy = 0.
	      };
	      var iz = sx*mg/2;
	      var size = round(sx*mg);
	      if (size > 60) {	prm.dir = "rcs/";
	      } else {	prm.dir = "pics/";
	      };
	      var kx = wd/2;				// unterer Halbkreis
	      var kr = kx - (sx/4.);
	      var ky = bt - kx*hw;
	      var rsq = kr*kr;
	      var ofs = (prm.sys-1)% 2;		// jeden-zweiten-runter-Rücker
	      var ordImg = "";
	      var tx;  var ty;  				// Zwischenergebnisse
	      var xofs = 0;	var yofs = 0;		// Pixelkoordinaten
	      var k = 0;
	      for (var j = 0; j < ny; j++) {
	        for (var i = 0; i < nx; i++) {
	          tx = (i*dx)+(sx/2);
	          ty = (j*dy)+(sy/2)+oy;
	          if (i%2 == ofs)  ty = ty + iy;
	          xofs = round(px+tx-iz);
	          yofs = round(py+ty-iz);
		  addition = "";
		  if (prm.evt != "") {
		    addition = " "+prm.evt;
		  };
		  if (prm.nme != "") {
		    addition = addition+" name='"+prm.nme+k+"'";
		  };
		  if ((bts % 2 == 1)||(alle == 0)) {
	            ordImg = "<img src='"+prm.url+prm.dir+subDir[prm.typ]+prm.src1+"' width='"+size+"' height='"+size+"' style='position:absolute; left:"+xofs+"px; top:"+yofs+"px; zIndex:"+zidx+";'"+addition+">\n";
	          } else {
	            ordImg = "<img src='"+prm.url+prm.dir+subDir[prm.typ]+"passiv.gif' width='"+size+"' height='"+size+"' style='position:absolute; left:"+xofs+"px; top:"+yofs+"px; zIndex:"+zidx+";'"+addition+">\n";
		  };
		  tx = tx - kx;		
	          ty = (ty - ky)/hw;
	          if ((ty <= 0. ) || ((tx*tx) + (ty*ty) <= rsq)) {
 	            if ((alle == 0) || (bts % 2 == 1) || (edit == true)) {
	              ordStr = ordStr + ordImg;
		      if (bts % 2 == 1) prm.act++;
	            }; // if bits
		    prm.anz++;
	            bts = bts >> 1;
	            k++;
	          }; // if ty || tx
	        }; // for i
	      }; // for j
	    }; // if kreis
	  }; // if n
	  return ordStr;
	}; // newOrd

	function newTier(wpix, hpix, zidx) {		
			    // zeicnet ein Wappentier mit farbiger Bewehrung in das Rechteck
			    // aus den Daten von prm mit prm.typ = "W"
	  var tierStr = "";
	  var px = wpix*xf;		var py = hpix*yf;		// Rechteck
	  var wd = wpix*wf;		var bt = hpix*bf;
	  var hd = wpix*(bf-hf);
	  var mg = (9. + prm.mgn)/(27. - prm.mgn);
	  var iy = round(py + ((1 - mg)*(bt*Math.floor(prm.sys / 3) - hd)/2));
	  var ix = round(px + ((1 - mg)*wd*(prm.sys % 3)/2));
	  var sx = round(mg*wd);
	  var sy = round(mg*bt);
	  prm.dir = "pics/";
	  if ((sx > 80) || (sy > 88))  prm.dir = "rcs/";
	  tierStr = "<img src='"+prm.url+prm.dir+subDir[prm.typ]+"frb/"+prm.src1+"' width='"+sx+"' height='"+sy+"' style='position:absolute; left:"+ix+"px; top:"+iy+"px; zIndex:"+zidx+";'>\n";
	  if ((prm.src1 != prm.src2)&&(prm.src2 != "")) {
	    tierStr = tierStr + "<img src='"+prm.url+prm.dir+subDir[prm.typ]+"bew/"+prm.src2+"' width='"+sx+"' height='"+sy+"' style='position:absolute; left:"+ix+"px; top:"+iy+"px; zIndex:"+zidx+";'>\n";
	  };
	  return tierStr;
	}; // newTier

	function Wappen(code, xsize, ysize, url) {
			// Zeichnet das komplette Wappen in das Rechteck aus dem Wappencode und den Bildern der url
	  if (url) {
	    if ((url.length > 0)&&(url.substring(url.length-1, url.length) != "/"))  url = url+"/";
	  } else {
	    url = "";
	  };
	  prm.url = url;
	  if (!(ysize)) ysize = xsize;
	  if ((xsize < 20) || (ysize < 20)) return "";
	  if (code.length < 4) {
	    return  ( "<div style='position:relative; width:"+xsize+"px; height:"+ysize+"px;'>\n<img src='"+url+"pics/leer.gif' width='"+xsize+"' height='"+ysize+"' style='position:absolute; left:0px; top:0px;'>\n</div>\n");
	  };
	  max = xsize;
	  if (ysize > max) max = ysize;
	  var htmlStr = "<div style='position:relative; width:"+xsize+"px; height:"+ysize+"px;'>\n";
	  var subdir = "";
	  code = code.substring(1,code.length);	// ersten Punkt entfernen
	  var q = code.indexOf("·");			// zweiten Punkt suchen
	  if (q < 1) {				// fehlerhafter Code
	    return  ( "<div style='position:relative; width:"+xsize+"px; height:"+ysize+"px;'>\n<img src='"+url+"pics/fehl.gif' width='"+xsize+"' height='"+ysize+"' style='position:absolute; left:0px; top:0px;'>\n</div>\n");
	  };
	  for (var z = 2; q > 0; z++) {
	    switch (parseSubCode(code.substring(0,q))) {
	      case "G":				// Grundfarbe
	      case "T":				// Teilung
	      case "H":				// Heroldsstück
		prm.dir = "pics/";
		if (max > 96)  prm.dir = "rcs/"; 
		htmlStr = htmlStr + "<img src='"+url+prm.dir+subDir[prm.typ]+prm.src1+"' width='"+xsize+"' height='"+ysize+"' style='position:absolute; left:0px; top:0px; zIndex:"+z+";'>\n";
		break;
	      case "W":				// Wappentier
		htmlStr = htmlStr + newTier(xsize, ysize, z, false);
		break;
	      case "F":				// Figur
		htmlStr = htmlStr + newOrd(xsize, ysize, z);
		break;
	      case "U":				// URL eines Bildes
		htmlStr = htmlStr + "<img src='"+layerCode+"' width='"+xsize+"' height='"+ysize+"' style='position:absolute; left:0px; top:0px;'>\n";
		break;
	      default:				// fehlerhafter Code!
		return  ( "<div style='position:relative; width:"+xsize+"px; height:"+ysize+"px;'>\n<img src='"+url+"pics/fehl.gif' width='"+xsize+"' height='"+ysize+"' style='position:absolute; left:0px; top:0px;'>\n</div>\n");
	    }; // switch parseSubCode
	    code = code.substring(q+1, code.length);
	    q = code.indexOf("·");
	  }; // for i
	  return htmlStr+"</div>";
	}; // Wappen

// Ende
