jablonka.czprosek.czf

weathermap

Subversion Repositories:
[/] [Weathermap.class.php] - Blame information for rev 68

 

Line No. Rev Author Line
11simandl<?php
213simandl// PHP Weathermap 0.92
31simandl// Copyright Howard Jones, 2005-2007 howie@thingy.com
4// http://www.network-weathermap.com/
5// Released under the GNU Public License
6 
7require_once "HTML_ImageMap.class.php";
8 
913simandl$WEATHERMAP_VERSION="0.92";
101simandl$weathermap_debugging=FALSE;
11 
12// Turn on ALL error reporting for now.
13error_reporting (E_ALL);
14 
1513simandl// parameterise the in/out stuff a bit
16define("IN",0);
17define("OUT",1);
18define("WMCHANNELS",2);
19 
201simandl// Utility functions
21// Check for GD & PNG support This is just in here so that both the editor and CLI can use it without the need for another file
22function module_checks()
23{
24 if (!extension_loaded('gd'))
25 {
26 warn ("\n\nNo image (gd) extension is loaded. This is required by weathermap.\n\n");
2713simandl warn ("\nrun check.php to check PHP requirements.\n\n");
281simandl 
29 return (FALSE);
30 }
31 
32 if (!function_exists('imagecreatefrompng'))
33 {
34 warn ("Your GD php module doesn't support PNG format.\n");
3513simandl warn ("\nrun check.php to check PHP requirements.\n\n");
361simandl return (FALSE);
37 }
38 
39 if (!function_exists('imagecreatetruecolor'))
40 {
41 warn ("Your GD php module doesn't support truecolor.\n");
4213simandl warn ("\nrun check.php to check PHP requirements.\n\n");
431simandl return (FALSE);
44 }
45 
46 if (!function_exists('imagecopyresampled'))
47 {
48 warn ("Your GD php module doesn't support thumbnail creation (imagecopyresampled).\n");
49 }
50 return (TRUE);
51}
52 
53function debug($string)
54{
55 global $weathermap_debugging;
56 
57 if ($weathermap_debugging)
58 {
59 // use Cacti's debug log, if we are running from the poller
60 if (function_exists('debug_log_insert') && (!function_exists('show_editor_startpage')))
61 { cacti_log(rtrim($string), true, "WEATHERMAP"); }
62 else
63 {
64 $stderr=fopen('php://stderr', 'w');
65 fwrite($stderr, $string);
66 fclose ($stderr);
67 }
68 }
69}
70 
71function warn($string)
72{
73 // use Cacti's debug log, if we are running from the poller
74 if (function_exists('cacti_log') && (!function_exists('show_editor_startpage')))
75 { cacti_log(rtrim($string), true, "WEATHERMAP"); }
76 else
77 {
78 $stderr=fopen('php://stderr', 'w');
79 fwrite($stderr, $string);
80 fclose ($stderr);
81 }
82}
83 
84function js_escape($str, $wrap=TRUE)
85{
86 $str=str_replace('\\', '\\\\', $str);
87 $str=str_replace("'", "\\'", $str);
88 
89 if($wrap) $str="'" . $str . "'";
90 
91 return ($str);
92}
93 
94function mysprintf($format,$value,$kilo=1000)
95{
96 $output = "";
97 
98 debug("mysprintf: $format $value\n");
99 if(preg_match("/%(\d*\.?\d*)k/",$format,$matches))
100 {
101 $spec = $matches[1];
102 $places = 2;
103 if($spec !='')
104 {
105 preg_match("/(\d*)\.?(\d*)/",$spec,$matches);
106 if($matches[2] != '') $places=$matches[2];
107 // we don't really need the justification (pre-.) part...
108 }
109 debug("KMGT formatting $value with $spec.\n");
110 $result = nice_scalar($value, $kilo, $places);
111 $output = preg_replace("/%".$spec."k/",$format,$result);
112 }
113 else
114 {
115 debug("Falling through to standard sprintf\n");
116 $output = sprintf($format,$value);
117 }
118 return $output;
119}
120 
121// wrapper around imagecolorallocate to try and re-use palette slots where possible
122function myimagecolorallocate($image, $red, $green, $blue)
123{
124 // it's possible that we're being called early - just return straight away, in that case
125 if(!isset($image)) return(-1);
126 
127 $existing=imagecolorexact($image, $red, $green, $blue);
128 
129 if ($existing > -1)
130 return $existing;
131 
132 return (imagecolorallocate($image, $red, $green, $blue));
133}
134 
135function render_colour($col)
136{
137 if (($col[0] < 0) && ($col[1] < 0) && ($col[1] < 0)) { return 'none'; }
138 else { return sprintf("%d %d %d", $col[0], $col[1], $col[2]); }
139}
140 
141// take the same set of points that imagepolygon does, but don't close the shape
142function imagepolyline($image, $points, $npoints, $color)
143{
144 for ($i=0; $i < ($npoints - 1);
145 $i++) { imageline($image, $points[$i * 2], $points[$i * 2 + 1], $points[$i * 2 + 2], $points[$i * 2 + 3],
146 $color); }
147}
148 
149function imagecreatefromfile($filename)
150{
151 $bgimage=NULL;
152 $formats = imagetypes();
153 if (is_readable($filename))
154 {
155 list($width, $height, $type, $attr) = getimagesize($filename);
156 switch($type)
157 {
158 case IMAGETYPE_GIF:
159 if(imagetypes() & IMG_GIF)
160 {
161 $bgimage=imagecreatefromgif($filename);
162 }
163 else
164 {
165 warn("Image file $filename is GIF, but GIF is not supported by your GD library.\n");
166 }
167 break;
168 
169 case IMAGETYPE_JPEG:
170 if(imagetypes() & IMG_JPEG)
171 {
172 $bgimage=imagecreatefromjpeg($filename);
173 }
174 else
175 {
176 warn("Image file $filename is JPEG, but JPEG is not supported by your GD library.\n");
177 }
178 break;
179 
180 case IMAGETYPE_PNG:
181 if(imagetypes() & IMG_PNG)
182 {
183 $bgimage=imagecreatefrompng($filename);
184 }
185 else
186 {
187 warn("Image file $filename is PNG, but PNG is not supported by your GD library.\n");
188 }
189 break;
190 
191 default:
192 warn("Image file $filename wasn't recognised (type=$type). Check format is supported by your GD library.\n");
193 break;
194 }
195 }
196 else
197 {
198 warn("Image file $filename is unreadable. Check permissions.\n");
199 }
200 return $bgimage;
201}
202 
20313simandl// rotate a list of points around cx,cy by an angle in radians, IN PLACE
204function RotateAboutPoint(&$points, $cx,$cy, $angle=0)
205{
206 $npoints = count($points)/2;
207 
208 for($i=0;$i<$npoints;$i++)
209 {
210 $ox = $points[$i*2] - $cx;
211 $oy = $points[$i*2+1] - $cy;
212 $rx = $ox * cos($angle) - $oy*sin($angle);
213 $ry = $oy * cos($angle) + $ox*sin($angle);
214 
215 $points[$i*2] = $rx + $cx;
216 $points[$i*2+1] = $ry + $cy;
217 }
218}
219 
2201simandl// calculate the points for a span of the curve. We pass in the distance so far, and the array index, so that
221// the chunk of array generated by this function can be array_merged with existing points from before.
222// Considering how many array functions there are, PHP has horrible list support
223// Each point is a 3-tuple - x,y,distance - which is used later to figure out where the 25%, 50% marks are on the curve
224function calculate_catmull_rom_span($startn, $startdistance, $numsteps, $x0, $y0, $x1, $y1, $x2, $y2, $x3, $y3)
225{
226 $Ap_x=-$x0 + 3 * $x1 - 3 * $x2 + $x3;
227 $Bp_x=2 * $x0 - 5 * $x1 + 4 * $x2 - $x3;
228 $Cp_x=-$x0 + $x2;
229 $Dp_x=2 * $x1;
230 
231 $Ap_y=-$y0 + 3 * $y1 - 3 * $y2 + $y3;
232 $Bp_y=2 * $y0 - 5 * $y1 + 4 * $y2 - $y3;
233 $Cp_y=-$y0 + $y2;
234 $Dp_y=2 * $y1;
235 
236 $d=2;
237 $n=$startn;
238 $distance=$startdistance;
239 
240 $lx=$x0;
241 $ly=$y0;
24213simandl 
2431simandl $allpoints[]=array
244 (
245 $x0,
246 $y0,
247 $distance
248 );
249 
250 for ($i=0; $i <= $numsteps; $i++)
251 {
252 $t=$i / $numsteps;
253 $t2=$t * $t;
254 $t3=$t2 * $t;
255 $x=(($Ap_x * $t3) + ($Bp_x * $t2) + ($Cp_x * $t) + $Dp_x) / $d;
256 $y=(($Ap_y * $t3) + ($Bp_y * $t2) + ($Cp_y * $t) + $Dp_y) / $d;
257 
258 if ($i > 0)
259 {
260 $step=sqrt((($x - $lx) * ($x - $lx)) + (($y - $ly) * ($y - $ly)));
261 $distance=$distance + $step;
262 $allpoints[$n]=array
263 (
264 $x,
265 $y,
266 $distance
267 );
268 
269 $n++;
270 }
271 
272 $lx=$x;
273 $ly=$y;
274 }
275 
276 return array($allpoints, $distance, $n);
277}
278 
27913simandlfunction find_distance_coords(&$pointarray,$distance)
280{
281 // We find the nearest lower point for each distance,
282 // then linearly interpolate to get a more accurate point
283 // this saves having quite so many points-per-curve
284 
285 $index=find_distance($pointarray, $distance);
286 
287 $ratio=($distance - $pointarray[$index][2]) / ($pointarray[$index + 1][2] - $pointarray[$index][2]);
288 $x = $pointarray[$index][0] + $ratio * ($pointarray[$index + 1][0] - $pointarray[$index][0]);
289 $y = $pointarray[$index][1] + $ratio * ($pointarray[$index + 1][1] - $pointarray[$index][1]);
290 
291 return(array($x,$y,$index));
292}
293 
294function find_distance_coords_angle(&$pointarray,$distance)
295{
296 // This is the point we need
297 list($x,$y,$index) = find_distance_coords($pointarray,$distance);
298 
299 // now to find one either side of it, to get a line to find the angle of
300 $left = $index;
301 $right = $left+1;
302 $max = count($pointarray)-1;
303 // if we're right up against the last point, then step backwards one
304 if($right>=$max)
305 {
306 $left--;
307 $right--;
308 }
309 # if($left<=0) { $left = 0; }
310 
311 $x1 = $pointarray[$left][0];
312 $y1 = $pointarray[$left][1];
313 
314 $x2 = $pointarray[$right][0];
315 $y2 = $pointarray[$right][1];
316 
317 $dx = $x2 - $x1;
318 $dy = $y2 - $y1;
319 
320 $angle = rad2deg(atan2(-$dy,$dx));
321 
322 return(array($x,$y,$index,$angle));
323}
324 
3251simandl// return the index of the point either at (unlikely) or just before the target distance
326// we will linearly interpolate afterwards to get a true point - pointarray is an array of 3-tuples produced by the function above
32713simandlfunction find_distance(&$pointarray, $distance)
3281simandl{
329 $left=0;
330 $right=count($pointarray) - 1;
331 
332 if ($left == $right)
333 return ($left);
334 
335 // if it's a point past the end of the line, then just return the end of the line
336 // Weathermap should *never* ask for this, anyway
337 if ($pointarray[$right][2] < $distance) { return ($right); }
338 
339 // if somehow we have a 0-length curve, then don't try and search, just give up
340 // in a somewhat predictable manner
341 if ($pointarray[$left][2] == $pointarray[$right][2]) { return ($left); }
342 
343 while ($left <= $right)
344 {
345 $mid=floor(($left + $right) / 2);
346 
347 if (($pointarray[$mid][2] < $distance) && ($pointarray[$mid + 1][2] >= $distance)) { return $mid; }
348 
349 if ($distance <= $pointarray[$mid][2]) { $right=$mid - 1; }
350 else { $left=$mid + 1; }
351 }
352 
353 print "FELL THROUGH\n";
354 die ("Howie's crappy binary search is wrong after all.\n");
355}
356 
35713simandl// Give a list of key points, calculate a curve through them
358// return value is an array of triples (x,y,distance)
359function calc_curve(&$in_xarray, &$in_yarray,$pointsperspan = 12)
3601simandl{
361 // search through the point list, for consecutive duplicate points
362 // (most common case will be a straight link with both NODEs at the same place, I think)
363 // strip those out, because they'll break the binary search/centre-point stuff
364 
365 $last_x=NULL;
366 $last_y=NULL;
367 
368 for ($i=0; $i < count($in_xarray); $i++)
369 {
370 if (($in_xarray[$i] == $last_x) && ($in_yarray[$i] == $last_y)) { debug
371 ("Dumping useless duplicate point on curve\n"); }
372 else
373 {
374 $xarray[]=$in_xarray[$i];
375 $yarray[]=$in_yarray[$i];
376 }
377 
378 $last_x=$in_xarray[$i];
379 $last_y=$in_yarray[$i];
380 }
381 
382 // only proceed if we still have at least two points!
38313simandl if(count($xarray) <= 1)
3841simandl {
38513simandl warn ("Arrow not drawn, as it's 1-dimensional.\n");
386 return (array(NULL, NULL, NULL, NULL));
387 }
3881simandl 
38913simandl // duplicate the first and last points, so that all points are drawn
390 // (C-R normally would draw from x[1] to x[n-1]
391 array_unshift($xarray, $xarray[0]);
392 array_unshift($yarray, $yarray[0]);
3931simandl 
39413simandl $x=array_pop($xarray);
395 $y=array_pop($yarray);
396 array_push($xarray, $x);
397 array_push($xarray, $x);
398 array_push($yarray, $y);
399 array_push($yarray, $y);
4001simandl 
40113simandl $npoints=count($xarray);
4021simandl 
40313simandl $curvepoints=array
404 (
4051simandl );
406 
40713simandl // add in the very first point manually (the calc function skips this one to avoid duplicates, which mess up the distance stuff)
408 $curvepoints[]=array
409 (
410 $xarray[0],
411 $yarray[0],
412 
413 );
4141simandl 
41513simandl $np=0;
416 $distance=0;
4171simandl 
41813simandl for ($i=0; $i < ($npoints - 3); $i++)
419 {
420 list($newpoints,
421 $distance,
422 $np)=calculate_catmull_rom_span($np, $distance, $pointsperspan, $xarray[$i],
423 $yarray[$i], $xarray[$i + 1], $yarray[$i + 1], $xarray[$i + 2],
424 $yarray[$i + 2], $xarray[$i + 3], $yarray[$i + 3]);
425 $curvepoints=$curvepoints + $newpoints;
426 }
4271simandl 
42813simandl return ($curvepoints);
429}
4301simandl 
43113simandlfunction calc_arrowsize($width,&$map,$linkname)
432{
433 $arrowlengthfactor=4;
434 $arrowwidthfactor=2;
4351simandl 
43613simandl if ($map->links[$linkname]->arrowstyle == 'compact')
437 {
438 $arrowlengthfactor=1;
439 $arrowwidthfactor=1;
440 }
4411simandl 
44213simandl if (preg_match('/(\d+) (\d+)/', $map->links[$linkname]->arrowstyle, $matches))
443 {
444 $arrowlengthfactor=$matches[1];
445 $arrowwidthfactor=$matches[2];
446 }
4471simandl 
44813simandl $arrowsize = $width * $arrowlengthfactor;
449 $arrowwidth = $width * $arrowwidthfactor;
450 
451 return( array($arrowsize,$arrowwidth) );
452}
4531simandl 
45413simandl// top-level function that takes a two lists to define some points, and draws a weathermap link
455// - this takes care of all the extras, like arrowheads, and where to put the bandwidth labels
456// curvepoints is an array of the points the curve passes through
457// width is the link width (the actual width is twice this)
458// outlinecolour is a GD colour reference
459// fillcolours is an array of two more colour references, one for the out, and one for the in spans
460function draw_curve($image, &$curvepoints, $width, $outlinecolour, $comment_colour, $fillcolours, $linkname, &$map,
461 $q2_percent=50)
462{
463 // now we have a 'spine' - all the central points for this curve.
464 // time to flesh it out to the right width, and figure out where to draw arrows and bandwidth boxes...
465 $unidirectional = FALSE;
466 
467 // get the full length of the curve from the last point
468 $totaldistance = $curvepoints[count($curvepoints)-1][2];
469 // find where the in and out arrows will join (normally halfway point)
470 $halfway = $totaldistance * ($q2_percent/100);
471 
472 $dirs = array(OUT,IN);
4731simandl 
47413simandl // for a unidirectional map, we just ignore the second half (direction = -1)
475 if($unidirectional)
476 {
477 $halfway = $totaldistance;
478 $dirs = array(OUT);
479 }
480 
481 // loop increment, start point, width, labelpos, fillcolour, outlinecolour, commentpos
482 $arrowsettings[OUT] = array(+1, 0, $width, 0, $fillcolours[OUT], $outlinecolour, 5);
483 $arrowsettings[IN] = array(-1, count($curvepoints) - 1, $width, 0, $fillcolours[IN], $outlinecolour, 95);
4841simandl 
48513simandl // we calculate the arrow size up here, so that we can decide on the
486 // minimum length for a link. The arrowheads are the limiting factor.
487 list($arrowsize,$arrowwidth) = calc_arrowsize($width,$map,$linkname);
488 
489 // the 2.7 here is empirical. It ought to be 2 in theory.
490 // in practice, a link this short is useless anyway, especially with bwlabels.
491 $minimumlength = 2.7*$arrowsize;
4921simandl 
49313simandl # warn("$linkname: Total: $totaldistance $arrowsize $arrowwidth $minimumlength\n");
494 if($totaldistance <= $minimumlength)
495 {
496 warn("Skipping drawing very short link ($linkname). Impossible to draw! Try changing WIDTH or ARROWSTYLE?\n");
497 return;
498 }
4991simandl 
50013simandl 
501 list($halfway_x,$halfway_y,$halfwayindex) = find_distance_coords($curvepoints,$halfway);
5021simandl 
50313simandl // loop over direction here
504 // direction is 1.0 for the first half (forwards through the pointlist), and -1.0 for the second half (backwards from the end)
505 // - used as a multiplier on anything that looks forwards or backwards through the list
5061simandl 
50713simandl foreach ($dirs as $dir)
508 {
509 $direction = $arrowsettings[$dir][0];
510 // this is the last index before the arrowhead starts
511 list($pre_mid_x,$pre_mid_y,$pre_midindex) = find_distance_coords($curvepoints,$halfway - $direction * $arrowsize);
512 
513 $there_points=array();
514 $back_points=array();
515 $arrowpoints=array();
5161simandl 
51713simandl # if ($direction < 0) { $start=count($curvepoints) - 1; }
518 # else { $start=0; }
519 $start = $arrowsettings[$dir][1];
5201simandl 
52113simandl for ($i=$start; $i != $pre_midindex; $i+=$direction)
522 {
523 // for each point on the spine, produce two points normal to it's direction,
524 // each is $width away from the spine, but we build up the two lists in the opposite order,
525 // so that when they are joined together, we get one continuous line
5261simandl 
52713simandl $dx=$curvepoints[$i + $direction][0] - $curvepoints[$i][0];
528 $dy=$curvepoints[$i + $direction][1] - $curvepoints[$i][1];
529 $l=sqrt(($dx * $dx) + ($dy * $dy));
530 $nx=$dy / $l;
531 $ny=-$dx / $l;
5321simandl 
53313simandl $there_points[]=$curvepoints[$i][0] + $direction * $width * $nx;
534 $there_points[]=$curvepoints[$i][1] + $direction * $width * $ny;
5351simandl 
53613simandl $back_points[]=$curvepoints[$i][0] - $direction * $width * $nx;
537 $back_points[]=$curvepoints[$i][1] - $direction * $width * $ny;
538 }
5391simandl 
54013simandl // all the normal line is done, now lets add an arrowhead on
5411simandl 
54213simandl $adx=($halfway_x - $pre_mid_x);
543 $ady=($halfway_y - $pre_mid_y);
544 $l=sqrt(($adx * $adx) + ($ady * $ady));
5451simandl 
54613simandl $anx=$ady / $l;
547 $any=-$adx / $l;
5481simandl 
54913simandl $there_points[]=$pre_mid_x + $direction * $width * $anx;
550 $there_points[]=$pre_mid_y + $direction * $width * $any;
5511simandl 
55213simandl $there_points[]=$pre_mid_x + $direction * $arrowwidth * $anx;
553 $there_points[]=$pre_mid_y + $direction * $arrowwidth * $any;
5541simandl 
55513simandl $there_points[]=$halfway_x;
556 $there_points[]=$halfway_y;
5571simandl 
55813simandl $there_points[]=$pre_mid_x - $direction * $arrowwidth * $anx;
559 $there_points[]=$pre_mid_y - $direction * $arrowwidth * $any;
5601simandl 
56113simandl $there_points[]=$pre_mid_x - $direction * $width * $anx;
562 $there_points[]=$pre_mid_y - $direction * $width * $any;
5631simandl 
56413simandl // all points done, now combine the lists, and produce the final result.
5651simandl 
56613simandl $y=array_pop($back_points);
567 $x=array_pop($back_points);
568 do
569 {
570 $there_points[]=$x;
571 $there_points[]=$y;
5721simandl $y=array_pop($back_points);
573 $x=array_pop($back_points);
57413simandl } while (!is_null($y));
5751simandl 
57613simandl $arrayindex=0;
5771simandl 
57813simandl if ($direction < 0) $arrayindex=1;
5791simandl 
58013simandl if (!is_null($fillcolours[$arrayindex]))
581 { imagefilledpolygon($image, $there_points, count($there_points) / 2, $arrowsettings[$dir][4]); }
582 
583 $map->imap->addArea("Polygon", "LINK:" . $linkname, '', $there_points);
584 debug ("Adding Poly imagemap for $linkname\n");
5851simandl 
58613simandl if (!is_null($outlinecolour))
587 imagepolygon($image, $there_points, count($there_points) / 2, $arrowsettings[$dir][5]);
5881simandl }
589}
590 
591function unformat_number($instring, $kilo = 1000)
592{
593 $matches=0;
594 $number=0;
595 
59613simandl if (preg_match("/([0-9\.]+)(M|G|K|T|m|u)/", $instring, $matches))
5971simandl {
598 $number=floatval($matches[1]);
599 
600 if ($matches[2] == 'K') { $number=$number * $kilo; }
601 if ($matches[2] == 'M') { $number=$number * $kilo * $kilo; }
602 if ($matches[2] == 'G') { $number=$number * $kilo * $kilo * $kilo; }
603 if ($matches[2] == 'T') { $number=$number * $kilo * $kilo * $kilo * $kilo; }
604 // new, for absolute datastyle. Think seconds.
605 if ($matches[2] == 'm') { $number=$number / $kilo; }
606 if ($matches[2] == 'u') { $number=$number / ($kilo * $kilo); }
607 }
608 else { $number=floatval($instring); }
609 
610 return ($number);
611}
612 
613// given a compass-point, and a width & height, return a tuple of the x,y offsets
614function calc_offset($offsetstring, $width, $height)
615{
61613simandl if(preg_match("/^([-+]?\d+):([-+]?\d+)$/",$offsetstring,$matches))
6171simandl {
618 debug("Numeric Offset found\n");
619 return(array($matches[1],$matches[2]));
620 }
621 else
622 {
623 switch (strtoupper($offsetstring))
624 {
625 case 'N':
626 return (array(0, -$height / 2));
627 
628 break;
629 
630 case 'S':
631 return (array(0, $height / 2));
632 
633 break;
634 
635 case 'E':
636 return (array(+$width / 2, 0));
637 
638 break;
639 
640 case 'W':
641 return (array(-$width / 2, 0));
642 
643 break;
644 
645 case 'NW':
646 return (array(-$width / 2, -$height / 2));
647 
648 break;
649 
650 case 'NE':
651 return (array($width / 2, -$height / 2));
652 
653 break;
654 
655 case 'SW':
656 return (array(-$width / 2, $height / 2));
657 
658 break;
659 
660 case 'SE':
661 return (array($width / 2, $height / 2));
662 
663 break;
664 
665 default:
666 return (array(0, 0));
667 
668 break;
669 }
670 }
671}
672 
673// These next two are based on perl's Number::Format module
674// by William R. Ward, chopped down to just what I needed
675 
676function format_number($number, $precision = 2, $trailing_zeroes = 0)
677{
678 $sign=1;
679 
680 if ($number < 0)
681 {
682 $number=abs($number);
683 $sign=-1;
684 }
685 
686 $number=round($number, $precision);
687 $integer=intval($number);
688 
689 if (strlen($integer) < strlen($number)) { $decimal=substr($number, strlen($integer) + 1); }
690 
691 if (!isset($decimal)) { $decimal=''; }
692 
693 $integer=$sign * $integer;
694 
695 if ($decimal == '') { return ($integer); }
696 else { return ($integer . "." . $decimal); }
697}
698 
699function nice_bandwidth($number, $kilo = 1000,$decimals=1)
700{
701 $suffix='';
702 
703 if ($number == 0)
704 return '0';
705 
706 $mega=$kilo * $kilo;
707 $giga=$mega * $kilo;
708 $tera=$giga * $kilo;
709 
710 if ($number > $tera)
711 {
712 $number/=$tera;
713 $suffix="T";
714 }
715 elseif ($number > $giga)
716 {
717 $number/=$giga;
718 $suffix="G";
719 }
720 elseif ($number > $mega)
721 {
722 $number/=$mega;
723 $suffix="M";
724 }
725 elseif ($number > $kilo)
726 {
727 $number/=$kilo;
728 $suffix="K";
729 }
730 
731 $result=format_number($number, $decimals) . $suffix;
732 return ($result);
733}
734 
735function nice_scalar($number, $kilo = 1000, $decimals=1)
736{
737 $suffix='';
738 
739 if ($number == 0)
740 return '0';
741 
742 $mega=$kilo * $kilo;
743 $giga=$mega * $kilo;
744 $tera=$giga * $kilo;
745 
746 if ($number > $tera)
747 {
748 $number/=$tera;
749 $suffix="T";
750 }
751 elseif ($number > $giga)
752 {
753 $number/=$giga;
754 $suffix="G";
755 }
756 elseif ($number > $mega)
757 {
758 $number/=$mega;
759 $suffix="M";
760 }
761 elseif ($number > $kilo)
762 {
763 $number/=$kilo;
764 $suffix="K";
765 }
766 elseif ($number < (1 / ($kilo)))
767 {
768 $number=$number * $mega;
769 $suffix="u";
770 }
771 elseif ($number < 1)
772 {
773 $number=$number * $kilo;
774 $suffix="m";
775 }
776 
777 $result=format_number($number, $decimals) . $suffix;
778 return ($result);
779}
780 
781 
782// ***********************************************
783 
78413simandl// we use enough points in various places to make it worth a small class to save some variable-pairs.
785class Point
786{
787 var $x, $y;
788 function Point($x=0,$y=0)
789 {
790 $this->x = $x;
791 $this->y = $y;
792 }
793}
794 
795// similarly for 2D vectors
796class Vector
797{
798 var $dx, $dy;
799 
800 function Vector($dx=0,$dy=0)
801 {
802 $this->dx = $dx;
803 $this->dy = $dy;
804 }
805 
806 function normalise()
807 {
808 $len = $this->length();
809 $this->dx = $this->dx/$len;
810 $this->dy = $this->dy/$len;
811 }
812 
813 function length()
814 {
815 return( sqrt(($this->dx)*($this->dx) + ($this->dy)*($this->dy)) );
816 }
817}
818 
819// ***********************************************
820 
8211simandl// template class for data sources. All data sources extend this class.
822// I really wish PHP4 would just die overnight
823class WeatherMapDataSource
824{
825 // Initialize - called after config has been read (so SETs are processed)
826 // but just before ReadData. Used to allow plugins to verify their dependencies
827 // (if any) and bow out gracefully. Return FALSE to signal that the plugin is not
828 // in a fit state to run at the moment.
829 function Init(&$map) { return TRUE; }
830 
831 // called with the TARGET string. Returns TRUE or FALSE, depending on whether it wants to handle this TARGET
832 // called by map->ReadData()
833 function Recognise( $targetstring ) { return FALSE; }
834 
835 // the actual ReadData
836 // returns an array of two values (in,out). -1,-1 if it couldn't get valid data
837 // configline is passed in, to allow for better error messages
838 // itemtype and itemname may be used as part of the target (e.g. for TSV source line)
839 function ReadData($targetstring, $configline, $itemtype, $itemname, $map) { return (array(-1,-1)); }
840}
841 
842// template classes for the pre- and post-processor plugins
843class WeatherMapPreProcessor
844{
845 function run($map) { return FALSE; }
846}
847 
848class WeatherMapPostProcessor
849{
850 function run($map) { return FALSE; }
851}
852 
853// ***********************************************
854 
855// Links, Nodes and the Map object inherit from this class ultimately.
856// Just to make some common code common.
857class WeatherMapBase
858{
859 var $notes = array();
860 var $hints = array();
861 var $inherit_fieldlist;
862 
863 function add_note($name,$value)
864 {
865 $this->notes[$name] = $value;
866 }
867 
868 
869 function get_note($name)
870 {
871 if(isset($this->notes[$name]))
872 {
873 return($this->notes[$name]);
874 }
875 else
876 {
877 return(NULL);
878 }
879 }
880 
881 function add_hint($name,$value)
882 {
883 $this->hints[$name] = $value;
88413simandl # warn("Adding hint $name to ".$this->my_type()."/".$this->name."\n");
8851simandl }
886 
887 
888 function get_hint($name)
889 {
890 if(isset($this->hints[$name]))
891 {
892 return($this->hints[$name]);
893 }
894 else
895 {
896 return(NULL);
897 }
898 }
899}
900 
901// The 'things on the map' class. More common code (mainly variables, actually)
902class WeatherMapItem extends WeatherMapBase
903{
904 var $owner;
905 
906 var $configline;
907 var $infourl;
908 var $overliburl;
909 var $overlibwidth, $overlibheight;
910 var $overlibcaption;
911 var $my_default;
912 
913 function my_type() { return "ITEM"; }
914 
915}
916 
917 
918class WeatherMapNode extends WeatherMapItem
919{
920 var $owner;
921 var $x,
922 $y;
923 var $original_x, $original_y,$relative_resolved;
924 var $width,
925 $height;
926 var $label, $proclabel,
927 $labelfont;
928 var $name;
929 var $infourl;
930 var $notes;
931 var $overliburl;
932 var $overlibwidth,
933 $overlibheight;
934 var $overlibcaption;
935 var $maphtml;
936 var $selected = 0;
937 var $iconfile, $iconscalew, $iconscaleh;
938 var $targets = array();
939 var $bandwidth_in, $bandwidth_out;
940 var $inpercent, $outpercent;
941 var $max_bandwidth_in, $max_bandwidth_out;
942 var $max_bandwidth_in_cfg, $max_bandwidth_out_cfg;
943 var $labeloffset, $labeloffsetx, $labeloffsety;
94413simandl 
9451simandl var $inherit_fieldlist;
946 
947 var $labelbgcolour;
948 var $labeloutlinecolour;
949 var $labelfontcolour;
950 var $labelfontshadowcolour;
951 var $cachefile;
952 var $usescale;
953 var $inscalekey,$outscalekey;
95413simandl # var $incolour,$outcolour;
9551simandl var $scalevar;
956 var $notestext;
957 var $image;
958 var $centre_x, $centre_y;
959 var $relative_to;
960 
961 function WeatherMapNode()
962 {
963 $this->inherit_fieldlist=array
964 (
965 'my_default' => NULL,
966 'label' => '',
967 'proclabel' => '',
968 'usescale' => 'DEFAULT',
969 'scalevar' => 'in',
970 'labelfont' => 3,
971 'relative_to' => '',
972 'relative_resolved' => FALSE,
973 'x' => 0,
974 'y' => 0,
975 'inscalekey'=>'', 'outscalekey'=>'',
97613simandl #'incolour'=>-1,'outcolour'=>-1,
9771simandl 'original_x' => 0,
978 'original_y' => 0,
979 'inpercent'=>0,
980 'outpercent'=>0,
981 'iconfile' => '',
982 'iconscalew' => 0,
983 'iconscaleh' => 0,
984 'targets' => array(),
985 'infourl' => '',
986 'notestext' => '',
987 'notes' => array(),
98813simandl 'hints' => array(),
9891simandl 'overliburl' => '',
990 'overlibwidth' => 0,
991 'overlibheight' => 0,
992 'overlibcaption' => '',
993 'labeloutlinecolour' => array(0, 0, 0),
994 'labelbgcolour' => array(255, 255, 255),
995 'labelfontcolour' => array(0, 0, 0),
996 'labelfontshadowcolour' => array(-1, -1, -1),
997 
998 'labeloffset' => '',
999 'labeloffsetx' => 0,
1000 'labeloffsety' => 0,
1001 'max_bandwidth_in' => 100,
1002 'max_bandwidth_out' => 100,
1003 'max_bandwidth_in_cfg' => '100',
1004 'max_bandwidth_out_cfg' => '100'
1005 );
1006 
1007 $this->width = 0;
1008 $this->height = 0;
1009 $this->centre_x = 0;
1010 $this->centre_y = 0;
1011 $this->image = NULL;
1012 }
1013 
1014 function my_type() { return "NODE"; }
1015 
1016 // make a mini-image, containing this node and nothing else
1017 // figure out where the real NODE centre is, relative to the top-left corner.
1018 function pre_render($im, &$map)
1019 {
1020 // apparently, some versions of the gd extension will crash
1021 // if we continue...
1022 if($this->label == '' && $this->iconfile=='') return;
1023 
1024 // start these off with sensible values, so that bbox
1025 // calculations are easier.
1026 $icon_x1 = $this->x; $icon_x2 = $this->x;
1027 $icon_y1 = $this->y; $icon_y2 = $this->y;
1028 $label_x1 = $this->x; $label_x2 = $this->x;
1029 $label_y1 = $this->y; $label_y2 = $this->y;
1030 $boxwidth = 0; $boxheight = 0;
1031 $icon_w = 0;
1032 $icon_h = 0;
1033 
1034 // figure out a bounding rectangle for the label
1035 if ($this->label != '')
1036 {
1037 $padding = 4.0;
1038 $padfactor = 1.0;
1039 
1040 $this->proclabel = $map->ProcessString($this->label,$this);
1041 
1042 list($strwidth, $strheight) = $map->myimagestringsize($this->labelfont, $this->proclabel);
1043 
1044 $boxwidth = ($strwidth * $padfactor) + $padding;
1045 $boxheight = ($strheight * $padfactor) + $padding;
1046 
1047 debug ("Node->pre_render: Label Metrics are: $strwidth x $strheight -> $boxwidth x $boxheight\n");
1048 
1049 $label_x1 = $this->x - ($boxwidth / 2);
1050 $label_y1 = $this->y - ($boxheight / 2);
1051 
1052 $label_x2 = $this->x + ($boxwidth / 2);
1053 $label_y2 = $this->y + ($boxheight / 2);
1054 
1055 $txt_x = $this->x - ($strwidth / 2);
1056 $txt_y = $this->y + ($strheight / 2);
1057 
1058 # $this->width = $boxwidth;
1059 # $this->height = $boxheight;
1060 $map->nodes[$this->name]->width = $boxwidth;
1061 $map->nodes[$this->name]->height = $boxheight;
1062 
1063 # print "TEXT at $txt_x , $txt_y\n";
1064 
1065 }
1066 
1067 // figure out a bounding rectangle for the icon
1068 if ($this->iconfile != '')
1069 {
1070 $this->iconfile = $map->ProcessString($this->iconfile ,$this);
1071 if (is_readable($this->iconfile))
1072 {
1073 imagealphablending($im, true);
1074 // draw the supplied icon, instead of the labelled box
1075 
1076 $icon_im = imagecreatefromfile($this->iconfile);
1077 # $icon_im = imagecreatefrompng($this->iconfile);
1078 
1079 if ($icon_im)
1080 {
1081 $icon_w = imagesx($icon_im);
1082 $icon_h = imagesy($icon_im);
1083 
1084 if(($this->iconscalew * $this->iconscaleh) > 0)
1085 {
1086 imagealphablending($icon_im, true);
1087 
1088 debug("SCALING ICON here\n");
1089 if($icon_w > $icon_h)
1090 {
1091 $scalefactor = $icon_w/$this->iconscalew;
1092 }
1093 else
1094 {
1095 $scalefactor = $icon_h/$this->iconscaleh;
1096 }
1097 $new_width = $icon_w / $scalefactor;
1098 $new_height = $icon_h / $scalefactor;
1099 $scaled = imagecreatetruecolor($new_width, $new_height);
1100 imagealphablending($scaled,false);
1101 imagecopyresampled($scaled, $icon_im, 0, 0, 0, 0, $new_width, $new_height, $icon_w, $icon_h);
1102 imagedestroy($icon_im);
1103 $icon_im = $scaled;
1104 $icon_w = imagesx($icon_im);
1105 $icon_h = imagesy($icon_im);
1106 }
1107 
1108 $icon_x1 = $this->x - $icon_w / 2;
1109 $icon_y1 = $this->y - $icon_h / 2;
1110 $icon_x2 = $this->x + $icon_w / 2;
1111 $icon_y2 = $this->y + $icon_h / 2;
1112 
1113 # $this->width = imagesx($icon_im);
1114 # $this->height = imagesy($icon_im);
1115 $map->nodes[$this->name]->width = imagesx($icon_im);
1116 $map->nodes[$this->name]->height = imagesy($icon_im);
1117 
1118 $map->imap->addArea("Rectangle", "NODE:" . $this->name, '', array($icon_x1, $icon_y1, $icon_x2, $icon_y2));
1119 
1120 }
1121 else { warn ("Couldn't open PNG ICON: " . $this->iconfile . " - is it a PNG?\n"); }
1122 }
1123 else
1124 {
1125 warn ("ICON " . $this->iconfile . " does not exist, or is not readable. Check path and permissions.\n");
1126 }
1127 }
1128 
1129 // do any offset calculations
1130 
1131 if ( ($this->labeloffset != '') && (($this->iconfile != '')) )
1132 {
1133 $this->labeloffsetx = 0;
1134 $this->labeloffsety = 0;
1135 
1136 list($dx, $dy) = calc_offset($this->labeloffset,
1137 ($icon_w + $boxwidth -1),
1138 ($icon_h + $boxheight)
1139 );
1140 
1141 $this->labeloffsetx = $dx;
1142 $this->labeloffsety = $dy;
1143 
1144 }
1145 
1146 $label_x1 += $this->labeloffsetx;
1147 $label_x2 += $this->labeloffsetx;
1148 $label_y1 += $this->labeloffsety;
1149 $label_y2 += $this->labeloffsety;
1150 
1151 if($this->label != '')
1152 {
1153 $map->imap->addArea("Rectangle", "NODE:" . $this->name, '', array($label_x1, $label_y1, $label_x2, $label_y2));
1154 }
1155 
1156 // work out the bounding box of the whole thing
1157 
1158 $bbox_x1 = min($label_x1,$icon_x1);
1159 $bbox_x2 = max($label_x2,$icon_x2)+1;
1160 $bbox_y1 = min($label_y1,$icon_y1);
1161 $bbox_y2 = max($label_y2,$icon_y2)+1;
1162 
1163 # imagerectangle($im,$bbox_x1,$bbox_y1,$bbox_x2,$bbox_y2,$map->selected);
1164 # imagerectangle($im,$label_x1,$label_y1,$label_x2,$label_y2,$map->black);
1165 # imagerectangle($im,$icon_x1,$icon_y1,$icon_x2,$icon_y2,$map->black);
1166 
1167 // create TWO imagemap entries - one for the label and one for the icon
1168 // (so we can have close-spaced icons better)
1169 
1170 
1171 $temp_width = $bbox_x2-$bbox_x1;
1172 $temp_height = $bbox_y2-$bbox_y1;
1173 // create an image of that size and draw into it
1174 $node_im=imagecreatetruecolor($temp_width,$temp_height );
1175 // ImageAlphaBlending($node_im, FALSE);
1176 imageSaveAlpha($node_im, TRUE);
1177 
1178 $nothing=imagecolorallocatealpha($node_im,128,0,0,127);
1179 imagefill($node_im, 0, 0, $nothing);
1180 
1181 // imagefilledrectangle($node_im,0,0,$temp_width,$temp_height, $nothing);
1182 
1183 $label_x1 -= $bbox_x1;
1184 $label_x2 -= $bbox_x1;
1185 $label_y1 -= $bbox_y1;
1186 $label_y2 -= $bbox_y1;
1187 
1188 $icon_x1 -= $bbox_x1;
1189 $icon_x2 -= $bbox_x1;
1190 $icon_y1 -= $bbox_y1;
1191 $icon_y2 -= $bbox_y1;
1192 
1193 
1194 // Draw the icon, if any
1195 if(isset($icon_im))
1196 {
1197 imagecopy($node_im, $icon_im, $icon_x1, $icon_y1, 0, 0, imagesx($icon_im), imagesy($icon_im));
1198 imagedestroy($icon_im);
1199 }
1200 
1201 // Draw the label, if any
1202 if ($this->label != '')
1203 {
1204 $txt_x -= $bbox_x1;
1205 $txt_x += $this->labeloffsetx;
1206 $txt_y -= $bbox_y1;
1207 $txt_y += $this->labeloffsety;
1208 
1209 # print "FINAL TEXT at $txt_x , $txt_y\n";
1210 
1211 // if there's an icon, then you can choose to have no background
1212 
1213 $col = -1;
1214 
1215 // if a target is specified, and you haven't forced no background, then the background will
1216 // come from the SCALE in USESCALE
1217 if( !empty($this->targets) && $this->usescale != 'none' )
1218 {
1219 $pc = 0;
1220 
1221 if($this->scalevar == 'in')
1222 {
1223 $pc = $this->inpercent;
1224 
1225 }
1226 if($this->scalevar == 'out')
1227 {
1228 $pc = $this->outpercent;
1229 
1230 }
1231 
1232 // debug("Choosing NODE BGCOLOR for ".$this->name." based on $pc %\n");
1233 
123413simandl list($col,$node_scalekey) = $map->ColourFromPercent($pc, $this->usescale,$this->name);
12351simandl // $map->nodes[$this->name]->scalekey = $node_scalekey;
1236 }
1237 elseif($this->labelbgcolour != array(-1,-1,-1))
1238 {
1239 $col=myimagecolorallocate($node_im, $this->labelbgcolour[0], $this->labelbgcolour[1], $this->labelbgcolour[2]);
1240 }
1241 
1242 if($col != -1)
1243 {
1244 imagefilledrectangle($node_im, $label_x1, $label_y1, $label_x2, $label_y2, $col);
1245 }
1246 
1247 if ($this->selected)
1248 {
1249 imagerectangle($node_im, $label_x1, $label_y1, $label_x2, $label_y2, $map->selected);
1250 // would be nice if it was thicker, too...
1251 imagerectangle($node_im, $label_x1 + 1, $label_y1 + 1, $label_x2 - 1, $label_y2 - 1, $map->selected);
1252 }
1253 else
1254 {
1255 if ($this->labeloutlinecolour != array(-1,-1,-1))
1256 {
1257 $col=myimagecolorallocate($node_im,$this->labeloutlinecolour[0],
1258 $this->labeloutlinecolour[1], $this->labeloutlinecolour[2]);
1259 imagerectangle($node_im, $label_x1, $label_y1, $label_x2, $label_y2, $col);
1260 }
1261 }
1262 #}
1263 
1264 if ($this->labelfontshadowcolour != array(-1,-1,-1))
1265 {
1266 $col=myimagecolorallocate($im, $this->labelfontshadowcolour[0], $this->labelfontshadowcolour[1],
1267 $this->labelfontshadowcolour[2]);
1268 $map->myimagestring($node_im, $this->labelfont, $txt_x + 1, $txt_y + 1, $this->proclabel, $col);
1269 }
1270 
1271 $col=myimagecolorallocate($node_im, $this->labelfontcolour[0], $this->labelfontcolour[1],
1272 $this->labelfontcolour[2]);
1273 $map->myimagestring($node_im, $this->labelfont, $txt_x, $txt_y, $this->proclabel, $col);
1274 }
1275 
1276 # imagerectangle($node_im,$label_x1,$label_y1,$label_x2,$label_y2,$map->black);
1277 # imagerectangle($node_im,$icon_x1,$icon_y1,$icon_x2,$icon_y2,$map->black);
1278 
1279 $map->nodes[$this->name]->centre_x = $this->x - $bbox_x1;
1280 $map->nodes[$this->name]->centre_y = $this->y - $bbox_y1;
1281 
1282 if(1==0)
1283 {
1284 
1285 imageellipse($node_im, $this->centre_x, $this->centre_y, 8, 8, $map->selected);
1286 
1287 foreach (array("N","S","E","W","NE","NW","SE","SW") as $corner)
1288 {
1289 list($dx, $dy)=calc_offset($corner, $this->width, $this->height);
1290 imageellipse($node_im, $this->centre_x + $dx, $this->centre_y + $dy, 5, 5, $map->selected);
1291 }
1292 }
1293 
1294 # $this->image = $node_im;
1295 $map->nodes[$this->name]->image = $node_im;
1296 }
1297 
1298 function update_cache($cachedir,$mapname)
1299 {
1300 $cachename = $cachedir."/node_".md5($mapname."/".$this->name).".png";
1301 // save this image to a cache, for the editor
1302 imagepng($this->image,$cachename);
1303 }
1304 
1305 // draw the node, using the pre_render() output
1306 function NewDraw($im, &$map)
1307 {
1308 // take the offset we figured out earlier, and just blit
1309 // the image on. Who says "blit" anymore?
1310 
1311 // it's possible that there is no image, so better check.
1312 if(isset($this->image))
1313 {
1314 imagealphablending($im, true);
1315 imagecopy ( $im, $this->image, $this->x - $this->centre_x, $this->y - $this->centre_y, 0, 0, imagesx($this->image), imagesy($this->image) );
1316 }
1317 
1318 }
1319 
1320 // take the pre-rendered node and write it to a file so that
1321 // the editor can get at it.
1322 function WriteToCache()
1323 {
1324 }
1325 
1326 function DrawNINK($im, &$map, $size=32)
1327 {
1328 $quarter = $size/4;
1329 
1330 $x = $this->x;
1331 $y = $this->y;
1332 
1333 $col1 = imagecolorallocate($im,255,0,0);
1334 $col2 = imagecolorallocate($im,0,255,0);
1335 $outline = imagecolorallocate($im,255,255,255);
1336 $font = 2;
1337 
1338 imagefilledarc($im,$x,$y,$size,$size,270,90,$col1,IMG_ARC_PIE);
1339 imagefilledarc($im,$x,$y,$size,$size,90,270,$col2,IMG_ARC_PIE);
1340 
1341 imagefilledarc($im,$x,$y+$quarter,$quarter*2,$quarter*2,0,360,$col1,IMG_ARC_PIE);
1342 imagefilledarc($im,$x,$y-$quarter,$quarter*2,$quarter*2,0,360,$col2,IMG_ARC_PIE);
1343 
1344 // draw in the text shadows first, if needed
1345 if ($this->labelfontshadowcolour != array(-1,-1,-1))
1346 {
1347 $col=myimagecolorallocate($im, $this->labelfontshadowcolour[0], $this->labelfontshadowcolour[1],
1348 $this->labelfontshadowcolour[2]);
1349 
1350 imagestring($im, $font, 1 + $x - imagefontwidth($font)*2, 1 + $y-$quarter-imagefontheight($font)/2,"2.5M",$col);
1351 imagestring($im, $font, 1 + $x - imagefontwidth($font)*2, 1 + $y+$quarter-imagefontheight($font)/2,"786M",$col);
1352 }
1353 
1354 imagestring($im, $font, $x - imagefontwidth($font)*2, $y-$quarter-imagefontheight($font)/2,"2.5M",$outline);
1355 imagestring($im, $font, $x - imagefontwidth($font)*2, $y+$quarter-imagefontheight($font)/2,"786M",$outline);
1356 
1357 }
1358 
1359 function calc_size()
1360 {
1361 $this->width=0;
1362 $this->height=0;
1363 
1364 // calculate the size of the NODE box, so we can make links end at corners.
1365 if ($this->label != '')
1366 {
1367 $padding=0;
1368 $font=$this->labelfont;
1369 
1370 list($strwidth, $strheight)=$this->owner->myimagestringsize($font, $this->label);
1371 
1372 $boxwidth=$strwidth * 1.1;
1373 $boxheight=$strheight * 1.1;
1374 
1375 $this->width=$boxwidth;
1376 $this->height=$boxheight;
1377 }
1378 
1379 // if there's an icon, then that's what the corners relate to
1380 if ($this->iconfile != '')
1381 {
1382 # $temp_im=imagecreatefrompng($this->iconfile);
1383 $temp_im = imagecreatefromfile($this->iconfile);
1384 
1385 if ($temp_im)
1386 {
1387 $this->width=imagesx($temp_im);
1388 $this->height=imagesy($temp_im);
1389 }
1390 
1391 imagedestroy ($temp_im);
1392 }
1393 
1394 debug ("PRECALC $this->name: $this->width x $this->height\n");
1395 }
1396 
1397 function Reset(&$newowner)
1398 {
1399 $this->owner=$newowner;
1400 
1401 if (isset($this->owner->defaultnode) && $this->name != 'DEFAULT') {
1402 // use the defaults from DEFAULT
1403 $this->CopyFrom($this->owner->defaultnode);
1404 $this->my_default = $this->owner->defaultnode;
1405 }
1406 else
1407 {
1408 // use the default defaults
140913simandl foreach (array_keys($this->inherit_fieldlist)as $fld)
1410 { $this->$fld = $this->inherit_fieldlist[$fld]; }
14111simandl }
141213simandl # warn($this->name.": ".var_dump($this->hints)."\n");
1413 # warn("DEF: ".var_dump($this->owner->defaultnode->hints)."\n");
1414 #if($this->name == 'North')
1415 #{
1416 # warn("In Reset, North says: ".$this->nodes['North']->hints['sigdigits']."\n");
1417 # }
14181simandl }
1419 
142013simandl function CopyFrom(&$source)
14211simandl {
1422 foreach (array_keys($this->inherit_fieldlist)as $fld) { $this->$fld=$source->$fld; }
1423 }
1424 
1425 function WriteConfig($fd)
1426 {
1427 $output='';
1428 
1429 $comparison=($this->name == 'DEFAULT'
1430 ? $this->inherit_fieldlist['label'] : $this->owner->defaultnode->label);
1431 
1432 if ($this->label != $comparison) { $output.="\tLABEL " . $this->label . "\n"; }
1433 
1434 $comparison=($this->name == 'DEFAULT'
1435 ? $this->inherit_fieldlist['infourl'] : $this->owner->defaultnode->infourl);
1436 
1437 if ($this->infourl != $comparison) { $output.="\tINFOURL " . $this->infourl . "\n"; }
1438 
1439 $comparison=($this->name == 'DEFAULT'
1440 ? $this->inherit_fieldlist['notestext'] : $this->owner->defaultnode->notestext);
1441 
1442 if ($this->notestext != $comparison) { $output.="\tNOTES " . $this->notestext . "\n"; }
1443 
1444 $comparison=($this->name == 'DEFAULT'
1445 ? $this->inherit_fieldlist['overliburl'] : $this->owner->defaultnode->overliburl);
1446 
1447 if ($this->overliburl != $comparison) { $output.="\tOVERLIBGRAPH " . $this->overliburl . "\n"; }
1448 
1449 $comparison=($this->name == 'DEFAULT'
1450 ? $this->inherit_fieldlist['iconfile'] : $this->owner->defaultnode->iconfile);
1451 if ($this->iconfile != $comparison) {
1452 $output.="\tICON ";
1453 if($this->iconscalew > 0) {
1454 $output .= $this->iconscalew." ".$this->iconscaleh." ";
1455 }
1456 $output .= $this->iconfile . "\n";
1457 }
1458 
1459 $comparison=($this->name == 'DEFAULT'
1460 ? $this->inherit_fieldlist['labelfont'] : $this->owner->defaultnode->labelfont);
1461 
1462 if ($this->labelfont != $comparison) { $output.="\tLABELFONT " . $this->labelfont . "\n"; }
1463 
1464 $comparison=($this->name == 'DEFAULT'
1465 ? $this->inherit_fieldlist['labeloffset'] : $this->owner->defaultnode->labeloffset);
1466 
1467 if ($this->labeloffset != $comparison) { $output.="\tLABELOFFSET " . $this->labeloffset . "\n"; }
1468 
1469 
1470 $comparison=($this->name == 'DEFAULT'
1471 ? $this->inherit_fieldlist['targets'] : $this->owner->defaultnode->targets);
1472 
1473 if ($this->targets != $comparison)
1474 {
1475 $output.="\tTARGET";
1476 
1477 foreach ($this->targets as $target) { $output.=" " . $target[4]; }
1478 
1479 $output.="\n";
1480 }
1481 
1482 $comparison = ($this->name == 'DEFAULT'
1483 ? $this->inherit_fieldlist['usescale'] : $this->owner->defaultnode->usescale);
1484 $comparison2 = ($this->name == 'DEFAULT'
1485 ? $this->inherit_fieldlist['scalevar'] : $this->owner->defaultnode->scalevar);
1486 
1487 if ( ($this->usescale != $comparison) || ($this->scalevar != $comparison2) )
1488 { $output.="\tUSESCALE " . $this->usescale . " " . $this->scalevar . "\n"; }
1489 
1490 
1491 
1492 $comparison=($this->name == 'DEFAULT'
1493 ? $this->inherit_fieldlist['overlibcaption'] : $this->owner->defaultnode->overlibcaption);
1494 
1495 if ($this->overlibcaption != $comparison) { $output.="\tOVERLIBCAPTION " . $this->overlibcaption . "\n"; }
1496 
1497 
1498 $comparison=($this->name == 'DEFAULT'
1499 ? $this->inherit_fieldlist['overlibwidth'] : $this->owner->defaultnode->overlibwidth);
1500 
1501 if ($this->overlibwidth != $comparison) { $output.="\tOVERLIBWIDTH " . $this->overlibwidth . "\n"; }
1502 
1503 $comparison=($this->name == 'DEFAULT'
1504 ? $this->inherit_fieldlist['overlibheight'] : $this->owner->defaultnode->overlibheight);
1505 
1506 if ($this->overlibheight != $comparison) { $output.="\tOVERLIBHEIGHT " . $this->overlibheight . "\n"; }
1507 
1508 $comparison=($this->name == 'DEFAULT'
1509 ? $this->inherit_fieldlist['labelbgcolour'] : $this->owner->defaultnode->labelbgcolour);
1510 
1511 if ($this->labelbgcolour != $comparison) { $output.="\tLABELBGCOLOR " . render_colour(
1512 $this->labelbgcolour)
1513 . "\n"; }
1514 
1515 $comparison=($this->name == 'DEFAULT' ? $this->inherit_fieldlist['labelfontcolour']
1516 : $this->owner->defaultnode->labelfontcolour);
1517 
1518 if ($this->labelfontcolour != $comparison) { $output.="\tLABELFONTCOLOR " . render_colour(
1519 $this->labelfontcolour)
1520 . "\n"; }
1521 
1522 $comparison=($this->name == 'DEFAULT' ? $this->inherit_fieldlist['labeloutlinecolour']
1523 : $this->owner->defaultnode->labeloutlinecolour);
1524 
1525 if ($this->labeloutlinecolour != $comparison) { $output.="\tLABELOUTLINECOLOR " . render_colour(
1526 $this->labeloutlinecolour) . "\n";
1527 }
1528 
1529 $comparison=($this->name == 'DEFAULT' ? $this->inherit_fieldlist['labelfontshadowcolour']
1530 : $this->owner->defaultnode->labelfontshadowcolour);
1531 
1532 if ($this->labelfontshadowcolour != $comparison)
1533 { $output.="\tLABELFONTSHADOWCOLOR " . render_colour($this->labelfontshadowcolour) . "\n"; }
1534 
1535 $comparison=($this->name == 'DEFAULT'
1536 ? $this->inherit_fieldlist['labeloffsetx'] : $this->owner->defaultnode->labeloffsetx);
1537 $comparison2=($this->name == 'DEFAULT'
1538 ? $this->inherit_fieldlist['labeloffsety'] : $this->owner->defaultnode->labeloffsety);
1539 
1540 if (($this->labeloffsetx != $comparison) || ($this->labeloffsety != $comparison2))
1541 { $output.="\tLABELOFFSET " . $this->labeloffsetx . " " . $this->labeloffsety . "\n"; }
1542 
1543 $comparison=($this->name == 'DEFAULT' ? $this->inherit_fieldlist['x'] : $this->owner->defaultnode->x);
1544 $comparison2=($this->name == 'DEFAULT' ? $this->inherit_fieldlist['y'] : $this->owner->defaultnode->y);
1545 
1546 if (($this->x != $comparison) || ($this->y != $comparison2))
1547 {
1548 if($this->relative_to == '')
1549 { $output.="\tPOSITION " . $this->x . " " . $this->y . "\n"; }
1550 else
1551 { $output.="\tPOSITION " . $this->relative_to . " " . $this->original_x . " " . $this->original_y . "\n"; }
1552 }
1553 
1554 if (($this->max_bandwidth_in != $this->owner->defaultnode->max_bandwidth_in)
1555 || ($this->max_bandwidth_out != $this->owner->defaultnode->max_bandwidth_out)
1556 || ($this->name == 'DEFAULT'))
1557 {
1558 if ($this->max_bandwidth_in == $this->max_bandwidth_out)
1559 { $output.="\tMAXVALUE " . $this->max_bandwidth_in_cfg . "\n"; }
1560 else { $output
1561 .="\tMAXVALUE " . $this->max_bandwidth_in_cfg . " " . $this->max_bandwidth_out_cfg . "\n"; }
1562 }
1563 
1564 foreach ($this->hints as $hintname=>$hint)
1565 {
1566 // all hints for DEFAULT node are for writing
1567 // only changed ones, or unique ones, otherwise
1568 if(
1569 ($this->name == 'DEFAULT')
1570 ||
1571 (isset($this->owner->defaultnode->hints[$hintname])
1572 &&
1573 $this->owner->defaultnode->hints[$hintname] != $hint)
1574 ||
1575 (!isset($this->owner->defaultnode->hints[$hintname]))
1576 )
1577 {
1578 $output .= "\tSET $hintname $hint\n";
1579 }
1580 }
1581 
1582 if ($output != '')
1583 {
1584 fwrite($fd, "NODE " . $this->name . "\n");
1585 fwrite($fd, "$output\n");
1586 }
1587 }
1588 
1589 function asJS()
1590 {
1591 $js='';
1592 $js.="Nodes[" . js_escape($this->name) . "] = {";
1593 $js.="x:" . $this->x . ", ";
1594 $js.="y:" . $this->y . ", ";
1595 $js.="label:" . js_escape($this->label) . ", ";
1596 $js.="name:" . js_escape($this->name) . ", ";
1597 $js.="infourl:" . js_escape($this->infourl) . ", ";
1598 $js.="overlibcaption:" . js_escape($this->overlibcaption) . ", ";
1599 $js.="overliburl:" . js_escape($this->overliburl) . ", ";
1600 $js.="overlibwidth:" . $this->overlibheight . ", ";
1601 $js.="overlibheight:" . $this->overlibwidth . ", ";
1602 $js.="iconfile:" . js_escape($this->iconfile);
1603 $js.="};\n";
1604 return $js;
1605 }
1606 
1607 function asJSON()
1608 {
1609 $js = '';
1610 $js .= "" . js_escape($this->name) . ": {";
1611 $js .= "x:" . ($this->x - $this->centre_x). ", ";
1612 $js .= "y:" . ($this->y - $this->centre_y) . ", ";
1613 $js .= "label:" . js_escape($this->label) . ", ";
1614 $js .= "name:" . js_escape($this->name) . ", ";
1615 $js .= "infourl:" . js_escape($this->infourl) . ", ";
1616 $js .= "overliburl:" . js_escape($this->overliburl) . ", ";
1617 $js.="overlibcaption:" . js_escape($this->overlibcaption) . ", ";
1618 
1619 $js .= "overlibwidth:" . $this->overlibheight . ", ";
1620 $js .= "overlibheight:" . $this->overlibwidth . ", ";
1621 $js .= "iconfile:" . js_escape($this->iconfile). ", ";
1622 $js .= "iconcachefile:" . js_escape($this->cachefile);
1623 $js .= "},\n";
1624 return $js;
1625 }
1626 
1627 // Set the bandwidth for this link. Convert from KMGT as necessary
1628 function SetBandwidth($inbw, $outbw)
1629 {
1630 
1631 $kilo = $this->owner->kilo;
1632 $this->max_bandwidth_in=unformat_number($inbw, $kilo);
1633 $this->max_bandwidth_out=unformat_number($outbw, $kilo);
1634 $this->max_bandwidth_in_cfg=$inbw;
1635 $this->max_bandwidth_out_cfg=$outbw;
1636 debug (sprintf("Setting bandwidth (%s -> %d bps, %s -> %d bps, KILO = %d)\n", $inbw, $this->max_bandwidth_in, $outbw, $this->max_bandwidth_out, $kilo));
1637 }
1638 
1639 function Draw($im, &$map)
1640 {
1641 $strwidth=0;
1642 $strheight=0;
1643 
1644 // we do this little bit first, so that the label-offset stuff can know it
1645 if ($this->label != '')
1646 {
1647 $padding=0;
1648 $font=$this->labelfont;
1649 
1650 list($strwidth, $strheight)=$map->myimagestringsize($font, $this->label);
1651 
1652 $boxwidth=$strwidth * 1.0;
1653 $boxheight=$strheight * 1.0;
1654 
1655 debug ("Node->Draw: Metrics are: $font $strwidth x $strheight -> $boxwidth x $boxheight\n");
1656 }
1657 
1658 if ($this->iconfile != '')
1659 {
1660 if (is_readable($this->iconfile))
1661 {
1662 imagealphablending($im, true);
1663 // draw the supplied icon, instead of the labelled box
1664 $temp_im=imagecreatefrompng($this->iconfile);
1665 
1666 if ($temp_im)
1667 {
1668 $w=imagesx($temp_im);
1669 $h=imagesy($temp_im);
1670 $x1=$this->x - $w / 2;
1671 $y1=$this->y - $h / 2;
1672 $x2=$this->x + $w / 2;
1673 $y2=$this->y + $h / 2;
1674 
1675 imagecopy($im, $temp_im, $x1, $y1, 0, 0, $w, $h);
1676 $map->imap->addArea("Rectangle", "NODE:" . $this->name, '', array($x1, $y1, $x2, $y2));
1677 imagedestroy ($temp_im);
1678 
1679 if ($this->labeloffset != '')
1680 {
1681 $this->labeloffsetx=0;
1682 $this->labeloffsety=0;
1683 
1684 list($dx, $dy)=calc_offset($this->labeloffset, ($w + $strwidth), ($h + $strheight));
1685 
1686 $this->labeloffsetx=$dx;
1687 $this->labeloffsety=$dy;
1688 }
1689 }
1690 else { warn ("Couldn't open PNG ICON: " . $this->iconfile . " - is it a PNG?\n"); }
1691 }
1692 else { warn ("ICON " . $this->iconfile
1693 . " does not exist, or is not readble. Check path and permissions.\n"); }
1694 }
1695 
1696 if ($this->label != '')
1697 {
1698 $x=$this->x + $this->labeloffsetx;
1699 $y=$this->y + $this->labeloffsety;
1700 
1701 $x1 = $x - ($boxwidth / 2) - 2;
1702 $x2 = $x + ($boxwidth / 2) + 2;
1703 $y1 = $y - ($boxheight / 2) - 2;
1704 $y2 = $y + ($boxheight / 2) + 2;
1705 
1706 $txt_x = $x - $strwidth / 2;
1707 $txt_y = $y + $strheight / 2;
1708 
1709 if ($this->iconfile == '')
1710 {
1711 if ($this->labelbgcolour != array
1712 (
1713 -1,
1714 -1,
1715 -1
1716 ))
1717 {
1718 $col=myimagecolorallocate($im, $this->labelbgcolour[0], $this->labelbgcolour[1],
1719 $this->labelbgcolour[2]);
1720 imagefilledrectangle($im, $x1, $y1, $x2, $y2, $col);
1721 }
1722 
1723 if ($this->selected)
1724 {
1725 imagerectangle($im, $x1, $y1, $x2, $y2, $map->selected);
1726 // would be nice if it was thicker, too...
1727 imagerectangle($im, $x1 - 1, $y1 - 1, $x2 + 1, $y2 + 1, $map->selected);
1728 }
1729 else
1730 {
1731 if ($this->labeloutlinecolour != array
1732 (
1733 -1,
1734 -1,
1735 -1
1736 ))
1737 {
1738 $col=myimagecolorallocate($im, $this->labeloutlinecolour[0],
1739 $this->labeloutlinecolour[1], $this->labeloutlinecolour[2]);
1740 imagerectangle($im, $x1, $y1, $x2, $y2, $col);
1741 }
1742 }
1743 }
1744 
1745 if ($this->labelfontshadowcolour != array
1746 (
1747 -1,
1748 -1,
1749 -1
1750 ))
1751 {
1752 $col=myimagecolorallocate($im, $this->labelfontshadowcolour[0], $this->labelfontshadowcolour[1],
1753 $this->labelfontshadowcolour[2]);
1754 $map->myimagestring($im, $font, $txt_x + 1, $txt_y + 1, $this->label, $col);
1755 }
1756 
1757 $col=myimagecolorallocate($im, $this->labelfontcolour[0], $this->labelfontcolour[1],
1758 $this->labelfontcolour[2]);
1759 $map->myimagestring($im, $font, $txt_x, $txt_y, $this->label, $col);
1760 
1761 $map->imap->addArea("Rectangle", "NODE:" . $this->name, '', array($x1, $y1, $x2, $y2));
1762 }
1763 }
1764}
1765 
1766;
1767 
1768class WeatherMapLink extends WeatherMapItem
1769{
1770 var $owner, $name;
1771 var $maphtml;
1772 var $a, $b; // the ends - references to nodes
1773 var $width, $arrowstyle;
177413simandl var $bwfont, $labelstyle, $labelboxstyle;
17751simandl var $overliburl, $infourl;
1776 var $notes;
1777 var $overlibcaption;
1778 var $overlibwidth, $overlibheight;
1779 var $bandwidth_in, $bandwidth_out;
1780 var $max_bandwidth_in, $max_bandwidth_out;
1781 var $max_bandwidth_in_cfg, $max_bandwidth_out_cfg;
1782 var $targets = array();
1783 var $a_offset, $b_offset;
1784 var $in_ds, $out_ds;
1785 var $selected;
1786 var $inpercent, $outpercent;
1787 var $inherit_fieldlist;
1788 var $vialist = array();
1789 var $usescale;
1790 var $outlinecolour;
1791 var $bwoutlinecolour;
1792 var $bwboxcolour;
1793 var $commentfont,$notestext;
1794 var $inscalekey,$outscalekey;
179513simandl # var $incolour,$outcolour;
17961simandl var $commentfontcolour;
1797 var $bwfontcolour;
179813simandl # var $incomment, $outcomment;
1799 var $comments = array();
1800 var $curvepoints;
18011simandl var $labeloffset_in, $labeloffset_out;
180213simandl var $commentoffset_in, $commentoffset_out;
18031simandl 
1804 function WeatherMapLink() { $this->inherit_fieldlist=array
1805 (
1806 'my_default' => NULL,
1807 'width' => 7,
1808 'commentfont' => 1,
1809 'bwfont' => 2,
1810 'labeloffset_out' => 25,
1811 'labeloffset_in' => 75,
181213simandl 'commentoffset_out' => 5,
1813 'commentoffset_in' => 95,
18141simandl 'arrowstyle' => 'classic',
1815 'usescale' => 'DEFAULT',
1816 'targets' => array(),
1817 'infourl' => '',
1818 'notestext' => '',
1819 'notes' => array(),
182013simandl 'hints' => array(),
1821 'comments' => array('',''),
18221simandl 'overliburl' => '',
1823 'labelstyle' => 'percent',
182413simandl 'labelboxstyle' => 'classic',
18251simandl 'overlibwidth' => 0,
1826 'overlibheight' => 0,
1827 'outlinecolour' => array(0, 0, 0),
1828 'bwoutlinecolour' => array(0, 0, 0),
1829 'bwfontcolour' => array(0, 0, 0),
1830 'bwboxcolour' => array(255, 255, 255),
1831 'commentfontcolour' => array(192,192,192),
1832 'inpercent'=>0, 'outpercent'=>0,
1833 'inscalekey'=>'', 'outscalekey'=>'',
183413simandl # 'incolour'=>-1,'outcolour'=>-1,
18351simandl 'a_offset' => 'C',
1836 'b_offset' => 'C',
183713simandl #'incomment' => '',
1838 #'outcomment' => '',
18391simandl 'overlibcaption' => '',
1840 'max_bandwidth_in' => 100000000,
1841 'max_bandwidth_out' => 100000000,
1842 'max_bandwidth_in_cfg' => '100M',
1843 'max_bandwidth_out_cfg' => '100M'
1844 );
1845 // $this->a_offset = 'C';
1846 // $this->b_offset = 'C';
1847 // $this->targets = array();
1848 }
1849 
1850 function Reset(&$newowner)
1851 {
1852 $this->owner=$newowner;
1853 
1854 if (isset($this->owner->defaultlink) && $this->name != 'DEFAULT') {
1855 // use the defaults from DEFAULT
1856 $this->CopyFrom($this->owner->defaultlink);
1857 $this->my_default = $this->owner->defaultlink;
1858 }
1859 else
1860 {
1861 foreach (array_keys($this->inherit_fieldlist)as
1862 $fld) { $this->$fld=$this->inherit_fieldlist[$fld]; }
1863 }
1864 }
1865 
1866 function my_type() { return "LINK"; }
1867 
1868 function CopyFrom($source)
1869 {
187013simandl foreach (array_keys($this->inherit_fieldlist)as $fld) { $this->$fld = $source->$fld; }
18711simandl }
1872 
1873 // Set the bandwidth for this link. Convert from KMGT as necessary
1874 function SetBandwidth($inbw, $outbw)
1875 {
1876 $kilo = $this->owner->kilo;
1877 $this->max_bandwidth_in=unformat_number($inbw, $kilo);
1878 $this->max_bandwidth_out=unformat_number($outbw, $kilo);
1879 $this->max_bandwidth_in_cfg=$inbw;
1880 $this->max_bandwidth_out_cfg=$outbw;
1881 debug (sprintf("Setting bandwidth (%s -> %d bps, %s -> %d bps, KILO = %d)\n", $inbw, $this->max_bandwidth_in, $outbw,
1882 $this->max_bandwidth_out, $kilo));
1883 }
1884 
188513simandl function DrawComments($image,$col,$width)
1886 {
1887 $curvepoints =& $this->curvepoints;
1888 $last = count($curvepoints)-1;
1889 $totaldistance = $curvepoints[$last][2];
1890 
1891 $start[OUT] = 0;
1892 $commentpos[OUT] = $this->commentoffset_out;
1893 $commentpos[IN] = $this->commentoffset_in;
1894 $start[IN] = $last;
1895 
1896 foreach (array(OUT,IN) as $dir)
1897 {
1898 // Time to deal with Link Comments, if any
1899 $comment = $this->owner->ProcessString($this->comments[$dir], $this);
1900 
1901 if($comment != '')
1902 {
1903 // XXX - redundant extra variable
1904 $startindex = $start[$dir];
1905 $extra_percent = $commentpos[$dir];
1906 
1907 $font = $this->commentfont;
1908 // nudge pushes the comment out along the link arrow a little bit
1909 // (otherwise there are more problems with text disappearing underneath links)
1910 # $nudgealong = 0; $nudgeout=0;
1911 $nudgealong = intval($this->get_hint("comment_nudgealong"));
1912 $nudgeout = intval($this->get_hint("comment_nudgeout"));
1913 
1914 $extra = ($totaldistance * ($extra_percent/100));
1915 # $comment_index = find_distance($curvepoints,$extra);
1916 
1917 list($x,$y,$comment_index,$angle) = find_distance_coords_angle($curvepoints,$extra);
1918 $dx = $x - $curvepoints[$comment_index][0];
1919 $dy = $y - $curvepoints[$comment_index][1];
1920 
1921 #$ratio = ($extra - $curvepoints[$comment_index][2]) / ($curvepoints[$comment_index + 1][2] - $curvepoints[$comment_index][2]);
1922 #$dx = -$curvepoints[$startindex][0] + ($curvepoints[$comment_index][0] + $ratio * ($curvepoints[$comment_index + 1][0] - $curvepoints[$comment_index][0]));
1923 #$dy = -$curvepoints[$startindex][1] + ($curvepoints[$comment_index][1] + $ratio * ($curvepoints[$comment_index + 1][1] - $curvepoints[$comment_index][1]));
1924 // we need the angle to draw the text
1925 #$angle = rad2deg(atan2(-$dy,$dx));
1926 // find the normal to our link, so we can get outside the arrow
1927 
1928 $l=sqrt(($dx * $dx) + ($dy * $dy));
1929 $dx = $dx/$l; $dy = $dy/$l;
1930 $nx = $dy; $ny = -$dx;
1931 
1932 # warn($commentpos[$dir]." $extra/$totaldistance ".$comment_index."\n");
1933 # warn("$dx/$dy $nx/$ny\n");
1934 #$edge_x = $x + $nudge*$dx + $nx * ($width + 4);
1935 #$edge_y = $y + $nudge*$dy + $ny * ($width + 4);
1936 $flipped = FALSE;
1937 // if the text will be upside-down, rotate it, flip it, and right-justify it
1938 // not quite as catchy as Missy's version
1939 if(abs($angle)>90)
1940 {
1941 # $col = $map->selected;
1942 $angle -= 180;
1943 if($angle < -180) $angle +=360;
1944 $edge_x = $x + $nudgealong*$dx - $nx * ($width + 4 + $nudgeout);
1945 $edge_y = $y + $nudgealong*$dy - $ny * ($width + 4 + $nudgeout);
1946 # $comment .= "@";
1947 $flipped = TRUE;
1948 }
1949 else
1950 {
1951 $edge_x = $x + $nudgealong*$dx + $nx * ($width + 4 + $nudgeout);
1952 $edge_y = $y + $nudgealong*$dy + $ny * ($width + 4 + $nudgeout);
1953 }
1954 
1955 list($textlength, $textheight) = $this->owner->myimagestringsize($font, $comment);
1956 
1957 if( !$flipped && ($extra + $textlength) > $totaldistance)
1958 {
1959 $edge_x -= $dx * $textlength;
1960 $edge_y -= $dy * $textlength;
1961 # $comment .= "#";
1962 }
1963 
1964 if( $flipped && ($extra - $textlength) < 0)
1965 {
1966 $edge_x += $dx * $textlength;
1967 $edge_y += $dy * $textlength;
1968 # $comment .= "%";
1969 }
1970 
1971 // FINALLY, draw the text!
1972 # imagefttext($image, $fontsize, $angle, $edge_x, $edge_y, $col, $font,$comment);
1973 $this->owner->myimagestring($image, $font, $edge_x, $edge_y, $comment, $col, $angle);
1974 #imagearc($image,$x,$y,10,10,0, 360,$this->owner->selected);
1975 #imagearc($image,$edge_x,$edge_y,10,10,0, 360,$this->owner->selected);
1976 }
1977 }
1978 }
1979 
19801simandl function Draw($im, &$map)
1981 {
198213simandl // Get the positions of the end-points
19831simandl $x1=$map->nodes[$this->a->name]->x;
1984 $y1=$map->nodes[$this->a->name]->y;
1985 
1986 $x2=$map->nodes[$this->b->name]->x;
1987 $y2=$map->nodes[$this->b->name]->y;
198813simandl 
1989 // Adjust them if there's an offset requested
1990 #$a_height=$map->nodes[$this->a->name]->height;
1991 #$a_width=$map->nodes[$this->a->name]->width;
19921simandl 
199313simandl# $b_height=$map->nodes[$this->b->name]->height;
1994# $b_width=$map->nodes[$this->b->name]->width;
19951simandl 
199613simandl list($dx, $dy)=calc_offset($this->a_offset, $map->nodes[$this->a->name]->width, $map->nodes[$this->a->name]->height);
19971simandl $x1+=$dx;
1998 $y1+=$dy;
1999 
200013simandl list($dx, $dy)=calc_offset($this->b_offset, $map->nodes[$this->b->name]->width, $map->nodes[$this->b->name]->height);
20011simandl $x2+=$dx;
2002 $y2+=$dy;
2003 
2004 $outline_colour=NULL;
2005 $comment_colour=NULL;
2006 
200713simandl if ($this->outlinecolour != array(-1,-1,-1))
2008 {
2009 $outline_colour=myimagecolorallocate(
2010 $im, $this->outlinecolour[0], $this->outlinecolour[1],
2011 $this->outlinecolour[2]);
2012 }
20131simandl 
201413simandl if ($this->commentfontcolour != array(-1,-1,-1))
2015 {
2016 $comment_colour=myimagecolorallocate(
2017 $im, $this->commentfontcolour[0], $this->commentfontcolour[1],
2018 $this->commentfontcolour[2]);
2019 }
20201simandl 
2021 $xpoints = array ( );
2022 $ypoints = array ( );
2023 
2024 $xpoints[]=$x1;
2025 $ypoints[]=$y1;
2026 
2027 # warn("There are VIAs.\n");
2028 foreach ($this->vialist as $via)
2029 {
2030 # imagearc($im, $via[0],$via[1],20,20,0,360,$map->selected);
2031 $xpoints[]=$via[0];
2032 $ypoints[]=$via[1];
2033 }
2034 
2035 $xpoints[]=$x2;
2036 $ypoints[]=$y2;
2037 
203813simandl list($link_in_colour,$link_in_scalekey) = $map->ColourFromPercent($this->inpercent,$this->usescale,$this->name);
2039 list($link_out_colour,$link_out_scalekey) = $map->ColourFromPercent($this->outpercent,$this->usescale,$this->name);
20401simandl 
2041 // $map->links[$this->name]->inscalekey = $link_in_scalekey;
2042 // $map->links[$this->name]->outscalekey = $link_out_scalekey;
2043 
2044 $link_width=$this->width;
2045 // these will replace the one above, ultimately.
2046 $link_in_width=$this->width;
2047 $link_out_width=$this->width;
2048 
2049 // for bulging animations
2050 if ( ($map->widthmod) || ($map->get_hint('link_bulge') == 1))
2051 {
205213simandl // a few 0.1s and +1s to fix div-by-zero, and invisible links
20531simandl $link_width = (($link_width * $this->inpercent * 1.5 + 0.1) / 100) + 1;
2054 // these too
2055 $link_in_width = (($link_in_width * $this->inpercent * 1.5 + 0.1) / 100) + 1;
2056 $link_out_width = (($link_out_width * $this->outpercent * 1.5 + 0.1) / 100) + 1;
2057 }
2058 
205913simandl 
2060 // Calculate the spine points - the actual curve
2061 $this->curvepoints = calc_curve($xpoints, $ypoints);
2062 
2063 draw_curve($im, $this->curvepoints,
2064 $link_width, $outline_colour, $comment_colour, array($link_in_colour, $link_out_colour),
2065 $this->name, $map);
20661simandl 
206713simandl $this->DrawComments($im,$comment_colour,$link_width*1.1);
2068 
2069 $curvelength = $this->curvepoints[count($this->curvepoints)-1][2];
2070 // figure out where the labels should be, and what the angle of the curve is at that point
2071 list($q1_x,$q1_y,$junk,$q1_angle) = find_distance_coords_angle($this->curvepoints,($this->labeloffset_out/100)*$curvelength);
2072 list($q3_x,$q3_y,$junk,$q3_angle) = find_distance_coords_angle($this->curvepoints,($this->labeloffset_in/100)*$curvelength);
2073 
2074 # imageline($im, $q1_x+20*cos(deg2rad($q1_angle)),$q1_y-20*sin(deg2rad($q1_angle)), $q1_x-20*cos(deg2rad($q1_angle)), $q1_y+20*sin(deg2rad($q1_angle)), $this->owner->selected );
2075 # imageline($im, $q3_x+20*cos(deg2rad($q3_angle)),$q3_y-20*sin(deg2rad($q3_angle)), $q3_x-20*cos(deg2rad($q3_angle)), $q3_y+20*sin(deg2rad($q3_angle)), $this->owner->selected );
2076 
2077 # warn("$q1_angle $q3_angle\n");
2078 
20791simandl if (!is_null($q1_x))
2080 {
2081 $outbound=array
2082 (
2083 $q1_x,
2084 $q1_y,
2085 0,
2086 0,
2087 $this->outpercent,
2088 $this->bandwidth_out,
208913simandl $q1_angle
20901simandl );
2091 
2092 $inbound=array
2093 (
2094 $q3_x,
2095 $q3_y,
2096 0,
2097 0,
2098 $this->inpercent,
209913simandl $this->bandwidth_in,
2100 $q3_angle
21011simandl );
2102 
2103 if ($map->sizedebug)
2104 {
2105 $outbound[5]=$this->max_bandwidth_out;
2106 $inbound[5]=$this->max_bandwidth_in;
2107 }
2108 
2109 foreach (array($inbound, $outbound)as $task)
2110 {
2111 $thelabel="";
2112 
2113 if ($this->labelstyle != 'none')
2114 {
2115 debug("Bandwidth is ".$task[5]."\n");
2116 if ($this->labelstyle == 'bits') { $thelabel=nice_bandwidth($task[5], $this->owner->kilo); }
2117 elseif ($this->labelstyle == 'unformatted') { $thelabel=$task[5]; }
2118 elseif ($this->labelstyle == 'percent') { $thelabel=format_number($task[4]) . "%"; }
2119 
212013simandl $padding = intval($this->get_hint('bwlabel_padding'));
2121 
2122 if($this->labelboxstyle == 'angled')
2123 {
2124 $map->DrawLabelRotated($im, $task[0], $task[1],$task[6], $thelabel, $this->bwfont, $padding,
2125 $this->name, $this->bwfontcolour, $this->bwboxcolour, $this->bwoutlinecolour,$map);
2126 }
2127 else
2128 {
2129 $map->DrawLabel($im, $task[0], $task[1], $thelabel, $this->bwfont, $padding,
2130 $this->name, $this->bwfontcolour, $this->bwboxcolour, $this->bwoutlinecolour,$map);
2131 }
2132 
21331simandl }
2134 }
2135 }
2136 }
2137 
2138 function WriteConfig($fd)
2139 {
2140 $output='';
2141 
2142 $comparison=($this->name == 'DEFAULT'
2143 ? $this->inherit_fieldlist['infourl'] : $this->owner->defaultlink->infourl);
2144 
2145 if ($this->infourl != $comparison) { $output.="\tINFOURL " . $this->infourl . "\n"; }
2146 
2147 $comparison=($this->name == 'DEFAULT'
2148 ? $this->inherit_fieldlist['notestext'] : $this->owner->defaultlink->notestext);
2149 
2150 if ($this->notestext != $comparison) { $output.="\tNOTES " . $this->notestext . "\n"; }
2151 
2152 $comparison=($this->name == 'DEFAULT'
2153 ? $this->inherit_fieldlist['overliburl'] : $this->owner->defaultlink->overliburl);
2154 
2155 if ($this->overliburl != $comparison) { $output.="\tOVERLIBGRAPH " . $this->overliburl . "\n"; }
2156 
2157 $comparison=($this->name == 'DEFAULT'
2158 ? $this->inherit_fieldlist['overlibcaption'] : $this->owner->defaultlink->overlibcaption);
2159 
2160 if ($this->overlibcaption != $comparison) { $output.="\tOVERLIBCAPTION " . $this->overlibcaption . "\n"; }
2161 
2162 $comparison=($this->name == 'DEFAULT'
2163 ? $this->inherit_fieldlist['overlibwidth'] : $this->owner->defaultlink->overlibwidth);
2164 
2165 if ($this->overlibwidth != $comparison) { $output.="\tOVERLIBWIDTH " . $this->overlibwidth . "\n"; }
2166 
2167 $comparison=($this->name == 'DEFAULT'
2168 ? $this->inherit_fieldlist['overlibheight'] : $this->owner->defaultlink->overlibheight);
2169 
2170 if ($this->overlibheight != $comparison) { $output.="\tOVERLIBHEIGHT " . $this->overlibheight . "\n"; }
2171 
2172 $comparison=($this->name == 'DEFAULT'
2173 ? $this->inherit_fieldlist['arrowstyle'] : $this->owner->defaultlink->arrowstyle);
2174 
2175 if ($this->arrowstyle != $comparison) { $output.="\tARROWSTYLE " . $this->arrowstyle . "\n"; }
2176 
2177 $comparison=($this->name == 'DEFAULT'
217813simandl ? ($this->inherit_fieldlist['labelstyle']) : ($this->owner->defaultlink->labelstyle));
21791simandl if ($this->labelstyle != $comparison) { $output.="\tBWLABEL " . $this->labelstyle . "\n"; }
2180 
218113simandl $comparison=($this->name == 'DEFAULT'
2182 ? ($this->inherit_fieldlist['labelboxstyle']) : ($this->owner->defaultlink->labelboxstyle));
2183 if ($this->labelboxstyle != $comparison) { $output.="\tBWSTYLE " . $this->labelboxstyle . "\n"; }
21841simandl 
2185 $comparison = ($this->name == 'DEFAULT'
2186 ? $this->inherit_fieldlist['labeloffset_in'] : $this->owner->defaultlink->labeloffset_in);
2187 $comparison2 = ($this->name == 'DEFAULT'
2188 ? $this->inherit_fieldlist['labeloffset_out'] : $this->owner->defaultlink->labeloffset_out);
2189 
2190 if ( ($this->labeloffset_in != $comparison) || ($this->labeloffset_out != $comparison2) )
2191 { $output.="\tBWLABELPOS " . $this->labeloffset_in . " " . $this->labeloffset_out . "\n"; }
2192 
219313simandl $comparison=($this->name == 'DEFAULT'
2194 ? ($this->inherit_fieldlist['commentoffset_in'].":".$this->inherit_fieldlist['commentoffset_out']) : ($this->owner->defaultlink->commentoffset_in.":".$this->owner->defaultlink->commentoffset_out));
2195 $mine = $this->commentoffset_in.":".$this->commentoffset_out;
2196 if ($mine != $comparison) { $output.="\tCOMMENTPOS " . $this->commentoffset_in." ".$this->commentoffset_out. "\n"; }
21971simandl 
219813simandl 
21991simandl $comparison=($this->name == 'DEFAULT'
2200 ? $this->inherit_fieldlist['targets'] : $this->owner->defaultlink->targets);
2201 
2202 if ($this->targets != $comparison)
2203 {
2204 $output.="\tTARGET";
2205 
2206 foreach ($this->targets as $target) { $output.=" " . $target[4]; }
2207 
2208 $output.="\n";
2209 }
2210 
2211 $comparison=($this->name == 'DEFAULT'
2212 ? $this->inherit_fieldlist['usescale'] : $this->owner->defaultlink->usescale);
2213 if ($this->usescale != $comparison) { $output.="\tUSESCALE " . $this->usescale . "\n"; }
2214 
2215 
2216 
2217 $comparison=($this->name == 'DEFAULT'
221813simandl ? $this->inherit_fieldlist['comments'][IN] : $this->owner->defaultlink->comments[IN]);
2219 if ($this->comments[IN] != $comparison) { $output.="\tINCOMMENT " . $this->comments[IN] . "\n"; }
22201simandl 
2221 
2222 $comparison=($this->name == 'DEFAULT'
222313simandl ? $this->inherit_fieldlist['comments'][OUT] : $this->owner->defaultlink->comments[OUT]);
2224 if ($this->comments[OUT] != $comparison) { $output.="\tOUTCOMMENT " . $this->comments[OUT] . "\n"; }
22251simandl 
2226 
2227 
2228 $comparison=($this->name == 'DEFAULT'
2229 ? $this->inherit_fieldlist['usescale'] : $this->owner->defaultlink->usescale);
2230 if ($this->usescale != $comparison) { $output.="\tUSESCALE " . $this->usescale . "\n"; }
2231 
2232 
2233 
2234 
2235 $comparison=($this->name == 'DEFAULT'
2236 ? $this->inherit_fieldlist['bwfont'] : $this->owner->defaultlink->bwfont);
2237 
2238 if ($this->bwfont != $comparison) { $output.="\tBWFONT " . $this->bwfont . "\n"; }
2239 
2240 $comparison=($this->name == 'DEFAULT'
2241 ? $this->inherit_fieldlist['commentfont'] : $this->owner->defaultlink->commentfont);
2242 
2243 if ($this->commentfont != $comparison) { $output.="\tCOMMENTFONT " . $this->commentfont . "\n"; }
2244 
2245 
2246 $comparison=($this->name == 'DEFAULT'
2247 ? $this->inherit_fieldlist['width'] : $this->owner->defaultlink->width);
2248 
2249 if ($this->width != $comparison) { $output.="\tWIDTH " . $this->width . "\n"; }
2250 
2251 $comparison=($this->name == 'DEFAULT'
2252 ? $this->inherit_fieldlist['outlinecolour'] : $this->owner->defaultlink->outlinecolour);
2253 
2254 if ($this->outlinecolour != $comparison) { $output.="\tOUTLINECOLOR " . render_colour(
2255 $this->outlinecolour)
2256 . "\n"; }
2257 
2258 $comparison=($this->name == 'DEFAULT' ? $this->inherit_fieldlist['bwoutlinecolour']
2259 : $this->owner->defaultlink->bwoutlinecolour);
2260 
2261 if ($this->bwoutlinecolour != $comparison) { $output.="\tBWOUTLINECOLOR " . render_colour(
2262 $this->bwoutlinecolour)
2263 . "\n"; }
2264 
2265 $comparison=($this->name == 'DEFAULT'
2266 ? $this->inherit_fieldlist['bwfontcolour'] : $this->owner->defaultlink->bwfontcolour);
2267 
2268 if ($this->bwfontcolour != $comparison) { $output.="\tBWFONTCOLOR " . render_colour(
2269 $this->bwfontcolour) . "\n"; }
2270 
2271 $comparison=($this->name == 'DEFAULT'
2272 ? $this->inherit_fieldlist['commentfontcolour'] : $this->owner->defaultlink->commentfontcolour);
2273 
2274 if ($this->commentfontcolour != $comparison) { $output.="\tCOMMENTFONTCOLOR " . render_colour(
2275 $this->commentfontcolour) . "\n"; }
2276 
2277 
2278 $comparison=($this->name == 'DEFAULT'
2279 ? $this->inherit_fieldlist['bwboxcolour'] : $this->owner->defaultlink->bwboxcolour);
2280 
2281 if ($this->bwboxcolour != $comparison) { $output.="\tBWBOXCOLOR " . render_colour(
2282 $this->bwboxcolour) . "\n"; }
2283 
2284 if (isset($this->a) && isset($this->b))
2285 {
2286 $output.="\tNODES " . $this->a->name;
2287 
2288 if ($this->a_offset != 'C')
2289 $output.=":" . $this->a_offset;
2290 
2291 $output.=" " . $this->b->name;
2292 
2293 if ($this->b_offset != 'C')
2294 $output.=":" . $this->b_offset;
2295 
2296 $output.="\n";
2297 }
2298 
2299 if (count($this->vialist) > 0)
2300 {
2301 foreach ($this->vialist as $via)
2302 $output.=sprintf("\tVIA %d %d\n", $via[0], $via[1]);
2303 }
2304 
2305 if (($this->max_bandwidth_in != $this->owner->defaultlink->max_bandwidth_in)
2306 || ($this->max_bandwidth_out != $this->owner->defaultlink->max_bandwidth_out)
2307 || ($this->name == 'DEFAULT'))
2308 {
2309 if ($this->max_bandwidth_in == $this->max_bandwidth_out)
2310 { $output.="\tBANDWIDTH " . $this->max_bandwidth_in_cfg . "\n"; }
2311 else { $output
2312 .="\tBANDWIDTH " . $this->max_bandwidth_in_cfg . " " . $this->max_bandwidth_out_cfg . "\n"; }
2313 }
2314 
2315 
2316 foreach ($this->hints as $hintname=>$hint)
2317 {
2318 // all hints for DEFAULT node are for writing
2319 // only changed ones, or unique ones, otherwise
2320 if(
2321 ($this->name == 'DEFAULT')
2322 ||
2323 (isset($this->owner->defaultlink->hints[$hintname])
2324 &&
2325 $this->owner->defaultlink->hints[$hintname] != $hint)
2326 ||
2327 (!isset($this->owner->defaultlink->hints[$hintname]))
2328 )
2329 {
2330 $output .= "\tSET $hintname $hint\n";
2331 }
2332 }
2333 
2334 if ($output != '')
2335 {
2336 fwrite($fd, "LINK " . $this->name . "\n");
2337 fwrite($fd, "$output\n");
2338 }
2339 }
2340 
2341 function asJS()
2342 {
2343 $js='';
2344 $js.="Links[" . js_escape($this->name) . "] = {";
2345 
2346 if ($this->name != 'DEFAULT')
2347 {
2348 $js.="a:'" . $this->a->name . "', ";
2349 $js.="b:'" . $this->b->name . "', ";
2350 }
2351 
2352 $js.="width:'" . $this->width . "', ";
2353 $js.="target:";
2354 
2355 $tgt='';
2356 
2357 foreach ($this->targets as $target) { $tgt.=$target[4] . ' '; }
2358 
2359 $js.=js_escape(trim($tgt));
2360 $js.=",";
2361 
2362 $js.="bw_in:" . js_escape($this->max_bandwidth_in_cfg) . ", ";
2363 $js.="bw_out:" . js_escape($this->max_bandwidth_out_cfg) . ", ";
2364 
2365 $js.="name:" . js_escape($this->name) . ", ";
2366 $js.="overlibwidth:'" . $this->overlibheight . "', ";
2367 $js.="overlibheight:'" . $this->overlibwidth . "', ";
2368 $js.="overlibcaption:" . js_escape($this->overlibcaption) . ", ";
2369 
2370 $js.="infourl:" . js_escape($this->infourl) . ", ";
2371 $js.="overliburl:" . js_escape($this->overliburl);
2372 $js.="};\n";
2373 return $js;
2374 }
2375 
2376 function asJSON()
2377 {
2378 $js='';
2379 $js.="" . js_escape($this->name) . ": {";
2380 
2381 if ($this->name != 'DEFAULT')
2382 {
2383 $js.="a:'" . $this->a->name . "', ";
2384 $js.="b:'" . $this->b->name . "', ";
2385 }
2386 
2387 $js.="width:'" . $this->width . "', ";
2388 $js.="target:";
2389 
2390 $tgt='';
2391 
2392 foreach ($this->targets as $target) { $tgt.=$target[4] . ' '; }
2393 
2394 $js.=js_escape(trim($tgt));
2395 $js.=",";
2396 
2397 $js.="bw_in:" . js_escape($this->max_bandwidth_in_cfg) . ", ";
2398 $js.="bw_out:" . js_escape($this->max_bandwidth_out_cfg) . ", ";
2399 
2400 $js.="name:" . js_escape($this->name) . ", ";
2401 $js.="overlibwidth:'" . $this->overlibheight . "', ";
2402 $js.="overlibheight:'" . $this->overlibwidth . "', ";
2403 $js.="overlibcaption:" . js_escape($this->overlibcaption) . ", ";
2404 
2405 $js.="infourl:" . js_escape($this->infourl) . ", ";
2406 $js.="overliburl:" . js_escape($this->overliburl);
2407 $js.="},\n";
2408 return $js;
2409 }
2410}
2411 
2412;
2413 
2414class WeatherMap extends WeatherMapBase
2415{
2416 var $nodes = array(); // an array of WeatherMapNodes
2417 var $links = array(); // an array of WeatherMapLinks
2418 var $texts = array(); // an array containing all the extraneous text bits
2419 var $used_images = array(); // an array of image filenames referred to (used by editor)
2420 var $background;
2421 var $htmlstyle;
2422 var $imap;
2423 var $colours;
2424 var $configfile;
2425 var $imagefile,
2426 $imageuri;
2427 var $rrdtool;
2428 var $title,
2429 $titlefont;
2430 var $kilo;
2431 var $sizedebug,
2432 $widthmod,
2433 $debugging;
2434 var $linkfont,
2435 $nodefont,
2436 $keyfont,
2437 $timefont;
2438 // var $bg_r, $bg_g, $bg_b;
2439 var $timex,
2440 $timey;
2441 var $width,
2442 $height;
2443 var $keyx,
2444 $keyy;
2445 var $titlex,
2446 $titley;
2447 var $keytext,
244813simandl $stamptext, $datestamp;
24491simandl var $htmloutputfile,
2450 $imageoutputfile;
2451 var $defaultlink,
2452 $defaultnode;
2453 var $need_size_precalc;
2454 var $keystyle,$keysize;
2455 var $rrdtool_check;
2456 var $inherit_fieldlist;
2457 var $context;
2458 var $cachefolder,$mapcache;
2459 var $name;
2460 var $black,
2461 $white,
2462 $grey,
2463 $selected;
2464 
2465 var $datasourceclasses;
2466 var $preprocessclasses;
2467 var $postprocessclasses;
2468 var $activedatasourceclasses;
2469 
2470 function WeatherMap()
2471 {
2472 $this->inherit_fieldlist=array
2473 (
2474 'width' => 800,
2475 'height' => 600,
2476 'kilo' => 1000,
2477 'numscales' => array('DEFAULT' => 0),
2478 'datasourceclasses' => array(),
2479 'preprocessclasses' => array(),
2480 'postprocessclasses' => array(),
2481 'context' => '',
2482 'dumpconfig' => FALSE,
2483 'rrdtool_check' => '',
2484 'background' => '',
2485 'imageoutputfile' => '',
2486 'htmloutputfile' => '',
2487 'labelstyle' => 'percent', // redundant?
2488 'htmlstyle' => 'static',
2489 'keystyle' => array('DEFAULT' => 'classic'),
2490 'title' => 'Network Weathermap',
2491 'keytext' => array('DEFAULT' => 'Traffic Load'),
2492 'keyx' => array('DEFAULT' => -1),
2493 'keyy' => array('DEFAULT' => -1),
2494 'keysize' => array('DEFAULT' => 400),
2495 'stamptext' => 'Created: %b %d %Y %H:%M:%S',
2496 'keyfont' => 4,
2497 'titlefont' => 2,
2498 'timefont' => 2,
2499 'timex' => 0,
2500 'timey' => 0,
2501 'titlex' => -1,
2502 'titley' => -1,
2503 'cachefolder' => 'cached',
2504 'mapcache' => '',
2505 'sizedebug' => FALSE,
2506 'debugging' => FALSE,
2507 'widthmod' => FALSE,
2508 'name' => 'MAP'
2509 );
2510 
2511 $this->Reset();
2512 }
2513 
2514 function Reset()
2515 {
2516 foreach (array_keys($this->inherit_fieldlist)as $fld) { $this->$fld=$this->inherit_fieldlist[$fld]; }
2517 
2518 // these two are used for default settings
2519 $this->defaultlink=new WeatherMapLink;
2520 $this->defaultlink->name="DEFAULT";
2521 $this->defaultlink->Reset($this);
2522 
2523 $this->defaultnode=new WeatherMapNode;
2524 $this->defaultnode->name="DEFAULT";
2525 $this->defaultnode->Reset($this);
2526 
2527 $this->need_size_precalc=FALSE;
2528 
2529 $this->nodes=array
2530 (
2531 ); // an array of WeatherMapNodes
2532 
2533 $this->links=array
2534 (
2535 ); // an array of WeatherMapLinks
2536 
2537 $this->imap=new HTML_ImageMap('weathermap');
2538 $this->colours=array
2539 (
2540 );
2541 
2542 debug ("Adding default map colour set.\n");
2543 $defaults=array
2544 (
2545 'KEYTEXT' => array('bottom' => -2, 'top' => -1, 'red1' => 0, 'green1' => 0, 'blue1' => 0),
2546 'KEYBG' => array('bottom' => -2, 'top' => -1, 'red1' => 255, 'green1' => 255, 'blue1' => 255),
2547 'BG' => array('bottom' => -2, 'top' => -1, 'red1' => 255, 'green1' => 255, 'blue1' => 255),
2548 'TITLE' => array('bottom' => -2, 'top' => -1, 'red1' => 0, 'green1' => 0, 'blue1' => 0),
2549 'TIME' => array('bottom' => -2, 'top' => -1, 'red1' => 0, 'green1' => 0, 'blue1' => 0)
2550 );
2551 
2552 foreach ($defaults as $key => $def) { $this->colours['DEFAULT'][$key]=$def; }
2553 
2554 $this->configfile='';
2555 $this->imagefile='';
2556 $this->imageuri='';
2557 
2558 // $this->bg_r = 255;
2559 // $this->bg_g = 255;
2560 // $this->bg_b = 255;
2561 
256213simandl $this->fonts=array();
25631simandl 
256413simandl // Adding these makes the editor's job a little easier, mainly
2565 for($i=1; $i<=5; $i++)
2566 {
2567 $this->fonts[$i]->type="GD builtin";
2568 $this->fonts[$i]->file='';
2569 $this->fonts[$i]->size=0;
2570 }
2571 
25721simandl $this->LoadPlugins('data', 'lib' . DIRECTORY_SEPARATOR . 'datasources');
2573 $this->LoadPlugins('pre', 'lib' . DIRECTORY_SEPARATOR . 'pre');
2574 $this->LoadPlugins('post', 'lib' . DIRECTORY_SEPARATOR . 'post');
2575 
2576 debug("WeatherMap class Reset() complete\n");
2577 }
2578 
2579 function myimagestring($image, $fontnumber, $x, $y, $string, $colour, $angle=0)
2580 {
2581 // if it's supposed to be a special font, and it hasn't been defined, then fall through
2582 if ($fontnumber > 5 && !isset($this->fonts[$fontnumber]))
2583 {
2584 warn ("Using a non-existent special font ($fontnumber) - falling back to internal GD fonts\n");
2585 if($angle != 0) warn("Angled text doesn't work with non-FreeType fonts\n");
2586 $fontnumber=5;
2587 }
2588 
2589 if (($fontnumber > 0) && ($fontnumber < 6))
2590 {
2591 imagestring($image, $fontnumber, $x, $y - imagefontheight($fontnumber), $string, $colour);
2592 if($angle != 0) warn("Angled text doesn't work with non-FreeType fonts\n");
2593 }
2594 else
2595 {
2596 // look up what font is defined for this slot number
2597 if ($this->fonts[$fontnumber]->type == 'truetype')
2598 {
2599 imagettftext($image, $this->fonts[$fontnumber]->size, $angle, $x, $y,
2600 $colour, $this->fonts[$fontnumber]->file, $string);
2601 }
2602 
2603 if ($this->fonts[$fontnumber]->type == 'gd')
2604 {
2605 imagestring($image, $this->fonts[$fontnumber]->gdnumber,
2606 $x, $y - imagefontheight($this->fonts[$fontnumber]->gdnumber),
2607 $string, $colour);
2608 if($angle != 0) warn("Angled text doesn't work with non-FreeType fonts\n");
2609 }
2610 }
2611 }
2612 
2613 function myimagestringsize($fontnumber, $string)
2614 {
2615 if (($fontnumber > 0) && ($fontnumber < 6))
2616 { return array(imagefontwidth($fontnumber) * strlen($string), imagefontheight($fontnumber)); }
2617 else
2618 {
2619 // look up what font is defined for this slot number
2620 if (!isset($this->fonts[$fontnumber]))
2621 {
2622 warn ("Using a non-existent special font ($fontnumber) - falling back to internal GD fonts\n");
2623 $fontnumber=5;
2624 return array(imagefontwidth($fontnumber) * strlen($string), imagefontheight($fontnumber));
2625 }
2626 else
2627 {
2628 if ($this->fonts[$fontnumber]->type == 'truetype')
2629 {
2630 $bounds=imagettfbbox($this->fonts[$fontnumber]->size, 0, $this->fonts[$fontnumber]->file,
2631 $string);
2632 return (array($bounds[4] - $bounds[0], $bounds[1] - $bounds[5]));
2633 }
2634 
2635 if ($this->fonts[$fontnumber]->type == 'gd')
2636 { return array(imagefontwidth($this->fonts[$fontnumber]->gdnumber) * strlen($string),
2637 imagefontheight($this->fonts[$fontnumber]->gdnumber)); }
2638 }
2639 }
2640 }
2641 
2642 function ProcessString($input,&$context, $include_notes=TRUE)
2643 {
2644 $output = $input;
2645 
2646 # debug("ProcessString: input is $input\n");
2647 
2648 # while( preg_match("/(\{[^}]+\})/",$input,$matches) )
2649 while( preg_match("/(\{(?:node|map|link)[^}]+\})/",$input,$matches) )
2650 {
2651 $value = "[UNKNOWN]";
2652 $format = "";
2653 $key = $matches[1];
2654 # debug("ProcessString: working on ".$key."\n");
2655 
2656 if ( preg_match("/\{(node|map|link):([^}]+)\}/",$key,$matches) )
2657 {
2658 $type = $matches[1];
2659 $args = $matches[2];
2660 # debug("ProcessString: type is ".$type.", arguments are ".$args."\n");
2661 
2662 if($type == 'map')
2663 {
2664 $the_item = $this;
2665 if(preg_match("/map:([^:]+):*([^:]*)/",$args,$matches))
2666 {
2667 $args = $matches[1];
2668 $format = $matches[2];
2669 }
2670 }
2671 
2672 if(($type == 'link') || ($type == 'node'))
2673 {
2674 if(preg_match("/([^:]+):([^:]+):*([^:]*)/",$args,$matches))
2675 {
2676 $itemname = $matches[1];
2677 $args = $matches[2];
2678 $format = $matches[3];
2679 
2680 # debug("ProcessString: item is $itemname, and args are now $args\n");
2681 
2682 $the_item = NULL;
2683 if( ($itemname == "this") && ($type == strtolower($context->my_type())) )
2684 {
2685 $the_item = $context;
2686 }
2687 elseif( ($itemname == "parent") && ($type == strtolower($context->my_type())) && ($type=='node') && ($context->relative_to != '') )
2688 {
2689 $the_item = $this->nodes[$context->relative_to];
2690 }
2691 else
2692 {
2693 if( ($type == 'link') && isset($this->links[$itemname]) )
2694 {
2695 $the_item = $this->links[$itemname];
2696 }
2697 if( ($type == 'node') && isset($this->nodes[$itemname]) )
2698 {
2699 $the_item = $this->nodes[$itemname];
2700 }
2701 }
2702 }
2703 }
2704 
2705 if(is_null($the_item))
2706 {
2707 warn("ProcessString: $key refers to unknown item\n");
2708 }
2709 else
2710 {
271113simandl # warn($the_item->name.": ".var_dump($the_item->hints)."\n");
2712 debug("ProcessString: Found appropriate item: ".get_class($the_item)." ".$the_item->name."\n");
27131simandl 
271413simandl # warn($the_item->name."/hints: ".var_dump($the_item->hints)."\n");
2715 # warn($the_item->name."/notes: ".var_dump($the_item->notes)."\n");
2716 
27171simandl // SET and notes have precedent over internal properties
2718 // this is my laziness - it saves me having a list of reserved words
2719 // which are currently used for internal props. You can just 'overwrite' any of them.
2720 if(isset($the_item->hints[$args]))
2721 {
2722 $value = $the_item->hints[$args];
272313simandl debug("ProcessString: used hint\n");
27241simandl }
2725 // for some things, we don't want to allow notes to be considered.
2726 // mainly - TARGET (which can define command-lines), shouldn't be
2727 // able to get data from uncontrolled sources (i.e. data sources rather than SET in config files).
2728 elseif($include_notes && isset($the_item->notes[$args]))
2729 {
2730 $value = $the_item->notes[$args];
273113simandl debug("ProcessString: used note\n");
27321simandl 
2733 }
2734 elseif(isset($the_item->$args))
2735 {
2736 $value = $the_item->$args;
273713simandl debug("ProcessString: used internal property\n");
27381simandl }
2739 }
2740 }
2741 
2742 // format, and sanitise the value string here, before returning it
2743 
274413simandl debug("ProcessString: replacing ".$key." with $value\n");
27451simandl 
2746 # if($format != '') $value = sprintf($format,$value);
2747 if($format != '')
2748 {
2749 
2750 # debug("Formatting with mysprintf($format,$value)\n");
2751 $value = mysprintf($format,$value);
2752 }
2753 
2754 # debug("ProcessString: formatted to $value\n");
2755 $input = str_replace($key,'',$input);
2756 $output = str_replace($key,$value,$output);
2757 }
2758 #debug("ProcessString: output is $output\n");
2759 return ($output);
2760}
2761 
2762function RandomData()
2763{
2764 foreach ($this->links as $link)
2765 {
2766 $this->links[$link->name]->bandwidth_in=rand(0, $link->max_bandwidth_in);
2767 $this->links[$link->name]->bandwidth_out=rand(0, $link->max_bandwidth_out);
2768 }
2769}
2770 
2771function LoadPlugins( $type="data", $dir="lib/datasources" )
2772{
2773 debug("Beginning to load $type plugins from $dir\n");
2774 # $this->datasourceclasses = array();
277513simandl $dh=@opendir($dir);
27761simandl 
277713simandl if(!$dh) { // try to find it with the script, if the relative path fails
2778 $srcdir = substr($_SERVER['argv'][0], 0, strrpos($_SERVER['argv'][0], DIRECTORY_SEPARATOR));
2779 $dh = opendir($srcdir.DIRECTORY_SEPARATOR.$dir);
2780 if ($dh) $dir = $srcdir.DIRECTORY_SEPARATOR.$dir;
2781 }
2782 
27831simandl if ($dh)
2784 {
2785 while ($file=readdir($dh))
2786 {
2787 $realfile = $dir . DIRECTORY_SEPARATOR . $file;
2788 
2789 if( is_file($realfile) && preg_match( '/\.php$/', $realfile ) )
2790 {
2791 debug("Loading $type Plugin class from $file\n");
2792 
2793 include_once( $realfile );
2794 $class = preg_replace( "/\.php$/", "", $file );
2795 if($type == 'data')
2796 {
2797 $this->datasourceclasses [$class]= $class;
2798 $this->activedatasourceclasses[$class]=1;
2799 }
2800 if($type == 'pre') $this->preprocessclasses [$class]= $class;
2801 if($type == 'post') $this->postprocessclasses [$class]= $class;
2802 
2803 debug("Loaded $type Plugin class $class from $file\n");
2804 }
2805 else
2806 {
2807 debug("Skipping $file\n");
2808 }
2809 }
2810 }
2811 else
2812 {
2813 warn("Couldn't open $type Plugin directory ($dir). Things will probably go wrong.\n");
2814 }
2815}
2816 
2817function ReadData()
2818{
2819 
2820 debug("Running Init() for Data Source Plugins...\n");
2821 foreach ($this->datasourceclasses as $ds_class)
2822 {
2823 debug("Running $ds_class"."->Init()\n");
2824 $ret = call_user_func(array($ds_class, 'Init'), $this);
2825 if(! $ret)
2826 {
282713simandl debug("Removing $ds_class from Data Source list, since Init() failed\n");
28281simandl $this->activedatasourceclasses[$ds_class]=0;
2829 # unset($this->datasourceclasses[$ds_class]);
2830 }
2831 }
2832 debug("Finished Initialising Plugins...\n");
2833 
2834 debug ("================== ReadData: Updating link data for all links and nodes\n");
2835 
2836 if ($this->sizedebug == 0)
2837 {
2838 
2839 $allitems = array(&$this->links, &$this->nodes);
2840 reset($allitems);
2841 
2842 while( list($kk,) = each($allitems))
2843 {
2844 unset($objects);
2845 # $objects = &$this->links;
2846 $objects = &$allitems[$kk];
2847 
2848 reset($objects);
2849 while (list($k,) = each($objects))
2850 {
2851 unset($myobj);
2852 $myobj = &$objects[$k];
2853 
2854 $type = $myobj->my_type();
2855 
2856 $total_in=0;
2857 $total_out=0;
2858 $name=$myobj->name;
2859 debug ("\n\nReadData for $type $name: \n");
2860 
2861 if (count($myobj->targets)>0)
2862 {
2863 foreach ($myobj->targets as $target)
2864 {
2865 debug ("ReadData: New Target: $target[0]\n");
2866 
2867 
2868 
2869 $in = 0;
2870 $out = 0;
2871 if ($target[4] != '')
2872 {
2873 // processstring won't use notes (only hints) for this string
2874 $targetstring = $this->ProcessString($target[4], $myobj, FALSE);
2875 if($target[4] != $targetstring) debug("Targetstring is now $targetstring\n");
2876 
2877 // if the targetstring starts with a -, then we're taking this value OFF the aggregate
2878 $multiply = 1;
2879 if(preg_match("/^-(.*)/",$target[4],$matches))
2880 {
2881 $targetstring = $matches[1];
2882 $multiply = -1;
2883 }
2884 
2885 $matched = FALSE;
2886 $matched_by = '';
2887 foreach ($this->datasourceclasses as $ds_class)
2888 {
2889 if(!$matched)
2890 {
2891 $recognised = call_user_func(array($ds_class, 'Recognise'), $targetstring);
2892 
2893 if( $recognised )
2894 {
2895 if($this->activedatasourceclasses[$ds_class])
2896 {
2897 debug("ReadData: Matched for $ds_class. Calling ${ds_class}->ReadData()\n");
2898 
2899 // line number is in $target[3]
2900 # list($in,$out,$datatime) = call_user_func( array($ds_class, 'ReadData'), $targetstring, $this, $myobj );
2901 list($in,$out,$datatime) = call_user_func_array( array($ds_class, 'ReadData'), array($targetstring, &$this, &$myobj));
2902 }
2903 else
2904 {
2905 warn("ReadData: $type $name, target: $targetstring on config line $target[3] was recognised as a valid TARGET by a plugin that is unable to run ($ds_class)\n");
2906 }
2907 $matched = TRUE;
2908 $matched_by = $ds_class;
2909 }
2910 }
2911 }
2912 
2913 if(! $matched)
2914 {
2915 // **
2916 warn("ReadData: $type $name, target: $target[4] on config line $target[3] was not recognised as a valid TARGET\n");
2917 }
2918 
2919 if (($in < 0) || ($out < 0))
2920 {
2921 $in=0;
2922 $out=0;
2923 // **
2924 warn
2925 ("ReadData: $type $name, target: $targetstring on config line $target[3] had no valid data, according to $matched_by\n");
2926 }
2927 
2928 $total_in=$total_in + $multiply*$in;
2929 $total_out=$total_out + $multiply*$out;
2930 }
2931 }
2932 }
2933 else
2934 {
2935 debug("ReadData: No targets for $type $name\n");
2936 }
2937 
2938 # $this->links[$name]->bandwidth_in=$total_in;
2939 # $this->links[$name]->bandwidth_out=$total_out;
2940 $myobj->bandwidth_in = $total_in;
2941 $myobj->bandwidth_out = $total_out;
2942 
2943 $myobj->outpercent = (($total_out) / ($myobj->max_bandwidth_out)) * 100;
2944 $myobj->inpercent = (($total_in) / ($myobj->max_bandwidth_in)) * 100;
2945 
294613simandl list($incol,$inscalekey) = $this->ColourFromPercent($myobj->inpercent,$myobj->usescale,$myobj->name);
2947 list($outcol,$outscalekey) = $this->ColourFromPercent($myobj->outpercent,$myobj->usescale,$myobj->name);
29481simandl 
2949 // $myobj->incolour = $incol;
2950 $myobj->inscalekey = $inscalekey;
2951 // $myobj->outcolour = $outcol;
2952 $myobj->outscalekey = $outscalekey;
2953 
2954 debug ("ReadData: Setting $total_in,$total_out\n");
2955 unset($myobj);
2956 }
2957 }
2958 debug ("\nReadData Completed.\n--------------\n");
2959 }
2960}
2961 
2962// nodename is a vestigal parameter, from the days when nodes where just big labels
2963function DrawLabel($im, $x, $y, $text, $font, $padding, $linkname, $textcolour, $bgcolour, $outlinecolour, &$map)
2964{
2965 list($strwidth, $strheight)=$this->myimagestringsize($font, $text);
2966 
2967 $extra=3;
2968 
2969 $x1=$x - ($strwidth / 2) - $padding - $extra;
2970 $x2=$x + ($strwidth / 2) + $padding + $extra;
2971 $y1=$y - ($strheight / 2) - $padding - $extra;
2972 $y2=$y + ($strheight / 2) + $padding + $extra;
2973 
2974 if ($bgcolour != array
2975 (
2976 -1,
2977 -1,
2978 -1
2979 ))
2980 {
2981 $bgcol=myimagecolorallocate($im, $bgcolour[0], $bgcolour[1], $bgcolour[2]);
2982 imagefilledrectangle($im, $x1, $y1, $x2, $y2, $bgcol);
2983 }
2984 
2985 if ($outlinecolour != array
2986 (
2987 -1,
2988 -1,
2989 -1
2990 ))
2991 {
2992 $outlinecol=myimagecolorallocate($im, $outlinecolour[0], $outlinecolour[1], $outlinecolour[2]);
2993 imagerectangle($im, $x1, $y1, $x2, $y2, $outlinecol);
2994 }
2995 
2996 $textcol=myimagecolorallocate($im, $textcolour[0], $textcolour[1], $textcolour[2]);
2997 $this->myimagestring($im, $font, $x - $strwidth / 2, $y + $strheight / 2 + 1, $text, $textcol);
2998 
2999 $this->imap->addArea("Rectangle", "LINK:".$linkname, '', array($x1, $y1, $x2, $y2));
3000 
3001}
3002 
300313simandl// nodename is a vestigal parameter, from the days when nodes where just big labels
3004function DrawLabelRotated($im, $x, $y, $angle, $text, $font, $padding, $linkname, $textcolour, $bgcolour, $outlinecolour, &$map)
3005{
3006 list($strwidth, $strheight)=$this->myimagestringsize($font, $text);
3007 
3008 if(abs($angle)>90)
3009 {
3010 $angle -= 180;
3011 if($angle < -180) $angle +=360;
3012 }
3013 
3014 $rangle = -deg2rad($angle);
3015 
3016 $extra=3;
3017 
3018 $x1= $x - ($strwidth / 2) - $padding - $extra;
3019 $x2= $x + ($strwidth / 2) + $padding + $extra;
3020 $y1= $y - ($strheight / 2) - $padding - $extra;
3021 $y2= $y + ($strheight / 2) + $padding + $extra;
3022 
3023 // a box. the last point is the start point for the text.
3024 $points = array($x1,$y1, $x1,$y2, $x2,$y2, $x2,$y1, $x-$strwidth/2, $y+$strheight/2 + 1);
3025 $npoints = count($points)/2;
3026 
3027 RotateAboutPoint($points, $x,$y, $rangle);
3028 
3029 if ($bgcolour != array
3030 (
3031 -1,
3032 -1,
3033 -1
3034 ))
3035 {
3036 $bgcol=myimagecolorallocate($im, $bgcolour[0], $bgcolour[1], $bgcolour[2]);
3037 # imagefilledrectangle($im, $x1, $y1, $x2, $y2, $bgcol);
3038 imagefilledpolygon($im,$points,4,$bgcol);
3039 }
3040 
3041 if ($outlinecolour != array
3042 (
3043 -1,
3044 -1,
3045 -1
3046 ))
3047 {
3048 $outlinecol=myimagecolorallocate($im, $outlinecolour[0], $outlinecolour[1], $outlinecolour[2]);
3049 # imagerectangle($im, $x1, $y1, $x2, $y2, $outlinecol);
3050 imagepolygon($im,$points,4,$outlinecol);
3051 }
3052 
3053 $textcol=myimagecolorallocate($im, $textcolour[0], $textcolour[1], $textcolour[2]);
3054 $this->myimagestring($im, $font, $points[8], $points[9], $text, $textcol,$angle);
3055 
3056 $this->imap->addArea("Rectangle", "LINK:".$linkname, '', array($x1, $y1, $x2, $y2));
3057 
3058}
3059 
306011simandlfunction ColourFromPercent($percent,$scalename="DEFAULT",$name="")
30611simandl{
3062 $col = NULL;
3063 
3064 if(isset($this->colours[$scalename]))
3065 {
3066 $colours=$this->colours[$scalename];
3067 
3068 if ($percent > 100)
3069 {
307011simandl warn ("ColourFromPercent: Clipped $name $percent% to 100%\n");
30711simandl $percent=100;
3072 }
3073 
3074 foreach ($colours as $key => $colour)
3075 {
3076 if (($percent >= $colour['bottom']) and ($percent <= $colour['top']))
3077 {
3078 // we get called early now, so might not need to actually allocate a colour
3079 if(isset($this->image))
3080 {
3081 if (isset($colour['red2']))
3082 {
308313simandl if($colour["bottom"] == $colour["top"])
3084 {
3085 $ratio = 0;
3086 }
3087 else
3088 {
3089 $ratio=($percent - $colour["bottom"]) / ($colour["top"] - $colour["bottom"]);
3090 }
30911simandl 
3092 $r=$colour["red1"] + ($colour["red2"] - $colour["red1"]) * $ratio;
3093 $g=$colour["green1"] + ($colour["green2"] - $colour["green1"]) * $ratio;
3094 $b=$colour["blue1"] + ($colour["blue2"] - $colour["blue1"]) * $ratio;
3095 
3096 $col = myimagecolorallocate($this->image, $r, $g, $b);
3097 }
3098 else {
3099 $col = $colour['gdref1'];
3100 }
3101 }
3102 
3103 return(array($col,$key));
3104 }
3105 }
3106 }
3107 else
3108 {
310913simandl warn("ColourFromPercent: Attempted to use non-existent scale: $scalename for $name\n");
31101simandl }
3111 
3112 // you'll only get grey for a COMPLETELY quiet link if there's no 0 in the SCALE lines
3113 if ($percent == 0) { return array($this->grey,''); }
3114 
3115 // and you'll only get white for a link with no colour assigned
3116 return array($this->white,'');
3117}
3118 
3119function coloursort($a, $b)
3120{
3121 if ($a['bottom'] == $b['bottom'])
3122 {
3123 if($a['top'] < $b['top']) { return -1; };
3124 if($a['top'] > $b['top']) { return 1; };
3125 return 0;
3126 }
3127 
3128 if ($a['bottom'] < $b['bottom']) { return -1; }
3129 
3130 return 1;
3131}
3132 
3133function DrawLegend_Horizontal($im,$scalename="DEFAULT",$width=400)
3134{
3135 $title=$this->keytext[$scalename];
3136 
3137 $colours=$this->colours[$scalename];
3138 $nscales=$this->numscales[$scalename];
3139 
3140 debug("Drawing $nscales colours into SCALE\n");
3141 
3142 $font=$this->keyfont;
3143 
3144 $x=$this->keyx[$scalename];
3145 $y=$this->keyy[$scalename];
3146 
3147 # $width = 400;
3148 $scalefactor = $width/100;
3149 
3150 list($tilewidth, $tileheight)=$this->myimagestringsize($font, "100%");
3151 $box_left = $x;
3152 $scale_left = $box_left + 4 + $scalefactor/2;
3153 $box_right = $scale_left + $width + $tilewidth + 4 + $scalefactor/2;
3154 $scale_right = $scale_left + $width;
3155 
3156 $box_top = $y;
3157 $scale_top = $box_top + $tileheight + 6;
3158 $scale_bottom = $scale_top + $tileheight * 1.5;
3159 $box_bottom = $scale_bottom + $tileheight * 2 + 6;
3160 
3161 imagefilledrectangle($im, $box_left, $box_top, $box_right, $box_bottom,
3162 $this->colours['DEFAULT']['KEYBG']['gdref1']);
3163 imagerectangle($im, $box_left, $box_top, $box_right, $box_bottom,
3164 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3165 
3166 $this->myimagestring($im, $font, $scale_left, $scale_bottom + $tileheight * 2 + 2 , $title,
3167 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3168 
3169 for($p=0;$p<=100;$p++)
3170 {
3171 $dx = $p*$scalefactor;
3172 
3173 if( ($p % 25) == 0)
3174 {
3175 imageline($im, $scale_left + $dx, $scale_top - $tileheight,
3176 $scale_left + $dx, $scale_bottom + $tileheight,
3177 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3178 $labelstring=sprintf("%d%%", $p);
3179 $this->myimagestring($im, $font, $scale_left + $dx + 2, $scale_top - 2, $labelstring,
3180 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3181 }
3182 
3183 list($col,$junk) = $this->ColourFromPercent($p,$scalename);
3184 imagefilledrectangle($im, $scale_left + $dx - $scalefactor/2, $scale_top,
3185 $scale_left + $dx + $scalefactor/2, $scale_bottom,
3186 $col);
3187 }
3188 
3189 $this->imap->addArea("Rectangle", "LEGEND:$scalename", '',
3190 array($box_left, $box_top, $box_right, $box_bottom));
3191 
3192}
3193 
3194function DrawLegend_Vertical($im,$scalename="DEFAULT",$height=400)
3195{
3196 $title=$this->keytext[$scalename];
3197 
3198 $colours=$this->colours[$scalename];
3199 $nscales=$this->numscales[$scalename];
3200 
3201 debug("Drawing $nscales colours into SCALE\n");
3202 
3203 $font=$this->keyfont;
3204 
3205 $x=$this->keyx[$scalename];
3206 $y=$this->keyy[$scalename];
3207 
3208 # $height = 400;
3209 $scalefactor = $height/100;
3210 
3211 list($tilewidth, $tileheight)=$this->myimagestringsize($font, "100%");
3212 
3213 $box_left = $x;
3214 $box_top = $y;
3215 
3216 $scale_left = $box_left+$scalefactor*2 +4 ;
3217 $scale_right = $scale_left + $tileheight*2;
3218 $box_right = $scale_right + $tilewidth + $scalefactor*2 + 4;
3219 
3220 list($titlewidth,$titleheight) = $this->myimagestringsize($font,$title);
3221 if( ($box_left + $titlewidth + $scalefactor*3) > $box_right)
3222 {
3223 $box_right = $box_left + $scalefactor*4 + $titlewidth;
3224 }
3225 
3226 $scale_top = $box_top + 4 + $scalefactor + $tileheight*2;
3227 $scale_bottom = $scale_top + $height;
3228 $box_bottom = $scale_bottom + $scalefactor + $tileheight/2 + 4;
3229 
3230 imagefilledrectangle($im, $box_left, $box_top, $box_right, $box_bottom,
3231 $this->colours['DEFAULT']['KEYBG']['gdref1']);
3232 imagerectangle($im, $box_left, $box_top, $box_right, $box_bottom,
3233 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3234 
3235 $this->myimagestring($im, $font, $scale_left-$scalefactor, $scale_top - $tileheight , $title,
3236 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3237 
3238 for($p=0;$p<=100;$p++)
3239 {
3240 $dy = $p*$scalefactor;
3241 $dx = $dy;
3242 
3243 if( ($p % 25) == 0)
3244 {
3245 imageline($im, $scale_left - $scalefactor, $scale_top + $dy,
3246 $scale_right + $scalefactor, $scale_top + $dy,
3247 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3248 $labelstring=sprintf("%d%%", $p);
3249 $this->myimagestring($im, $font, $scale_right + $scalefactor*2 , $scale_top + $dy + $tileheight/2,
3250 $labelstring, $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3251 }
3252 
3253 list($col,$junk) = $this->ColourFromPercent($p,$scalename);
3254 imagefilledrectangle($im, $scale_left, $scale_top + $dy - $scalefactor/2,
3255 $scale_right, $scale_top + $dy + $scalefactor/2,
3256 $col);
3257 }
3258 
3259 $this->imap->addArea("Rectangle", "LEGEND:$scalename", '',
3260 array($box_left, $box_top, $box_right, $box_bottom));
3261}
3262 
3263function DrawLegend_Classic($im,$scalename="DEFAULT")
3264{
3265 $title=$this->keytext[$scalename];
3266 
3267 $colours=$this->colours[$scalename];
3268 $nscales=$this->numscales[$scalename];
3269 
3270 debug("Drawing $nscales colours into SCALE\n");
3271 
327213simandl $hide_zero = intval($this->get_hint("key_hidezero_".$scalename));
3273 $hide_percent = intval($this->get_hint("key_hidepercent_".$scalename));
3274 
3275 if( ($hide_zero == 1) && isset($colours['0_0']) )
3276 {
3277 $nscales--;
3278 }
3279 
32801simandl $font=$this->keyfont;
3281 
3282 $x=$this->keyx[$scalename];
3283 $y=$this->keyy[$scalename];
3284 
3285 list($tilewidth, $tileheight)=$this->myimagestringsize($font, "MMMM");
3286 $tileheight=$tileheight * 1.1;
3287 $tilespacing=$tileheight + 2;
3288 
3289 if (($x >= 0) && ($y >= 0))
3290 {
3291 
3292 # $minwidth = imagefontwidth($font) * strlen('XX 100%-100%')+10;
3293 # $boxwidth = imagefontwidth($font) * strlen($title) + 10;
3294 list($minwidth, $junk)=$this->myimagestringsize($font, 'MMMM 100%-100%');
3295 list($boxwidth, $junk)=$this->myimagestringsize($font, $title);
3296 
3297 $minwidth+=10;
3298 $boxwidth+=10;
3299 
3300 if ($boxwidth < $minwidth) { $boxwidth=$minwidth; }
3301 
3302 $boxheight=$tilespacing * ($nscales + 1) + 10;
3303 
3304 $boxx=$x;
3305 $boxy=$y;
3306 
3307 // allow for X11-style negative positioning
3308 if ($boxx < 0) { $boxx+=$this->width; }
3309 
3310 if ($boxy < 0) { $boxy+=$this->height; }
3311 
3312 imagefilledrectangle($im, $boxx, $boxy, $boxx + $boxwidth, $boxy + $boxheight,
3313 $this->colours['DEFAULT']['KEYBG']['gdref1']);
3314 imagerectangle($im, $boxx, $boxy, $boxx + $boxwidth, $boxy + $boxheight,
3315 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3316 $this->myimagestring($im, $font, $boxx + 4, $boxy + 4 + $tileheight, $title,
3317 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3318 
3319 usort($colours, array("Weathermap", "coloursort"));
3320 
3321 $i=1;
3322 
3323 foreach ($colours as $colour)
3324 {
332513simandl if ($colour['bottom'] >= 0)
3326 {
3327 # debug("$i: drawing\n");
3328 if( ($hide_zero == 0) || $colour['key'] != '0_0')
33291simandl {
333013simandl $y=$boxy + $tilespacing * $i + 8;
3331 $x=$boxx + 6;
3332 
3333 if (isset($colour['red2']))
33341simandl {
333513simandl for ($n=0; $n <= $tilewidth; $n++)
3336 {
3337 $percent
3338 =$colour['bottom'] + ($n / $tilewidth) * ($colour['top'] - $colour['bottom']);
3339 list($col,$junk) = $this->ColourFromPercent($percent,$scalename);
3340 imagefilledrectangle($im, $x + $n, $y, $x + $n, $y + $tileheight,
3341 $col);
3342 }
3343 }
3344 else
3345 {
3346 // pick a percentage in the middle...
3347 $percent=($colour['bottom'] + $colour['top']) / 2;
33481simandl list($col,$junk) = $this->ColourFromPercent($percent,$scalename);
334913simandl imagefilledrectangle($im, $x, $y, $x + $tilewidth, $y + $tileheight,
33501simandl $col);
3351 }
335213simandl 
3353 $labelstring=sprintf("%s-%s", $colour['bottom'], $colour['top']);
3354 if($hide_percent==0) { $labelstring.="%"; }
3355 $this->myimagestring($im, $font, $x + 4 + $tilewidth, $y + $tileheight, $labelstring,
3356 $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
3357 $i++;
33581simandl }
3359 }
3360 }
3361 
3362 $this->imap->addArea("Rectangle", "LEGEND:$scalename", '',
3363 array($boxx, $boxy, $boxx + $boxwidth, $boxy + $boxheight));
3364 # $this->imap->setProp("href","#","LEGEND");
3365 # $this->imap->setProp("extrahtml","onclick=\"position_legend();\"","LEGEND");
3366 
3367 }
3368}
3369 
3370function DrawTimestamp($im, $font, $colour)
3371{
3372 // add a timestamp to the corner, so we can tell if it's all being updated
3373 # $datestring = "Created: ".date("M d Y H:i:s",time());
337413simandl # $this->datestamp=strftime($this->stamptext, time());
33751simandl 
337613simandl list($boxwidth, $boxheight)=$this->myimagestringsize($font, $this->datestamp);
33771simandl 
3378 $x=$this->width - $boxwidth;
3379 $y=$boxheight;
3380 
3381 if (($this->timex > 0) && ($this->timey > 0))
3382 {
3383 $x=$this->timex;
3384 $y=$this->timey;
3385 }
3386 
338713simandl $this->myimagestring($im, $font, $x, $y, $this->datestamp, $colour);
33881simandl 
3389 $this->imap->addArea("Rectangle", "TIMESTAMP", '', array($x, $y, $x + $boxwidth, $y - $boxheight));
3390}
3391 
3392function DrawTitle($im, $font, $colour)
3393{
3394 $string = $this->ProcessString($this->title,$this);
3395 
3396 list($boxwidth, $boxheight)=$this->myimagestringsize($font, $string);
3397 
3398 $x=10;
3399 $y=$this->titley - $boxheight;
3400 
3401 if (($this->titlex >= 0) && ($this->titley >= 0))
3402 {
3403 $x=$this->titlex;
3404 $y=$this->titley;
3405 }
3406 
3407 $this->myimagestring($im, $font, $x, $y, $string, $colour);
3408 
3409 $this->imap->addArea("Rectangle", "TITLE", '', array($x, $y, $x + $boxwidth, $y - $boxheight));
3410}
3411 
3412function ReadConfig($filename)
3413{
3414 $curnode=null;
3415 $curlink=null;
3416 $matches=0;
3417 $nodesseen=0;
3418 $linksseen=0;
3419 $scalesseen=0;
3420 
3421 $last_seen="---";
3422 $fd=fopen($filename, "r");
3423 
3424 if ($fd)
3425 {
3426 $linecount = 0;
3427 
3428 while (!feof($fd))
3429 {
3430 $buffer=fgets($fd, 4096);
3431 // strip out any Windows line-endings that have gotten in here
3432 $buffer=str_replace("\r", "", $buffer);
3433 $linematched=0;
3434 $linecount++;
3435 
3436 if (preg_match("/^\s*#/", $buffer)) {
3437 // this is a comment line
3438 }
3439 else
3440 {
3441 // for any other config elements that are shared between nodes and links, they can use this
3442 unset($curobj);
3443 $curobj = NULL;
3444 if($last_seen == "LINK") $curobj = &$curlink;
3445 if($last_seen == "NODE") $curobj = &$curnode;
3446 
3447 if (preg_match("/^\s*(LINK|NODE)\s+(\S+)\s*$/i", $buffer, $matches))
3448 {
3449 // first, save the previous item, before starting work on the new one
3450 if ($last_seen == "NODE")
3451 {
3452 if ($curnode->name == 'DEFAULT')
3453 {
345413simandl $this->defaultnode = $curnode;
34551simandl debug ("Saving Default Node: " . $curnode->name . "\n");
3456 }
3457 else
3458 {
3459 $this->nodes[$curnode->name]=$curnode;
3460 debug ("Saving Node: " . $curnode->name . "\n");
3461 }
3462 }
3463 
3464 if ($last_seen == "LINK")
3465 {
3466 if ($curlink->name == 'DEFAULT')
3467 {
3468 $this->defaultlink=$curlink;
3469 debug ("Saving Default Link: " . $curlink->name . "\n");
3470 }
3471 else
3472 {
3473 if (isset($curlink->a) && isset($curlink->b))
3474 {
3475 $this->links[$curlink->name]=$curlink;
3476 debug ("Saving Link: " . $curlink->name . "\n");
3477 }
3478 else { warn
3479 ("Dropping LINK " . $curlink->name . " - it hasn't got 2 NODES!\n"); }
3480 }
3481 }
3482 
3483 if ($matches[1] == 'LINK')
3484 {
3485 if ($matches[2] == 'DEFAULT')
3486 {
3487 if ($linksseen > 0) { warn
3488 ("LINK DEFAULT is not the first LINK. Defaults will not apply to earlier LINKs.\n");
3489 }
349013simandl unset($curlink);
3491 $curlink = $this->defaultlink;
34921simandl }
3493 else
3494 {
349513simandl unset($curlink);
34961simandl $curlink=new WeatherMapLink;
3497 $curlink->name=$matches[2];
3498 $curlink->Reset($this);
3499 $linksseen++;
3500 }
3501 
3502 $last_seen="LINK";
3503 $curlink->configline = $linecount;
3504 $linematched++;
3505 }
3506 
3507 if ($matches[1] == 'NODE')
3508 {
3509 if ($matches[2] == 'DEFAULT')
3510 {
3511 if ($nodesseen > 0) { warn
3512 ("NODE DEFAULT is not the first NODE. Defaults will not apply to earlier NODEs.\n");
3513 }
3514 
351513simandl unset($curnode);
3516 $curnode = $this->defaultnode;
35171simandl }
3518 else
3519 {
352013simandl unset($curnode);
35211simandl $curnode=new WeatherMapNode;
3522 $curnode->name=$matches[2];
3523 $curnode->Reset($this);
3524 $nodesseen++;
3525 }
3526 
3527 $curnode->configline = $linecount;
3528 $last_seen="NODE";
3529 $linematched++;
3530 }
3531 }
3532 
3533 
3534 
3535 if (preg_match("/^\s*POSITION\s+([-+]?\d+)\s+([-+]?\d+)\s*$/i", $buffer, $matches))
3536 {
3537 if ($last_seen == 'NODE')
3538 {
3539 $curnode->x=$matches[1];
3540 $curnode->y=$matches[2];
3541 $linematched++;
3542 }
3543 }
3544 
3545 if (preg_match("/^\s*POSITION\s+(\S+)\s+([-+]?\d+)\s+([-+]?\d+)\s*$/i", $buffer, $matches))
3546 {
3547 if ($last_seen == 'NODE')
3548 {
3549 $curnode->relative_to = $matches[1];
3550 $curnode->relative_resolved = FALSE;
3551 $curnode->x = $matches[2];
3552 $curnode->y = $matches[3];
3553 $curnode->original_x = $matches[2];
3554 $curnode->original_y = $matches[3];
3555 $linematched++;
3556 }
3557 }
3558 
3559 if (preg_match("/^\s*LABEL\s+(.*)\s*$/i", $buffer, $matches))
3560 {
3561 if ($last_seen == 'NODE')
3562 {
3563 $curnode->label=$matches[1];
3564 $linematched++;
3565 }
3566 }
3567 
3568 if (preg_match("/^\s*NODES\s+(\S+)\s+(\S+)\s*$/i", $buffer, $matches))
3569 {
3570 if ($last_seen == 'LINK')
3571 {
3572 $valid_nodes=2;
3573 
3574 foreach (array(1, 2)as $i)
3575 {
3576 $endoffset[$i]='C';
3577 $nodenames[$i]=$matches[$i];
3578 
3579 if (preg_match("/:(NE|SE|NW|SW|N|S|E|W)$/i", $matches[$i], $submatches))
3580 {
3581 $endoffset[$i]=$submatches[1];
3582 $nodenames[$i]=preg_replace("/:(NE|SE|NW|SW|N|S|E|W)$/i", '', $matches[$i]);
3583 $this->need_size_precalc=TRUE;
3584 }
3585 
3586 if (preg_match("/:([-+]?\d+):([-+]?\d+)$/i", $matches[$i], $submatches))
3587 {
3588 $xoff = $submatches[1];
3589 $yoff = $submatches[2];
3590 $endoffset[$i]=$xoff.":".$yoff;
3591 $nodenames[$i]=preg_replace("/:$xoff:$yoff$/i", '', $matches[$i]);
3592 $this->need_size_precalc=TRUE;
3593 }
3594 
3595 if (!array_key_exists($nodenames[$i], $this->nodes))
3596 {
3597 warn ("Unknown node '" . $nodenames[$i]
3598 . "' on line $linecount of config\n");
3599 $valid_nodes--;
3600 }
3601 }
3602 
3603 // TODO - really, this should kill the whole link, and reset for the next one
3604 if ($valid_nodes == 2)
3605 {
3606 $curlink->a=$this->nodes[$nodenames[1]];
3607 $curlink->b=$this->nodes[$nodenames[2]];
3608 $curlink->a_offset=$endoffset[1];
3609 $curlink->b_offset=$endoffset[2];
3610 }
3611 else {
3612 // this'll stop the current link being added
3613 $last_seen="broken"; }
3614 
3615 $linematched++;
3616 }
3617 }
3618 
3619 if (preg_match("/^\s*TARGET\s+(.*)\s*$/i", $buffer, $matches))
3620 {
3621 $linematched++;
3622 
3623 $targets=preg_split('/\s+/', $matches[1], -1, PREG_SPLIT_NO_EMPTY);
3624 // wipe any existing targets, otherwise things in the DEFAULT accumulate with the new ones
3625 $curobj->targets = array();
3626 foreach ($targets as $target)
3627 {
3628 // we store the original TARGET string, and line number, along with the breakdown, to make nicer error messages later
3629 $newtarget=array($target,'','',$linecount,$target);
3630 if ($curobj)
3631 {
3632 $curobj->targets[]=$newtarget;
3633 }
3634 }
3635 }
3636 
3637 if (preg_match("/^\s*WIDTH\s+(\d+)\s*$/i", $buffer, $matches))
3638 {
3639 if ($last_seen == 'LINK')
3640 {
3641 $curlink->width=$matches[1];
3642 $linematched++;
3643 }
3644 else // we're talking about the global WIDTH
3645 {
3646 $this->width=$matches[1];
3647 $linematched++;
3648 }
3649 }
3650 
3651 if (preg_match("/^\s*HEIGHT\s+(\d+)\s*$/i", $buffer, $matches))
3652 {
3653 $this->height=$matches[1];
3654 $linematched++;
3655 }
3656 
3657 if ( ($last_seen == 'LINK') && (preg_match("/^\s*INCOMMENT\s+(.*)\s*$/i", $buffer, $matches)))
3658 {
365913simandl # $curlink->incomment = $matches[1];
3660 $curlink->comments[IN] = $matches[1];
36611simandl $linematched++;
3662 }
3663 
3664 if ( ($last_seen == 'LINK') && (preg_match("/^\s*OUTCOMMENT\s+(.*)\s*$/i", $buffer, $matches)))
3665 {
366613simandl # $curlink->outcomment = $matches[1];
3667 $curlink->comments[OUT] = $matches[1];
36681simandl $linematched++;
3669 }
3670 
3671 
3672 if ( ($last_seen == 'LINK') && (preg_match("/^\s*(BANDWIDTH|MAXVALUE)\s+(\d+\.?\d*[KMGT]?)\s*$/i", $buffer, $matches)))
3673 {
3674 $curlink->SetBandwidth($matches[2], $matches[2]);
3675 $linematched++;
3676 }
3677 
3678 if ( ($last_seen == 'LINK') && (preg_match("/^\s*(MAXVALUE|BANDWIDTH)\s+(\d+\.?\d*[KMGT]?)\s+(\d+\.?\d*[KMGT]?)\s*$/i", $buffer,
3679 $matches)))
3680 {
3681 $curlink->SetBandwidth($matches[2], $matches[3]);
3682 $linematched++;
3683 }
3684 
3685 if ( ($last_seen == 'NODE') && (preg_match("/^\s*MAXVALUE\s+(\d+\.?\d*[KMGT]?)\s+(\d+\.?\d*[KMGT]?)\s*$/i", $buffer,
3686 $matches)))
3687 {
3688 $curnode->SetBandwidth($matches[1], $matches[2]);
3689 $linematched++;
3690 }
3691 
3692 if ( ($last_seen == 'NODE') && (preg_match("/^\s*MAXVALUE\s+(\d+\.?\d*[KMGT]?)\s*$/i", $buffer,
3693 $matches)))
3694 {
3695 $curnode->SetBandwidth($matches[1], $matches[1]);
3696 $linematched++;
3697 }
3698 
3699 if (preg_match("/^\s*ICON\s+(\S+)\s*$/i", $buffer, $matches))
3700 {
3701 if ($last_seen == 'NODE')
3702 {
3703 if($matches[1]=='none')
3704 {
3705 $curnode->iconfile='';
3706 }
3707 else
3708 {
3709 $curnode->iconfile=$matches[1];
3710 $this->used_images[] = $matches[1];
3711 }
3712 $linematched++;
3713 }
3714 }
3715 
3716 if (preg_match("/^\s*ICON\s+(\d+)\s+(\d+)\s+(\S+)\s*$/i", $buffer, $matches))
3717 {
3718 if ($last_seen == 'NODE')
3719 {
3720 $curnode->iconfile=$matches[3];
3721 $this->used_images[] = $matches[3];
3722 $curnode->iconscalew = $matches[1];
3723 $curnode->iconscaleh = $matches[2];
3724 $linematched++;
3725 }
3726 }
3727 
3728 if (preg_match("/^\s*SET\s+(\S+)\s+(.*)\s*$/i", $buffer, $matches))
3729 {
3730 if($curobj)
3731 {
373213simandl // THIS IS NOT UPDATING THE 'REAL' DEFAULT NODE
37331simandl $curobj->add_hint($matches[1],$matches[2]);
3734 $linematched++;
373513simandl # warn("POST-SET ".$curobj->name."::".var_dump($curobj->hints)."::\n");
3736 # warn("DEFAULT FIRST SAYS ".$this->defaultnode->hints['sigdigits']."\n");
37371simandl }
3738 else
3739 {
374013simandl // it's a global thing, for the map
37411simandl $this->add_hint($matches[1],$matches[2]);
3742 $linematched++;
3743 }
3744 }
3745 
3746 if (preg_match("/^\s*NOTES\s+(.*)\s*$/i", $buffer, $matches))
3747 {
3748 if($curobj)
3749 {
3750 $curobj->notestext=$matches[1];
3751 $linematched++;
3752 }
3753 }
3754 
3755 if (preg_match("/^\s*INFOURL\s+(\S+)\s*$/i", $buffer, $matches))
3756 {
3757 if($curobj)
3758 {
3759 $curobj->infourl=$matches[1];
3760 $linematched++;
3761 }
3762 }
3763 
3764 if (preg_match("/^\s*OVERLIBGRAPH\s+(\S+)\s*$/i", $buffer, $matches))
3765 {
3766 if($curobj)
3767 {
3768 $curobj->overliburl=$matches[1];
3769 $linematched++;
3770 }
3771 }
3772 
3773 if (preg_match("/^\s*OVERLIBCAPTION\s+(.+)\s*$/i", $buffer, $matches))
3774 {
3775 if($curobj)
3776 {
3777 $curobj->overlibcaption=$matches[1];
3778 $linematched++;
3779 }
3780 }
3781 
3782 if (preg_match("/^\s*OVERLIBHEIGHT\s+(\d+)\s*$/i", $buffer, $matches))
3783 {
3784 if($curobj)
3785 {
3786 $curobj->overlibheight=$matches[1];
3787 $linematched++;
3788 }
3789 }
3790 
3791 if (preg_match("/^\s*OVERLIBWIDTH\s+(\d+)\s*$/i", $buffer, $matches))
3792 {
3793 if($curobj)
3794 {
3795 $curobj->overlibwidth=$matches[1];
3796 $linematched++;
3797 }
3798 }
3799 
3800 if ($last_seen == 'NODE' && preg_match("/^\s*LABELFONT\s+(\d+)\s*$/i", $buffer, $matches))
3801 {
3802 $curnode->labelfont=$matches[1];
3803 $linematched++;
3804 }
3805 
3806 if ($last_seen == 'NODE' && preg_match(
3807 "/^\s*LABELOFFSET\s+([-+]?\d+)\s+([-+]?\d+)\s*$/i", $buffer,
3808 $matches))
3809 {
3810 $curnode->labeloffsetx=$matches[1];
3811 $curnode->labeloffsety=$matches[2];
3812 
3813 $linematched++;
3814 }
3815 
3816 if ($last_seen == 'NODE' && preg_match(
3817 "/^\s*LABELOFFSET\s+(C|NE|SE|NW|SW|N|S|E|W)\s*$/i", $buffer,
3818 $matches))
3819 {
3820 $curnode->labeloffset=$matches[1];
3821 $linematched++;
3822 }
3823 
3824 if ($last_seen == 'LINK' && preg_match("/^\s*VIA\s+(\d+)\s+(\d+)\s*$/i", $buffer, $matches))
3825 {
3826 $curlink->vialist[]=array
3827 (
3828 $matches[1],
3829 $matches[2]
3830 );
3831 
3832 $linematched++;
3833 }
3834 
3835 if ($last_seen == 'LINK' && preg_match("/^\s*BWFONT\s+(\d+)\s*$/i", $buffer, $matches))
3836 {
3837 $curlink->bwfont=$matches[1];
3838 $linematched++;
3839 }
3840 
3841 if ($last_seen == 'LINK' && preg_match("/^\s*COMMENTFONT\s+(\d+)\s*$/i", $buffer, $matches))
3842 {
3843 $curlink->commentfont=$matches[1];
3844 $linematched++;
3845 }
3846 
3847 if ($last_seen == 'LINK' && preg_match(
3848 "/^\s*BWLABEL\s+(bits|percent|unformatted|none)\s*$/i", $buffer,
3849 $matches))
3850 {
3851 $curlink->labelstyle=strtolower($matches[1]);
3852 $linematched++;
3853 }
3854 
3855 if ($last_seen == 'LINK' && preg_match(
385613simandl "/^\s*BWSTYLE\s+(classic|angled)\s*$/i", $buffer,
3857 $matches))
3858 {
3859 $curlink->labelboxstyle=$matches[1];
3860 $linematched++;
3861 }
3862 
3863 if ($last_seen == 'LINK' && preg_match(
38641simandl "/^\s*BWLABELPOS\s+(\d+)\s(\d+)\s*$/i", $buffer,
3865 $matches))
3866 {
3867 $curlink->labeloffset_in = $matches[1];
3868 $curlink->labeloffset_out = $matches[2];
3869 $linematched++;
3870 }
387113simandl 
3872 if ($last_seen == 'LINK' && preg_match(
3873 "/^\s*COMMENTPOS\s+(\d+)\s(\d+)\s*$/i", $buffer,
3874 $matches))
3875 {
3876 $curlink->commentoffset_in = $matches[1];
3877 $curlink->commentoffset_out = $matches[2];
3878 $linematched++;
3879 }
38801simandl 
3881 if( ($last_seen == 'NODE') && preg_match("/^\s*USESCALE\s+([A-Za-z][A-Za-z0-9_]*)(\s+(in|out))?\s*$/i",$buffer,$matches))
3882 {
3883 $svar = '';
3884 if(isset($matches[2]))
3885 {
3886 $svar = trim($matches[2]);
3887 }
3888 
3889 if($matches[1] == 'none')
3890 {
3891 $curnode->usescale = $matches[1];
3892 if($svar != '')
3893 {
3894 $curnode->scalevar = $svar;
3895 }
3896 }
3897 else
3898 {
3899 $curnode->usescale = $matches[1];
3900 if($svar != '')
3901 {
3902 $curnode->scalevar = $svar;
3903 }
3904 }
3905 $linematched++;
3906 }
3907 
3908 if( ($last_seen == 'LINK') && preg_match("/^\s*USESCALE\s+([A-Za-z][A-Za-z0-9_]*)\s*$/i",$buffer,$matches))
3909 {
3910 $curlink->usescale = $matches[1];
3911 
3912 $linematched++;
3913 }
3914 
3915 // one REGEXP to rule them all:
3916 if(preg_match("/^\s*SCALE\s+([A-Za-z][A-Za-z0-9_]*\s+)?(\d+\.?\d*)\s+(\d+\.?\d*)\s+(\d+)\s+(\d+)\s+(\d+)(?:\s+(\d+)\s+(\d+)\s+(\d+))?\s*$/i",
3917 $buffer, $matches))
3918 {
3919 // The default scale name is DEFAULT
3920 if($matches[1]=='') $matches[1] = 'DEFAULT';
3921 else $matches[1] = trim($matches[1]);
3922 
3923 $key=$matches[2] . '_' . $matches[3];
3924 
392513simandl $this->colours[$matches[1]][$key]['key']=$key;
39261simandl $this->colours[$matches[1]][$key]['bottom'] = (float)($matches[2]);
3927 $this->colours[$matches[1]][$key]['top'] = (float)($matches[3]);
3928 
3929 $this->colours[$matches[1]][$key]['red1'] = (int)($matches[4]);
3930 $this->colours[$matches[1]][$key]['green1'] = (int)($matches[5]);
3931 $this->colours[$matches[1]][$key]['blue1'] = (int)($matches[6]);
3932 
3933 // this is the second colour, if there is one
3934 if(isset($matches[7]))
3935 {
3936 $this->colours[$matches[1]][$key]['red2'] = (int) ($matches[7]);
3937 $this->colours[$matches[1]][$key]['green2'] = (int) ($matches[8]);
3938 $this->colours[$matches[1]][$key]['blue2'] = (int) ($matches[9]);
3939 }
3940 
394113simandl 
39421simandl if(! isset($this->numscales[$matches[1]]))
3943 {
3944 $this->numscales[$matches[1]]=1;
3945 }
3946 else
3947 {
3948 $this->numscales[$matches[1]]++;
3949 }
3950 // we count if we've seen any default scale, otherwise, we have to add
3951 // one at the end.
3952 if($matches[1]=='DEFAULT')
3953 {
3954 $scalesseen++;
3955 }
3956 
3957 $linematched++;
3958 }
3959 
3960 if (preg_match("/^\s*KEYPOS\s+([A-Za-z][A-Za-z0-9_]*\s+)?(-?\d+)\s+(-?\d+)(.*)/i", $buffer, $matches))
3961 {
3962 $whichkey = trim($matches[1]);
3963 if($whichkey == '') $whichkey = 'DEFAULT';
3964 
3965 $this->keyx[$whichkey]=$matches[2];
3966 $this->keyy[$whichkey]=$matches[3];
3967 $extra=trim($matches[4]);
3968 
3969 if ($extra != '')
3970 $this->keytext[$whichkey] = $extra;
3971 if(!isset($this->keytext[$whichkey]))
3972 $this->keytext[$whichkey] = "DEFAULT TITLE";
3973 if(!isset($this->keystyle[$whichkey]))
3974 $this->keystyle[$whichkey] = "classic";
3975 
3976 $linematched++;
3977 }
3978 
3979 if (preg_match("/^\s*TITLEPOS\s+(-?\d+)\s+(-?\d+)\s+(.*)\s*$/i", $buffer, $matches))
3980 {
3981 $this->titlex=$matches[1];
3982 $this->titley=$matches[2];
3983 $extra=trim($matches[3]);
3984 
3985 if ($extra != '')
3986 $this->title=$extra;
3987 
3988 $linematched++;
3989 }
3990 
3991 // truetype font definition (actually, we don't really check if it's truetype) - filename + size
3992 if (preg_match("/^\s*FONTDEFINE\s+(\d+)\s+(\S+)\s+(\d+)\s*$/i", $buffer, $matches))
3993 {
3994 if (function_exists("imagettfbbox"))
3995 {
3996 // test if this font is valid, before adding it to the font table...
3997 $bounds=@imagettfbbox($matches[3], 0, $matches[2], "Ignore me");
3998 
3999 if (isset($bounds[0]))
4000 {
4001 $this->fonts[$matches[1]]->type="truetype";
4002 $this->fonts[$matches[1]]->file=$matches[2];
4003 $this->fonts[$matches[1]]->size=$matches[3];
4004 }
4005 else { warn
4006 ("Failed to load ttf font " . $matches[2] . " - at config line $linecount\n"); }
4007 }
4008 else { warn
4009 ("imagettfbbox() is not a defined function. You don't seem to have FreeType compiled into your gd module.\n");
4010 }
4011 
4012 $linematched++;
4013 }
4014 
4015 // GD font definition (no size here)
4016 if (preg_match("/^\s*FONTDEFINE\s+(\d+)\s+(\S+)\s*$/i", $buffer, $matches))
4017 {
4018 $newfont=imageloadfont($matches[2]);
4019 
4020 if ($newfont)
4021 {
4022 $this->fonts[$matches[1]]->type="gd";
4023 $this->fonts[$matches[1]]->file=$matches[2];
4024 $this->fonts[$matches[1]]->gdnumber=$newfont;
4025 }
4026 else { warn ("Failed to load GD font: " . $matches[2]
4027 . " ($newfont) at config line $linecount\n"); }
4028 
4029 $linematched++;
4030 }
4031 
4032 if (preg_match("/^\s*KEYFONT\s+(\d+)\s*$/i", $buffer, $matches))
4033 {
4034 $this->keyfont=$matches[1];
4035 $linematched++;
4036 }
4037 
4038 if (preg_match("/^\s*TIMEFONT\s+(\d+)\s*$/i", $buffer, $matches))
4039 {
4040 $this->timefont=$matches[1];
4041 $linematched++;
4042 }
4043 
4044 if (preg_match("/^\s*TITLEFONT\s+(\d+)\s*$/i", $buffer, $matches))
4045 {
4046 $this->titlefont=$matches[1];
4047 $linematched++;
4048 }
4049 
4050 if (preg_match("/^\s*NODEFONT\s+(\d+)\s*$/i", $buffer, $matches))
4051 {
4052 $this->nodefont=$matches[1];
4053 $this->defaultnode->labelfont=$matches[1];
4054 warn
4055 ("NODEFONT is deprecated. Use NODE DEFAULT and LABELFONT instead. config line $linecount\n");
4056 $linematched++;
4057 }
4058 
4059 if (preg_match("/^\s*LINKFONT\s+(\d+)\s*$/i", $buffer, $matches))
4060 {
4061 $this->linkfont=$matches[1];
4062 $this->defaultlink->bwfont=$matches[1];
4063 warn
4064 ("LINKFONT is deprecated. Use LINK DEFAULT and BWFONT instead. config line $linecount\n");
4065 $linematched++;
4066 }
4067 
4068 if (preg_match("/^\s*TIMEPOS\s+(\d+)\s+(\d+)(.*)\s*$/i", $buffer, $matches))
4069 {
4070 $this->timex=$matches[1];
4071 $this->timey=$matches[2];
4072 $extra=trim($matches[3]);
4073 
4074 if ($extra != '')
4075 $this->stamptext=$extra;
4076 
4077 $linematched++;
4078 }
4079 
4080 if(preg_match("/^\s*KEYSTYLE\s+([A-Za-z][A-Za-z0-9_]+\s+)?(classic|horizontal|vertical)\s+?(\d+)?\s*$/i",$buffer, $matches))
4081 {
4082 $whichkey = trim($matches[1]);
4083 if($whichkey == '') $whichkey = 'DEFAULT';
4084 $this->keystyle[$whichkey] = strtolower($matches[2]);
4085 
4086 if(isset($matches[3]) && $matches[3] != '')
4087 {
4088 $this->keysize[$whichkey] = $matches[3];
4089 }
4090 else
4091 {
4092 $this->keysize[$whichkey] = $this->keysize['DEFAULT'];
4093 }
4094 
4095 $linematched++;
4096 }
4097 
4098 if (preg_match("/^\s*BWLABELS\s+(bits|percent|none)\s*$/i", $buffer, $matches))
4099 {
4100 # $this->labelstyle = strtolower($matches[1]);
4101 $this->defaultlink->labelstyle=strtolower($matches[1]);
4102 warn
4103 ("BWLABELS is deprecated. Use LINK DEFAULT and BWLABEL instead. config line $linecount\n");
4104 
4105 $linematched++;
4106 }
4107 
4108 if (preg_match("/^\s*KILO\s+(\d+)\s*$/i", $buffer, $matches))
4109 {
4110 $this->kilo=$matches[1];
4111 $this->defaultlink->owner->kilo=$matches[1];
4112 $linematched++;
4113 }
4114 
4115 if (preg_match("/^\s*BACKGROUND\s+(.+)\s*$/i", $buffer, $matches))
4116 {
4117 $this->background=$matches[1];
4118 $this->used_images[] = $matches[1];
4119 $linematched++;
4120 }
4121 
4122 if (preg_match(
4123 "/^\s*(TIME|TITLE|KEYBG|KEYTEXT|KEYOUTLINE|BG)COLOR\s+(\d+)\s+(\d+)\s+(\d+)\s*$/i",
4124 $buffer,
4125 $matches))
4126 {
4127 $key=$matches[1];
4128 # "Found colour line for $key\n";
4129 $this->colours['DEFAULT'][$key]['red1']=$matches[2];
4130 $this->colours['DEFAULT'][$key]['green1']=$matches[3];
4131 $this->colours['DEFAULT'][$key]['blue1']=$matches[4];
4132 $this->colours['DEFAULT'][$key]['bottom']=-2;
4133 $this->colours['DEFAULT'][$key]['top']=-1;
4134 
4135 $linematched++;
4136 }
4137 
4138 if (($last_seen == 'NODE') && (preg_match(
4139 "/^\s*(LABELFONT|LABELFONTSHADOW|LABELBG|LABELOUTLINE)COLOR\s+(\d+)\s+(\d+)\s+(\d+)\s*$/i",
4140 $buffer,
4141 $matches)))
4142 {
4143 $key=$matches[1];
4144 # print "Found NODE colour line for $key\n";
4145 $field=strtolower($matches[1]) . 'colour';
4146 $curnode->$field=array
4147 (
4148 $matches[2],
4149 $matches[3],
4150 $matches[4]
4151 );
4152 
4153 $linematched++;
4154 }
4155 
4156 if (($last_seen == 'LINK') && (preg_match(
4157 "/^\s*(COMMENTFONT|BWBOX|BWFONT|BWOUTLINE|OUTLINE)COLOR\s+(\d+)\s+(\d+)\s+(\d+)\s*$/i",
4158 $buffer,
4159 $matches)))
4160 {
4161 $key=$matches[1];
4162 # print "Found LINK colour line for $key\n";
4163 $field=strtolower($matches[1]) . 'colour';
4164 $curlink->$field=array
4165 (
4166 $matches[2],
4167 $matches[3],
4168 $matches[4]
4169 );
4170 
4171 $linematched++;
4172 }
4173 
4174 if (($last_seen == 'NODE') && (preg_match(
4175 "/^\s*(LABELFONTSHADOW|LABELBG|LABELOUTLINE)COLOR\s+none\s*$/i",
4176 $buffer,
4177 $matches)))
4178 {
4179 $key=$matches[1];
4180 # print "Found NODE non-colour line for $key\n";
4181 $field=strtolower($matches[1]) . 'colour';
4182 $curnode->$field=array
4183 (
4184 -1,
4185 -1,
4186 -1
4187 );
4188 
4189 $linematched++;
4190 }
4191 
4192 if (($last_seen == 'LINK') && (preg_match(
4193 "/^\s*(BWBOX|BWOUTLINE|OUTLINE)COLOR\s+none\s*$/i", $buffer,
4194 $matches)))
4195 {
4196 $key=$matches[1];
4197 # print "Found LINK non-colour line for $key\n";
4198 $field=strtolower($matches[1]) . 'colour';
4199 $curlink->$field=array
4200 (
4201 -1,
4202 -1,
4203 -1
4204 );
4205 
4206 $linematched++;
4207 }
4208 
4209 if (preg_match("/^\s*HTMLSTYLE\s+(static|overlib)\s*$/i", $buffer, $matches))
4210 {
4211 $this->htmlstyle=$matches[1];
4212 $linematched++;
4213 }
4214 
4215 if ($last_seen == 'LINK' && preg_match(
4216 "/^\s*ARROWSTYLE\s+(classic|compact)\s*$/i", $buffer, $matches))
4217 {
4218 $curlink->arrowstyle=$matches[1];
4219 $linematched++;
4220 }
4221 
4222 if ($last_seen == 'LINK' && preg_match(
4223 "/^\s*ARROWSTYLE\s+(\d+)\s+(\d+)\s*$/i", $buffer, $matches))
4224 {
4225 $curlink->arrowstyle=$matches[1] . ' ' . $matches[2];
4226 $linematched++;
4227 }
4228 
4229 if ($last_seen == '---' && preg_match(
4230 "/^\s*ARROWSTYLE\s+(classic|compact)\s*$/i", $buffer, $matches))
4231 {
4232 warn ("Global ARROWSTYLE is deprecated. Use LINK DEFAULT and ARROWSTYLE instead.\n");
4233 $this->defaultlink->arrowstyle=$matches[1];
4234 $linematched++;
4235 }
4236 
4237 if (preg_match("/^\s*TITLE\s+(.*)\s*$/i", $buffer, $matches))
4238 {
4239 $this->title=$matches[1];
4240 $linematched++;
4241 }
4242 
4243 if (preg_match("/^\s*HTMLOUTPUTFILE\s+(.*)\s*$/i", $buffer, $matches))
4244 {
4245 $this->htmloutputfile=trim($matches[1]);
4246 $linematched++;
4247 }
4248 
4249 if (preg_match("/^\s*IMAGEOUTPUTFILE\s+(.*)\s*$/i", $buffer, $matches))
4250 {
4251 $this->imageoutputfile=trim($matches[1]);
4252 $linematched++;
4253 }
4254 
4255 if ($linematched == 0 && trim($buffer) != '') { warn
4256 ("Unrecognised config on line $linecount: $buffer"); }
4257 
4258 if ($linematched > 1) { warn
4259 ("Same line ($linecount) interpreted twice. This is a program error. Please report to Howie with your config!\nThe line was: $buffer");
4260 }
4261 } // if blankline
4262 } // while
4263 
4264 if ($last_seen == "NODE")
4265 {
4266 # $this->nodes[$curnode->name] = $curnode;
4267 if ($curnode->name == 'DEFAULT')
4268 {
4269 $this->defaultnode=$curnode;
4270 debug ("Saving Default Node: " . $curnode->name . "\n");
4271 }
4272 else
4273 {
4274 $this->nodes[$curnode->name]=$curnode;
4275 debug ("Saving Node: " . $curnode->name . "\n");
4276 }
4277 }
4278 
4279 if ($last_seen == "LINK")
4280 {
4281 # $this->links[$curlink->name] = $curlink;
4282 if ($curlink->name == 'DEFAULT')
4283 {
4284 $this->defaultlink=$curlink;
4285 debug ("Saving Default Link: " . $curlink->name . "\n");
4286 }
4287 else
4288 {
4289 if (isset($curlink->a) && isset($curlink->b))
4290 {
4291 $this->links[$curlink->name]=$curlink;
4292 debug ("Saving Link: " . $curlink->name . "\n");
4293 }
4294 else { warn ("Dropping LINK " . $curlink->name . " - it hasn't got 2 NODES!"); }
4295 }
4296 }
4297 } // if $fd
4298 else
4299 {
4300 warn ("Couldn't open config file $filename for reading\n");
4301 return (FALSE);
4302 }
4303 
4304 fclose ($fd);
4305 
4306 // load some default colouring, otherwise it all goes wrong
4307 if ($scalesseen == 0)
4308 {
4309 debug ("Adding default SCALE set.\n");
4310 $defaults=array
4311 (
4312 '1_10' => array('bottom' => 1, 'top' => 10, 'red1' => 140, 'green1' => 0, 'blue1' => 255),
4313 '10_25' => array('bottom' => 10, 'top' => 25, 'red1' => 32, 'green1' => 32, 'blue1' => 255),
4314 '25_40' => array('bottom' => 25, 'top' => 40, 'red1' => 0, 'green1' => 192, 'blue1' => 255),
4315 '40_55' => array('bottom' => 40, 'top' => 55, 'red1' => 0, 'green1' => 240, 'blue1' => 0),
4316 '55_70' => array('bottom' => 55, 'top' => 70, 'red1' => 240, 'green1' => 240, 'blue1' => 0),
4317 '70_85' => array('bottom' => 70, 'top' => 85, 'red1' => 255, 'green1' => 192, 'blue1' => 0),
4318 '85_100' => array('bottom' => 85, 'top' => 100, 'red1' => 255, 'green1' => 0, 'blue1' => 0)
4319 );
4320 
4321 foreach ($defaults as $key => $def)
4322 {
4323 $this->colours['DEFAULT'][$key]=$def;
4324 $scalesseen++;
4325 }
4326 }
4327 else { debug ("Already have $scalesseen scales, no defaults added.\n"); }
4328 
4329 $this->numscales['DEFAULT']=$scalesseen;
4330 $this->configfile="$filename";
4331 
4332 // calculate any relative positions here - that way, nothing else
4333 // really needs to know about them
4334 
4335 // safety net for cyclic dependencies
4336 $i=100;
4337 do
4338 {
4339 $skipped = 0; $set=0;
4340 foreach ($this->nodes as $node)
4341 {
4342 if( ($node->relative_to != '') && (!$node->relative_resolved))
4343 {
4344 debug("Resolving relative position for NODE ".$node->name." to ".$node->relative_to."\n");
4345 if(array_key_exists($node->relative_to,$this->nodes))
4346 {
4347 // check if we are relative to another node which is in turn relative to something
4348 // we need to resolve that one before we can resolve this one!
4349 if( ($this->nodes[$node->relative_to]->relative_to != '') && (!$this->nodes[$node->relative_to]->relative_resolved) )
4350 {
4351 debug("Skipping unresolved relative_to. Let's hope it's not a circular one\n");
4352 $skipped++;
4353 }
4354 else
4355 {
4356 // save the relative coords, so that WriteConfig can work
4357 // resolve the relative stuff
4358 
4359 $newpos_x = $this->nodes[$node->relative_to]->x + $this->nodes[$node->name]->x;
4360 $newpos_y = $this->nodes[$node->relative_to]->y + $this->nodes[$node->name]->y;
4361 debug("->$newpos_x,$newpos_y\n");
4362 $this->nodes[$node->name]->x = $newpos_x;
4363 $this->nodes[$node->name]->y = $newpos_y;
4364 $this->nodes[$node->name]->relative_resolved=TRUE;
4365 $set++;
4366 }
4367 }
4368 else
4369 {
4370 warn("NODE ".$node->name." has a relative position to an unknown node!\n");
4371 }
4372 }
4373 }
4374 debug("Cycle $i - set $set and Skipped $skipped for unresolved dependencies\n");
4375 $i--;
4376 } while( ($set>0) && ($i!=0) );
4377 
4378 if($skipped>0)
4379 {
4380 warn("There are Circular dependencies in relative POSITION lines for $skipped nodes.\n");
4381 }
4382 
438313simandl # warn("---\n\nDEFAULT NODE AGAIN::".var_dump($this->defaultnode->hints)."::\n");
4384 #warn("DEFAULT NOW SAYS ".$this->defaultnode->hints['sigdigits']."\n");
4385 #warn("North NOW SAYS ".$this->nodes['North']->hints['sigdigits']."\n");
43861simandl 
438713simandl 
43881simandl debug("Running Pre-Processing Plugins...\n");
4389 foreach ($this->preprocessclasses as $pre_class)
4390 {
4391 debug("Running $pre_class"."->run()\n");
4392 # call_user_func(array($pre_class, 'run'), $this);
4393 call_user_func_array(array($pre_class, 'run'), array(&$this));
4394 
4395 }
4396 debug("Finished Pre-Processing Plugins...\n");
4397 
4398 return (TRUE);
4399}
4400 
4401function WriteConfig($filename)
4402{
4403 global $WEATHERMAP_VERSION;
4404 
4405 $fd=fopen($filename, "w");
4406 $output="";
4407 
4408 if ($fd)
4409 {
4410 $output.="# Automatically generated by php-weathermap v$WEATHERMAP_VERSION\n\n";
4411 
4412 if ($this->background != '') { $output.="BACKGROUND " . $this->background . "\n"; }
4413 else
4414 {
4415 $output.="WIDTH " . $this->width . "\n";
4416 $output.="HEIGHT " . $this->height . "\n";
4417 }
4418 
4419 if ($this->htmlstyle != $this->inherit_fieldlist['htmlstyle'])
4420 { $output.="HTMLSTYLE " . $this->htmlstyle . "\n"; }
4421 
4422 # if( $this->keystyle != $this->inherit_fieldlist['keystyle']) { $output .= "KEYSTYLE ".$this->keystyle."\n"; }
4423 if ($this->kilo != $this->inherit_fieldlist['kilo']) { $output.="KILO " . $this->kilo . "\n"; }
4424 
4425 $output.="\n";
4426 
4427 if (count($this->fonts) > 0)
4428 {
4429 foreach ($this->fonts as $fontnumber => $font)
4430 {
4431 if ($font->type == 'truetype')
4432 $output.=sprintf("FONTDEFINE %d %s %d\n", $fontnumber, $font->file, $font->size);
4433 
4434 if ($font->type == 'gd')
4435 $output.=sprintf("FONTDEFINE %d %s\n", $fontnumber, $font->file);
4436 }
4437 
4438 $output.="\n";
4439 }
4440 
4441 if ($this->keyfont != $this->inherit_fieldlist['keyfont'])
4442 { $output.="KEYFONT " . $this->keyfont . "\n"; }
4443 
4444 if ($this->timefont != $this->inherit_fieldlist['timefont'])
4445 { $output.="TIMEFONT " . $this->timefont . "\n"; }
4446 
4447 if ($this->titlefont != $this->inherit_fieldlist['titlefont'])
4448 { $output.="TITLEFONT " . $this->titlefont . "\n"; }
4449 
4450 if (trim($this->title) != $this->inherit_fieldlist['title'])
4451 { $output.="TITLE " . $this->title . "\n"; }
4452 
4453 if (trim($this->htmloutputfile) != $this->inherit_fieldlist['htmloutputfile'])
4454 { $output.="HTMLOUTPUTFILE " . $this->htmloutputfile . "\n"; }
4455 
4456 if (trim($this->imageoutputfile) != $this->inherit_fieldlist['imageoutputfile'])
4457 { $output.="IMAGEOUTPUTFILE " . $this->imageoutputfile . "\n"; }
4458 
4459 if (($this->timex != $this->inherit_fieldlist['timex'])
4460 || ($this->timey != $this->inherit_fieldlist['timey'])
4461 || ($this->stamptext != $this->inherit_fieldlist['stamptext']))
4462 $output.="TIMEPOS " . $this->timex . " " . $this->timey . " " . $this->stamptext . "\n";
4463 
4464 if (($this->titlex != $this->inherit_fieldlist['titlex'])
4465 || ($this->titley != $this->inherit_fieldlist['titley']))
4466 $output.="TITLEPOS " . $this->titlex . " " . $this->titley . "\n";
4467 
4468 $output.="\n";
4469 
4470 foreach ($this->colours as $scalename=>$colours)
4471 {
4472 // not all keys will have keypos but if they do, then all three vars should be defined
4473 if ( (isset($this->keyx[$scalename]))
4474 || ($this->keytext[$scalename] != $this->inherit_fieldlist['keytext'])
4475 || ($this->keyx[$scalename] != $this->inherit_fieldlist['keyx'])
4476 || ($this->keyy[$scalename] != $this->inherit_fieldlist['keyy']))
4477 $output.="KEYPOS " . $scalename." ". $this->keyx[$scalename] . " " . $this->keyy[$scalename] . " " . $this->keytext[$scalename] . "\n";
4478 
4479 if ( (isset($this->keystyle[$scalename])) && ($this->keystyle[$scalename] != $this->inherit_fieldlist['keystyle']['DEFAULT']) )
4480 {
4481 $extra='';
4482 if ( (isset($this->keysize[$scalename])) && ($this->keysize[$scalename] != $this->inherit_fieldlist['keysize']['DEFAULT']) )
4483 {
4484 $extra = " ".$this->keysize[$scalename];
4485 }
4486 $output.="KEYSTYLE " . $scalename." ". $this->keystyle[$scalename] . $extra . "\n";
4487 }
4488 
4489 foreach ($colours as $k => $colour)
4490 {
4491 if ($colour['top'] >= 0)
4492 {
4493 $top = rtrim(rtrim(sprintf("%f",$colour['top']),"0"),".");
4494 $bottom= rtrim(rtrim(sprintf("%f",$colour['bottom']),"0"),".");
4495 
4496 if (!isset($colour['red2']))
4497 $output.=sprintf("SCALE %s %s %s %d %d %d\n", $scalename,
4498 $bottom, $top,
4499 $colour['red1'], $colour['green1'], $colour['blue1']);
4500 else
4501 $output.=sprintf("SCALE %s %s %s %d %d %d %d %d %d\n", $scalename,
4502 $bottom, $top,
4503 $colour['red1'],
4504 $colour['green1'], $colour['blue1'],
4505 $colour['red2'], $colour['green2'],
4506 $colour['blue2']);
4507 }
4508 else { $output.=sprintf("%sCOLOR %d %d %d\n", $k, $colour['red1'], $colour['green1'],
4509 $colour['blue1']); }
4510 }
4511 $output .= "\n";
4512 }
4513 
4514 foreach ($this->hints as $hintname=>$hint)
4515 {
4516 $output .= "SET $hintname $hint\n";
4517 }
4518 
4519 $output.="\n# End of global section\n\n# DEFAULT definitions:\n";
4520 
4521 fwrite($fd, $output);
4522 
4523 $this->defaultnode->WriteConfig($fd);
4524 $this->defaultlink->WriteConfig($fd);
4525 
4526 fwrite($fd, "\n# End of DEFAULTS section\n\n# Node definitions:\n");
4527 
4528 foreach ($this->nodes as $node) { $node->WriteConfig($fd); }
4529 
4530 fwrite($fd, "\n# End of NODE section\n\n# Link definitions:\n");
4531 
4532 foreach ($this->links as $link) { $link->WriteConfig($fd); }
4533 
4534 fwrite($fd, "\n# End of LINK section\n\n# That's All Folks!\n");
4535 }
4536 else
4537 {
4538 warn ("Couldn't open config file $filename for writing");
4539 return (FALSE);
4540 }
4541 
4542 return (TRUE);
4543}
4544 
4545// pre-allocate colour slots for the colours used by the arrows
4546// this way, it's the pretty icons that suffer if there aren't enough colours, and
4547// not the actual useful data
4548// we skip any gradient scales
4549function AllocateScaleColours($im)
4550{
4551 # $colours=$this->colours['DEFAULT'];
4552 foreach ($this->colours as $scalename=>$colours)
4553 {
4554 foreach ($colours as $key => $colour)
4555 {
4556 if (!isset($this->colours[$scalename][$key]['red2']))
4557 {
4558 $r=$colour['red1'];
4559 $g=$colour['green1'];
4560 $b=$colour['blue1'];
4561 debug ("AllocateScaleColours: $scalename $key ($r,$g,$b)\n");
4562 $this->colours[$scalename][$key]['gdref1']=myimagecolorallocate($im, $r, $g, $b);
4563 }
4564 }
4565 }
4566}
4567 
4568function DrawMap($filename = '', $thumbnailfile = '', $thumbnailmax = 250, $withnodes = TRUE)
4569{
4570 $bgimage=NULL;
4571 
4572 debug("Running Post-Processing Plugins...\n");
4573 foreach ($this->postprocessclasses as $post_class)
4574 {
4575 debug("Running $post_class"."->run()\n");
4576 call_user_func_array(array($post_class, 'run'), array(&$this));
4577 
4578 }
4579 debug("Finished Post-Processing Plugins...\n");
4580 
458113simandl $this->datestamp = strftime($this->stamptext, time());
4582 
45831simandl // do the basic prep work
4584 if ($this->background != '')
4585 {
4586 if (is_readable($this->background))
4587 {
4588 $bgimage=imagecreatefromfile($this->background);
4589 
4590 if (!$bgimage) { warn
4591 ("Failed to open background image. One possible reason: Is your BACKGROUND really a PNG?\n");
4592 }
4593 else
4594 {
4595 $this->width=imagesx($bgimage);
4596 $this->height=imagesy($bgimage);
4597 }
4598 }
4599 else { warn
4600 ("Your background image file could not be read. Check the filename, and permissions, for "
4601 . $this->background . "\n"); }
4602 }
4603 
4604 $image=imagecreatetruecolor($this->width, $this->height);
4605 
4606 # $image = imagecreate($this->width, $this->height);
4607 if (!$image) { warn
4608 ("Couldn't create output image in memory (" . $this->width . "x" . $this->height . ")."); }
4609 else
4610 {
4611 ImageAlphaBlending($image, true);
4612 # imageantialias($image,true);
4613 
4614 // by here, we should have a valid image handle
4615 
4616 // save this away, now
4617 $this->image=$image;
4618 
4619 $this->white=myimagecolorallocate($image, 255, 255, 255);
4620 $this->black=myimagecolorallocate($image, 0, 0, 0);
4621 $this->grey=myimagecolorallocate($image, 192, 192, 192);
4622 $this->selected=myimagecolorallocate($image, 255, 0, 0); // for selections in the editor
4623 
4624 $this->AllocateScaleColours($image);
4625 
4626 // fill with background colour anyway, in case the background image failed to load
4627 imagefilledrectangle($image, 0, 0, $this->width, $this->height, $this->colours['DEFAULT']['BG']['gdref1']);
4628 
4629 if ($bgimage)
4630 {
4631 imagecopy($image, $bgimage, 0, 0, 0, 0, $this->width, $this->height);
4632 imagedestroy ($bgimage);
4633 }
4634 
4635 // Now it's time to draw a map
4636 
4637 # foreach ($this->nodes as $node) { $this->nodes[$node->name]->calc_size(); }
4638 
4639 foreach ($this->nodes as $node) { $node->pre_render($image, $this); }
4640 foreach ($this->links as $link) { $link->Draw($image, $this); }
4641 
4642 if($withnodes)
4643 {
464413simandl foreach ($this->nodes as $node) {
4645 $node->NewDraw($image, $this);
4646 # debug($node->name.": ".var_dump($node->notes)."\n");
4647 }
4648 # debug("DEFAULT: ".var_dump($this->defaultnode->notes)."\n");
46491simandl }
4650 
4651 foreach ($this->colours as $scalename=>$colours)
4652 {
4653 debug("Drawing KEY for $scalename if necessary.\n");
4654 
4655 if( (isset($this->numscales[$scalename])) && (isset($this->keyx[$scalename])) && ($this->keyx[$scalename] >= 0) && ($this->keyy[$scalename] >= 0) )
4656 {
4657 if($this->keystyle[$scalename]=='classic') $this->DrawLegend_Classic($image,$scalename);
4658 if($this->keystyle[$scalename]=='horizontal') $this->DrawLegend_Horizontal($image,$scalename,$this->keysize[$scalename]);
4659 if($this->keystyle[$scalename]=='vertical') $this->DrawLegend_Vertical($image,$scalename,$this->keysize[$scalename]);
4660 }
4661 }
4662 
4663 $this->DrawTimestamp($image, $this->timefont, $this->colours['DEFAULT']['TIME']['gdref1']);
4664 $this->DrawTitle($image, $this->titlefont, $this->colours['DEFAULT']['TITLE']['gdref1']);
4665 
4666 # $this->DrawNINK($image,300,300,48);
4667 
4668 // Ready to output the results...
4669 
4670 if($filename == 'null')
4671 {
4672 // do nothing at all - we just wanted the HTML AREAs for the editor or HTML output
4673 }
4674 else
4675 {
4676 if ($filename == '') { imagepng ($image); }
4677 else {
4678 $result = FALSE;
4679 $functions = TRUE;
4680 if(function_exists('imagejpeg') && preg_match("/\.jpg/i",$filename))
4681 {
4682 debug("Writing JPEG file\n");
4683 $result = imagejpeg($image, $filename);
4684 }
4685 elseif(function_exists('imagegif') && preg_match("/\.gif/i",$filename))
4686 {
4687 debug("Writing GIF file\n");
4688 $result = imagegif($image, $filename);
4689 }
4690 elseif(function_exists('imagepng') && preg_match("/\.png/i",$filename))
4691 {
4692 debug("Writing PNG file\n");
4693 $result = imagepng($image, $filename);
4694 }
4695 else
4696 {
4697 warn("Failed to write map image. No function existed for the image format you requested.\n");
4698 $functions = FALSE;
4699 }
4700 
4701 if(($result==FALSE) && ($functions==TRUE))
4702 {
4703 if(file_exists($filename))
4704 {
4705 warn("Failed to overwrite existing image file $filename - permissions of existing file are wrong?");
4706 }
4707 else
4708 {
4709 warn("Failed to create image file $filename - permissions of output directory are wrong?");
4710 }
4711 }
4712 }
4713 }
4714 
4715 if($this->context == 'editor2')
4716 {
4717 $cachefile = $this->cachefolder.DIRECTORY_SEPARATOR.dechex(crc32($this->configfile))."_bg.png";
4718 imagepng($image, $cachefile);
4719 $cacheuri = $this->cachefolder.'/'.dechex(crc32($this->configfile))."_bg.png";
4720 $this->mapcache = $cacheuri;
4721 }
4722 
4723 if (function_exists('imagecopyresampled'))
4724 {
4725 // if one is specified, and we can, write a thumbnail too
4726 if ($thumbnailfile != '')
4727 {
4728 $result = FALSE;
4729 if ($this->width > $this->height) { $factor=($thumbnailmax / $this->width); }
4730 else { $factor=($thumbnailmax / $this->height); }
4731 
4732 $twidth=$this->width * $factor;
4733 $theight=$this->height * $factor;
4734 
4735 $imagethumb=imagecreatetruecolor($twidth, $theight);
4736 imagecopyresampled($imagethumb, $image, 0, 0, 0, 0, $twidth, $theight,
4737 $this->width, $this->height);
4738 $result = imagepng($imagethumb, $thumbnailfile);
473913simandl imagedestroy($imagethumb);
47401simandl 
4741 if(($result==FALSE))
4742 {
4743 if(file_exists($filename))
4744 {
4745 warn("Failed to overwrite existing image file $filename - permissions of existing file are wrong?");
4746 }
4747 else
4748 {
4749 warn("Failed to create image file $filename - permissions of output directory are wrong?");
4750 }
4751 }
4752 }
4753 }
4754 else
4755 {
4756 warn("Skipping thumbnail creation, since we don't have the necessary function.");
4757 }
4758 imagedestroy ($image);
4759 }
4760}
4761 
4762function CleanUp()
4763{
4764 // destroy all the images we created, to prevent memory leaks
4765 foreach ($this->nodes as $node) { if(isset($node->image)) imagedestroy($node->image); }
476613simandl #foreach ($this->nodes as $node) { unset($node); }
4767 #foreach ($this->links as $link) { unset($link); }
47681simandl 
4769}
4770 
4771function PreloadMapHTML()
4772{
4773 if ($this->htmlstyle == "overlib")
4774 {
4775 // onmouseover="return overlib('<img src=graph.png>',DELAY,250,CAPTION,'$caption');" onmouseout="return nd();"
4776 
4777 $center_x=$this->width / 2;
4778 $center_y=$this->height / 2;
4779 
4780 foreach ($this->links as $link)
4781 {
4782 if ( ($link->overliburl != '') || ($link->notestext != '') )
4783 {
478413simandl # $overlibhtml = "onmouseover=\"return overlib('&lt;img src=".$link->overliburl."&gt;',DELAY,250,CAPTION,'".$link->name."');\" onmouseout=\"return nd();\"";
47851simandl $a_x=$link->a->x;
4786 $b_x=$link->b->x;
4787 $mid_x=($a_x + $b_x) / 2;
4788 $a_y=$link->a->y;
4789 $b_y=$link->b->y;
4790 $mid_y=($a_y + $b_y) / 2;
4791 
4792 # debug($link->overlibwidth."---".$link->overlibheight."---\n");
4793 
4794 $left="";
4795 $above="";
4796 
4797 if ($link->overlibwidth != 0)
4798 {
4799 $left="WIDTH," . $link->overlibwidth . ",";
4800 
4801 if ($mid_x > $center_x)
4802 $left.="LEFT,";
4803 }
4804 
4805 if ($link->overlibheight != 0)
4806 {
4807 $above="HEIGHT," . $link->overlibheight . ",";
4808 
4809 if ($mid_y > $center_y)
4810 $above.="ABOVE,";
4811 }
4812 
4813 $caption = ($link->overlibcaption != '' ? $link->overlibcaption : $link->name);
4814 $caption = $this->ProcessString($caption,$link);
4815 
4816 $overlibhtml = "onmouseover=\"return overlib('";
4817 if($link->overliburl != '')
4818 {
4819 $overlibhtml .= "&lt;img src=" . $this->ProcessString($link->overliburl,$link) . "&gt;";
4820 }
4821 if($link->notestext != '')
4822 {
4823 # put in a linebreak if there was an image AND notes
4824 if($link->overliburl != '') $overlibhtml .= '&lt;br /&gt;';
4825 $note = $this->ProcessString($link->notestext,$link);
4826 $note = htmlspecialchars($note, ENT_NOQUOTES);
4827 $note=str_replace("'", "\\&apos;", $note);
4828 $note=str_replace('"', "&quot;", $note);
4829 $overlibhtml .= $note;
4830 }
483113simandl $overlibhtml .= "',DELAY,250,${left}${above}CAPTION,'" . $caption
48321simandl . "');\" onmouseout=\"return nd();\"";
4833 
4834 $this->imap->setProp("extrahtml", $overlibhtml, "LINK:" . $link->name);
4835 }
4836 }
4837 
4838 foreach ($this->nodes as $node)
4839 {
4840 if ( ($node->overliburl != '') || ($node->notestext != '') )
4841 {
484213simandl # $overlibhtml = "onmouseover=\"return overlib('&lt;img src=".$node->overliburl."&gt;',DELAY,250,CAPTION,'".$node->name."');\" onmouseout=\"return nd();\"";
48431simandl 
4844 debug ($node->overlibwidth . "---" . $node->overlibheight . "---\n");
4845 
4846 $left="";
4847 $above="";
4848 
4849 if ($node->overlibwidth != 0)
4850 {
4851 $left="WIDTH," . $node->overlibwidth . ",";
4852 
4853 if ($node->x > $center_x)
4854 $left.="LEFT,";
4855 }
4856 
4857 if ($node->overlibheight != 0)
4858 {
4859 $above="HEIGHT," . $node->overlibheight . ",";
4860 
4861 if ($node->y > $center_y)
4862 $above.="ABOVE,";
4863 }
4864 
4865 $caption = ($node->overlibcaption != '' ? $node->overlibcaption : $node->name);
4866 $caption = $this->ProcessString($caption,$node);
4867 
4868 $overlibhtml = "onmouseover=\"return overlib('";
4869 if($node->overliburl != '')
4870 {
4871 $overlibhtml .= "&lt;img src=" . $this->ProcessString($node->overliburl,$node) . "&gt;";
4872 }
4873 if($node->notestext != '')
4874 {
4875 # put in a linebreak if there was an image AND notes
4876 if($node->overliburl != '') $overlibhtml .= '&lt;br /&gt;';
4877 $note = $this->ProcessString($node->notestext,$node);
4878 $note = htmlspecialchars($note, ENT_NOQUOTES);
4879 $note=str_replace("'", "\\&apos;", $note);
4880 $note=str_replace('"', "&quot;", $note);
4881 $overlibhtml .= $note;
4882 }
488313simandl $overlibhtml .= "',DELAY,250,${left}${above}CAPTION,'" . $caption
48841simandl . "');\" onmouseout=\"return nd();\"";
4885 
4886 # $overlibhtml .= " onclick=\"return overlib('Some Test or other',CAPTION,'MENU',)\"";
4887 
4888 $this->imap->setProp("extrahtml", $overlibhtml, "NODE:" . $node->name);
4889 }
4890 }
4891 }
4892 
4893 if ($this->htmlstyle == 'editor')
4894 {
4895 foreach ($this->links as $link) {
4896 # $this->imap->setProp("href","#","LINK:".$link->name);
4897 # $this->imap->setProp("extrahtml","onclick=\"click_handler('link','".$link->name."');\"","LINK:".$link->name);
4898 }
4899 
4900 foreach ($this->nodes as $node) {
4901 # $this->imap->setProp("href","#","NODE:".$node->name);
4902 # $this->imap->setProp("extrahtml","onclick=\"click_handler('node','".$node->name."');\"","NODE:".$node->name);
4903 # $this->imap->setProp("extrahtml","onclick=\"alert('".$node->name."');\"","NODE:".$node->name);
4904 }
4905 }
4906 else
4907 {
4908 foreach ($this->links as $link)
4909 {
4910 if ($link->infourl != '') { $this->imap->setProp("href", $this->ProcessString($link->infourl,$link),
4911 "LINK:" . $link->name); }
4912 }
4913 
4914 foreach ($this->nodes as $node)
4915 {
4916 if ($node->infourl != '') { $this->imap->setProp("href", $this->ProcessString($node->infourl,$node),
4917 "NODE:" . $node->name); }
4918 }
4919 }
4920}
4921 
4922function asJS()
4923{
4924 $js='';
4925 
4926 $js.="var Links = new Array();\n";
4927 $js.=$this->defaultlink->asJS();
4928 
4929 foreach ($this->links as $link) { $js.=$link->asJS(); }
4930 
4931 $js.="var Nodes = new Array();\n";
4932 $js.=$this->defaultnode->asJS();
4933 
4934 foreach ($this->nodes as $node) { $js.=$node->asJS(); }
4935 
4936 return $js;
4937}
4938 
4939function asJSON()
4940{
4941 $json = '';
4942 
4943 $json .= "{ \n";
4944 
4945 $json .= "'map': { \n";
4946 foreach (array_keys($this->inherit_fieldlist)as $fld)
4947 {
4948 $json .= js_escape($fld).": ";
4949 $json .= js_escape($this->$fld);
4950 $json .= ",\n";
4951 }
4952 $json = rtrim($json,", \n");
4953 $json .= "\n},\n";
4954 
4955 $json .= "'nodes': {\n";
4956 $json .= $this->defaultnode->asJSON();
4957 foreach ($this->nodes as $node) { $json .= $node->asJSON(); }
4958 $json = rtrim($json,", \n");
4959 $json .= "\n},\n";
4960 
4961 
4962 
4963 $json .= "'links': {\n";
4964 $json .= $this->defaultlink->asJSON();
4965 foreach ($this->links as $link) { $json .= $link->asJSON(); }
4966 $json = rtrim($json,", \n");
4967 $json .= "\n},\n";
4968 
4969 $json .= "'imap': [\n";
4970 $json .= $this->imap->subJSON("NODE:");
4971 // should check if there WERE nodes...
4972 $json .= ",\n";
4973 $json .= $this->imap->subJSON("LINK:");
4974 $json .= "\n]\n";
4975 $json .= "\n";
4976 
4977 $json .= ", valid: 1}\n";
4978 
4979 return($json);
4980}
4981 
4982// imagemapname is a parameter, so we can stack up several maps in the Cacti plugin
4983function MakeHTML($imagemapname = "weathermap_imap")
4984{
4985 $this->PreloadMapHTML();
4986 
4987 $html='';
4988 
498924simandl $html .= '<div class="weathermapimage" style="margin-left: 10px; margin-right: auto; width: '.$this->width.'px;" >';
49901simandl if ($this->imageuri != '') { $html.=sprintf(
4991 '<img src="%s" width="%s" height="%s" border="0" usemap="#'
4992 . $imagemapname . '" alt="network weathermap" />',
4993 $this->imageuri,
4994 $this->width,
4995 $this->height); }
4996 else { $html.=sprintf(
4997 '<img src="%s" width="%s" height="%s" border="0" usemap="#' . $imagemapname
4998 . '" alt="network weathermap" />',
4999 $this->imagefile,
5000 $this->width,
5001 $this->height); }
5002 $html .= '</div>';
5003 
500430simandl $html.='<map name="' . $imagemapname . '" id="' . $imagemapname . '">' . "\n";
50051simandl 
5006 $html.=$this->imap->subHTML("NODE:",true);
5007 $html.=$this->imap->subHTML("LINK:",true);
5008 
5009 $html.='</map>';
5010 
5011 return ($html);
5012}
5013 
5014// update any editor cache files.
5015// if the config file is newer than the cache files, or $agelimit seconds have passed,
5016// then write new stuff, otherwise just return.
5017// ALWAYS deletes files in the cache folder older than $agelimit, also!
5018function CacheUpdate($agelimit=600)
5019{
5020 $cachefolder = $this->cachefolder;
5021 $configchanged = filemtime($this->configfile );
5022 // make a unique, but safe, prefix for all cachefiles related to this map config
5023 // we use CRC32 because it makes for a shorter filename, and collisions aren't the end of the world.
5024 $cacheprefix = dechex(crc32($this->configfile));
5025 
5026 debug("Comparing files in $cachefolder starting with $cacheprefix, with date of $configchanged\n");
5027 
5028 $dh=opendir($cachefolder);
5029 
5030 if ($dh)
5031 {
5032 while ($file=readdir($dh))
5033 {
5034 $realfile = $cachefolder . DIRECTORY_SEPARATOR . $file;
5035 
5036 if(is_file($realfile) && ( preg_match('/^'.$cacheprefix.'/',$file) ))
5037 // if (is_file($realfile) )
5038 {
5039 debug("$realfile\n");
5040 if( (filemtime($realfile) < $configchanged) || ((time() - filemtime($realfile)) > $agelimit) )
5041 {
5042 debug("Cache: deleting $realfile\n");
5043 unlink($realfile);
5044 }
5045 }
5046 }
5047 
5048 closedir ($dh);
5049 
5050 foreach ($this->nodes as $node)
5051 {
5052 if(isset($node->image))
5053 {
5054 $nodefile = $cacheprefix."_".dechex(crc32($node->name)).".png";
5055 $this->nodes[$node->name]->cachefile = $nodefile;
5056 imagepng($node->image,$cachefolder.DIRECTORY_SEPARATOR.$nodefile);
5057 }
5058 }
5059 
5060 $json = "";
5061 $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_map.json","w");
5062 foreach (array_keys($this->inherit_fieldlist)as $fld)
5063 {
5064 $json .= js_escape($fld).": ";
5065 $json .= js_escape($this->$fld);
5066 $json .= ",\n";
5067 }
5068 $json = rtrim($json,", \n");
5069 fputs($fd,$json);
5070 fclose($fd);
5071 
5072 $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_nodes.json","w");
5073 $json = $this->defaultnode->asJSON();
5074 foreach ($this->nodes as $node) { $json .= $node->asJSON(); }
5075 $json = rtrim($json,", \n");
5076 fputs($fd,$json);
5077 fclose($fd);
5078 
5079 $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_links.json","w");
5080 $json = $this->defaultlink->asJSON();
5081 foreach ($this->links as $link) { $json .= $link->asJSON(); }
5082 $json = rtrim($json,", \n");
5083 fputs($fd,$json);
5084 fclose($fd);
5085 
5086 $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_imap.json","w");
5087 $json = '';
5088 $nodejson = trim($this->imap->subJSON("NODE:"));
5089 if($nodejson != '')
5090 {
5091 $json .= $nodejson;
5092 // should check if there WERE nodes...
5093 $json .= ",\n";
5094 }
5095 $json .= $this->imap->subJSON("LINK:");
5096 fputs($fd,$json);
5097 fclose($fd);
5098 
5099 }
5100 else { debug("Couldn't read cache folder.\n"); }
5101}
5102};
5103// vim:ts=4:sw=4:
5104?>

Powered by WebSVN 2.2.1