<?
/*
#============================================================================
# Program: Topology-Map.php
# Programmer: Remo Rickli
#
# DATE		COMMENT
# -----------------------------------------------------------
# 6/05/05		initial version.
# 10/03/06	new SQL query support
# 17/07/06	enhanced info and new network filter
# 21/02/07	refined layout and link weight computation, more hints and image map!
# 20/03/07	changes to mapping and GUI for RRD graohs...
# 10/05/07	Geographic, iconless & error map, rewrite for SVG output!
# 26/07/07	new location scheme, hierarchial maps
# 31/08/07	implemented CSS scheme
# 31/09/07	Recursive drawing, new GUI
# 20/09/07	implemented language support
# ?/10/07	almost completely rewritten to support new location scheme
*/

error_reporting(E_ALL ^ E_NOTICE);

$nocache= 1;
$refresh= 3600;

$mapinfo   = "";
$mapframes = "";
$maplinks  = "";
$mapitems  = "";

$ndev      = array();
$bldlink   = array();
$ctylink   = array();
$devlink   = array();

$imgmap    = "";

include_once ("inc/header.php");
include_once ('inc/libdev.php');
include_once ('inc/libgraph.php');

$_GET = sanitize($_GET);

$flt = isset($_GET['flt']) ? $_GET['flt'] : ".";
$ina = isset($_GET['ina']) ? $_GET['ina'] : "loc";
$fmt = isset($_GET['draw']) ? $_GET['draw'] : "";

$tit = isset($_GET['tit']) ? $_GET['tit'] : "$flt $netlbl";
$lev = isset($_GET['lev']) ? $_GET['lev'] : "";
$mod = isset($_GET['mod']) ? $_GET['mod'] : "";
$xo  = isset($_GET['xo']) ? $_GET['xo'] : 0;
$yo  = isset($_GET['yo']) ? $_GET['yo'] : 0;
$rot = isset($_GET['rot']) ? $_GET['rot'] : 0;

$ifi = isset($_GET['ifi']) ? "checked" : "";
$ipi = isset($_GET['ipi']) ? "checked" : "";
$loi = isset($_GET['loi']) ? "checked" : "";

$lis = isset($_GET['lis']) ? $_GET['lis'] : "";
$lit = isset($_GET['lit']) ? $_GET['lit'] : "";
$lwt = isset($_GET['lwt']) ? $_GET['lwt'] : 5;
$pos = isset($_GET['pos']) ? $_GET['pos'] : "";
$pwt = isset($_GET['pwt']) ? $_GET['pwt'] : 5;
$lsf = isset($_GET['lsf']) ? $_GET['lsf'] : 1.5;
$fco = isset($_GET['fco']) ? $_GET['fco'] : 6;

$dep = isset($_GET['dep']) ? $_GET['dep'] : 24;
$prs = isset($_GET['prs']) ? $_GET['prs'] : "";
if    ($prs == "vga") {$xm = "640"; $ym = "480";$len = 100;$fpa = 60;}
elseif($prs == "svga"){$xm = "800"; $ym = "600";$len = 150;$fpa = 70;}
elseif($prs == "xga") {$xm = "1024";$ym = "768";$len = 200;$fpa = 80;}
elseif($prs == "sxga"){$xm = "1280";$ym = "1024";$len = 250;$fpa = 100;}
elseif($prs == "uxga"){$xm = "1600";$ym = "1200";$len = 300;$fpa = 120;}
else{
	$xm  = isset($_GET['x']) ? $_GET['x'] : 1000;
	$ym  = isset($_GET['y']) ? $_GET['y'] : 600;
	$fpa = isset($_GET['fpa']) ? $_GET['fpa'] : 80;
	$len = isset($_GET['len']) ? $_GET['len'] : 200;
}
?>
<h1>Topology Map</h1>
<form method="get" name="map" action="<?=$self?>.php">
<table class="content" ><tr class="<?=$modgroup[$self]?>1">
<th width=80><a href="<?=$self?>.php"><img src="img/32/paint.png"></a></th>
<td valign="top" title="Size & depth of image"><h3>Image</h3>
<table>
<tr><td>Size</td><td>
<select size=1 name="prs">
<option value="">preset
<option value="vga">640x480
<option value="svga">800x600
<option value="xga">1024x768
<option value="sxga">1280x1024
<option value="uxga">1600x1200
</select>
</td></tr>
<tr><td>or XY</td><td>
<input type="text" name="x" value="<?=$xm?>" size=3>
<input type="text" name="y" value="<?=$ym?>" size=3>
</td></tr>
<tr><td>Depth</td><td>
<input type="radio" name="dep" value="8" <?=($dep == 8)?"checked":""?>>8bit
<input type="radio" name="dep" value="24"<?=($dep == 24)?"checked":""?>>24bit
</td></tr>
</table>
</td>

<td valign="top" title='Global settings'><h3>General</h3>
<table>
<tr><td>Title</td><td><input type="text" name="tit" value="<?=$tit?>" size=20></td></tr>
<tr><td>Mode</td><td>
<select size=1 name="lev" title="Select detail level">
<option value="1">region
<option value="2" <?=($lev == "2")?"selected":""?>>city
<option value="3" <?=($lev == "3")?"selected":""?>>building
<option value="4" <?=($lev == "4")?"selected":""?>>device
</select>
<select size=1 name="mod" title="Select drawing mode">
<option value="c">circle
<option value="g" <?=($mod == "g")?"selected":""?>>geo
</select>
</td></tr>
<tr><td>Offset</td><td>
<input type="text" name="xo" value="<?=$xo?>" size=2 title="Moves map horizontally"> X
<input type="text" name="yo" value="<?=$yo?>" size=2 title="Moves map vertically"> Y
<input type="text" name="rot" value="<?=$rot?>" size=2 title="Map rotation"> @
</td></tr>
</table>
</td>

