jablonka.czprosek.czf

weathermap

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

 

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

Powered by WebSVN 2.2.1