<td valign="top" title='Object placement properties'><h3>Layout</h3>
<table>
<tr><td>Link</td><td>
<select size=1 name="lit">
<option value=""><?=$emplbl?>
<option value="w" <?=($lit == "w")?"selected":""?>><?=$bwdlbl?>
<option value="">- <?=$trflbl?> <?=$gralbl?> -
<option value="ft" <?=($lit == "ft")?"selected":""?>><?=$siz['t']?>
<option value="fs" <?=($lit == "fs")?"selected":""?>><?=$siz['s']?>
<option value="fm" <?=($lit == "fm")?"selected":""?>><?=$siz['m']?>
<option value="">- <?=$errlbl?> <?=$gralbl?> -
<option value="et" <?=($lit == "et")?"selected":""?>><?=$siz['t']?>
<option value="es" <?=($lit == "es")?"selected":""?>><?=$siz['s']?>
<option value="em" <?=($lit == "em")?"selected":""?>><?=$siz['m']?>
</select>
<select size=1 name="lis">
<option value="">Line
<option value="c" <?=($lis == "c")?"selected":""?>>Curve
</select>
<input type="text" name="lwt" value="<?=$lwt?>" size=1 title="Weight for link info"> I
</td></tr>
<tr><td>Point</td><td>
<select size=1 name="pos" title="Select point style">
<option value="">icon
<option value="s" <?=($pos == "s")?"selected":""?>>shape
</select>
<input type="text" name="pwt" value="<?=$pwt?>" size=1 title="Weight based on # of links"> W
<input type="text" name="len" value="<?=$len?>" size=2 title="Link length"> L
<input type="text" name="lsf" value="<?=$lsf?>" size=1 title="Link shorten factor"> F
</td></tr>
<tr><td>Floor</td><td>
<input type="text" name="fpa" value="<?=$fpa?>" size=2 title="Floor padding"> P
<input type="text" name="fco" value="<?=$fco?>" size=1 title="Floor columns"> C
</td></tr>
</table>
</td>

<td valign="top"><h3>Info</h3>
<input type="checkbox" name="ifi" <?=$ifi?> title="Interface"> IF<p>
<input type="checkbox" name="ipi" <?=$ipi?> title="IP address"> IP<p>
<input type="checkbox" name="loi" <?=$loi?> title="Location"> Loc
</td>

<td valign="top" title="location or vlan filter, with presets"><h3>Filter</h3>
<table >
<tr><td>
<select size=1 name="ina">
<option value="">Location
<option value="t" <?=($ina == "t")?"selected":""?>>Device Type
<option value="v" <?=($ina == "v")?"selected":""?>>Vlan ID
<option value="n" <?=($ina == "n")?"selected":""?>>Network
</select>
</td></tr>
<tr><td><input type="text" name="flt" value="<?=$flt?>" size=15></td></tr>
<tr><td><select size=1 name="cs" onchange="document.map.flt.value=document.map.cs.options[document.map.cs.selectedIndex].value">
<option value="">or select
<?
$link	= @DbConnect($dbhost,$dbuser,$dbpass,$dbname);
$query	= GenQuery('devices','s','name,location');
$res	= @DbQuery($query,$link);
if($res){
	while( ($d = @DbFetchRow($res)) ){
		$devs[] = $d[0];
		$l = explode($locsep, $d[1]);
		$lopt[$l[0]][$l[1]]++;
	}
	@DbFreeResult($res);
}else{
	print @DbError($link);
}
ksort($lopt);
foreach(array_keys($lopt) as $r){
?><option value="<?=TopoLoc($r)?>" style="color:red"><?=$r?>

<?
	ksort($lopt[$r]);
	foreach(array_keys($lopt[$r]) as $c){
?><option value="<?=TopoLoc($r,$c)?>"><?=$c?> (<?=$lopt[$r][$c]?>)
<?
	}
}
?>
</select></td></tr>
</table>
</td>

<th width=80 valign="top" title="png is a common bitmap- svg a vector oriented format."><h3>Draw</h3>
<input type="submit" name="draw" value="png"><p>
<input type="submit" name="draw" value="svg">
</th></tr>
</tr></table><p>
<div align="center">
<?
if($fmt == 'svg'){
	echo "<h5>SVG Map</h5>";
	Map();
	WriteSVG($_SESSION['user'],count($dev) );
?>
	<embed width="<?=$xm?>" height="<?=$ym?>" src="log/map_<?=$_SESSION[user]?>.svg" name="SVG Map" type="image/svg+xml" style="border:1px solid black">
<?
}else{
	if($fmt){
		echo "<h5>PNG Map (clickable)</h5>";
		Map();
		WritePNG($_SESSION['user'],count($dev) );
	}else{
		echo "<h4>Previous Map (not clickable, without graphs!)</h4>";
	}
	if (file_exists("log/map_$_SESSION[user].php")) {
	?>
		<img usemap=#net src="log/map_<?=$_SESSION[user]?>.php" style="border:1px solid black">
		<map name=net>
		<?=$imgmap?>
		</map>
	<?
	}
}
?>
</div>
<?

include_once ("inc/footer.php");

#===================================================================
# Generate the php script for the image.

function WritePNG($usr,$nd) {

	global $trflbl,$errlbl,$inblbl,$tim;
	global $xm,$ym,$mod,$dep,$lit,$trfa,$trfw,$tit,$ina,$flt;
	global $mapbg,$mapinfo,$mapframes,$maplinks,$mapitems;

	$maphdr   = array();
	$mapftr   = array();

	$now = date ("G:i:s j.M y",time());

       	$map  = "<?PHP\n";
	$map .= "# PNG Map for $nd devices created on $now by NeDi (visit http://www.nedi.ch for more info)\n";
	$map .= "header(\"Content-type: image/png\");\n";
	$map .= "error_reporting(0);\n";
	if($mod == "g"){
		$map .= "\$image = Imagecreatefrompng(\"$mapbg\");\n";
		$map .= "Imagealphablending(\$image,true);\n";
		$map .= "\$gainsboro  = Imagecolorallocatealpha(\$image, 230, 230, 230, 40);\n";
		$map .= "\$whitesmoke = Imagecolorallocatealpha(\$image, 245, 245, 245, 40);\n";
	}elseif ($dep == "24"){
		$map .= "\$image = imagecreatetruecolor($xm, $ym);\n";
		$map .= "Imagealphablending(\$image,true);\n";
		$map .= "\$gainsboro  = Imagecolorallocatealpha(\$image, 230, 230, 230, 40);\n";
		$map .= "\$whitesmoke = Imagecolorallocatealpha(\$image, 245, 245, 245, 40);\n";
		$map .= "\$white      = ImageColorAllocate(\$image, 255, 255, 255);\n";
		$map .= "ImageFilledRectangle(\$image, 0, 0, $xm, $ym, \$white);\n";
	}else{
		$map .= "\$image = imagecreate($xm, $ym);\n";
		$map .= "\$gainsboro  = ImageColorAllocate(\$image, 230, 230, 230);\n";
		$map .= "\$whitesmoke = ImageColorAllocate(\$image, 245, 245, 245);\n";
		$map .= "\$white      = ImageColorAllocate(\$image, 255, 255, 255);\n";
		$map .= "ImageFilledRectangle(\$image, 0, 0, $xm, $ym, \$white);\n";
	}
	$map .= "\$red       = ImageColorAllocate(\$image, 200, 0, 0);\n";
	$map .= "\$purple    = ImageColorAllocate(\$image, 200, 0, 200);\n";
	$map .= "\$orange    = ImageColorAllocate(\$image, 240, 180, 0);\n";
	$map .= "\$green     = ImageColorAllocate(\$image, 0, 130, 0);\n";
	$map .= "\$limegreen = ImageColorAllocate(\$image, 50, 200, 50);\n";
	$map .= "\$navy      = ImageColorAllocate(\$image, 0, 0, 130);\n";
	$map .= "\$blue      = ImageColorAllocate(\$image, 0, 0, 250);\n";
	$map .= "\$cornflowerblue      = ImageColorAllocate(\$image, 100, 150, 220);\n";
	$map .= "\$gray      = ImageColorAllocate(\$image, 100, 100, 100);\n";
	$map .= "\$black     = ImageColorAllocate(\$image, 0, 0, 0);\n";
	$map .= "ImageString(\$image, 5, 8, 8, \"$tit\", \$black);\n";
	$map .= "ImageString(\$image, 1, 8, 26, \"$nd devices ($ina ~ /$flt/)\", \$gray);\n";
	$map .= "ImageString(\$image, 1, ".($xm - 120).",".($ym - 10).", \"NeDi $now\", \$gray);\n";
		
	$map .= $mapinfo . $mapframes . $maplinks . $mapitems;

	$map .= "Imagepng(\$image);\n";
	$map .= "Imagedestroy(\$image);\n";
	$map .= "?>\n";
	
	$fd =  @fopen("log/map_$usr.php","w") or die ("can't create log/map_$usr.php");
	fwrite($fd,$map);
	fclose($fd);
}

#===================================================================
# Generate the php script for the image.

function WriteSVG($usr,$nd) {

	global $xm,$ym,$mod,$dep,$lit,$trfa,$trfw,$tit,$ina,$flt,$mapinfo,$mapframes,$maplinks,$mapitems;

	$now = date ("G:i:s j.M y",time());

       	$map  = "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>\n";
	$map .= "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.0//EN\" \"http://www.w3.org/TR/SVG/DTD/svg10.dtd\">\n";
	$map .= "<svg viewBox=\"0 0 $xm $ym\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n";
	$map .= "<g id=\"main\" font-size=\"9\">\n";
	$map .= "<rect id=\"canvas\" width=\"$xm\" height=\"$ym\" x=\"0\" y=\"0\" stroke=\"black\" fill=\"white\" />\n";
	$map .= "<g id=\"title\">\n";
	$map .= "	<text x=\"8\" y=\"20\" font-size=\"16\" font-weight=\"bold\">$tit</text>\n";
	$map .= "	<text x=\"8\" y=\"32\" style=\"fill:gray;\">$nd devices for $ina ~ /$flt/</text>\n";
	$map .= "	<text x=\"".($xm - 120)."\" y=\"".($ym - 5)."\" style=\"fill:gray;\">NeDi $now</text>\n";
	$map .= "</g>\n";

	$map .= "<g id=\"info\">\n";
	$map .= $mapinfo;
	$map .= "</g>\n";

	$map .= "<g id=\"frames\">\n";
	$map .= $mapframes;
	$map .= "</g>\n";

	$map .= "<g id=\"links\">\n";
	$map .= $maplinks;
	$map .= "</g>\n";

	$map .= "<g id=\"items\">\n";
	$map .= $mapitems;
	$map .= "</g>\n";

	$map .= "</g></svg>\n";

	$fd =  @fopen("log/map_$usr.svg","w") or die ("can't create log/map_$usr.svg");
	fwrite($fd,$map);
	fclose($fd);
}

#===================================================================
# Draws a link.
function DrawLink($x1,$y1,$x2,$y2,$fb,$rb,$fif,$rif) {

	global $fmt,$lev,$lix,$liy,$lis,$lit,$lwt,$ipi,$ifi;
	global $dev,$maplinks,$mapitems,$errlbl,$trflbl,$rrdcmd,$rrdpath;

        if($x1 == $x2){							# offset coherent, horizontal links...
                $lix[$x1]+= 2;
                $x1 += $lix[$x1];
                $x2 = $x1;
        }
        if($y1 == $y2){							# offset coherent, verical links...
                $liy[$y1]+= 2;
                $y1 += $liy[$y1];
                $y2 = $y1;
        }

	$xlm   = intval($x1  + $x2) / 2;				# middle of link
	$ylm   = intval($y1  + $y2) / 2;

	if( is_array($fif) ){
		$yof = 0;
		foreach ($fif as $fi){
			$f = explode(';;', $fi);
			if( preg_match("/^[fe]/",$lit) ){
				$rrd = "$rrdpath/" . rawurlencode($f[0]) . "/" . rawurlencode($f[1]) . ".rrd";
				if (file_exists($rrd)){
					$rrdif["$f[0]-$f[1]"] = $rrd;
				}else{
					echo "RRD:$rrd not found!\n";
				}
			}
			if($lev > 3){
				$ifl = ($ifi)?$f[1]:"";
			}else{
				$ifl = ($ifi)?"$f[0] $f[1]":"";
			}
			$ipl = ($ipi)?$dev[$f[0]]['iip'][$f[1]]:"";
			$mapitems .= DrawLabel(	intval($x2+($x1-$x2)/(1 + $lwt/20)),
						intval($y2+($y1-$y2)/(1 + $lwt/20))+$yof,
						Safelabel("$ifl$ipl"),1,"gray");
			$yof += 8;
		}
	}
	if( is_array($rif) ){
		$yof = 0;
		foreach ($rif as $ri){
			$r = explode(';;', $ri);
			if($lev > 3){
				$ifl = ($ifi)?$r[1]:"";
			}else{
				$ifl = ($ifi)?"$r[0] $r[1]":"";
			}
			$ipl = ($ipi)?$dev[$r[0]]['iip'][$r[1]]:"";
			$mapitems .= DrawLabel(	intval($x1+($x2-$x1)/(1 + $lwt/20)),
						intval($y1+($y2-$y1)/(1 + $lwt/20))+$yof,
						Safelabel("$ifl$ipl"),1,"gray");
			$yof += 8;
		}
	}

	if($fb == 11000000 or $fb == 54000000){
		$t = '5';
		$c = 'gainsboro';
	}elseif($fb < 10000000){
		$t = '1';
		$c = 'limegreen';
	}elseif($fb < 100000000){
		$t = '1';
		$c = 'blue';
	}elseif($fb < 1000000000){
		$t = '1';
		$c = 'orange';
	}elseif($fb == 1000000000){
		$t = '1';
		$c = 'red';
	}else{
		$t = ($fb/1000000000 < 10)?($fb/1000000000):10;
		$c = 'red';
	}
	if($lit == 'w'){
		$mapitems .= DrawLabel($xlm,$ylm-8,ZFix($fb) . "/" . ZFix($rb),1,"green");
	}
	if( is_array($rrdif) ){
		if( preg_match("/^f/",$lit) ){
			$opts = GraphOpts(substr($lit,1),0,"Link $trflbl",$fb);
			list($drawin,$drawout,$tit) = GraphTraffic($rrdif,'trf');
		}else{
			$opts = GraphOpts(substr($lit,1),0,"Link $errlbl",0);
			list($drawin,$drawout,$tit) = GraphTraffic($rrdif,'err');
		}
		exec("$rrdcmd graph log/$xlm$ylm.png -a PNG $opts $drawin $drawout");
		if($fmt == "svg"){
			$mapitems .= "	<text x=\"$xlm\" y=\"$ylm\" fill=\"green\">no RRDs in SVG!</text>\n";
		}else{
			$mapitems .= "\$icon = Imagecreatefrompng(\"$xlm$ylm.png\");\n";
			$mapitems .= "\$w = Imagesx(\$icon);\n";
			$mapitems .= "\$h = Imagesy(\$icon);\n";
			$mapitems .= "Imagecopy(\$image, \$icon,$xlm-\$w/2,$ylm-\$h/2,0,0,\$w,\$h);\n";
			$mapitems .= "Imagedestroy(\$icon);\n";
			$mapitems .= "unlink(\"$xlm$ylm.png\");\n";
		}
	}

	if($lis == "c"){
		$w = 2*abs($x2-$x1);
		$h = 2*abs($y2-$y1);
		if($x1 > $x2){
			$x = $x2;
			$y = $y1;
			$ya= $y2;
		}else{
			$x = $x1;
			$y = $y2;
			$ya= $y1;
		}
		if($y < $ya){
			$s = 0;
			$e = 90;
		}else{
			$s = -90;
			$e = 0;
		}
		if($fmt == "svg"){
			$maplinks .= "<path d=\"M $x1 $y1 A $w $h 0 0 1 $x2 $y2\" stroke=\"$c\" stroke-width=\"$t\" fill = \"none\"/>\n";
		}else{
			$maplinks .= "imagesetthickness(\$image,$t);\n";
			$maplinks .= "imagearc(\$image, $x, $y, $w, $h, $s, $e, \$$c);\n";
		}
	}else{
		if($fmt == "svg"){
			$maplinks .= "<line x1=\"$x1\" y1=\"$y1\" x2=\"$x2\" y2=\"$y2\" stroke=\"$c\" stroke-width=\"$t\"/>\n";
		}else{
			$maplinks .= "imagesetthickness(\$image,$t);\n";
			$maplinks .= "imageline(\$image,$x1,$y1,$x2,$y2,\$$c);\n";
		}
	}
}
#===================================================================
# Draws box

function Drawbuilding($x,$y,$r,$c,$b) {

	global $flr,$fpa,$fco,$fmt;
	global $mapframes,$mapitems,$imgmap;

	$row = $rows = $cols = 0;
	foreach(array_keys($flr[$r][$c][$b]) as $f){			# Determine building size
		$curcol = count($flr[$r][$c][$b][$f]);
		$cols   = max($curcol,$cols);
		if($curcol > $fco){					# Break row, if > Floor columns
			$rows += ceil($curcol / $fco);			# How many rows result?
			$cols = $fco;
		}else{
			$rows++;
		}
	}
	$woff = intval($fpa*($cols-1)/2);
	$hoff = intval($fpa*($rows-1)/2);

	$x1 = $x - $woff - intval($fpa/2) - 10;
	$y1 = $y - $hoff - intval($fpa/2);
	$x2 = $x + $woff + intval($fpa/2);
	$y2 = $y + $hoff + intval($fpa/2);

	if($fmt == "svg"){
		$mapframes .= "	<rect fill=\"whitesmoke\" x=\"$x1\" y=\"$y1\" width=\"".($x2-$x1)."\" height=\"".($y2-$y1)."\" fill-opacity=\"0.6\" />\n";
		$mapframes .= "	<rect fill=\"gainsboro\" x=\"$x1\" y=\"".($y1+20)."\" width=\"20\" height=\"".($y2-$y1-20)."\" fill-opacity=\"0.6\" />\n";
		$mapframes .= "	<rect fill=\"none\" stroke=\"black\" x=\"$x1\" y=\"$y1\" width=\"".($x2-$x1)."\" height=\"".($y2-$y1)."\"/>\n";
		$mapframes .= "	<text x=\"".($x1+4)."\" y=\"".($y1+12)."\" font-size=\"12\" fill=\"blue\">$b</text>\n";
	}else{
		$mapframes .= "Imagefilledrectangle(\$image, $x1, $y1, $x2, $y2, \$whitesmoke);\n";
		$mapframes .= "Imagefilledrectangle(\$image, $x1, ".($y1+20).", ".($x1+20).", $y2, \$gainsboro);\n";
		$mapframes .= "Imagerectangle(\$image, $x1, $y1, $x2, $y2, \$black);\n";
		$mapframes .= "ImageString(\$image, 3, ".($x1+4).", ".($y1+4).",\"$b\", \$blue);\n";
	}
	uksort($flr[$r][$c][$b], "Floorsort");
	foreach(array_keys($flr[$r][$c][$b]) as $f){
		$mapitems .= Drawitem(	$x - $woff - intval($fpa/2),
					$y - $hoff + $row*$fpa,
					0,$f,'fl');
		usort( $flr[$r][$c][$b][$f],"Roomsort" );
		$col = 0;
		foreach($flr[$r][$c][$b][$f] as $dv){
			if($col == $fco){
				$col = 0;
				$row++;
			}
			$dev[$dv]['x'] = $x - $woff + $col*$fpa;
			$dev[$dv]['y'] = $y - $hoff + $row*$fpa;
			$mapitems .= Drawitem($dev[$dv]['x'],$dev[$dv]['y'],'0',$dv,'d');
			$imgmap .= "<area href=\"Devices-Status.php?dev=".rawurlencode($dv)."\" coords=\"".($dev[$dv]['x']-20) .",". ($dev[$dv]['y']-20) .",". ($dev[$dv]['x']+20) .",". ($dev[$dv]['y']+20)."\" shape=rect title=\"$dv Status\">\n";
			$col++;
		}
		$row++;
	}	

}

#===================================================================
# Draws a single item

function Drawitem($x,$y,$opt,$label,$typ) {

	global $fmt,$dev,$pos,$loi,$ipi,$redbuild;

	$r  = ($opt > 2)?10:5;
	$lx = intval($x-strlen($label) * 2);

	if($typ == 3){
		if($pos == "s"){
			$bc = ( preg_match("/$redbuild/",$label) )?"red":"cornflowerblue";
			$itxt .= IconRect($x,$y,$r,$r,$bc);
		}else{
			$itxt .= IconPng($x,$y,BldImg($opt,$label),30);
		}
		$itxt .= DrawLabel($x,$y+15,Safelabel($label),3,"navy");
	}elseif($typ == 2){
		if($pos == "s"){
			$itxt .= IconCircle($x,$y,$r,$r,"blue");
		}else{
			$itxt .= IconPng($x,$y,CtyImg($opt),50);
		}
		$itxt .= DrawLabel($x,$y+25,Safelabel($label),4,"navy");
	}elseif($typ == 1){
		if($pos == "s"){
			$itxt .= IconCircle($x,$y,12,12,"blue");
		}else{
			$itxt .= IconPng($x,$y,"32/glob",40);
		}
		$itxt .= DrawLabel($x,$y+10,Safelabel($label),4,"navy");
	}elseif($typ == "ri"){
		if($pos == "s"){
			$itxt .= IconCircle($x,$y,10,6,"gainsboro");
		}else{
			$itxt .= IconPng($x,$y,"regg",25);
		}
		$itxt .= DrawLabel($x,$y+10,Safelabel($label),3,"gray");
	}elseif($typ == "ci"){
		if($pos == "s"){
			$itxt .= IconRect($x,$y,10,6,"whitesmoke");
		}else{
			$itxt .= IconPng($x,$y,"cityg",30);
		}
		$itxt .= DrawLabel($x,$y+10,Safelabel($label),3,"gray");
	}elseif($typ == "fl"){
		if($pos == "s"){
			$itxt .= IconRect($x,$y,2,4,"black");
		}else{
			$itxt .= IconPng($x,$y,"stair",10);
		}
		$itxt .= DrawLabel($x,$y+6,Safelabel($label),3,"navy");
	}elseif($typ == "d"){
		$dev[$label]['x'] = $x;
		$dev[$label]['y'] = $y;
		if($pos == "s"){
			$itxt .= IconRect($x,$y,10,4,"blue");
		}else{
			$itxt .= IconPng($x,$y,"dev/" . $dev[$label]['ico'],30);
		}
		$itxt .= DrawLabel($x,$y+15,Safelabel($label),1,"black");
		if ($loi){$itxt .= DrawLabel($x,$y-25,Safelabel($dev[$label]['rom']),1,"cornflowerblue");}
		if ($ipi){$itxt .= DrawLabel($x,$y+25,$dev[$label]['ip'],1,"gray");}
	}
	return $itxt;
}

#===================================================================
# Generate PNG icon text
function IconPng($x,$y,$i,$s){

	global $fmt;

	if($i){
		if($fmt == "png"){
			$icon = "\$icon = Imagecreatefrompng(\"../img/$i.png\");\n";
			$icon .= "\$w = Imagesx(\$icon);\n";
			$icon .= "\$h = Imagesy(\$icon);\n";
			$icon .= "Imagecopy(\$image, \$icon,intval($x - \$w/2),intval($y - \$h/2),0,0,\$w,\$h);\n";
			$icon .= "Imagedestroy(\$icon);\n";
			return $icon;
		}elseif($fmt == "svg"){
			return "<image x=\"".($x-$s/2)."\" y=\"".($y-$s/2)."\" width=\"$s\" height=\"$s\" xlink:href=\"../img/$i.png\"/>\n";
		}
	}
}

#===================================================================
# Generate rectangular shape (and set $h to height for following labeloffset)
function IconRect($x,$y,$w,$h,$c){

	global $fmt;

	if($fmt == "png"){
		$icon = "Imagefilledrectangle(\$image, ".($x-$w).", ".($y-$h).", ".($x+$w).", ".($y+$h).", \$$c);\n";
		$icon .= "Imagerectangle(\$image, ".($x-$w).", ".($y-$h).", ".($x+$w).", ".($y+$h).", \"\$black\");\n";
		$icon .= "\$h = $h;";
		return $icon;
	}elseif($fmt == "svg"){
		return "<rect fill=\"$c\" stroke=\"black\" x=\"".($x-$w)."\" y=\"".($y-$h)."\" width=\"".(2*$w)."\" height=\"".(2*$h)."\" />\n";
	}
}

#===================================================================
# Generate circular shape  (and set $h to height for following labeloffset)
function IconCircle($x,$y,$rx,$ry,$c){

	global $fmt;

	if($fmt == "png"){
		$icon = "Imagefilledellipse(\$image, $x, $y, ".(2*$rx).", ".(2*$ry).", \"\$$c\");\n";
		$icon .= "Imageellipse(\$image, $x, $y, ".(2*$rx).", ".(2*$ry).", \"\$black\");\n";
		$icon .= "\$h = $ry;";
		return $icon;
	}elseif($fmt == "svg"){
		return "<ellipse  fill=\"$c\" stroke=\"black\" cx=\"$x\" cy=\"$y\" rx=\"$rx\" ry=\"$ry\"/>\n";
	}
}

#===================================================================
# Generate label text
function DrawLabel($x,$y,$t,$s,$c){

	global $fmt;

	if($t){
		$fs = ($s == 1)?9:(4*$s);
		$lx = intval($x-strlen($t) * $fs/4);
		if($fmt == "png"){
			return "ImageString(\$image, $s, $lx, $y, \"$t\", \$$c);\n";
		}elseif($fmt == "svg"){
			return "<text x=\"$lx\" y=\"".($y+$fs)."\" font-size=\"$fs\" fill=\"$c\">$t</text>\n";
		}
	}

}

#===================================================================
# Generate the map.
function Map() {

	global $link,$locsep,$vallbl,$shobtn,$sumlbl;
	global $xm,$ym,$xo,$yo,$rot,$len,$lsf,$mod,$ina,$flt,$lev,$loi,$ipi;
	global $mapbg,$mapitems,$maplinks,$mapinfo,$imgmap,$reg,$cty,$bld,$flr,$dev;

	$rlnk = array();
	$clnk = array();
	$blnk = array();
	$dlnk = array();
# Gather Device Info
	if($ina == "v"){
		$query	= GenQuery('vlans','g','device','device','',array('vlanid'),array('regexp'),array($flt));
		$res	= @DbQuery($query,$link);
		if($res){
			while( ($vl = @DbFetchRow($res)) ){
				$devs[] = preg_replace('/([\^\$+])/','\\\\\\\\$1',$vl[0]);		# \Q...\E Doesn't seem to work in MySQL?
			}
			@DbFreeResult($res);
		}else{
			echo @DbError($link);
		}
		if (! is_array ($devs) ){echo "0 $vallbl";die;}
		$query	= GenQuery('devices','s','name,ip,location,icon','','',array('name'),array('regexp'),array(implode("|",$devs)));
	}elseif($ina == "n"){
		$query	= GenQuery('networks','g','device','device','',array('ip'),array('='),array($flt));
		$res	= @DbQuery($query,$link);
		if($res){
			while( ($n = @DbFetchRow($res)) ){
				$devs[] = preg_replace('/([\^\$\*\+])/','\\\\\\\\$1',$n[0]);
			}
			@DbFreeResult($res);
		}else{
			echo @DbError($link);
		}
		if (! is_array ($devs) ){echo "0 $vallbl";die;}
		$query	= GenQuery('devices','s','name,ip,location,icon','','',array('name'),array('regexp'),array(implode("|",$devs)));
	}elseif($ina == "t"){
		$query	= GenQuery('devices','s','name,ip,location,icon','','',array('type'),array('regexp'),array($flt));
	}else{
		$query	= GenQuery('devices','s','name,ip,location,icon','','',array('location'),array('regexp'),array($flt));
	}
	$res	= @DbQuery($query,$link);
	if($res){
		while( ($d = @DbFetchRow($res)) ){
			$l = explode($locsep, $d[2]);
			$reg[$l[0]]['ndv']++;
			$dev[$d[0]]['reg'] = $l[0];
			if($ipi){						# Get IP info for links
				$nquery	= GenQuery('networks','s','*','','',array('device'),array('='),array($d[0]) );
				$nres	= @DbQuery($nquery,$link);
				if($nres){
					while( ($n = @DbFetchRow($nres)) ){
						$dev[$d[0]]['iip'][$n[1]] .= " ". long2ip($n[2]);
					}
				}else{
					echo @DbError($nlink);
				}
				@DbFreeResult($nres);
			}
			if($lev > 1){
				$cty[$l[0]][$l[1]]['ndv']++;
				$dev[$d[0]]['cty'] = $l[1];
			}
			if($lev > 2){
				$bld[$l[0]][$l[1]][$l[2]]['ndv']++;
				$dev[$d[0]]['bld'] = $l[2];
			}
			if($lev > 3){
				$flr[$l[0]][$l[1]][$l[2]][$l[3]][] = $d[0];
				if($ipi){$dev[$d[0]]['ip']  = long2ip($d[1]);}
				$dev[$d[0]]['rom'] = $l[4];
				$dev[$d[0]]['ico'] = $d[3];
			}
		}
		@DbFreeResult($res);
	}else{
		echo @DbError($link);
	}

# Precalculate Links
	foreach(array_keys($dev) as $d){
		$lquery	= GenQuery('links','s','*','','',array('device'),array('='),array($d));
		$lres	= @DbQuery($lquery,$link);
		while( ($k = @DbFetchRow($lres)) ){
			if( isset($dev[$k[3]]['reg']) ){					# Only use, if we have complete devs
				if( array_key_exists("$k[3];;$k[4];;$k[1];;$k[2]",$dlnk) ){
					$dlnk["$k[3];;$k[4];;$k[1];;$k[2]"]['rbw'] = $k[5];
					$dlnk["$k[3];;$k[4];;$k[1];;$k[2]"]['rif'][] = "$k[1];;$k[2]";
				}else{
					$dlnk["$k[1];;$k[2];;$k[3];;$k[4]"]['fbw'] = $k[5];
					$dlnk["$k[1];;$k[2];;$k[3];;$k[4]"]['fif'][] = "$k[1];;$k[2]";
				}
				$ra = $dev[$k[1]]['reg'];
				$rb = $dev[$k[3]]['reg'];
				$ca = $dev[$k[1]]['cty'];
				$cb = $dev[$k[3]]['cty'];
				$ba = $dev[$k[1]]['bld'];
				$bb = $dev[$k[3]]['bld'];
				if($ra != $rb ){
					$reg[$ra]['nlk']++;
					$reg[$ra]['alk'][$rb]++;				# Needed for arranging
					if( array_key_exists("$rb;;$ra",$rlnk) ){		# Reverse link exists?
						$rlnk["$rb;;$ra"]['rbw']  += $k[5];
						$rlnk["$rb;;$ra"]['rif'][] = "$k[1];;$k[2]";
					}else{
						$rlnk["$ra;;$rb"]['fbw']  += $k[5];
						$rlnk["$ra;;$rb"]['fif'][] = "$k[1];;$k[2]";
					}
				}else{
					if($ca != $cb){$cty[$ra][$ca]['alk'][$cb]++;}		# Needed for arranging
				}
				if($lev > 1){
					if("$ra;;$ca" != "$rb;;$cb"){
						$cty[$ra][$ca]['nlk']++;
						if( array_key_exists("$rb;;$cb;;$ra;;$ca",$clnk) ){
							$clnk["$rb;;$cb;;$ra;;$ca"]['rbw']  += $k[5];
							$clnk["$rb;;$cb;;$ra;;$ca"]['rif'][] = "$k[1];;$k[2]";
						}else{                                 
							$clnk["$ra;;$ca;;$rb;;$cb"]['fbw']  += $k[5];
							$clnk["$ra;;$ca;;$rb;;$cb"]['fif'][] = "$k[1];;$k[2]";

						}
					}else{
						if($ba != $bb){$bld[$ra][$ca][$ba]['alk'][$bb]++;}# Needed for arranging
					}
				}						
				if($lev > 2){
					if("$ra;;$ca;;$ba" != "$rb;;$cb;;$bb"){
						$bld[$ra][$ca][$ba]['nlk']++;
						if( array_key_exists("$rb;;$cb;;$bb;;$ra;;$ca;;$ba",$blnk) ){
							$blnk["$rb;;$cb;;$bb;;$ra;;$ca;;$ba"]['rbw']  += $k[5];
							$blnk["$rb;;$cb;;$bb;;$ra;;$ca;;$ba"]['rif'][] = "$k[1];;$k[2]";
						}else{                                          
							$blnk["$ra;;$ca;;$ba;;$rb;;$cb;;$bb"]['fbw']  += $k[5];
							$blnk["$ra;;$ca;;$ba;;$rb;;$cb;;$bb"]['fif'][] = "$k[1];;$k[2]";
						}
					}
				}

			}
		}
		@DbFreeResult($lres);
	}
	
	$nr = count( array_keys($reg) );
# Prepare geographic stuff
	if ($mod == "g") {
		if($nr == 1){
			$r   = array_keys($reg);
			if(count($reg[$r[0]]) == 1){
				$c = array_keys($reg[$r[0]]);
				$mapbg = TopoMap($r[0],$c[0]);
			}else{
				$mapbg = TopoMap($r[0]);
			}
		}else{
			$mapbg = TopoMap();
		}
		$bg = Imagecreatefrompng("log/$mapbg");
		$xm = Imagesx($bg);
		$ym = Imagesy($bg);
		Imagedestroy($bg);
	}

# Draw Layout
	$cur = 0;
	foreach(Arrange($reg) as $r){
		if ($mod == "g") {
			list($reg[$r]['x'],$reg[$r]['y'],$reg[$r]['cmt']) = DbCoords($r);
		}
		if(!$reg[$r]['x']){
			list($reg[$r]['x'],$reg[$r]['y']) = CircleCoords(intval($xm/2 + $xo),intval($ym/2 + $yo),$cur,$nr,$reg[$r]['nlk'],$len);
		}
		$rnum++;
		if( $lev == 1){
			$mapitems .= Drawitem($reg[$r]['x'],$reg[$r]['y'],$reg[$r]['ndv'],$r,1);
			$imgmap .= "<area href=\"?lev=2&mod=$mod&draw=png&loi=$loi&flt=". rawurlencode( TopoLoc($r) ) ."\" coords=\"".($reg[$r]['x']-20) .",". ($reg[$r]['y']-20) .",". ($reg[$r]['x']+20) .",". ($reg[$r]['y']+20)."\" shape=rect title=\"$shobtn\">\n";
		}else{
			if ($loi and $nr > 1){
				$mapinfo .= Drawitem($reg[$r]['x'],$reg[$r]['y'],'0',$r,'ri');
			}
			$cuc = 0;
			$nc = count( array_keys($cty[$r]) );
			foreach(Arrange($cty[$r]) as $c){
				if ($mod == "g") {
					list($cty[$r][$c]['x'],$cty[$r][$c]['y'],$cty[$r][$c]['cmt']) = DbCoords($r,$c);
				}
				if(!$cty[$r][$c]['x']){
					list($cty[$r][$c]['x'],$cty[$r][$c]['y']) = CircleCoords($reg[$r]['x'],$reg[$r]['y'],$cuc,$nc,$cty[$r][$c]['nlk'],$len/$lsf);
				}
				if( $lev == 2){
					$mapitems .= Drawitem($cty[$r][$c]['x'],$cty[$r][$c]['y'],$cty[$r][$c]['ndv'],$c,2);
					$imgmap .= "<area href=\"?lev=3&mod=$mod&draw=png&loi=$loi&flt=". rawurlencode( TopoLoc($r,$c) ) ."\" coords=\"".($cty[$r][$c]['x']-20) .",". ($cty[$r][$c]['y']-20) .",". ($cty[$r][$c]['x']+20) .",". ($cty[$r][$c]['y']+20)."\" shape=rect title=\"$shobtn\">\n";
				}else{
					if ($loi and count($bld[$r][$c]) > 1){
						$mapinfo .= Drawitem($cty[$r][$c]['x'],$cty[$r][$c]['y'],'0',$c,'ci');
					}
					$cub = 0;
					$nb = count( array_keys($bld[$r][$c]) );
					foreach(Arrange($bld[$r][$c]) as $b){
						if ($mod == "g") {
							list($bld[$r][$c][$b]['x'],$bld[$r][$c][$b]['y'],$bld[$r][$c][$b]['cmt']) = DbCoords($r,$c,$b);
						}
						if(!$bld[$r][$c][$b]['x']){
							list($bld[$r][$c][$b]['x'],$bld[$r][$c][$b]['y']) = CircleCoords($cty[$r][$c]['x'],$cty[$r][$c]['y'],$cub,$nb,$bld[$r][$c][$b]['nlk'],$len/$lsf/$lsf);
						}
						if($lev == 3){
							$mapitems .= Drawitem($bld[$r][$c][$b]['x'],$bld[$r][$c][$b]['y'],$bld[$r][$c][$b]['ndv'],$b,3);
							$imgmap .= "<area href=\"?lev=4&mod=$mod&draw=png&loi=$loi&flt=". rawurlencode( TopoLoc($r,$c,$b) ) ."\" coords=\"".($bld[$r][$c][$b]['x']-20) .",". ($bld[$r][$c][$b]['y']-20) .",". ($bld[$r][$c][$b]['x']+20) .",". ($bld[$r][$c][$b]['y']+20)."\" shape=rect title=\"$shobtn\">\n";
						}else{
							Drawbuilding($bld[$r][$c][$b]['x'],$bld[$r][$c][$b]['y'],$r,$c,$b);
						}
						$cub++;
					}
				}
				$cuc++;
			}
		}
		$cur++;
	}

# Draw Links
	if($lev == 1){
		foreach(array_keys($rlnk) as $li){
			$l = explode(';;', $li);
			DrawLink($reg[$l[0]]['x'],
				$reg[$l[0]]['y'],
				$reg[$l[1]]['x'],
				$reg[$l[1]]['y'],
				$rlnk[$li]['fbw'],$rlnk[$li]['rbw'],
				$rlnk[$li]['fif'],$rlnk[$li]['rif']);
		}
	}elseif($lev == 2){
		foreach(array_keys($clnk) as $li){
			$l = explode(';;', $li);
			DrawLink($cty[$l[0]][$l[1]]['x'],
				$cty[$l[0]][$l[1]]['y'],
				$cty[$l[2]][$l[3]]['x'],
				$cty[$l[2]][$l[3]]['y'],
				$clnk[$li]['fbw'],$clnk[$li]['rbw'],
				$clnk[$li]['fif'],$clnk[$li]['rif']);
		}
	}elseif($lev == 3){
		foreach(array_keys($blnk) as $li){
			$l = explode(';;', $li);
			DrawLink($bld[$l[0]][$l[1]][$l[2]]['x'],
				$bld[$l[0]][$l[1]][$l[2]]['y'],
				$bld[$l[3]][$l[4]][$l[5]]['x'],
				$bld[$l[3]][$l[4]][$l[5]]['y'],
				$blnk[$li]['fbw'],$blnk[$li]['rbw'],
				$blnk[$li]['fif'],$blnk[$li]['rif']);
		}
	}elseif($lev == 4){
		foreach(array_keys($dlnk) as $li){
			$l = explode(';;', $li);
			DrawLink($dev[$l[0]]['x'],
				$dev[$l[0]]['y'],
				$dev[$l[2]]['x'],
				$dev[$l[2]]['y'],
				$dlnk[$li]['fbw'],$dlnk[$li]['rbw'],
				$dlnk[$li]['fif'],$dlnk[$li]['rif']);
		}
	}
}

#===================================================================
# Lookup coordinates and return if map matches
function CircleCoords($x,$y,$curp,$nump,$nl,$l){

	global $rot,$pwt;

	if($nump == 1){
		$sx = 0;
		$sy = 0;
	}else{
		$sx = 1.3;
		$sy = 1;
	}
	$mywt  = pow( ($nl)?$nl:1,$pwt/50);
	$phi   = ($rot * M_PI/180) + 2 * $curp * M_PI / $nump;
	return array( intval($x + $l * cos($phi) * $sx / $mywt), intval($y + $l * sin($phi) * $sy / $mywt) );
}

#===================================================================
# Lookup coordinates and return if map matches
function DbCoords($r='', $c='', $b=''){

	global $mapbg,$link;

	$query	= GenQuery('locations','s','x,y,comment','','',array('region','city','building'),array('=','=','='),array($r,$c,$b),array('AND','AND'));
	$res	= @DbQuery($query,$link);
	$nloc	= @DbNumRows($res);
	if(!$c){$r="";}elseif(!$b){$c="";}						# Clear those for Topomap()
	if ($nloc == 1 and $mapbg == TopoMap($r,$c) ) {
		return @DbFetchRow($res);
	}
}

#===================================================================
# Arrange locations according to links
function Arrange($array){

	foreach(array_keys($array) as $key){
		if( is_array($array[$key]['alk']) ){
			$nbr = array_keys($array[$key]['alk']);
			if (count($nbr) == 1 ){						#echo "$key $nbr[0] LEAF<br>";
				$tmparray[$key] = $nbr[0];
				$nnbr[$nbr[0]]++;
			}else{
				$tmparray[$key] = $key;					#echo "$key HUB<br>";
			}
		}else{
			$tmparray[$key] = $key;						#echo "$key Unlinked<br>";
		}
	}
	foreach ($tmparray as $key => $value){
		if($key == $value){
			$newtmparray[$key] = $value . "2";
		}else{
			$newarrcnt[$value]++;
			if($newarrcnt[$value] > $nnbr[$value] /2 ){			# Distribute LEAFs around HUBs
				$newtmparray[$key] = $value . "1";
			}else{
				$newtmparray[$key] = $value . "3";
			}
		}
	}
	asort($newtmparray);
	return array_keys($newtmparray);
}

#===================================================================
# Sort by room and device name(on floors)
function Roomsort($a, $b){

	global $dev;

        if ($dev[$a]['rom'] == $dev[$b]['rom']){
		return ($a < $b) ? -1 : 1;
	}
        return ($dev[$a]['rom'] < $dev[$b]['rom']) ? -1 : 1;
}

?>
