jablonka.czprosek.czf

weathermap

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

 

Line No. Rev Author Line
11simandl<?php
285simandl// PHP Weathermap 0.97a
3// Copyright Howard Jones, 2005-2010 howie@thingy.com
41simandl// http://www.network-weathermap.com/
5// Released under the GNU Public License
6 
7require_once "HTML_ImageMap.class.php";
8 
985simandlrequire_once "WeatherMap.functions.php";
10require_once "WeatherMapNode.class.php";
11require_once "WeatherMapLink.class.php";
12 
13$WEATHERMAP_VERSION="0.97a";
141simandl$weathermap_debugging=FALSE;
1585simandl$weathermap_map="";
16$weathermap_warncount=0;
17$weathermap_debug_suppress = array("processstring","mysprintf");
18$weathemap_lazycounter=0;
191simandl 
20// Turn on ALL error reporting for now.
2185simandl// error_reporting (E_ALL|E_STRICT);
221simandl 
2313simandl// parameterise the in/out stuff a bit
24define("IN",0);
25define("OUT",1);
26define("WMCHANNELS",2);
27 
2885simandldefine('CONFIG_TYPE_LITERAL',0);
29define('CONFIG_TYPE_COLOR',1);
301simandl 
3185simandl// some strings that are used in more than one place
32define('FMT_BITS_IN',"{link:this:bandwidth_in:%2k}");
33define('FMT_BITS_OUT',"{link:this:bandwidth_out:%2k}");
34define('FMT_UNFORM_IN',"{link:this:bandwidth_in}");
35define('FMT_UNFORM_OUT',"{link:this:bandwidth_out}");
36define('FMT_PERC_IN',"{link:this:inpercent:%.2f}%");
37define('FMT_PERC_OUT',"{link:this:outpercent:%.2f}%");
381simandl 
3985simandl// the fields within a spine triple
40define("X",0);
41define("Y",1);
42define("DISTANCE",2);
431simandl 
44// ***********************************************
45 
46// template class for data sources. All data sources extend this class.
47// I really wish PHP4 would just die overnight
48class WeatherMapDataSource
49{
50 // Initialize - called after config has been read (so SETs are processed)
51 // but just before ReadData. Used to allow plugins to verify their dependencies
52 // (if any) and bow out gracefully. Return FALSE to signal that the plugin is not
53 // in a fit state to run at the moment.
54 function Init(&$map) { return TRUE; }
55 
56 // called with the TARGET string. Returns TRUE or FALSE, depending on whether it wants to handle this TARGET
57 // called by map->ReadData()
58 function Recognise( $targetstring ) { return FALSE; }
59 
60 // the actual ReadData
61 // returns an array of two values (in,out). -1,-1 if it couldn't get valid data
62 // configline is passed in, to allow for better error messages
63 // itemtype and itemname may be used as part of the target (e.g. for TSV source line)
6485simandl // function ReadData($targetstring, $configline, $itemtype, $itemname, $map) { return (array(-1,-1)); }
65 function ReadData($targetstring, &$map, &$item)
66 {
67 return(array(-1,-1));
68 }
69 
70 // pre-register a target + context, to allow a plugin to batch up queries to a slow database, or snmp for example
71 function Register($targetstring, &$map, &$item)
72 {
73 
74 }
75 
76 // called before ReadData, to allow plugins to DO the prefetch of targets known from Register
77 function Prefetch()
78 {
79 
80 }
811simandl}
82 
83// template classes for the pre- and post-processor plugins
84class WeatherMapPreProcessor
85{
86 function run($map) { return FALSE; }
87}
88 
89class WeatherMapPostProcessor
90{
91 function run($map) { return FALSE; }
92}
93 
94// ***********************************************
95 
96// Links, Nodes and the Map object inherit from this class ultimately.
97// Just to make some common code common.
98class WeatherMapBase
99{
100 var $notes = array();
101 var $hints = array();
102 var $inherit_fieldlist;
103 
104 function add_note($name,$value)
105 {
10685simandl debug("Adding note $name='$value' to ".$this->name."\n");
1071simandl $this->notes[$name] = $value;
108 }
109 
110 function get_note($name)
111 {
112 if(isset($this->notes[$name]))
113 {
11485simandl // debug("Found note $name in ".$this->name." with value of ".$this->notes[$name].".\n");
1151simandl return($this->notes[$name]);
116 }
117 else
118 {
11985simandl // debug("Looked for note $name in ".$this->name." which doesn't exist.\n");
1201simandl return(NULL);
121 }
122 }
123 
124 function add_hint($name,$value)
125 {
12685simandl debug("Adding hint $name='$value' to ".$this->name."\n");
1271simandl $this->hints[$name] = $value;
12813simandl # warn("Adding hint $name to ".$this->my_type()."/".$this->name."\n");
1291simandl }
130 
131 
132 function get_hint($name)
133 {
134 if(isset($this->hints[$name]))
135 {
13685simandl // debug("Found hint $name in ".$this->name." with value of ".$this->hints[$name].".\n");
1371simandl return($this->hints[$name]);
138 }
139 else
140 {
14185simandl // debug("Looked for hint $name in ".$this->name." which doesn't exist.\n");
1421simandl return(NULL);
143 }
144 }
145}
146 
14785simandlclass WeatherMapConfigItem
148{
149 var $defined_in;
150 var $name;
151 var $value;
152 var $type;
153}
154 
1551simandl// The 'things on the map' class. More common code (mainly variables, actually)
156class WeatherMapItem extends WeatherMapBase
157{
158 var $owner;
159 
160 var $configline;
161 var $infourl;
162 var $overliburl;
163 var $overlibwidth, $overlibheight;
164 var $overlibcaption;
165 var $my_default;
16685simandl var $defined_in;
167 var $config_override; # used by the editor to allow text-editing
1681simandl 
169 function my_type() { return "ITEM"; }
170}
171 
172class WeatherMap extends WeatherMapBase
173{
174 var $nodes = array(); // an array of WeatherMapNodes
175 var $links = array(); // an array of WeatherMapLinks
176 var $texts = array(); // an array containing all the extraneous text bits
177 var $used_images = array(); // an array of image filenames referred to (used by editor)
17885simandl var $seen_zlayers = array(0=>array(),1000=>array()); // 0 is the background, 1000 is the legends, title, etc
179 
180 var $config;
181 var $next_id;
182 var $min_ds_time;
183 var $max_ds_time;
1841simandl var $background;
185 var $htmlstyle;
186 var $imap;
187 var $colours;
188 var $configfile;
189 var $imagefile,
190 $imageuri;
191 var $rrdtool;
192 var $title,
193 $titlefont;
194 var $kilo;
195 var $sizedebug,
196 $widthmod,
197 $debugging;
198 var $linkfont,
199 $nodefont,
200 $keyfont,
201 $timefont;
202 // var $bg_r, $bg_g, $bg_b;
203 var $timex,
204 $timey;
205 var $width,
206 $height;
207 var $keyx,
20885simandl $keyy, $keyimage;
2091simandl var $titlex,
210 $titley;
211 var $keytext,
21213simandl $stamptext, $datestamp;
21385simandl var $min_data_time, $max_data_time;
2141simandl var $htmloutputfile,
215 $imageoutputfile;
21685simandl var $htmlstylesheet;
2171simandl var $defaultlink,
218 $defaultnode;
219 var $need_size_precalc;
220 var $keystyle,$keysize;
221 var $rrdtool_check;
222 var $inherit_fieldlist;
22385simandl var $mintimex, $maxtimex;
224 var $mintimey, $maxtimey;
225 var $minstamptext, $maxstamptext;
2261simandl var $context;
22785simandl var $cachefolder,$mapcache,$cachefile_version;
2281simandl var $name;
229 var $black,
230 $white,
231 $grey,
232 $selected;
233 
234 var $datasourceclasses;
235 var $preprocessclasses;
236 var $postprocessclasses;
237 var $activedatasourceclasses;
23885simandl var $thumb_width, $thumb_height;
239 var $has_includes;
240 var $has_overlibs;
241 var $node_template_tree;
242 var $link_template_tree;
2431simandl 
24485simandl var $plugins = array();
245 var $included_files = array();
246 var $usage_stats = array();
247 
2481simandl function WeatherMap()
249 {
250 $this->inherit_fieldlist=array
251 (
252 'width' => 800,
253 'height' => 600,
254 'kilo' => 1000,
255 'numscales' => array('DEFAULT' => 0),
256 'datasourceclasses' => array(),
257 'preprocessclasses' => array(),
258 'postprocessclasses' => array(),
25985simandl 'included_files' => array(),
2601simandl 'context' => '',
261 'dumpconfig' => FALSE,
262 'rrdtool_check' => '',
263 'background' => '',
264 'imageoutputfile' => '',
26585simandl 'imageuri' => '',
2661simandl 'htmloutputfile' => '',
26785simandl 'htmlstylesheet' => '',
2681simandl 'labelstyle' => 'percent', // redundant?
269 'htmlstyle' => 'static',
270 'keystyle' => array('DEFAULT' => 'classic'),
271 'title' => 'Network Weathermap',
272 'keytext' => array('DEFAULT' => 'Traffic Load'),
273 'keyx' => array('DEFAULT' => -1),
274 'keyy' => array('DEFAULT' => -1),
27585simandl 'keyimage' => array(),
2761simandl 'keysize' => array('DEFAULT' => 400),
277 'stamptext' => 'Created: %b %d %Y %H:%M:%S',
278 'keyfont' => 4,
279 'titlefont' => 2,
28085simandl 'timefont' => 2,
2811simandl 'timex' => 0,
282 'timey' => 0,
28385simandl 
284 'mintimex' => -10000,
285 'mintimey' => -10000,
286 'maxtimex' => -10000,
287 'maxtimey' => -10000,
288 'minstamptext' => 'Oldest Data: %b %d %Y %H:%M:%S',
289 'maxstamptext' => 'Newest Data: %b %d %Y %H:%M:%S',
290 
291 'thumb_width' => 0,
292 'thumb_height' => 0,
2931simandl 'titlex' => -1,
294 'titley' => -1,
295 'cachefolder' => 'cached',
296 'mapcache' => '',
297 'sizedebug' => FALSE,
298 'debugging' => FALSE,
299 'widthmod' => FALSE,
30085simandl 'has_includes' => FALSE,
301 'has_overlibs' => FALSE,
302 'name' => 'MAP'
3031simandl );
304 
305 $this->Reset();
306 }
307 
30885simandl function my_type() { return "MAP"; }
309 
3101simandl function Reset()
311 {
31285simandl $this->next_id = 100;
3131simandl foreach (array_keys($this->inherit_fieldlist)as $fld) { $this->$fld=$this->inherit_fieldlist[$fld]; }
31485simandl 
315 $this->min_ds_time = NULL;
316 $this->max_ds_time = NULL;
3171simandl 
31885simandl $this->need_size_precalc=FALSE;
3191simandl 
32085simandl $this->nodes=array(); // an array of WeatherMapNodes
321 $this->links=array(); // an array of WeatherMapLinks
322 
323 // these are the default defaults
324 // by putting them into a normal object, we can use the
325 // same code for writing out LINK DEFAULT as any other link.
326 debug("Creating ':: DEFAULT ::' DEFAULT LINK\n");
327 // these two are used for default settings
328 $deflink = new WeatherMapLink;
329 $deflink->name=":: DEFAULT ::";
330 $deflink->template=":: DEFAULT ::";
331 $deflink->Reset($this);
332 
333 $this->links[':: DEFAULT ::'] = &$deflink;
3341simandl 
33585simandl debug("Creating ':: DEFAULT ::' DEFAULT NODE\n");
336 $defnode = new WeatherMapNode;
337 $defnode->name=":: DEFAULT ::";
338 $defnode->template=":: DEFAULT ::";
339 $defnode->Reset($this);
340 
341 $this->nodes[':: DEFAULT ::'] = &$defnode;
342 
343 $this->node_template_tree = array();
344 $this->link_template_tree = array();
345 
346 $this->node_template_tree['DEFAULT'] = array();
347 $this->link_template_tree['DEFAULT'] = array();
3481simandl 
349 
35085simandl// ************************************
351 // now create the DEFAULT link and node, based on those.
352 // these can be modified by the user, but their template (and therefore comparison in WriteConfig) is ':: DEFAULT ::'
353 debug("Creating actual DEFAULT NODE from :: DEFAULT ::\n");
354 $defnode2 = new WeatherMapNode;
355 $defnode2->name = "DEFAULT";
356 $defnode2->template = ":: DEFAULT ::";
357 $defnode2->Reset($this);
358 
359 $this->nodes['DEFAULT'] = &$defnode2;
3601simandl 
36185simandl debug("Creating actual DEFAULT LINK from :: DEFAULT ::\n");
362 $deflink2 = new WeatherMapLink;
363 $deflink2->name = "DEFAULT";
364 $deflink2->template = ":: DEFAULT ::";
365 $deflink2->Reset($this);
366 
367 $this->links['DEFAULT'] = &$deflink2;
368 
369// for now, make the old defaultlink and defaultnode work too.
370// $this->defaultlink = $this->links['DEFAULT'];
371// $this->defaultnode = $this->nodes['DEFAULT'];
372 
373 assert('is_object($this->nodes[":: DEFAULT ::"])');
374 assert('is_object($this->links[":: DEFAULT ::"])');
375 assert('is_object($this->nodes["DEFAULT"])');
376 assert('is_object($this->links["DEFAULT"])');
377 
378// ************************************
379 
380 
3811simandl $this->imap=new HTML_ImageMap('weathermap');
382 $this->colours=array
383 (
384 );
385 
386 debug ("Adding default map colour set.\n");
387 $defaults=array
388 (
38985simandl 'KEYTEXT' => array('bottom' => -2, 'top' => -1, 'red1' => 0, 'green1' => 0, 'blue1' => 0, 'special' => 1),
390 'KEYOUTLINE' => array('bottom' => -2, 'top' => -1, 'red1' => 0, 'green1' => 0, 'blue1' => 0, 'special' => 1),
391 'KEYBG' => array('bottom' => -2, 'top' => -1, 'red1' => 255, 'green1' => 255, 'blue1' => 255, 'special' => 1),
392 'BG' => array('bottom' => -2, 'top' => -1, 'red1' => 255, 'green1' => 255, 'blue1' => 255, 'special' => 1),
393 'TITLE' => array('bottom' => -2, 'top' => -1, 'red1' => 0, 'green1' => 0, 'blue1' => 0, 'special' => 1),
394 'TIME' => array('bottom' => -2, 'top' => -1, 'red1' => 0, 'green1' => 0, 'blue1' => 0, 'special' => 1)
3951simandl );
396 
397 foreach ($defaults as $key => $def) { $this->colours['DEFAULT'][$key]=$def; }
398 
399 $this->configfile='';
400 $this->imagefile='';
401 $this->imageuri='';
402 
40313simandl $this->fonts=array();
4041simandl 
40513simandl // Adding these makes the editor's job a little easier, mainly
406 for($i=1; $i<=5; $i++)
407 {
408 $this->fonts[$i]->type="GD builtin";
409 $this->fonts[$i]->file='';
410 $this->fonts[$i]->size=0;
411 }
412 
4131simandl $this->LoadPlugins('data', 'lib' . DIRECTORY_SEPARATOR . 'datasources');
414 $this->LoadPlugins('pre', 'lib' . DIRECTORY_SEPARATOR . 'pre');
415 $this->LoadPlugins('post', 'lib' . DIRECTORY_SEPARATOR . 'post');
416 
417 debug("WeatherMap class Reset() complete\n");
418 }
419 
420 function myimagestring($image, $fontnumber, $x, $y, $string, $colour, $angle=0)
421 {
422 // if it's supposed to be a special font, and it hasn't been defined, then fall through
423 if ($fontnumber > 5 && !isset($this->fonts[$fontnumber]))
424 {
42585simandl warn ("Using a non-existent special font ($fontnumber) - falling back to internal GD fonts [WMWARN03]\n");
426 if($angle != 0) warn("Angled text doesn't work with non-FreeType fonts [WMWARN02]\n");
4271simandl $fontnumber=5;
428 }
429 
430 if (($fontnumber > 0) && ($fontnumber < 6))
431 {
432 imagestring($image, $fontnumber, $x, $y - imagefontheight($fontnumber), $string, $colour);
43385simandl if($angle != 0) warn("Angled text doesn't work with non-FreeType fonts [WMWARN02]\n");
4341simandl }
435 else
436 {
437 // look up what font is defined for this slot number
438 if ($this->fonts[$fontnumber]->type == 'truetype')
439 {
44085simandl wimagettftext($image, $this->fonts[$fontnumber]->size, $angle, $x, $y,
4411simandl $colour, $this->fonts[$fontnumber]->file, $string);
442 }
443 
444 if ($this->fonts[$fontnumber]->type == 'gd')
445 {
446 imagestring($image, $this->fonts[$fontnumber]->gdnumber,
447 $x, $y - imagefontheight($this->fonts[$fontnumber]->gdnumber),
448 $string, $colour);
44985simandl if($angle != 0) warn("Angled text doesn't work with non-FreeType fonts [WMWARN04]\n");
4501simandl }
451 }
452 }
453 
454 function myimagestringsize($fontnumber, $string)
455 {
45685simandl $linecount = 1;
457 
458 $lines = split("\n",$string);
459 $linecount = sizeof($lines);
460 $maxlinelength=0;
461 foreach($lines as $line)
462 {
463 $l = strlen($line);
464 if($l > $maxlinelength) $maxlinelength = $l;
465 }
466 
4671simandl if (($fontnumber > 0) && ($fontnumber < 6))
46885simandl { return array(imagefontwidth($fontnumber) * $maxlinelength, $linecount * imagefontheight($fontnumber)); }
4691simandl else
470 {
471 // look up what font is defined for this slot number
472 if (!isset($this->fonts[$fontnumber]))
473 {
47485simandl warn ("Using a non-existent special font ($fontnumber) - falling back to internal GD fonts [WMWARN36]\n");
4751simandl $fontnumber=5;
47685simandl return array(imagefontwidth($fontnumber) * $maxlinelength, $linecount * imagefontheight($fontnumber));
4771simandl }
478 else
479 {
480 if ($this->fonts[$fontnumber]->type == 'truetype')
481 {
48285simandl $ysize = 0;
483 $xsize = 0;
484 foreach($lines as $line)
485 {
486 $bounds=imagettfbbox($this->fonts[$fontnumber]->size, 0, $this->fonts[$fontnumber]->file, $line);
487 $cx = $bounds[4] - $bounds[0];
488 $cy = $bounds[1] - $bounds[5];
489 if($cx > $xsize) $xsize = $cx;
490 $ysize += ($cy*1.2);
491 # warn("Adding $cy (x was $cx)\n");
492 }
493 #$bounds=imagettfbbox($this->fonts[$fontnumber]->size, 0, $this->fonts[$fontnumber]->file,
494 # $string);
495 # return (array($bounds[4] - $bounds[0], $bounds[1] - $bounds[5]));
496 # warn("Size of $string is $xsize x $ysize over $linecount lines\n");
497 
498 return(array($xsize,$ysize));
4991simandl }
500 
501 if ($this->fonts[$fontnumber]->type == 'gd')
50285simandl { return array(imagefontwidth($this->fonts[$fontnumber]->gdnumber) * $maxlinelength,
503 $linecount * imagefontheight($this->fonts[$fontnumber]->gdnumber)); }
5041simandl }
505 }
506 }
507 
50885simandl function ProcessString($input,&$context, $include_notes=TRUE,$multiline=FALSE)
5091simandl {
510 # debug("ProcessString: input is $input\n");
511 
51285simandl assert('is_scalar($input)');
513 
514 $context_description = strtolower( $context->my_type() );
515 if($context_description != "map") $context_description .= ":" . $context->name;
516 
517 debug("Trace: ProcessString($input, $context_description)\n");
518 
519 if($multiline==TRUE)
520 {
521 $i = $input;
522 $input = str_replace("\\n","\n",$i);
523 # if($i != $input) warn("$i into $input\n");
524 }
525 
526 $output = $input;
527 
5281simandl # while( preg_match("/(\{[^}]+\})/",$input,$matches) )
529 while( preg_match("/(\{(?:node|map|link)[^}]+\})/",$input,$matches) )
530 {
531 $value = "[UNKNOWN]";
532 $format = "";
533 $key = $matches[1];
53485simandl debug("ProcessString: working on ".$key."\n");
5351simandl 
536 if ( preg_match("/\{(node|map|link):([^}]+)\}/",$key,$matches) )
537 {
538 $type = $matches[1];
539 $args = $matches[2];
54085simandl # debug("ProcessString: type is ".$type.", arguments are ".$args."\n");
5411simandl 
542 if($type == 'map')
543 {
544 $the_item = $this;
545 if(preg_match("/map:([^:]+):*([^:]*)/",$args,$matches))
546 {
547 $args = $matches[1];
548 $format = $matches[2];
549 }
550 }
551 
552 if(($type == 'link') || ($type == 'node'))
553 {
554 if(preg_match("/([^:]+):([^:]+):*([^:]*)/",$args,$matches))
555 {
556 $itemname = $matches[1];
557 $args = $matches[2];
558 $format = $matches[3];
559 
560 # debug("ProcessString: item is $itemname, and args are now $args\n");
561 
562 $the_item = NULL;
563 if( ($itemname == "this") && ($type == strtolower($context->my_type())) )
564 {
565 $the_item = $context;
566 }
56785simandl elseif( strtolower($context->my_type()) == "link" && $type == 'node' && ($itemname == '_linkstart_' || $itemname == '_linkend_') )
568 {
569 // this refers to the two nodes at either end of this link
570 if($itemname == '_linkstart_')
571 {
572 $the_item = $context->a;
573 }
574 
575 if($itemname == '_linkend_')
576 {
577 $the_item = $context->b;
578 }
579 }
5801simandl elseif( ($itemname == "parent") && ($type == strtolower($context->my_type())) && ($type=='node') && ($context->relative_to != '') )
581 {
58285simandl $the_item = $this->nodes[$context->relative_to];
5831simandl }
584 else
585 {
586 if( ($type == 'link') && isset($this->links[$itemname]) )
587 {
588 $the_item = $this->links[$itemname];
589 }
590 if( ($type == 'node') && isset($this->nodes[$itemname]) )
591 {
592 $the_item = $this->nodes[$itemname];
593 }
594 }
595 }
596 }
597 
598 if(is_null($the_item))
599 {
60085simandl warn("ProcessString: $key refers to unknown item (context is $context_description) [WMWARN05]\n");
6011simandl }
602 else
603 {
60413simandl # warn($the_item->name.": ".var_dump($the_item->hints)."\n");
60585simandl debug("ProcessString: Found appropriate item: ".get_class($the_item)." ".$the_item->name."\n");
606 
60713simandl # warn($the_item->name."/hints: ".var_dump($the_item->hints)."\n");
608 # warn($the_item->name."/notes: ".var_dump($the_item->notes)."\n");
60985simandl 
6101simandl // SET and notes have precedent over internal properties
611 // this is my laziness - it saves me having a list of reserved words
612 // which are currently used for internal props. You can just 'overwrite' any of them.
613 if(isset($the_item->hints[$args]))
614 {
615 $value = $the_item->hints[$args];
61613simandl debug("ProcessString: used hint\n");
6171simandl }
618 // for some things, we don't want to allow notes to be considered.
619 // mainly - TARGET (which can define command-lines), shouldn't be
620 // able to get data from uncontrolled sources (i.e. data sources rather than SET in config files).
621 elseif($include_notes && isset($the_item->notes[$args]))
622 {
623 $value = $the_item->notes[$args];
62413simandl debug("ProcessString: used note\n");
62585simandl 
626 }
6271simandl elseif(isset($the_item->$args))
628 {
629 $value = $the_item->$args;
63013simandl debug("ProcessString: used internal property\n");
63185simandl }
6321simandl }
633 }
634 
635 // format, and sanitise the value string here, before returning it
636 
63785simandl if($value===NULL) $value='NULL';
63813simandl debug("ProcessString: replacing ".$key." with $value\n");
6391simandl 
640 # if($format != '') $value = sprintf($format,$value);
64185simandl if($format != '')
6421simandl {
643 
644 # debug("Formatting with mysprintf($format,$value)\n");
645 $value = mysprintf($format,$value);
646 }
647 
648 # debug("ProcessString: formatted to $value\n");
649 $input = str_replace($key,'',$input);
650 $output = str_replace($key,$value,$output);
651 }
652 #debug("ProcessString: output is $output\n");
653 return ($output);
654}
655 
656function RandomData()
657{
658 foreach ($this->links as $link)
659 {
660 $this->links[$link->name]->bandwidth_in=rand(0, $link->max_bandwidth_in);
661 $this->links[$link->name]->bandwidth_out=rand(0, $link->max_bandwidth_out);
662 }
663}
664 
665function LoadPlugins( $type="data", $dir="lib/datasources" )
666{
667 debug("Beginning to load $type plugins from $dir\n");
66885simandl 
669 if ( ! file_exists($dir)) {
670 $dir = dirname(__FILE__) . DIRECTORY_SEPARATOR . $dir;
671 debug("Relative path didn't exist. Trying $dir\n");
672 }
6731simandl # $this->datasourceclasses = array();
67413simandl $dh=@opendir($dir);
6751simandl 
67613simandl if(!$dh) { // try to find it with the script, if the relative path fails
677 $srcdir = substr($_SERVER['argv'][0], 0, strrpos($_SERVER['argv'][0], DIRECTORY_SEPARATOR));
678 $dh = opendir($srcdir.DIRECTORY_SEPARATOR.$dir);
679 if ($dh) $dir = $srcdir.DIRECTORY_SEPARATOR.$dir;
680 }
681 
6821simandl if ($dh)
683 {
684 while ($file=readdir($dh))
685 {
686 $realfile = $dir . DIRECTORY_SEPARATOR . $file;
687 
688 if( is_file($realfile) && preg_match( '/\.php$/', $realfile ) )
689 {
690 debug("Loading $type Plugin class from $file\n");
691 
692 include_once( $realfile );
693 $class = preg_replace( "/\.php$/", "", $file );
69485simandl if($type == 'data')
6951simandl {
696 $this->datasourceclasses [$class]= $class;
697 $this->activedatasourceclasses[$class]=1;
698 }
699 if($type == 'pre') $this->preprocessclasses [$class]= $class;
700 if($type == 'post') $this->postprocessclasses [$class]= $class;
701 
702 debug("Loaded $type Plugin class $class from $file\n");
70385simandl $this->plugins[$type][$class] = new $class;
704 if(! isset($this->plugins[$type][$class]))
705 {
706 debug("** Failed to create an object for plugin $type/$class\n");
707 }
708 else
709 {
710 debug("Instantiated $class.\n");
711 }
7121simandl }
713 else
714 {
715 debug("Skipping $file\n");
716 }
717 }
718 }
719 else
720 {
72185simandl warn("Couldn't open $type Plugin directory ($dir). Things will probably go wrong. [WMWARN06]\n");
7221simandl }
723}
724 
72585simandlfunction DatasourceInit()
7261simandl{
727 debug("Running Init() for Data Source Plugins...\n");
728 foreach ($this->datasourceclasses as $ds_class)
729 {
73085simandl // make an instance of the class
731 $dsplugins[$ds_class] = new $ds_class;
7321simandl debug("Running $ds_class"."->Init()\n");
73385simandl # $ret = call_user_func(array($ds_class, 'Init'), $this);
734 assert('isset($this->plugins["data"][$ds_class])');
735 
736 $ret = $this->plugins['data'][$ds_class]->Init($this);
737 
7381simandl if(! $ret)
73985simandl {
74013simandl debug("Removing $ds_class from Data Source list, since Init() failed\n");
7411simandl $this->activedatasourceclasses[$ds_class]=0;
742 # unset($this->datasourceclasses[$ds_class]);
743 }
744 }
74585simandl debug("Finished Initialising Plugins...\n");
746}
7471simandl 
74885simandlfunction ProcessTargets()
749{
750 debug("Preprocessing targets\n");
751 
752 $allitems = array(&$this->links, &$this->nodes);
753 reset($allitems);
754 
755 debug("Preprocessing targets\n");
756 
757 while( list($kk,) = each($allitems))
758 {
759 unset($objects);
760 $objects = &$allitems[$kk];
7611simandl 
76285simandl reset($objects);
763 while (list($k,) = each($objects))
764 {
765 unset($myobj);
766 $myobj = &$objects[$k];
767 
768 $type = $myobj->my_type();
769 $name=$myobj->name;
770 
771 
772 if( ($type=='LINK' && isset($myobj->a)) || ($type=='NODE' && !is_null($myobj->x) ) )
773 {
774 if (count($myobj->targets)>0)
775 {
776 $tindex = 0;
777 foreach ($myobj->targets as $target)
778 {
779 debug ("ProcessTargets: New Target: $target[4]\n");
780 // processstring won't use notes (only hints) for this string
781 
782 $targetstring = $this->ProcessString($target[4], $myobj, FALSE, FALSE);
783 if($target[4] != $targetstring) debug("Targetstring is now $targetstring\n");
784 
785 // if the targetstring starts with a -, then we're taking this value OFF the aggregate
786 $multiply = 1;
787 if(preg_match("/^-(.*)/",$targetstring,$matches))
788 {
789 $targetstring = $matches[1];
790 $multiply = -1 * $multiply;
791 }
792 
793 // if the remaining targetstring starts with a number and a *-, then this is a scale factor
794 if(preg_match("/^(\d+\.?\d*)\*(.*)/",$targetstring,$matches))
795 {
796 $targetstring = $matches[2];
797 $multiply = $multiply * floatval($matches[1]);
798 }
799 
800 $matched = FALSE;
801 $matched_by = '';
802 foreach ($this->datasourceclasses as $ds_class)
803 {
804 if(!$matched)
805 {
806 // $recognised = call_user_func(array($ds_class, 'Recognise'), $targetstring);
807 $recognised = $this->plugins['data'][$ds_class]->Recognise($targetstring);
808 
809 if( $recognised )
810 {
811 $matched = TRUE;
812 $matched_by = $ds_class;
813 
814 if($this->activedatasourceclasses[$ds_class])
815 {
816 $this->plugins['data'][$ds_class]->Register($targetstring, $this, $myobj);
817 if($type == 'NODE')
818 {
819 $this->nodes[$name]->targets[$tindex][1] = $multiply;
820 $this->nodes[$name]->targets[$tindex][0] = $targetstring;
821 $this->nodes[$name]->targets[$tindex][5] = $matched_by;
822 }
823 if($type == 'LINK')
824 {
825 $this->links[$name]->targets[$tindex][1] = $multiply;
826 $this->links[$name]->targets[$tindex][0] = $targetstring;
827 $this->links[$name]->targets[$tindex][5] = $matched_by;
828 }
829 }
830 else
831 {
832 warn("ProcessTargets: $type $name, target: $targetstring on config line $target[3] of $target[2] was recognised as a valid TARGET by a plugin that is unable to run ($ds_class) [WMWARN07]\n");
833 }
834 }
835 }
836 }
837 if(! $matched)
838 {
839 warn("ProcessTargets: $type $name, target: $target[4] on config line $target[3] of $target[2] was not recognised as a valid TARGET [WMWARN08]\n");
840 }
841 
842 $tindex++;
843 }
844 }
845 }
846 }
847 }
848}
849 
850function ReadData()
851{
852 $this->DatasourceInit();
853 
854 debug ("======================================\n");
855 debug("ReadData: Updating link data for all links and nodes\n");
856 
857 // we skip readdata completely in sizedebug mode
8581simandl if ($this->sizedebug == 0)
859 {
86085simandl $this->ProcessTargets();
861 
862 debug ("======================================\n");
863 debug("Starting prefetch\n");
864 foreach ($this->datasourceclasses as $ds_class)
865 {
866 $this->plugins['data'][$ds_class]->Prefetch();
867 }
868 
869 debug ("======================================\n");
870 debug("Starting main collection loop\n");
871 
8721simandl $allitems = array(&$this->links, &$this->nodes);
873 reset($allitems);
87485simandl 
8751simandl while( list($kk,) = each($allitems))
87685simandl {
8771simandl unset($objects);
878 $objects = &$allitems[$kk];
879 
88085simandl reset($objects);
8811simandl while (list($k,) = each($objects))
882 {
883 unset($myobj);
884 $myobj = &$objects[$k];
885 
886 $type = $myobj->my_type();
88785simandl 
8881simandl $total_in=0;
889 $total_out=0;
890 $name=$myobj->name;
89185simandl debug ("\n");
892 debug ("ReadData for $type $name: \n");
8931simandl 
89485simandl if( ($type=='LINK' && isset($myobj->a)) || ($type=='NODE' && !is_null($myobj->x) ) )
8951simandl {
89685simandl if (count($myobj->targets)>0)
8971simandl {
89885simandl $tindex = 0;
899 foreach ($myobj->targets as $target)
9001simandl {
90185simandl debug ("ReadData: New Target: $target[4]\n");
902 # debug ( var_dump($target));
903 
904 $targetstring = $target[0];
905 $multiply = $target[1];
906 
907 # exit();
908 
909 $in = 0;
910 $out = 0;
911 $datatime = 0;
912 if ($target[4] != '')
9131simandl {
91485simandl // processstring won't use notes (only hints) for this string
915 
916 $targetstring = $this->ProcessString($target[0], $myobj, FALSE, FALSE);
917 if($target[0] != $targetstring) debug("Targetstring is now $targetstring\n");
918 if($multiply != 1) debug("Will multiply result by $multiply\n");
919 
920 if($target[0] != "")
9211simandl {
92285simandl $matched_by = $target[5];
923 list($in,$out,$datatime) = $this->plugins['data'][ $target[5] ]->ReadData($targetstring, $this, $myobj);
924 }
925 
926 if (($in === NULL) && ($out === NULL))
927 {
928 $in=0;
929 $out=0;
930 warn
931 ("ReadData: $type $name, target: $targetstring on config line $target[3] of $target[2] had no valid data, according to $matched_by\n");
932 }
933 else
934 {
935 if($in === NULL) $in = 0;
936 if($out === NULL) $out = 0;
937 }
938 
939 if($multiply != 1) {
940 debug("Pre-multiply: $in $out\n");
941 
942 $in = $multiply*$in;
943 $out = $multiply*$out;
944 
945 debug("Post-multiply: $in $out\n");
946 }
947 
948 $total_in=$total_in + $in;
949 $total_out=$total_out + $out;
950 debug("Aggregate so far: $total_in $total_out\n");
951 # keep a track of the range of dates for data sources (mainly for MRTG/textfile based DS)
952 if($datatime > 0)
953 {
954 if($this->max_data_time==NULL || $datatime > $this->max_data_time) $this->max_data_time = $datatime;
955 if($this->min_data_time==NULL || $datatime < $this->min_data_time) $this->min_data_time = $datatime;
9561simandl 
95785simandl debug("DataTime MINMAX: ".$this->min_data_time." -> ".$this->max_data_time."\n");
9581simandl }
95985simandl 
9601simandl }
96185simandl $tindex++;
9621simandl }
96385simandl 
964 debug ("ReadData complete for $type $name: $total_in $total_out\n");
9651simandl }
96685simandl else
967 {
968 debug("ReadData: No targets for $type $name\n");
969 }
9701simandl }
971 else
972 {
97385simandl debug("ReadData: Skipping $type $name that looks like a template\n.");
9741simandl }
975 
976 # $this->links[$name]->bandwidth_in=$total_in;
977 # $this->links[$name]->bandwidth_out=$total_out;
978 $myobj->bandwidth_in = $total_in;
979 $myobj->bandwidth_out = $total_out;
98085simandl 
981 if($type == 'LINK' && $myobj->duplex=='half')
982 {
983 // in a half duplex link, in and out share a common bandwidth pool, so percentages need to include both
984 debug("Calculating percentage using half-duplex\n");
985 $myobj->outpercent = (($total_in + $total_out) / ($myobj->max_bandwidth_out)) * 100;
986 $myobj->inpercent = (($total_out + $total_in) / ($myobj->max_bandwidth_in)) * 100;
987 if($myobj->max_bandwidth_out != $myobj->max_bandwidth_in)
988 {
989 warn("ReadData: $type $name: You're using asymmetric bandwidth AND half-duplex in the same link. That makes no sense. [WMWARN44]\n");
990 }
991 }
992 else
993 {
994 $myobj->outpercent = (($total_out) / ($myobj->max_bandwidth_out)) * 100;
995 $myobj->inpercent = (($total_in) / ($myobj->max_bandwidth_in)) * 100;
996 }
997 
998 # print $myobj->name."=>".$myobj->inpercent."%/".$myobj->outpercent."\n";
999 
1000 $warn_in = true;
1001 $warn_out = true;
1002 if($type=='NODE' && $myobj->scalevar =='in') $warn_out = false;
1003 if($type=='NODE' && $myobj->scalevar =='out') $warn_in = false;
1004 
1005 if($myobj->scaletype == 'percent')
1006 {
1007 list($incol,$inscalekey,$inscaletag) = $this->NewColourFromPercent($myobj->inpercent,$myobj->usescale,$myobj->name, TRUE, $warn_in);
1008 list($outcol,$outscalekey, $outscaletag) = $this->NewColourFromPercent($myobj->outpercent,$myobj->usescale,$myobj->name, TRUE, $warn_out);
1009 }
1010 else
1011 {
1012 // use absolute values, if that's what is requested
1013 list($incol,$inscalekey,$inscaletag) = $this->NewColourFromPercent($myobj->bandwidth_in,$myobj->usescale,$myobj->name, FALSE, $warn_in);
1014 list($outcol,$outscalekey, $outscaletag) = $this->NewColourFromPercent($myobj->bandwidth_out,$myobj->usescale,$myobj->name, FALSE, $warn_out);
1015 }
10161simandl 
101785simandl $myobj->add_note("inscalekey",$inscalekey);
1018 $myobj->add_note("outscalekey",$outscalekey);
10191simandl 
102085simandl $myobj->add_note("inscaletag",$inscaletag);
1021 $myobj->add_note("outscaletag",$outscaletag);
10221simandl 
102385simandl $myobj->add_note("inscalecolor",$incol->as_html());
1024 $myobj->add_note("outscalecolor",$outcol->as_html());
1025 
1026 $myobj->colours[IN] = $incol;
1027 $myobj->colours[OUT] = $outcol;
1028 
1029 ### warn("TAGS (setting) |$inscaletag| |$outscaletag| \n");
1030 
10311simandl debug ("ReadData: Setting $total_in,$total_out\n");
1032 unset($myobj);
1033 }
1034 }
103585simandl debug ("ReadData Completed.\n");
1036 debug("------------------------------\n");
10371simandl }
1038}
1039 
104085simandl// nodename is a vestigal parameter, from the days when nodes were just big labels
1041function DrawLabelRotated($im, $x, $y, $angle, $text, $font, $padding, $linkname, $textcolour, $bgcolour, $outlinecolour, &$map, $direction)
10421simandl{
1043 list($strwidth, $strheight)=$this->myimagestringsize($font, $text);
1044 
104585simandl if(abs($angle)>90) $angle -= 180;
1046 if($angle < -180) $angle +=360;
10471simandl 
104813simandl $rangle = -deg2rad($angle);
1049 
1050 $extra=3;
1051 
1052 $x1= $x - ($strwidth / 2) - $padding - $extra;
1053 $x2= $x + ($strwidth / 2) + $padding + $extra;
1054 $y1= $y - ($strheight / 2) - $padding - $extra;
1055 $y2= $y + ($strheight / 2) + $padding + $extra;
105685simandl 
105713simandl // a box. the last point is the start point for the text.
1058 $points = array($x1,$y1, $x1,$y2, $x2,$y2, $x2,$y1, $x-$strwidth/2, $y+$strheight/2 + 1);
1059 $npoints = count($points)/2;
106085simandl 
106113simandl RotateAboutPoint($points, $x,$y, $rangle);
106285simandl 
106313simandl if ($bgcolour != array
1064 (
1065 -1,
1066 -1,
1067 -1
1068 ))
1069 {
1070 $bgcol=myimagecolorallocate($im, $bgcolour[0], $bgcolour[1], $bgcolour[2]);
1071 # imagefilledrectangle($im, $x1, $y1, $x2, $y2, $bgcol);
107285simandl wimagefilledpolygon($im,$points,4,$bgcol);
107313simandl }
1074 
1075 if ($outlinecolour != array
1076 (
1077 -1,
1078 -1,
1079 -1
1080 ))
1081 {
1082 $outlinecol=myimagecolorallocate($im, $outlinecolour[0], $outlinecolour[1], $outlinecolour[2]);
1083 # imagerectangle($im, $x1, $y1, $x2, $y2, $outlinecol);
108485simandl wimagepolygon($im,$points,4,$outlinecol);
108513simandl }
1086 
1087 $textcol=myimagecolorallocate($im, $textcolour[0], $textcolour[1], $textcolour[2]);
1088 $this->myimagestring($im, $font, $points[8], $points[9], $text, $textcol,$angle);
1089 
109085simandl $areaname = "LINK:L".$map->links[$linkname]->id.':'.($direction+2);
1091 
1092 // the rectangle is about half the size in the HTML, and easier to optimise/detect in the browser
1093 if($angle==0)
1094 {
1095 $map->imap->addArea("Rectangle", $areaname, '', array($x1, $y1, $x2, $y2));
1096 debug ("Adding Rectangle imagemap for $areaname\n");
1097 }
1098 else
1099 {
1100 $map->imap->addArea("Polygon", $areaname, '', $points);
1101 debug ("Adding Poly imagemap for $areaname\n");
1102 }
110313simandl 
1104}
1105 
110685simandlfunction ColourFromPercent($image, $percent,$scalename="DEFAULT",$name="")
11071simandl{
1108 $col = NULL;
110985simandl $tag = '';
11101simandl 
111185simandl $nowarn_clipping = intval($this->get_hint("nowarn_clipping"));
1112 $nowarn_scalemisses = intval($this->get_hint("nowarn_scalemisses"));
1113 
1114 $bt = debug_backtrace();
1115 $function = (isset($bt[1]['function']) ? $bt[1]['function'] : '');
1116 print "$function calls ColourFromPercent\n";
1117 
1118 exit();
1119 
11201simandl if(isset($this->colours[$scalename]))
1121 {
1122 $colours=$this->colours[$scalename];
1123 
1124 if ($percent > 100)
1125 {
112685simandl if($nowarn_clipping==0) warn ("ColourFromPercent: Clipped $name $percent% to 100% [WMWARN33]\n");
11271simandl $percent=100;
1128 }
1129 
1130 foreach ($colours as $key => $colour)
1131 {
1132 if (($percent >= $colour['bottom']) and ($percent <= $colour['top']))
1133 {
113485simandl if(isset($colour['tag'])) $tag = $colour['tag'];
1135 
11361simandl // we get called early now, so might not need to actually allocate a colour
113785simandl if(isset($image))
11381simandl {
1139 if (isset($colour['red2']))
1140 {
114113simandl if($colour["bottom"] == $colour["top"])
1142 {
1143 $ratio = 0;
1144 }
1145 else
1146 {
1147 $ratio=($percent - $colour["bottom"]) / ($colour["top"] - $colour["bottom"]);
1148 }
114985simandl 
11501simandl $r=$colour["red1"] + ($colour["red2"] - $colour["red1"]) * $ratio;
1151 $g=$colour["green1"] + ($colour["green2"] - $colour["green1"]) * $ratio;
1152 $b=$colour["blue1"] + ($colour["blue2"] - $colour["blue1"]) * $ratio;
115385simandl 
1154 $col = myimagecolorallocate($image, $r, $g, $b);
11551simandl }
1156 else {
115785simandl $r=$colour["red1"];
1158 $g=$colour["green1"];
1159 $b=$colour["blue1"];
1160 
1161 $col = myimagecolorallocate($image, $r, $g, $b);
1162 # $col = $colour['gdref1'];
11631simandl }
116485simandl debug("CFPC $name $tag $key $r $g $b\n");
11651simandl }
116685simandl 
1167 ### warn(">>TAGS CFPC $tag\n");
1168 
1169 return(array($col,$key,$tag));
1170 }
1171 }
1172 }
1173 else
1174 {
1175 if($scalename != 'none')
1176 {
1177 warn("ColourFromPercent: Attempted to use non-existent scale: $scalename for $name [WMWARN09]\n");
1178 }
1179 else
1180 {
1181 return array($this->white,'','');
1182 }
1183 }
1184 
1185 // you'll only get grey for a COMPLETELY quiet link if there's no 0 in the SCALE lines
1186 if ($percent == 0) { return array($this->grey,'',''); }
1187 
1188 // and you'll only get white for a link with no colour assigned
1189 if($nowarn_scalemisses==0) warn("ColourFromPercent: Scale $scalename doesn't cover $percent% for $name [WMWARN29]\n");
1190 return array($this->white,'','');
1191}
1192 
1193function NewColourFromPercent($value,$scalename="DEFAULT",$name="",$is_percent=TRUE, $scale_warning=TRUE)
1194{
1195 $col = new Colour(0,0,0);
1196 $tag = '';
1197 $matchsize = NULL;
1198 
1199 $nowarn_clipping = intval($this->get_hint("nowarn_clipping"));
1200 $nowarn_scalemisses = (!$scale_warning) || intval($this->get_hint("nowarn_scalemisses"));
1201 
1202 if(isset($this->colours[$scalename]))
1203 {
1204 $colours=$this->colours[$scalename];
1205 
1206 if ($is_percent && $value > 100)
1207 {
1208 if($nowarn_clipping==0) warn ("NewColourFromPercent: Clipped $value% to 100% for item $name [WMWARN33]\n");
1209 $value = 100;
1210 }
1211 
1212 if ($is_percent && $value < 0)
1213 {
1214 if($nowarn_clipping==0) warn ("NewColourFromPercent: Clipped $value% to 0% for item $name [WMWARN34]\n");
1215 $value = 0;
1216 }
1217 
1218 foreach ($colours as $key => $colour)
1219 {
1220 if ( (!isset($colour['special']) || $colour['special'] == 0) and ($value >= $colour['bottom']) and ($value <= $colour['top']))
1221 {
1222 $range = $colour['top'] - $colour['bottom'];
1223 if (isset($colour['red2']))
1224 {
1225 if($colour["bottom"] == $colour["top"])
1226 {
1227 $ratio = 0;
1228 }
1229 else
1230 {
1231 $ratio=($value - $colour["bottom"]) / ($colour["top"] - $colour["bottom"]);
1232 }
1233 
1234 $r=$colour["red1"] + ($colour["red2"] - $colour["red1"]) * $ratio;
1235 $g=$colour["green1"] + ($colour["green2"] - $colour["green1"]) * $ratio;
1236 $b=$colour["blue1"] + ($colour["blue2"] - $colour["blue1"]) * $ratio;
1237 }
1238 else {
1239 $r=$colour["red1"];
1240 $g=$colour["green1"];
1241 $b=$colour["blue1"];
1242 
1243 # $col = new Colour($r, $g, $b);
1244 # $col = $colour['gdref1'];
1245 }
12461simandl 
124785simandl // change in behaviour - with multiple matching ranges for a value, the smallest range wins
1248 if( is_null($matchsize) || ($range < $matchsize) )
1249 {
1250 $col = new Colour($r, $g, $b);
1251 $matchsize = $range;
1252 }
1253 
1254 if(isset($colour['tag'])) $tag = $colour['tag'];
1255 #### warn(">>NCFPC TAGS $tag\n");
1256 debug("NCFPC $name $scalename $value '$tag' $key $r $g $b\n");
1257 
1258 return(array($col,$key,$tag));
12591simandl }
1260 }
1261 }
1262 else
1263 {
126485simandl if($scalename != 'none')
1265 {
1266 warn("ColourFromPercent: Attempted to use non-existent scale: $scalename for item $name [WMWARN09]\n");
1267 }
1268 else
1269 {
1270 return array(new Colour(255,255,255),'','');
1271 }
12721simandl }
1273 
127485simandl // shouldn't really get down to here if there's a complete SCALE
1275 
12761simandl // you'll only get grey for a COMPLETELY quiet link if there's no 0 in the SCALE lines
127785simandl if ($value == 0) { return array(new Colour(192,192,192),'',''); }
12781simandl 
127985simandl if($nowarn_scalemisses==0) warn("NewColourFromPercent: Scale $scalename doesn't include a line for $value".($is_percent ? "%" : "")." while drawing item $name [WMWARN29]\n");
1280 
12811simandl // and you'll only get white for a link with no colour assigned
128285simandl return array(new Colour(255,255,255),'','');
12831simandl}
1284 
128585simandl 
12861simandlfunction coloursort($a, $b)
1287{
1288 if ($a['bottom'] == $b['bottom'])
1289 {
1290 if($a['top'] < $b['top']) { return -1; };
1291 if($a['top'] > $b['top']) { return 1; };
1292 return 0;
1293 }
1294 
1295 if ($a['bottom'] < $b['bottom']) { return -1; }
1296 
1297 return 1;
129885simandl}
12991simandl 
130085simandlfunction FindScaleExtent($scalename="DEFAULT")
1301{
1302 $max = -999999999999999999999;
1303 $min = - $max;
1304 
1305 if(isset($this->colours[$scalename]))
1306 {
1307 $colours=$this->colours[$scalename];
1308 
1309 foreach ($colours as $key => $colour)
1310 {
1311 if(! $colour['special'])
1312 {
1313 $min = min($colour['bottom'], $min);
1314 $max = max($colour['top'], $max);
1315 }
1316 }
1317 }
1318 else
1319 {
1320 warn("FindScaleExtent: non-existent SCALE $scalename [WMWARN43]\n");
1321 }
1322 return array($min, $max);
1323}
1324 
13251simandlfunction DrawLegend_Horizontal($im,$scalename="DEFAULT",$width=400)
1326{
1327 $title=$this->keytext[$scalename];
1328 
1329 $colours=$this->colours[$scalename];
1330 $nscales=$this->numscales[$scalename];
1331 
1332 debug("Drawing $nscales colours into SCALE\n");
1333 
1334 $font=$this->keyfont;
1335 
133685simandl # $x=$this->keyx[$scalename];
1337 # $y=$this->keyy[$scalename];
1338 $x = 0;
1339 $y = 0;
13401simandl 
1341 # $width = 400;
1342 $scalefactor = $width/100;
1343 
1344 list($tilewidth, $tileheight)=$this->myimagestringsize($font, "100%");
1345 $box_left = $x;
134685simandl # $box_left = 0;
13471simandl $scale_left = $box_left + 4 + $scalefactor/2;
1348 $box_right = $scale_left + $width + $tilewidth + 4 + $scalefactor/2;
1349 $scale_right = $scale_left + $width;
1350 
1351 $box_top = $y;
135285simandl # $box_top = 0;
13531simandl $scale_top = $box_top + $tileheight + 6;
1354 $scale_bottom = $scale_top + $tileheight * 1.5;
1355 $box_bottom = $scale_bottom + $tileheight * 2 + 6;
1356 
135785simandl $scale_im = imagecreatetruecolor($box_right+1, $box_bottom+1);
1358 $scale_ref = 'gdref_legend_'.$scalename;
1359 $this->AllocateScaleColours($scale_im,$scale_ref);
13601simandl 
136185simandl wimagefilledrectangle($scale_im, $box_left, $box_top, $box_right, $box_bottom,
1362 $this->colours['DEFAULT']['KEYBG'][$scale_ref]);
1363 wimagerectangle($scale_im, $box_left, $box_top, $box_right, $box_bottom,
1364 $this->colours['DEFAULT']['KEYOUTLINE'][$scale_ref]);
13651simandl 
136685simandl $this->myimagestring($scale_im, $font, $scale_left, $scale_bottom + $tileheight * 2 + 2 , $title,
1367 $this->colours['DEFAULT']['KEYTEXT'][$scale_ref]);
1368 
13691simandl for($p=0;$p<=100;$p++)
1370 {
1371 $dx = $p*$scalefactor;
1372 
1373 if( ($p % 25) == 0)
1374 {
137585simandl imageline($scale_im, $scale_left + $dx, $scale_top - $tileheight,
13761simandl $scale_left + $dx, $scale_bottom + $tileheight,
137785simandl $this->colours['DEFAULT']['KEYTEXT'][$scale_ref]);
13781simandl $labelstring=sprintf("%d%%", $p);
137985simandl $this->myimagestring($scale_im, $font, $scale_left + $dx + 2, $scale_top - 2, $labelstring,
1380 $this->colours['DEFAULT']['KEYTEXT'][$scale_ref]);
13811simandl }
1382 
138385simandl list($col,$junk) = $this->NewColourFromPercent($p,$scalename);
1384 if($col->is_real())
1385 {
1386 $cc = $col->gdallocate($scale_im);
1387 wimagefilledrectangle($scale_im, $scale_left + $dx - $scalefactor/2, $scale_top,
1388 $scale_left + $dx + $scalefactor/2, $scale_bottom,
1389 $cc);
1390 }
13911simandl }
1392 
139385simandl imagecopy($im,$scale_im,$this->keyx[$scalename],$this->keyy[$scalename],0,0,imagesx($scale_im),imagesy($scale_im));
1394 $this->keyimage[$scalename] = $scale_im;
13951simandl 
139685simandl $rx = $this->keyx[$scalename];
1397 $ry = $this->keyy[$scalename];
1398 
1399 $this->imap->addArea("Rectangle", "LEGEND:$scalename", '',
1400 array($rx+$box_left, $ry+$box_top, $rx+$box_right, $ry+$box_bottom));
14011simandl}
1402 
140385simandlfunction DrawLegend_Vertical($im,$scalename="DEFAULT",$height=400,$inverted=false)
14041simandl{
1405 $title=$this->keytext[$scalename];
1406 
1407 $colours=$this->colours[$scalename];
1408 $nscales=$this->numscales[$scalename];
1409 
1410 debug("Drawing $nscales colours into SCALE\n");
1411 
1412 $font=$this->keyfont;
1413 
1414 $x=$this->keyx[$scalename];
1415 $y=$this->keyy[$scalename];
1416 
1417 # $height = 400;
1418 $scalefactor = $height/100;
1419 
1420 list($tilewidth, $tileheight)=$this->myimagestringsize($font, "100%");
1421 
142285simandl # $box_left = $x;
1423 # $box_top = $y;
1424 $box_left = 0;
1425 $box_top = 0;
14261simandl 
1427 $scale_left = $box_left+$scalefactor*2 +4 ;
1428 $scale_right = $scale_left + $tileheight*2;
1429 $box_right = $scale_right + $tilewidth + $scalefactor*2 + 4;
1430 
1431 list($titlewidth,$titleheight) = $this->myimagestringsize($font,$title);
1432 if( ($box_left + $titlewidth + $scalefactor*3) > $box_right)
1433 {
1434 $box_right = $box_left + $scalefactor*4 + $titlewidth;
1435 }
1436 
1437 $scale_top = $box_top + 4 + $scalefactor + $tileheight*2;
1438 $scale_bottom = $scale_top + $height;
1439 $box_bottom = $scale_bottom + $scalefactor + $tileheight/2 + 4;
1440 
144185simandl $scale_im = imagecreatetruecolor($box_right+1, $box_bottom+1);
1442 $scale_ref = 'gdref_legend_'.$scalename;
1443 $this->AllocateScaleColours($scale_im,$scale_ref);
1444 
1445 wimagefilledrectangle($scale_im, $box_left, $box_top, $box_right, $box_bottom,
14461simandl $this->colours['DEFAULT']['KEYBG']['gdref1']);
144785simandl wimagerectangle($scale_im, $box_left, $box_top, $box_right, $box_bottom,
1448 $this->colours['DEFAULT']['KEYOUTLINE']['gdref1']);
14491simandl 
145085simandl $this->myimagestring($scale_im, $font, $scale_left-$scalefactor, $scale_top - $tileheight , $title,
14511simandl $this->colours['DEFAULT']['KEYTEXT']['gdref1']);
1452 
145385simandl $updown = 1;
1454 if($inverted) $updown = -1;
1455 
1456 
14571simandl for($p=0;$p<=100;$p++)
1458 {
145985simandl if($inverted)
1460 {
1461 $dy = (100-$p) * $scalefactor;
1462 }
1463 else
1464 {
1465 $dy = $p*$scalefactor;
1466 }
1467 
14681simandl if( ($p % 25) == 0)
1469 {
147085simandl imageline($scale_im, $scale_left - $scalefactor, $scale_top + $dy,
14711simandl $scale_right + $scalefactor, $scale_top + $dy,
147285simandl $this->colours['DEFAULT']['KEYTEXT'][$scale_ref]);
14731simandl $labelstring=sprintf("%d%%", $p);
147485simandl $this->myimagestring($scale_im, $font, $scale_right + $scalefactor*2 , $scale_top + $dy + $tileheight/2,
1475 $labelstring, $this->colours['DEFAULT']['KEYTEXT'][$scale_ref]);
14761simandl }
1477 
147885simandl list($col,$junk) = $this->NewColourFromPercent($p,$scalename);
1479 if( $col->is_real())
1480 {
1481 $cc = $col->gdallocate($scale_im);
1482 wimagefilledrectangle($scale_im, $scale_left, $scale_top + $dy - $scalefactor/2,
1483 $scale_right, $scale_top + $dy + $scalefactor/2,
1484 $cc);
1485 }
14861simandl }
1487 
148885simandl imagecopy($im,$scale_im,$this->keyx[$scalename],$this->keyy[$scalename],0,0,imagesx($scale_im),imagesy($scale_im));
1489 $this->keyimage[$scalename] = $scale_im;
1490 
1491 $rx = $this->keyx[$scalename];
1492 $ry = $this->keyy[$scalename];
14931simandl $this->imap->addArea("Rectangle", "LEGEND:$scalename", '',
149485simandl array($rx+$box_left, $ry+$box_top, $rx+$box_right, $ry+$box_bottom));
14951simandl}
1496 
149785simandlfunction DrawLegend_Classic($im,$scalename="DEFAULT",$use_tags=FALSE)
14981simandl{
1499 $title=$this->keytext[$scalename];
1500 
1501 $colours=$this->colours[$scalename];
150285simandl usort($colours, array("Weathermap", "coloursort"));
1503 
15041simandl $nscales=$this->numscales[$scalename];
1505 
1506 debug("Drawing $nscales colours into SCALE\n");
1507 
150813simandl $hide_zero = intval($this->get_hint("key_hidezero_".$scalename));
1509 $hide_percent = intval($this->get_hint("key_hidepercent_".$scalename));
1510 
151185simandl // did we actually hide anything?
1512 $hid_zero = FALSE;
151313simandl if( ($hide_zero == 1) && isset($colours['0_0']) )
1514 {
1515 $nscales--;
151685simandl $hid_zero = TRUE;
151713simandl }
1518 
15191simandl $font=$this->keyfont;
1520 
1521 $x=$this->keyx[$scalename];
1522 $y=$this->keyy[$scalename];
1523 
1524 list($tilewidth, $tileheight)=$this->myimagestringsize($font, "MMMM");
1525 $tileheight=$tileheight * 1.1;
1526 $tilespacing=$tileheight + 2;
1527 
152885simandl if (($this->keyx[$scalename] >= 0) && ($this->keyy[$scalename] >= 0))
15291simandl {
1530 
1531 # $minwidth = imagefontwidth($font) * strlen('XX 100%-100%')+10;
1532 # $boxwidth = imagefontwidth($font) * strlen($title) + 10;
1533 list($minwidth, $junk)=$this->myimagestringsize($font, 'MMMM 100%-100%');
153485simandl list($minminwidth, $junk)=$this->myimagestringsize($font, 'MMMM ');
15351simandl list($boxwidth, $junk)=$this->myimagestringsize($font, $title);
153685simandl 
1537 if($use_tags)
1538 {
1539 $max_tag = 0;
1540 foreach ($colours as $colour)
1541 {
1542 if ( isset($colour['tag']) )
1543 {
1544 list($w, $junk)=$this->myimagestringsize($font, $colour['tag']);
1545 # print $colour['tag']." $w \n";
1546 if($w > $max_tag) $max_tag = $w;
1547 }
1548 }
1549 
1550 // now we can tweak the widths, appropriately to allow for the tag strings
1551 # print "$max_tag > $minwidth?\n";
1552 if( ($max_tag + $minminwidth) > $minwidth) $minwidth = $minminwidth + $max_tag;
1553 # print "minwidth is now $minwidth\n";
1554 }
15551simandl 
1556 $minwidth+=10;
1557 $boxwidth+=10;
1558 
1559 if ($boxwidth < $minwidth) { $boxwidth=$minwidth; }
1560 
1561 $boxheight=$tilespacing * ($nscales + 1) + 10;
1562 
156385simandl $boxx=$x; $boxy=$y;
1564 $boxx=0;
1565 $boxy=0;
15661simandl 
1567 // allow for X11-style negative positioning
1568 if ($boxx < 0) { $boxx+=$this->width; }
1569 
1570 if ($boxy < 0) { $boxy+=$this->height; }
1571 
157285simandl $scale_im = imagecreatetruecolor($boxwidth+1, $boxheight+1);
1573 $scale_ref = 'gdref_legend_'.$scalename;
1574 $this->AllocateScaleColours($scale_im,$scale_ref);
15751simandl 
157685simandl wimagefilledrectangle($scale_im, $boxx, $boxy, $boxx + $boxwidth, $boxy + $boxheight,
1577 $this->colours['DEFAULT']['KEYBG'][$scale_ref]);
1578 wimagerectangle($scale_im, $boxx, $boxy, $boxx + $boxwidth, $boxy + $boxheight,
1579 $this->colours['DEFAULT']['KEYOUTLINE'][$scale_ref]);
1580 $this->myimagestring($scale_im, $font, $boxx + 4, $boxy + 4 + $tileheight, $title,
1581 $this->colours['DEFAULT']['KEYTEXT'][$scale_ref]);
15821simandl 
1583 $i=1;
1584 
1585 foreach ($colours as $colour)
1586 {
158785simandl if (!isset($colour['special']) || $colour['special'] == 0)
1588 // if ( 1==1 || $colour['bottom'] >= 0)
1589 {
1590 // pick a value in the middle...
1591 $value = ($colour['bottom'] + $colour['top']) / 2;
1592 debug(sprintf("%f-%f (%f) %d %d %d\n", $colour['bottom'], $colour['top'], $value, $colour['red1'], $colour['green1'], $colour['blue1']));
1593 
159413simandl # debug("$i: drawing\n");
159585simandl if( ($hide_zero == 0) || $colour['key'] != '0_0')
15961simandl {
159713simandl $y=$boxy + $tilespacing * $i + 8;
1598 $x=$boxx + 6;
159985simandl 
1600 $fudgefactor = 0;
1601 if( $hid_zero && $colour['bottom']==0 )
1602 {
1603 // calculate a small offset that can be added, which will hide the zero-value in a
1604 // gradient, but not make the scale incorrect. A quarter of a pixel should do it.
1605 $fudgefactor = ($colour['top'] - $colour['bottom'])/($tilewidth*4);
1606 # warn("FUDGING $fudgefactor\n");
1607 }
1608 
1609 // if it's a gradient, red2 is defined, and we need to sweep the values
161013simandl if (isset($colour['red2']))
16111simandl {
161213simandl for ($n=0; $n <= $tilewidth; $n++)
1613 {
161485simandl $value
1615 = $fudgefactor + $colour['bottom'] + ($n / $tilewidth) * ($colour['top'] - $colour['bottom']);
1616 list($ccol,$junk) = $this->NewColourFromPercent($value, $scalename, "", FALSE);
1617 $col = $ccol->gdallocate($scale_im);
1618 wimagefilledrectangle($scale_im, $x + $n, $y, $x + $n, $y + $tileheight,
161913simandl $col);
1620 }
1621 }
1622 else
1623 {
162485simandl // pick a value in the middle...
1625 //$value = ($colour['bottom'] + $colour['top']) / 2;
1626 list($ccol,$junk) = $this->NewColourFromPercent($value, $scalename, "", FALSE);
1627 $col = $ccol->gdallocate($scale_im);
1628 wimagefilledrectangle($scale_im, $x, $y, $x + $tilewidth, $y + $tileheight,
16291simandl $col);
1630 }
163185simandl 
1632 if($use_tags)
1633 {
1634 $labelstring = "";
1635 if(isset($colour['tag'])) $labelstring = $colour['tag'];
1636 }
1637 else
1638 {
1639 $labelstring=sprintf("%s-%s", $colour['bottom'], $colour['top']);
1640 if($hide_percent==0) { $labelstring.="%"; }
1641 }
1642 
1643 $this->myimagestring($scale_im, $font, $x + 4 + $tilewidth, $y + $tileheight, $labelstring,
1644 $this->colours['DEFAULT']['KEYTEXT'][$scale_ref]);
164513simandl $i++;
16461simandl }
164785simandl imagecopy($im,$scale_im,$this->keyx[$scalename],$this->keyy[$scalename],0,0,imagesx($scale_im),imagesy($scale_im));
1648 $this->keyimage[$scalename] = $scale_im;
1649 
16501simandl }
1651 }
1652 
1653 $this->imap->addArea("Rectangle", "LEGEND:$scalename", '',
165485simandl array($this->keyx[$scalename], $this->keyy[$scalename], $this->keyx[$scalename] + $boxwidth, $this->keyy[$scalename] + $boxheight));
16551simandl # $this->imap->setProp("href","#","LEGEND");
1656 # $this->imap->setProp("extrahtml","onclick=\"position_legend();\"","LEGEND");
1657 
1658 }
1659}
1660 
166185simandlfunction DrawTimestamp($im, $font, $colour, $which="")
16621simandl{
1663 // add a timestamp to the corner, so we can tell if it's all being updated
1664 # $datestring = "Created: ".date("M d Y H:i:s",time());
166513simandl # $this->datestamp=strftime($this->stamptext, time());
16661simandl 
166785simandl switch($which)
1668 {
1669 case "MIN":
1670 $stamp = strftime($this->minstamptext, $this->min_data_time);
1671 $pos_x = $this->mintimex;
1672 $pos_y = $this->mintimey;
1673 break;
1674 case "MAX":
1675 $stamp = strftime($this->maxstamptext, $this->max_data_time);
1676 $pos_x = $this->maxtimex;
1677 $pos_y = $this->maxtimey;
1678 break;
1679 default:
1680 $stamp = $this->datestamp;
1681 $pos_x = $this->timex;
1682 $pos_y = $this->timey;
1683 break;
1684 }
1685 
1686 list($boxwidth, $boxheight)=$this->myimagestringsize($font, $stamp);
16871simandl 
1688 $x=$this->width - $boxwidth;
1689 $y=$boxheight;
1690 
169185simandl if (($pos_x != 0) && ($pos_y != 0))
16921simandl {
169385simandl $x = $pos_x;
1694 $y = $pos_y;
16951simandl }
169685simandl 
1697 $this->myimagestring($im, $font, $x, $y, $stamp, $colour);
1698 $this->imap->addArea("Rectangle", $which."TIMESTAMP", '', array($x, $y, $x + $boxwidth, $y - $boxheight));
16991simandl}
1700 
1701function DrawTitle($im, $font, $colour)
170285simandl{
17031simandl $string = $this->ProcessString($this->title,$this);
170485simandl 
1705 if($this->get_hint('screenshot_mode')==1) $string= screenshotify($string);
17061simandl 
1707 list($boxwidth, $boxheight)=$this->myimagestringsize($font, $string);
1708 
1709 $x=10;
1710 $y=$this->titley - $boxheight;
1711 
1712 if (($this->titlex >= 0) && ($this->titley >= 0))
1713 {
1714 $x=$this->titlex;
1715 $y=$this->titley;
1716 }
1717 
1718 $this->myimagestring($im, $font, $x, $y, $string, $colour);
1719 
1720 $this->imap->addArea("Rectangle", "TITLE", '', array($x, $y, $x + $boxwidth, $y - $boxheight));
1721}
1722 
172385simandlfunction ReadConfigNG($input, $is_include=FALSE, $initial_context="GLOBAL")
17241simandl{
172585simandl $valid_commands = array(
1726 "GLOBAL.set", "LINK.set", "NODE.set",
1727 "GLOBAL.#","LINK.#","NODE.#",
1728 "GLOBAL.include", "NODE.include", "LINK.include",
1729 
1730 "GLOBAL.width", "GLOBAL.height", "GLOBAL.background",
1731 "GLOBAL.scale", "GLOBAL.title", "GLOBAL.titlepos",
1732 "GLOBAL.fontdefine",
1733 "GLOBAL.keystyle", "GLOBAL.titlecolor", "GLOBAL.timecolor",
1734 "GLOBAL.titlefont", "GLOBAL.timefont", "GLOBAL.htmloutputfile",
1735 "GLOBAL.htmlstyle", "GLOBAL.imageoutputfile", "GLOBAL.keyfont",
1736 "GLOBAL.keytextcolor", "GLOBAL.keyoutlinecolor", "GLOBAL.keybgcolor",
1737 "GLOBAL.bgcolor",
1738 
1739 "SCALE.keypos", "SCALE.keystyle", "SCALE.scale",
1740 
1741 "LINK.width", "LINK.link", "LINK.nodes",
1742 "LINK.target", "LINK.usescale", "LINK.infourl",
1743 "LINK.linkstyle", "LINK.overlibcaption", "LINK.inoverlibcaption", "LINK.outoverlibcaption",
1744 "LINK.inoverlibgraph", "LINK.outoverlibgraph",
1745 "LINK.overlibgraph", "LINK.overlibwidth", "LINK.overlibheight",
1746 "LINK.bwlabel", "LINK.via", "LINK.zorder", "LINK.outlinecolor",
1747 "LINK.notes", "LINK.innotes", "LINK.outnotes","LINK.ininfourl", "LINK.outinfourl",
1748 "LINK.bwstyle", "LINK.template", "LINK.splitpos", "LINK.bwlabelpos", "LINK.incomment", "LINK.outcomment",
1749 "LINK.viastyle", "LINK.bandwidth", "LINK.inbwformat", "LINK.outbwformat",
1750 "LINK.commentstyle", "LINK.commentfont", "LINK.commentfontcolor", "LINK.bwfont",
1751 
1752 "NODE.icon", "NODE.target", "NODE.position", "NODE.infourl", "NODE.overlibgraph",
1753 "NODE.zorder", "NODE.label", "NODE.template", "NODE.labelbgcolor",
1754 "NODE.maxvalue",
1755 "NODE.labeloutlinecolor", "NODE.aiconoutlinecolor", "NODE.aiconfillcolor", "NODE.usescale",
1756 "NODE.labelfontcolor", "NODE.labelfont", "NODE.labelangle", "NODE.labelfontshadowcolor",
1757 "NODE.node", "NODE.overlibwidth", "NODE.overlibheight", "NODE.labeloffset"
1758 );
1759 
1760 
1761 if( (strchr($input,"\n")!=FALSE) || (strchr($input,"\r")!=FALSE ) )
1762 {
1763 debug("ReadConfig Detected that this is a config fragment.\n");
1764 // strip out any Windows line-endings that have gotten in here
1765 $input=str_replace("\r", "", $input);
1766 $lines = split("/n",$input);
1767 $filename = "{text insert}";
1768 }
1769 else
1770 {
1771 debug("ReadConfig Detected that this is a config filename.\n");
1772 $filename = $input;
1773 
1774 $fd=fopen($filename, "r");
1775 
1776 if ($fd)
1777 {
1778 while (!feof($fd))
1779 {
1780 $buffer=fgets($fd, 4096);
1781 // strip out any Windows line-endings that have gotten in here
1782 $buffer=str_replace("\r", "", $buffer);
1783 $lines[] = $buffer;
1784 }
1785 fclose($fd);
1786 }
1787 }
1788 
1789 $linecount = 0;
1790 $context = $initial_context;
1791 
1792 foreach($lines as $buffer)
1793 {
1794 $linematched=0;
1795 $linecount++;
1796 $nextcontext = "";
1797 $key = "";
1798 
1799 $buffer = trim($buffer);
1800 // alternative for use later where quoted strings are more useful
1801 $args = ParseString($buffer);
1802 
1803 if(sizeof($args) > 0)
1804 {
1805 $linematched++;
1806 $cmd = strtolower(array_shift($args));
1807 
1808 if($cmd == 'include')
1809 {
1810 $this->ReadConfigNG($args[0],TRUE, $context);
1811 }
1812 elseif($cmd == 'node')
1813 {
1814 $context = "NODE.".$args[0];
1815 }
1816 elseif($cmd == 'link')
1817 {
1818 $context = "LINK.".$args[0];
1819 $vcount = 0; # reset the via-number counter, it's a new link
1820 }
1821 elseif($cmd == 'scale' || $cmd == 'keystyle' || $cmd == 'keypos')
1822 {
1823 if( preg_match("/^[0-9\-]+/i",$args[0]) )
1824 {
1825 $scalename = "DEFAULT";
1826 }
1827 else
1828 {
1829 $scalename = array_shift($args);
1830 }
1831 if($cmd=="scale") $key = $args[0]."_".$args[1];
1832 $nextcontext = $context;
1833 $context = "SCALE.".$scalename;
1834 }
1835 
1836 array_unshift($args,$cmd);
1837 
1838 if($context == 'GLOBAL')
1839 {
1840 $ctype='GLOBAL';
1841 }
1842 else
1843 {
1844 list($ctype,$junk) = split("\\.", $context, 2);
1845 }
1846 
1847 $lookup = $ctype.".".$cmd;
1848 
1849 // Some things (scales, mainly) might define special keys
1850 // the key should be unique for that object
1851 // most (all?) things for a link or node are one-offs.
1852 if($key == "") $key = $cmd;
1853 if($cmd == 'set' || $cmd == 'fontdefine') $key .= "_".$args[1];
1854 if($cmd == 'via')
1855 {
1856 $key .= "_".$vcount;
1857 $vcount++;
1858 }
1859 
1860 # everything else
1861 if( substr($cmd, 0, 1) != '#')
1862 {
1863 if(! in_array($lookup, $valid_commands))
1864 {
1865 print "INVALID COMMAND: $lookup\n";
1866 }
1867 
1868 if(isset($config[$context][$key]))
1869 {
1870 print "REDEFINED $key in $context\n";
1871 }
1872 else
1873 {
1874 array_unshift($args,$linecount);
1875 array_unshift($args,$filename);
1876 $this->config[$context][$key] = $args;
1877 }
1878 }
1879 print "$context\\$key $filename:$linecount ".join("|",$args)."\n";
1880 
1881 if($nextcontext != "") $context = $nextcontext;
1882 }
1883 
1884 if ($linematched == 0 && trim($buffer) != '') { warn ("Unrecognised config on line $linecount: $buffer\n"); }
1885 
1886 }
1887 
1888 if(! $is_include)
1889 {
1890 print_r($this->config);
1891 
1892 foreach ($this->config as $context=>$values)
1893 {
1894 print "> $context\n";
1895 }
1896 }
1897 
1898 
1899}
1900 
1901function ReadConfigNNG($input, $is_include=FALSE, $initial_context="GLOBAL")
1902{
1903 global $valid_commands;
1904 
1905 if( (strchr($input,"\n")!=FALSE) || (strchr($input,"\r")!=FALSE ) )
1906 {
1907 debug("ReadConfig Detected that this is a config fragment.\n");
1908 // strip out any Windows line-endings that have gotten in here
1909 $input=str_replace("\r", "", $input);
1910 $lines = split("/n",$input);
1911 $filename = "{text insert}";
1912 }
1913 else
1914 {
1915 debug("ReadConfig Detected that this is a config filename.\n");
1916 $filename = $input;
1917 
1918 $fd=fopen($filename, "r");
1919 
1920 if ($fd)
1921 {
1922 while (!feof($fd))
1923 {
1924 $buffer=fgets($fd, 4096);
1925 // strip out any Windows line-endings that have gotten in here
1926 $buffer=str_replace("\r", "", $buffer);
1927 $lines[] = $buffer;
1928 }
1929 fclose($fd);
1930 }
1931 }
1932 
1933 $linecount = 0;
1934 $context = $initial_context;
1935 
1936 foreach($lines as $buffer)
1937 {
1938 $linematched=0;
1939 $linecount++;
1940 $nextcontext = "";
1941 $key = "";
1942 
1943 $buffer = trim($buffer);
1944 // alternative for use later where quoted strings are more useful
1945 $args = ParseString($buffer);
1946 
1947 if(sizeof($args) > 0)
1948 {
1949 $linematched++;
1950 $cmd = strtolower(array_shift($args));
1951 
1952 if($cmd == 'include')
1953 {
1954 $context = $this->ReadConfigNNG($args[0],TRUE, $context);
1955 }
1956 elseif($cmd == 'node')
1957 {
1958 $context = "NODE.".$args[0];
1959 }
1960 elseif($cmd == 'link')
1961 {
1962 $context = "LINK.".$args[0];
1963 $vcount = 0; # reset the via-number counter, it's a new link
1964 }
1965 elseif($cmd == 'scale' || $cmd == 'keystyle' || $cmd == 'keypos')
1966 {
1967 if( preg_match("/^[0-9\-]+/i",$args[0]) )
1968 {
1969 $scalename = "DEFAULT";
1970 }
1971 else
1972 {
1973 $scalename = array_shift($args);
1974 }
1975 if($cmd=="scale") $key = $args[0]."_".$args[1];
1976 $nextcontext = $context;
1977 $context = "SCALE.".$scalename;
1978 }
1979 
1980 array_unshift($args,$cmd);
1981 
1982 if($context == 'GLOBAL')
1983 {
1984 $ctype='GLOBAL';
1985 }
1986 else
1987 {
1988 list($ctype,$junk) = split("\\.", $context, 2);
1989 }
1990 
1991 $lookup = $ctype.".".$cmd;
1992 
1993 // Some things (scales, mainly) might define special keys
1994 // the key should be unique for that object
1995 // most (all?) things for a link or node are one-offs.
1996 if($key == "") $key = $cmd;
1997 if($cmd == 'set' || $cmd == 'fontdefine') $key .= "_".$args[1];
1998 if($cmd == 'via')
1999 {
2000 $key .= "_".$vcount;
2001 $vcount++;
2002 }
2003 
2004 # everything else
2005 if( substr($cmd, 0, 1) != '#')
2006 {
2007 if(! array_key_exists($lookup, $valid_commands))
2008 {
2009 print "INVALID COMMAND: $lookup\n";
2010 }
2011 
2012 if(isset($config[$context][$key]))
2013 {
2014 print "REDEFINED $key in $context\n";
2015 }
2016 else
2017 {
2018 array_unshift($args,$linecount);
2019 array_unshift($args,$filename);
2020 $this->config[$context][$key] = $args;
2021 }
2022 }
2023 print "$context\\$key $filename:$linecount ".join("|",$args)."\n";
2024 
2025 if($nextcontext != "") $context = $nextcontext;
2026 }
2027 
2028 if ($linematched == 0 && trim($buffer) != '') { warn ("Unrecognised config on line $linecount: $buffer\n"); }
2029 
2030 }
2031 
2032 if(! $is_include)
2033 {
2034 
2035 # print_r($this->config);
2036 
2037 foreach ($this->config as $context=>$values)
2038 {
2039 # print "> $context\n";
2040 }
2041 }
2042 
2043 return($context);
2044}
2045 
2046 
2047function WriteConfigNG($filename)
2048{
2049 global $WEATHERMAP_VERSION;
2050 
2051 $fd = fopen($filename);
2052 
2053 
2054 
2055 fclose($fd);
2056}
2057 
2058function ReadConfig($input, $is_include=FALSE)
2059{
20601simandl $curnode=null;
2061 $curlink=null;
2062 $matches=0;
2063 $nodesseen=0;
2064 $linksseen=0;
2065 $scalesseen=0;
206685simandl $last_seen="GLOBAL";
2067 $filename = "";
2068 $objectlinecount=0;
20691simandl 
207085simandl // check if $input is more than one line. if it is, it's a text of a config file
2071 // if it isn't, it's the filename
20721simandl 
207385simandl $lines = array();
2074 
2075 if( (strchr($input,"\n")!=FALSE) || (strchr($input,"\r")!=FALSE ) )
20761simandl {
207785simandl debug("ReadConfig Detected that this is a config fragment.\n");
2078 // strip out any Windows line-endings that have gotten in here
2079 $input=str_replace("\r", "", $input);
2080 $lines = split("/n",$input);
2081 $filename = "{text insert}";
2082 }
2083 else
2084 {
2085 debug("ReadConfig Detected that this is a config filename.\n");
2086 $filename = $input;
2087 
2088 if($is_include){
2089 debug("ReadConfig Detected that this is an INCLUDED config filename.\n");
2090 if($is_include && in_array($filename, $this->included_files))
2091 {
2092 warn("Attempt to include '$filename' twice! Skipping it.\n");
2093 return(FALSE);
20941simandl }
2095 else
2096 {
209785simandl $this->included_files[] = $filename;
2098 $this->has_includes = TRUE;
2099 }
2100 }
2101 
2102 $fd=fopen($filename, "r");
2103 
2104 if ($fd)
2105 {
2106 while (!feof($fd))
2107 {
2108 $buffer=fgets($fd, 4096);
2109 // strip out any Windows line-endings that have gotten in here
2110 $buffer=str_replace("\r", "", $buffer);
2111 $lines[] = $buffer;
2112 }
2113 fclose($fd);
2114 }
2115 }
2116 
2117 $linecount = 0;
2118 $objectlinecount = 0;
21191simandl 
212085simandl foreach($lines as $buffer)
2121 {
2122 $linematched=0;
2123 $linecount++;
2124 
2125 if (preg_match("/^\s*#/", $buffer)) {
2126 // this is a comment line
2127 }
2128 else
2129 {
2130 $buffer = trim($buffer);
2131 
2132 // for any other config elements that are shared between nodes and links, they can use this
2133 unset($curobj);
2134 $curobj = NULL;
2135 if($last_seen == "LINK") $curobj = &$curlink;
2136 if($last_seen == "NODE") $curobj = &$curnode;
2137 if($last_seen == "GLOBAL") $curobj = &$this;
2138 
2139 $objectlinecount++;
2140 
2141 #if (preg_match("/^\s*(LINK|NODE)\s+([A-Za-z][A-Za-z0-9_\.\-\:]*)\s*$/i", $buffer, $matches))
2142 if (preg_match("/^\s*(LINK|NODE)\s+(\S+)\s*$/i", $buffer, $matches))
2143 {
2144 $objectlinecount = 0;
2145 if(1==1)
21461simandl {
214785simandl $this->ReadConfig_Commit($curobj);
2148 }
2149 else
2150 {
21511simandl // first, save the previous item, before starting work on the new one
2152 if ($last_seen == "NODE")
2153 {
215485simandl $this->nodes[$curnode->name]=$curnode;
2155 if($curnode->template == 'DEFAULT') $this->node_template_tree[ "DEFAULT" ][]= $curnode->name;
2156 
2157 debug ("Saving Node: " . $curnode->name . "\n");
21581simandl }
2159 
2160 if ($last_seen == "LINK")
2161 {
216285simandl if (isset($curlink->a) && isset($curlink->b))
21631simandl {
216485simandl $this->links[$curlink->name]=$curlink;
2165 debug ("Saving Link: " . $curlink->name . "\n");
21661simandl }
2167 else
2168 {
216985simandl $this->links[$curlink->name]=$curlink;
2170 debug ("Saving Template-Only Link: " . $curlink->name . "\n");
21711simandl }
217285simandl if($curlink->template == 'DEFAULT') $this->link_template_tree[ "DEFAULT" ][]= $curlink->name;
21731simandl }
217485simandl }
21751simandl 
217685simandl if ($matches[1] == 'LINK')
2177 {
2178 if ($matches[2] == 'DEFAULT')
21791simandl {
218085simandl if ($linksseen > 0) { warn
2181 ("LINK DEFAULT is not the first LINK. Defaults will not apply to earlier LINKs. [WMWARN26]\n");
21821simandl }
218385simandl unset($curlink);
2184 debug("Loaded LINK DEFAULT\n");
2185 $curlink = $this->links['DEFAULT'];
2186 }
2187 else
2188 {
2189 unset($curlink);
2190 
2191 if(isset($this->links[$matches[2]]))
21921simandl {
219385simandl warn("Duplicate link name ".$matches[2]." at line $linecount - only the last one defined is used. [WMWARN25]\n");
21941simandl }
219585simandl 
2196 debug("New LINK ".$matches[2]."\n");
2197 $curlink=new WeatherMapLink;
2198 $curlink->name=$matches[2];
2199 $curlink->Reset($this);
2200 
2201 $linksseen++;
22021simandl }
2203 
220485simandl $last_seen="LINK";
2205 $curlink->configline = $linecount;
2206 $linematched++;
2207 $curobj = &$curlink;
2208 }
22091simandl 
221085simandl if ($matches[1] == 'NODE')
2211 {
2212 if ($matches[2] == 'DEFAULT')
2213 {
2214 if ($nodesseen > 0) { warn
2215 ("NODE DEFAULT is not the first NODE. Defaults will not apply to earlier NODEs. [WMWARN27]\n");
22161simandl }
221785simandl 
2218 unset($curnode);
2219 debug("Loaded NODE DEFAULT\n");
2220 $curnode = $this->nodes['DEFAULT'];
2221 }
2222 else
2223 {
2224 unset($curnode);
2225 
2226 if(isset($this->nodes[$matches[2]]))
22271simandl {
222885simandl warn("Duplicate node name ".$matches[2]." at line $linecount - only the last one defined is used. [WMWARN24]\n");
22291simandl }
2230 
223185simandl $curnode=new WeatherMapNode;
2232 $curnode->name=$matches[2];
2233 $curnode->Reset($this);
2234 
2235 $nodesseen++;
22361simandl }
223785simandl 
2238 $curnode->configline = $linecount;
2239 $last_seen="NODE";
2240 $linematched++;
2241 $curobj = &$curnode;
22421simandl }
224385simandl 
2244 # record where we first heard about this object
2245 $curobj->defined_in = $filename;
2246 }
22471simandl 
224885simandl // most of the config keywords just copy stuff into object properties.
2249 // these are all dealt with from this one array. The special-cases
2250 // follow on from that
2251 $config_keywords = array(
2252 array('LINK','/^\s*(MAXVALUE|BANDWIDTH)\s+(\d+\.?\d*[KMGT]?)\s+(\d+\.?\d*[KMGT]?)\s*$/i',array('max_bandwidth_in_cfg'=>2,'max_bandwidth_out_cfg'=>3)),
2253 array('LINK','/^\s*(MAXVALUE|BANDWIDTH)\s+(\d+\.?\d*[KMGT]?)\s*$/i',array('max_bandwidth_in_cfg'=>2,'max_bandwidth_out_cfg'=>2)),
2254 array('NODE','/^\s*(MAXVALUE)\s+(\d+\.?\d*[KMGT]?)\s+(\d+\.?\d*[KMGT]?)\s*$/i',array('max_bandwidth_in_cfg'=>2,'max_bandwidth_out_cfg'=>3)),
2255 array('NODE','/^\s*(MAXVALUE)\s+(\d+\.?\d*[KMGT]?)\s*$/i',array('max_bandwidth_in_cfg'=>2,'max_bandwidth_out_cfg'=>2)),
2256 array('GLOBAL','/^\s*BACKGROUND\s+(.*)\s*$/i',array('background'=>1)),
2257 array('GLOBAL','/^\s*HTMLOUTPUTFILE\s+(.*)\s*$/i',array('htmloutputfile'=>1)),
2258 array('GLOBAL','/^\s*HTMLSTYLESHEET\s+(.*)\s*$/i',array('htmlstylesheet'=>1)),
2259 array('GLOBAL','/^\s*IMAGEOUTPUTFILE\s+(.*)\s*$/i',array('imageoutputfile'=>1)),
2260 array('GLOBAL','/^\s*IMAGEURI\s+(.*)\s*$/i',array('imageuri'=>1)),
2261 array('GLOBAL','/^\s*TITLE\s+(.*)\s*$/i',array('title'=>1)),
2262 array('GLOBAL','/^\s*HTMLSTYLE\s+(static|overlib)\s*$/i',array('htmlstyle'=>1)),
2263 array('GLOBAL','/^\s*KEYFONT\s+(\d+)\s*$/i',array('keyfont'=>1)),
2264 array('GLOBAL','/^\s*TITLEFONT\s+(\d+)\s*$/i',array('titlefont'=>1)),
2265 array('GLOBAL','/^\s*TIMEFONT\s+(\d+)\s*$/i',array('timefont'=>1)),
2266 array('GLOBAL','/^\s*TITLEPOS\s+(-?\d+)\s+(-?\d+)\s*$/i',array('titlex'=>1, 'titley'=>2)),
2267 array('GLOBAL','/^\s*TITLEPOS\s+(-?\d+)\s+(-?\d+)\s+(.*)\s*$/i',array('titlex'=>1, 'titley'=>2, 'title'=>3)),
2268 array('GLOBAL','/^\s*TIMEPOS\s+(-?\d+)\s+(-?\d+)\s*$/i',array('timex'=>1, 'timey'=>2)),
2269 array('GLOBAL','/^\s*TIMEPOS\s+(-?\d+)\s+(-?\d+)\s+(.*)\s*$/i',array('timex'=>1, 'timey'=>2, 'stamptext'=>3)),
2270 array('GLOBAL','/^\s*MINTIMEPOS\s+(-?\d+)\s+(-?\d+)\s*$/i',array('mintimex'=>1, 'mintimey'=>2)),
2271 array('GLOBAL','/^\s*MINTIMEPOS\s+(-?\d+)\s+(-?\d+)\s+(.*)\s*$/i',array('mintimex'=>1, 'mintimey'=>2, 'minstamptext'=>3)),
2272 array('GLOBAL','/^\s*MAXTIMEPOS\s+(-?\d+)\s+(-?\d+)\s*$/i',array('maxtimex'=>1, 'maxtimey'=>2)),
2273 array('GLOBAL','/^\s*MAXTIMEPOS\s+(-?\d+)\s+(-?\d+)\s+(.*)\s*$/i',array('maxtimex'=>1, 'maxtimey'=>2, 'maxstamptext'=>3)),
2274 array('NODE', "/^\s*LABEL\s*$/i", array('label'=>'')), # special case for blank labels
2275 array('NODE', "/^\s*LABEL\s+(.*)\s*$/i", array('label'=>1)),
2276 array('(LINK|GLOBAL)', "/^\s*WIDTH\s+(\d+)\s*$/i", array('width'=>1)),
2277 array('(LINK|GLOBAL)', "/^\s*HEIGHT\s+(\d+)\s*$/i", array('height'=>1)),
2278 array('LINK', "/^\s*WIDTH\s+(\d+\.\d+)\s*$/i", array('width'=>1)),
2279 array('LINK', '/^\s*ARROWSTYLE\s+(classic|compact)\s*$/i', array('arrowstyle'=>1)),
2280 array('LINK', '/^\s*VIASTYLE\s+(curved|angled)\s*$/i', array('viastyle'=>1)),
2281 array('LINK', '/^\s*INCOMMENT\s+(.*)\s*$/i', array('comments[IN]'=>1)),
2282 array('LINK', '/^\s*OUTCOMMENT\s+(.*)\s*$/i', array('comments[OUT]'=>1)),
2283 array('LINK', '/^\s*BWFONT\s+(\d+)\s*$/i', array('bwfont'=>1)),
2284 array('LINK', '/^\s*COMMENTFONT\s+(\d+)\s*$/i', array('commentfont'=>1)),
2285 array('LINK', '/^\s*COMMENTSTYLE\s+(edge|center)\s*$/i', array('commentstyle'=>1)),
2286 array('LINK', '/^\s*DUPLEX\s+(full|half)\s*$/i', array('duplex'=>1)),
2287 array('LINK', '/^\s*BWSTYLE\s+(classic|angled)\s*$/i', array('labelboxstyle'=>1)),
2288 array('LINK', '/^\s*LINKSTYLE\s+(twoway|oneway)\s*$/i', array('linkstyle'=>1)),
2289 array('LINK', '/^\s*BWLABELPOS\s+(\d+)\s(\d+)\s*$/i', array('labeloffset_in'=>1,'labeloffset_out'=>2)),
2290 array('LINK', '/^\s*COMMENTPOS\s+(\d+)\s(\d+)\s*$/i', array('commentoffset_in'=>1, 'commentoffset_out'=>2)),
2291 array('LINK', '/^\s*USESCALE\s+([A-Za-z][A-Za-z0-9_]*)\s*$/i', array('usescale'=>1)),
2292 array('LINK', '/^\s*USESCALE\s+([A-Za-z][A-Za-z0-9_]*)\s+(absolute|percent)\s*$/i', array('usescale'=>1,'scaletype'=>2)),
22931simandl 
229485simandl array('LINK', '/^\s*SPLITPOS\s+(\d+)\s*$/i', array('splitpos'=>1)),
2295 
2296 array('NODE', '/^\s*LABELOFFSET\s+([-+]?\d+)\s+([-+]?\d+)\s*$/i', array('labeloffsetx'=>1,'labeloffsety'=>2)),
2297 array('NODE', '/^\s*LABELOFFSET\s+(C|NE|SE|NW|SW|N|S|E|W)\s*$/i', array('labeloffset'=>1)),
2298 array('NODE', '/^\s*LABELOFFSET\s+((C|NE|SE|NW|SW|N|S|E|W)\d+)\s*$/i', array('labeloffset'=>1)),
2299 array('NODE', '/^\s*LABELOFFSET\s+(-?\d+r\d+)\s*$/i', array('labeloffset'=>1)),
2300 
2301 array('NODE', '/^\s*LABELFONT\s+(\d+)\s*$/i', array('labelfont'=>1)),
2302 array('NODE', '/^\s*LABELANGLE\s+(0|90|180|270)\s*$/i', array('labelangle'=>1)),
2303 # array('(NODE|LINK)', '/^\s*TEMPLATE\s+(\S+)\s*$/i', array('template'=>1)),
2304 
2305 array('LINK', '/^\s*OUTBWFORMAT\s+(.*)\s*$/i', array('bwlabelformats[OUT]'=>1,'labelstyle'=>'--')),
2306 array('LINK', '/^\s*INBWFORMAT\s+(.*)\s*$/i', array('bwlabelformats[IN]'=>1,'labelstyle'=>'--')),
2307 # array('NODE','/^\s*ICON\s+none\s*$/i',array('iconfile'=>'')),
2308 array('NODE','/^\s*ICON\s+(\S+)\s*$/i',array('iconfile'=>1, 'iconscalew'=>'#0', 'iconscaleh'=>'#0')),
2309 array('NODE','/^\s*ICON\s+(\S+)\s*$/i',array('iconfile'=>1)),
2310 array('NODE','/^\s*ICON\s+(\d+)\s+(\d+)\s+(inpie|outpie|box|rbox|round|gauge|nink)\s*$/i',array('iconfile'=>3, 'iconscalew'=>1, 'iconscaleh'=>2)),
2311 array('NODE','/^\s*ICON\s+(\d+)\s+(\d+)\s+(\S+)\s*$/i',array('iconfile'=>3, 'iconscalew'=>1, 'iconscaleh'=>2)),
2312 
2313 array('NODE','/^\s*NOTES\s+(.*)\s*$/i',array('notestext[IN]'=>1,'notestext[OUT]'=>1)),
2314 array('LINK','/^\s*NOTES\s+(.*)\s*$/i',array('notestext[IN]'=>1,'notestext[OUT]'=>1)),
2315 array('LINK','/^\s*INNOTES\s+(.*)\s*$/i',array('notestext[IN]'=>1)),
2316 array('LINK','/^\s*OUTNOTES\s+(.*)\s*$/i',array('notestext[OUT]'=>1)),
2317 
2318 array('NODE','/^\s*INFOURL\s+(.*)\s*$/i',array('infourl[IN]'=>1,'infourl[OUT]'=>1)),
2319 array('LINK','/^\s*INFOURL\s+(.*)\s*$/i',array('infourl[IN]'=>1,'infourl[OUT]'=>1)),
2320 array('LINK','/^\s*ININFOURL\s+(.*)\s*$/i',array('infourl[IN]'=>1)),
2321 array('LINK','/^\s*OUTINFOURL\s+(.*)\s*$/i',array('infourl[OUT]'=>1)),
2322 
2323 array('NODE','/^\s*OVERLIBCAPTION\s+(.*)\s*$/i',array('overlibcaption[IN]'=>1,'overlibcaption[OUT]'=>1)),
2324 array('LINK','/^\s*OVERLIBCAPTION\s+(.*)\s*$/i',array('overlibcaption[IN]'=>1,'overlibcaption[OUT]'=>1)),
2325 array('LINK','/^\s*INOVERLIBCAPTION\s+(.*)\s*$/i',array('overlibcaption[IN]'=>1)),
2326 array('LINK','/^\s*OUTOVERLIBCAPTION\s+(.*)\s*$/i',array('overlibcaption[OUT]'=>1)),
2327 
2328 array('(NODE|LINK)', "/^\s*ZORDER\s+([-+]?\d+)\s*$/i", array('zorder'=>1)),
2329 array('(NODE|LINK)', "/^\s*OVERLIBWIDTH\s+(\d+)\s*$/i", array('overlibwidth'=>1)),
2330 array('(NODE|LINK)', "/^\s*OVERLIBHEIGHT\s+(\d+)\s*$/i", array('overlibheight'=>1)),
2331 array('NODE', "/^\s*POSITION\s+([-+]?\d+)\s+([-+]?\d+)\s*$/i", array('x'=>1,'y'=>2)),
2332 array('NODE', "/^\s*POSITION\s+(\S+)\s+([-+]?\d+)\s+([-+]?\d+)\s*$/i", array('x'=>2,'y'=>3,'original_x'=>2,'original_y'=>3,'relative_to'=>1,'relative_resolved'=>FALSE)),
2333 array('NODE', "/^\s*POSITION\s+(\S+)\s+([-+]?\d+)r(\d+)\s*$/i", array('x'=>2,'y'=>3,'original_x'=>2,'original_y'=>3,'relative_to'=>1,'polar'=>TRUE,'relative_resolved'=>FALSE))
2334 );
23351simandl 
233685simandl // alternative for use later where quoted strings are more useful
2337 $args = ParseString($buffer);
23381simandl 
233985simandl // this loop replaces a whole pile of duplicated ifs with something with consistent handling
2340 foreach ($config_keywords as $keyword)
2341 {
2342 if(preg_match("/".$keyword[0]."/",$last_seen))
23431simandl {
234485simandl $statskey = $last_seen."-".$keyword[1];
2345 $statskey = str_replace( array('/^\s*','\s*$/i'),array('',''), $statskey);
2346 if(!isset($this->usage_stats[$statskey])) $this->usage_stats[$statskey] = 0;
2347 
2348 if(preg_match($keyword[1],$buffer,$matches))
23491simandl {
235085simandl # print "CONFIG MATCHED: ".$keyword[1]."\n";
2351 
2352 $this->usage_stats[$statskey]++;
2353 
2354 foreach ($keyword[2] as $key=>$val)
2355 {
2356 // so we can poke in numbers too, if the value starts with #
2357 // then take the # off, and treat the rest as a number literal
2358 if(preg_match("/^#(.*)/",$val,$m))
2359 {
2360 $val = $m[1];
2361 }
2362 elseif(is_numeric($val))
2363 {
2364 // if it's a number, then it;s a match number,
2365 // otherwise it's a literal to be put into a variable
2366 $val = $matches[$val];
2367 }
2368 
2369 assert('is_object($curobj)');
2370 
2371 if(preg_match('/^(.*)\[([^\]]+)\]$/',$key,$m))
2372 {
2373 $index = constant($m[2]);
2374 $key = $m[1];
2375 $curobj->{$key}[$index] = $val;
2376 }
2377 else
2378 {
2379 $curobj->$key = $val;
2380 }
2381 }
23821simandl $linematched++;
238385simandl # print "\n\n";
2384 break;
23851simandl }
2386 }
238785simandl }
23881simandl 
238985simandl if (preg_match("/^\s*NODES\s+(\S+)\s+(\S+)\s*$/i", $buffer, $matches))
2390 {
2391 if ($last_seen == 'LINK')
23921simandl {
239385simandl $valid_nodes=2;
23941simandl 
239585simandl foreach (array(1, 2)as $i)
23961simandl {
239785simandl $endoffset[$i]='C';
2398 $nodenames[$i]=$matches[$i];
23991simandl 
240085simandl // percentage of compass - must be first
2401 if (preg_match("/:(NE|SE|NW|SW|N|S|E|W|C)(\d+)$/i", $matches[$i], $submatches))
24021simandl {
240385simandl $endoffset[$i]=$submatches[1].$submatches[2];
2404 $nodenames[$i]=preg_replace("/:(NE|SE|NW|SW|N|S|E|W|C)\d+$/i", '', $matches[$i]);
2405 $this->need_size_precalc=TRUE;
2406 }
2407 
2408 if (preg_match("/:(NE|SE|NW|SW|N|S|E|W|C)$/i", $matches[$i], $submatches))
2409 {
2410 $endoffset[$i]=$submatches[1];
2411 $nodenames[$i]=preg_replace("/:(NE|SE|NW|SW|N|S|E|W|C)$/i", '', $matches[$i]);
2412 $this->need_size_precalc=TRUE;
2413 }
24141simandl 
241585simandl if( preg_match("/:(-?\d+r\d+)$/i", $matches[$i], $submatches) )
2416 {
2417 $endoffset[$i]=$submatches[1];
2418 $nodenames[$i]=preg_replace("/:(-?\d+r\d+)$/i", '', $matches[$i]);
2419 $this->need_size_precalc=TRUE;
24201simandl }
2421 
242285simandl if (preg_match("/:([-+]?\d+):([-+]?\d+)$/i", $matches[$i], $submatches))
24231simandl {
242485simandl $xoff = $submatches[1];
2425 $yoff = $submatches[2];
2426 $endoffset[$i]=$xoff.":".$yoff;
2427 $nodenames[$i]=preg_replace("/:$xoff:$yoff$/i", '', $matches[$i]);
2428 $this->need_size_precalc=TRUE;
24291simandl }
2430 
243185simandl if (!array_key_exists($nodenames[$i], $this->nodes))
2432 {
2433 warn ("Unknown node '" . $nodenames[$i] . "' on line $linecount of config\n");
2434 $valid_nodes--;
2435 }
24361simandl }
243785simandl 
2438 // TODO - really, this should kill the whole link, and reset for the next one
2439 if ($valid_nodes == 2)
2440 {
2441 $curlink->a=$this->nodes[$nodenames[1]];
2442 $curlink->b=$this->nodes[$nodenames[2]];
2443 $curlink->a_offset=$endoffset[1];
2444 $curlink->b_offset=$endoffset[2];
2445 }
2446 else {
2447 // this'll stop the current link being added
2448 $last_seen="broken"; }
2449 
2450 $linematched++;
24511simandl }
245285simandl }
24531simandl 
245485simandl if ( $last_seen=='GLOBAL' && preg_match("/^\s*INCLUDE\s+(.*)\s*$/i", $buffer, $matches))
2455 {
2456 if(file_exists($matches[1])){
2457 debug("Including '{$matches[1]}'\n");
2458 $this->ReadConfig($matches[1], TRUE);
2459 $last_seen = "GLOBAL";
2460 }else{
2461 warn("INCLUDE File '{$matches[1]}' not found!\n");
2462 }
2463 $linematched++;
2464 }
2465 
2466 if ( ( $last_seen=='NODE' || $last_seen=='LINK' ) && preg_match("/^\s*TARGET\s+(.*)\s*$/i", $buffer, $matches))
2467 {
2468 $linematched++;
2469 # $targets=preg_split('/\s+/', $matches[1], -1, PREG_SPLIT_NO_EMPTY);
2470 $rawtargetlist = $matches[1]." ";
2471 
2472 if($args[0]=='TARGET')
24731simandl {
2474 // wipe any existing targets, otherwise things in the DEFAULT accumulate with the new ones
2475 $curobj->targets = array();
247685simandl array_shift($args); // take off the actual TARGET keyword
2477 
2478 foreach($args as $arg)
24791simandl {
2480 // we store the original TARGET string, and line number, along with the breakdown, to make nicer error messages later
248185simandl // array of 7 things:
2482 // - only 0,1,2,3,4 are used at the moment (more used to be before DS plugins)
2483 // 0 => final target string (filled in by ReadData)
2484 // 1 => multiplier (filled in by ReadData)
2485 // 2 => config filename where this line appears
2486 // 3 => linenumber in that file
2487 // 4 => the original target string
2488 // 5 => the plugin to use to pull data
2489 $newtarget=array('','',$filename,$linecount,$arg,"","");
24901simandl if ($curobj)
2491 {
249285simandl debug(" TARGET: $arg\n");
24931simandl $curobj->targets[]=$newtarget;
2494 }
2495 }
2496 }
249785simandl }
2498 
2499 if ($last_seen == 'LINK' && preg_match(
2500 "/^\s*BWLABEL\s+(bits|percent|unformatted|none)\s*$/i", $buffer,
2501 $matches))
2502 {
2503 $format_in = '';
2504 $format_out = '';
2505 $style = strtolower($matches[1]);
2506 if($style=='percent')
25071simandl {
250885simandl $format_in = FMT_PERC_IN;
2509 $format_out = FMT_PERC_OUT;
25101simandl }
251185simandl if($style=='bits')
25121simandl {
251385simandl $format_in = FMT_BITS_IN;
2514 $format_out = FMT_BITS_OUT;
25151simandl }
251685simandl if($style=='unformatted')
25171simandl {
251885simandl $format_in = FMT_UNFORM_IN;
2519 $format_out = FMT_UNFORM_OUT;
25201simandl }
2521 
252285simandl $curobj->labelstyle=$style;
2523 $curobj->bwlabelformats[IN] = $format_in;
2524 $curobj->bwlabelformats[OUT] = $format_out;
2525 $linematched++;
2526 }
2527 
2528 if (preg_match("/^\s*SET\s+(\S+)\s+(.*)\s*$/i", $buffer, $matches))
2529 {
2530 $curobj->add_hint($matches[1],trim($matches[2]));
25311simandl $linematched++;
253285simandl }
25331simandl 
253485simandl // allow setting a variable to ""
2535 if (preg_match("/^\s*SET\s+(\S+)\s*$/i", $buffer, $matches))
2536 {
2537 $curobj->add_hint($matches[1],'');
25381simandl $linematched++;
253985simandl }
2540 
2541 if (preg_match("/^\s*(IN|OUT)?OVERLIBGRAPH\s+(.+)$/i", $buffer, $matches))
2542 {
2543 $this->has_overlibs = TRUE;
2544 if($last_seen == 'NODE' && $matches[1] != '') {
2545 warn("IN/OUTOVERLIBGRAPH make no sense for a NODE! [WMWARN42]\n");
2546 } else if($last_seen == 'LINK' || $last_seen=='NODE' ) {
25471simandl 
254885simandl $urls = preg_split('/\s+/', $matches[2], -1, PREG_SPLIT_NO_EMPTY);
25491simandl 
255085simandl if($matches[1] == 'IN') $index = IN;
2551 if($matches[1] == 'OUT') $index = OUT;
2552 if($matches[1] == '') {
2553 $curobj->overliburl[IN]=$urls;
2554 $curobj->overliburl[OUT]=$urls;
2555 } else {
2556 $curobj->overliburl[$index]=$urls;
25571simandl }
2558 $linematched++;
2559 }
256085simandl }
2561 
2562 // array('(NODE|LINK)', '/^\s*TEMPLATE\s+(\S+)\s*$/i', array('template'=>1)),
2563 
2564 if ( ( $last_seen=='NODE' || $last_seen=='LINK' ) && preg_match("/^\s*TEMPLATE\s+(\S+)\s*$/i", $buffer, $matches))
2565 {
2566 $tname = $matches[1];
2567 if( ($last_seen=='NODE' && isset($this->nodes[$tname])) || ($last_seen=='LINK' && isset($this->links[$tname])) )
25681simandl {
256985simandl $curobj->template = $matches[1];
2570 debug("Resetting to template $last_seen ".$curobj->template."\n");
2571 $curobj->Reset($this);
2572 if( $objectlinecount > 1 ) warn("line $linecount: TEMPLATE is not first line of object. Some data may be lost. [WMWARN39]\n");
2573 // build up a list of templates - this will be useful later for the tree view
2574 
2575 if($last_seen == 'NODE') $this->node_template_tree[ $tname ][]= $curobj->name;
2576 if($last_seen == 'LINK') $this->link_template_tree[ $tname ][]= $curobj->name;
25771simandl }
257885simandl else
25791simandl {
258085simandl warn("line $linecount: $last_seen TEMPLATE '$tname' doesn't exist! (if it does exist, check it's defined first) [WMWARN40]\n");
25811simandl }
258285simandl $linematched++;
2583 
2584 }
25851simandl 
258685simandl if ($last_seen == 'LINK' && preg_match("/^\s*VIA\s+([-+]?\d+)\s+([-+]?\d+)\s*$/i", $buffer, $matches))
2587 {
2588 $curlink->vialist[]=array
2589 (
2590 $matches[1],
2591 $matches[2]
2592 );
25931simandl 
259485simandl $linematched++;
2595 }
25961simandl 
259785simandl if ($last_seen == 'LINK' && preg_match("/^\s*VIA\s+(\S+)\s+([-+]?\d+)\s+([-+]?\d+)\s*$/i", $buffer, $matches))
2598 {
2599 $curlink->vialist[]=array
2600 (
2601 $matches[2],
2602 $matches[3],
2603 $matches[1]
2604 );
26051simandl 
260685simandl $linematched++;
2607 }
26081simandl 
260985simandl if( ($last_seen == 'NODE') && preg_match("/^\s*USE(ICON)?SCALE\s+([A-Za-z][A-Za-z0-9_]*)(\s+(in|out))?(\s+(absolute|percent))?\s*$/i",$buffer,$matches))
2610 {
2611 $svar = '';
2612 $stype = 'percent';
2613 if(isset($matches[3]))
26141simandl {
261585simandl $svar = trim($matches[3]);
26161simandl }
261785simandl if(isset($matches[6]))
26181simandl {
261985simandl $stype = strtolower(trim($matches[6]));
26201simandl }
262185simandl // opens the door for other scaley things...
2622 switch($matches[1])
26231simandl {
262485simandl case 'ICON':
2625 $varname = 'iconscalevar';
2626 $uvarname = 'useiconscale';
2627 $tvarname = 'iconscaletype';
2628 
2629 // if(!function_exists("imagefilter"))
2630 // {
2631 // warn("ICON SCALEs require imagefilter, which is not present in your PHP [WMWARN040]\n");
2632 // }
2633 break;
2634 default:
2635 $varname = 'scalevar';
2636 $uvarname = 'usescale';
2637 $tvarname = 'scaletype';
2638 break;
26391simandl }
2640 
264185simandl if($svar != '')
26421simandl {
264385simandl $curnode->$varname = $svar;
26441simandl }
264585simandl $curnode->$tvarname = $stype;
2646 $curnode->$uvarname = $matches[2];
26471simandl 
264885simandl // warn("Set $varname and $uvarname\n");
26491simandl 
265085simandl // print ">> $stype $svar ".$matches[2]." ".$curnode->name." \n";
26511simandl 
265285simandl $linematched++;
2653 }
26541simandl 
265585simandl // one REGEXP to rule them all:
2656// 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",
2657// 0.95b 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",
2658 if(preg_match("/^\s*SCALE\s+([A-Za-z][A-Za-z0-9_]*\s+)?(\-?\d+\.?\d*[munMGT]?)\s+(\-?\d+\.?\d*[munMGT]?)\s+(?:(\d+)\s+(\d+)\s+(\d+)(?:\s+(\d+)\s+(\d+)\s+(\d+))?|(none))\s*(.*)$/i",
2659 $buffer, $matches))
2660 {
2661 // The default scale name is DEFAULT
2662 if($matches[1]=='') $matches[1] = 'DEFAULT';
2663 else $matches[1] = trim($matches[1]);
26641simandl 
266585simandl $key=$matches[2] . '_' . $matches[3];
26661simandl 
266785simandl $this->colours[$matches[1]][$key]['key']=$key;
26681simandl 
266985simandl $tag = $matches[11];
267013simandl 
267185simandl $this->colours[$matches[1]][$key]['tag']=$tag;
26721simandl 
267385simandl $this->colours[$matches[1]][$key]['bottom'] = unformat_number($matches[2], $this->kilo);
2674 $this->colours[$matches[1]][$key]['top'] = unformat_number($matches[3], $this->kilo);
2675 $this->colours[$matches[1]][$key]['special'] = 0;
26761simandl 
267785simandl if(isset($matches[10]) && $matches[10] == 'none')
26781simandl {
267985simandl $this->colours[$matches[1]][$key]['red1'] = -1;
2680 $this->colours[$matches[1]][$key]['green1'] = -1;
2681 $this->colours[$matches[1]][$key]['blue1'] = -1;
26821simandl }
268385simandl else
26841simandl {
2685 $this->colours[$matches[1]][$key]['red1'] = (int)($matches[4]);
2686 $this->colours[$matches[1]][$key]['green1'] = (int)($matches[5]);
2687 $this->colours[$matches[1]][$key]['blue1'] = (int)($matches[6]);
2688 }
2689 
269085simandl // this is the second colour, if there is one
2691 if(isset($matches[7]) && $matches[7] != '')
26921simandl {
269385simandl $this->colours[$matches[1]][$key]['red2'] = (int) ($matches[7]);
2694 $this->colours[$matches[1]][$key]['green2'] = (int) ($matches[8]);
2695 $this->colours[$matches[1]][$key]['blue2'] = (int) ($matches[9]);
26961simandl }
2697 
2698 
269985simandl if(! isset($this->numscales[$matches[1]]))
27001simandl {
270185simandl $this->numscales[$matches[1]]=1;
27021simandl }
270385simandl else
27041simandl {
270585simandl $this->numscales[$matches[1]]++;
27061simandl }
270785simandl // we count if we've seen any default scale, otherwise, we have to add
2708 // one at the end.
2709 if($matches[1]=='DEFAULT')
27101simandl {
271185simandl $scalesseen++;
27121simandl }
2713 
271485simandl $linematched++;
2715 }
27161simandl 
271785simandl if (preg_match("/^\s*KEYPOS\s+([A-Za-z][A-Za-z0-9_]*\s+)?(-?\d+)\s+(-?\d+)(.*)/i", $buffer, $matches))
2718 {
2719 $whichkey = trim($matches[1]);
2720 if($whichkey == '') $whichkey = 'DEFAULT';
27211simandl 
272285simandl $this->keyx[$whichkey]=$matches[2];
2723 $this->keyy[$whichkey]=$matches[3];
2724 $extra=trim($matches[4]);
27251simandl 
272685simandl if ($extra != '')
2727 $this->keytext[$whichkey] = $extra;
2728 if(!isset($this->keytext[$whichkey]))
2729 $this->keytext[$whichkey] = "DEFAULT TITLE";
2730 if(!isset($this->keystyle[$whichkey]))
2731 $this->keystyle[$whichkey] = "classic";
27321simandl 
273385simandl $linematched++;
2734 }
27351simandl 
273685simandl 
2737 // truetype font definition (actually, we don't really check if it's truetype) - filename + size
2738 if (preg_match("/^\s*FONTDEFINE\s+(\d+)\s+(\S+)\s+(\d+)\s*$/i", $buffer, $matches))
2739 {
2740 if (function_exists("imagettfbbox"))
27411simandl {
274285simandl // test if this font is valid, before adding it to the font table...
2743 $bounds=@imagettfbbox($matches[3], 0, $matches[2], "Ignore me");
2744 
2745 if (isset($bounds[0]))
27461simandl {
274785simandl $this->fonts[$matches[1]]->type="truetype";
2748 $this->fonts[$matches[1]]->file=$matches[2];
2749 $this->fonts[$matches[1]]->size=$matches[3];
27501simandl }
275185simandl else { warn
2752 ("Failed to load ttf font " . $matches[2] . " - at config line $linecount\n [WMWARN30]"); }
27531simandl }
275485simandl else { warn
2755 ("imagettfbbox() is not a defined function. You don't seem to have FreeType compiled into your gd module. [WMWARN31]\n");
2756 }
27571simandl 
275885simandl $linematched++;
2759 }
27601simandl 
276185simandl // GD font definition (no size here)
2762 if (preg_match("/^\s*FONTDEFINE\s+(\d+)\s+(\S+)\s*$/i", $buffer, $matches))
2763 {
2764 $newfont=imageloadfont($matches[2]);
27651simandl 
276685simandl if ($newfont)
27671simandl {
276885simandl $this->fonts[$matches[1]]->type="gd";
2769 $this->fonts[$matches[1]]->file=$matches[2];
2770 $this->fonts[$matches[1]]->gdnumber=$newfont;
27711simandl }
277285simandl else { warn ("Failed to load GD font: " . $matches[2]
2773 . " ($newfont) at config line $linecount [WMWARN32]\n"); }
27741simandl 
277585simandl $linematched++;
2776 }
27771simandl 
277885simandl if(preg_match("/^\s*KEYSTYLE\s+([A-Za-z][A-Za-z0-9_]+\s+)?(classic|horizontal|vertical|inverted|tags)\s?(\d+)?\s*$/i",$buffer, $matches))
2779 {
2780 $whichkey = trim($matches[1]);
2781 if($whichkey == '') $whichkey = 'DEFAULT';
2782 $this->keystyle[$whichkey] = strtolower($matches[2]);
27831simandl 
278485simandl if(isset($matches[3]) && $matches[3] != '')
27851simandl {
278685simandl $this->keysize[$whichkey] = $matches[3];
27871simandl }
278885simandl else
27891simandl {
279085simandl $this->keysize[$whichkey] = $this->keysize['DEFAULT'];
27911simandl }
2792 
279385simandl $linematched++;
2794 }
27951simandl 
279685simandl 
2797 if (preg_match("/^\s*KILO\s+(\d+)\s*$/i", $buffer, $matches))
2798 {
2799 $this->kilo=$matches[1];
2800 # $this->defaultlink->owner->kilo=$matches[1];
2801 # $this->links['DEFAULT']=$matches[1];
2802 $linematched++;
2803 }
2804 
2805 if (preg_match(
2806 "/^\s*(TIME|TITLE|KEYBG|KEYTEXT|KEYOUTLINE|BG)COLOR\s+(\d+)\s+(\d+)\s+(\d+)\s*$/i",
2807 $buffer,
2808 $matches))
2809 {
2810 $key=$matches[1];
2811 # "Found colour line for $key\n";
2812 $this->colours['DEFAULT'][$key]['red1']=$matches[2];
2813 $this->colours['DEFAULT'][$key]['green1']=$matches[3];
2814 $this->colours['DEFAULT'][$key]['blue1']=$matches[4];
2815 $this->colours['DEFAULT'][$key]['bottom']=-2;
2816 $this->colours['DEFAULT'][$key]['top']=-1;
2817 $this->colours['DEFAULT'][$key]['special']=1;
28181simandl 
281985simandl $linematched++;
2820 }
28211simandl 
282285simandl if (($last_seen == 'NODE') && (preg_match(
2823 "/^\s*(AICONOUTLINE|AICONFILL|LABELFONT|LABELFONTSHADOW|LABELBG|LABELOUTLINE)COLOR\s+((\d+)\s+(\d+)\s+(\d+)|none|contrast|copy)\s*$/i",
2824 $buffer,
2825 $matches)))
2826 {
2827 $key=$matches[1];
2828 $field=strtolower($matches[1]) . 'colour';
2829 $val = strtolower($matches[2]);
28301simandl 
283185simandl if(isset($matches[3])) // this is a regular colour setting thing
28321simandl {
283385simandl $curnode->$field=array( $matches[3],$matches[4],$matches[5]);
28341simandl $linematched++;
2835 }
2836 
283785simandl if($val == 'none' && ($matches[1]=='LABELFONTSHADOW' || $matches[1]=='LABELBG' || $matches[1]=='LABELOUTLINE' || $matches[1]=='AICONOUTLINE'))
28381simandl {
283985simandl $curnode->$field=array(-1,-1,-1);
28401simandl $linematched++;
2841 }
284285simandl 
2843 if($val == 'contrast' && $matches[1]=='LABELFONT')
28441simandl {
284585simandl $curnode->$field=array(-3,-3,-3);
28461simandl $linematched++;
2847 }
2848 
284985simandl if($matches[2] == 'copy' && $matches[1]=='AICONFILL')
28501simandl {
285185simandl $curnode->$field=array(-2,-2,-2);
28521simandl $linematched++;
2853 }
285485simandl }
28551simandl 
285685simandl if (($last_seen == 'LINK') && (preg_match(
2857 "/^\s*(COMMENTFONT|BWBOX|BWFONT|BWOUTLINE|OUTLINE)COLOR\s+((\d+)\s+(\d+)\s+(\d+)|none|contrast|copy)\s*$/i",
2858 $buffer,
2859 $matches)))
2860 {
2861 $key=$matches[1];
2862 $field=strtolower($matches[1]) . 'colour';
2863 $val = strtolower($matches[2]);
2864 
2865 if(isset($matches[3])) // this is a regular colour setting thing
28661simandl {
286785simandl $curlink->$field=array( $matches[3],$matches[4],$matches[5]);
28681simandl $linematched++;
2869 }
287085simandl 
2871 if($val == 'none' && ($key=='BWBOX' || $key=='BWOUTLINE' || $key=='OUTLINE'))
28721simandl {
287385simandl // print "***********************************\n";
2874 $curlink->$field=array(-1,-1,-1);
28751simandl $linematched++;
2876 }
287785simandl 
2878 if($val == 'contrast' && $key=='COMMENTFONT')
28791simandl {
288085simandl // print "***********************************\n";
2881 $curlink->$field=array(-3,-3,-3);
28821simandl $linematched++;
2883 }
288485simandl }
28851simandl 
288685simandl if ($last_seen == 'LINK' && preg_match(
2887 "/^\s*ARROWSTYLE\s+(\d+)\s+(\d+)\s*$/i", $buffer, $matches))
28881simandl {
288985simandl $curlink->arrowstyle=$matches[1] . ' ' . $matches[2];
2890 $linematched++;
28911simandl }
289285simandl 
28931simandl 
289485simandl if ($linematched == 0 && trim($buffer) != '') { warn
2895 ("Unrecognised config on line $linecount: $buffer\n"); }
2896 
2897 if ($linematched > 1) { warn
2898 ("Same line ($linecount) interpreted twice. This is a program error. Please report to Howie with your config!\nThe line was: $buffer");
28991simandl }
290085simandl } // if blankline
2901 } // while
2902 
2903 if(1==1)
2904 {
2905 $this->ReadConfig_Commit($curobj);
2906 }
29071simandl else
2908 {
290985simandl if ($last_seen == "NODE")
2910 {
2911 $this->nodes[$curnode->name]=$curnode;
2912 debug ("Saving Node: " . $curnode->name . "\n");
2913 if($curnode->template == 'DEFAULT') $this->node_template_tree[ "DEFAULT" ][]= $curnode->name;
29141simandl }
2915 
291685simandl if ($last_seen == "LINK")
2917 {
2918 if (isset($curlink->a) && isset($curlink->b))
2919 {
2920 $this->links[$curlink->name]=$curlink;
2921 debug ("Saving Link: " . $curlink->name . "\n");
2922 if($curlink->template == 'DEFAULT') $this->link_template_tree[ "DEFAULT" ][]= $curlink->name;
2923 }
2924 else { warn ("Dropping LINK " . $curlink->name . " - it hasn't got 2 NODES!"); }
2925 }
2926 }
2927 
2928 
2929 debug("ReadConfig has finished reading the config ($linecount lines)\n");
2930 debug("------------------------------------------\n");
29311simandl 
2932 // load some default colouring, otherwise it all goes wrong
2933 if ($scalesseen == 0)
2934 {
293585simandl debug ("Adding default SCALE colour set (no SCALE lines seen).\n");
29361simandl $defaults=array
2937 (
293885simandl '0_0' => array('bottom' => 0, 'top' => 0, 'red1' => 192, 'green1' => 192, 'blue1' => 192, 'special'=>0),
2939 '0_1' => array('bottom' => 0, 'top' => 1, 'red1' => 255, 'green1' => 255, 'blue1' => 255, 'special'=>0),
2940 '1_10' => array('bottom' => 1, 'top' => 10, 'red1' => 140, 'green1' => 0, 'blue1' => 255, 'special'=>0),
2941 '10_25' => array('bottom' => 10, 'top' => 25, 'red1' => 32, 'green1' => 32, 'blue1' => 255, 'special'=>0),
2942 '25_40' => array('bottom' => 25, 'top' => 40, 'red1' => 0, 'green1' => 192, 'blue1' => 255, 'special'=>0),
2943 '40_55' => array('bottom' => 40, 'top' => 55, 'red1' => 0, 'green1' => 240, 'blue1' => 0, 'special'=>0),
2944 '55_70' => array('bottom' => 55, 'top' => 70, 'red1' => 240, 'green1' => 240, 'blue1' => 0, 'special'=>0),
2945 '70_85' => array('bottom' => 70, 'top' => 85, 'red1' => 255, 'green1' => 192, 'blue1' => 0, 'special'=>0),
2946 '85_100' => array('bottom' => 85, 'top' => 100, 'red1' => 255, 'green1' => 0, 'blue1' => 0, 'special'=>0)
29471simandl );
2948 
2949 foreach ($defaults as $key => $def)
2950 {
2951 $this->colours['DEFAULT'][$key]=$def;
295285simandl $this->colours['DEFAULT'][$key]['key']=$key;
29531simandl $scalesseen++;
2954 }
295585simandl // we have a 0-0 line now, so we need to hide that.
2956 $this->add_hint("key_hidezero_DEFAULT",1);
29571simandl }
2958 else { debug ("Already have $scalesseen scales, no defaults added.\n"); }
295985simandl 
29601simandl $this->numscales['DEFAULT']=$scalesseen;
2961 $this->configfile="$filename";
2962 
296385simandl if($this->has_overlibs && $this->htmlstyle == 'static')
2964 {
2965 warn("OVERLIBGRAPH is used, but HTMLSTYLE is static. This is probably wrong. [WMWARN41]\n");
2966 }
2967 
2968 debug("Building cache of z-layers and finalising bandwidth.\n");
2969 
2970// $allitems = array_merge($this->links, $this->nodes);
2971 
2972 $allitems = array();
2973 foreach ($this->nodes as $node)
2974 {
2975 $allitems[] = $node;
2976 }
2977 foreach ($this->links as $link)
2978 {
2979 $allitems[] = $link;
2980 }
2981 
2982 # foreach ($allitems as &$item)
2983 foreach ($allitems as $ky=>$vl)
2984 {
2985 $item =& $allitems[$ky];
2986 $z = $item->zorder;
2987 if(!isset($this->seen_zlayers[$z]) || !is_array($this->seen_zlayers[$z]))
2988 {
2989 $this->seen_zlayers[$z]=array();
2990 }
2991 array_push($this->seen_zlayers[$z], $item);
2992 
2993 // while we're looping through, let's set the real bandwidths
2994 if($item->my_type() == "LINK")
2995 {
2996 $this->links[$item->name]->max_bandwidth_in = unformat_number($item->max_bandwidth_in_cfg, $this->kilo);
2997 $this->links[$item->name]->max_bandwidth_out = unformat_number($item->max_bandwidth_out_cfg, $this->kilo);
2998 }
2999 elseif($item->my_type() == "NODE")
3000 {
3001 $this->nodes[$item->name]->max_bandwidth_in = unformat_number($item->max_bandwidth_in_cfg, $this->kilo);
3002 $this->nodes[$item->name]->max_bandwidth_out = unformat_number($item->max_bandwidth_out_cfg, $this->kilo);
3003 }
3004 else
3005 {
3006 warn("Internal bug - found an item of type: ".$item->my_type()."\n");
3007 }
3008 // $item->max_bandwidth_in=unformat_number($item->max_bandwidth_in_cfg, $this->kilo);
3009 // $item->max_bandwidth_out=unformat_number($item->max_bandwidth_out_cfg, $this->kilo);
3010 
3011 debug (sprintf(" Setting bandwidth on ".$item->my_type()." $item->name (%s -> %d bps, %s -> %d bps, KILO = %d)\n", $item->max_bandwidth_in_cfg, $item->max_bandwidth_in, $item->max_bandwidth_out_cfg, $item->max_bandwidth_out, $this->kilo));
3012 }
3013 
3014 debug("Found ".sizeof($this->seen_zlayers)." z-layers including builtins (0,100).\n");
3015 
30161simandl // calculate any relative positions here - that way, nothing else
3017 // really needs to know about them
3018 
301985simandl debug("Resolving relative positions for NODEs...\n");
30201simandl // safety net for cyclic dependencies
3021 $i=100;
3022 do
3023 {
3024 $skipped = 0; $set=0;
3025 foreach ($this->nodes as $node)
3026 {
3027 if( ($node->relative_to != '') && (!$node->relative_resolved))
302885simandl {
30291simandl debug("Resolving relative position for NODE ".$node->name." to ".$node->relative_to."\n");
3030 if(array_key_exists($node->relative_to,$this->nodes))
3031 {
303285simandl 
30331simandl // check if we are relative to another node which is in turn relative to something
3034 // we need to resolve that one before we can resolve this one!
3035 if( ($this->nodes[$node->relative_to]->relative_to != '') && (!$this->nodes[$node->relative_to]->relative_resolved) )
3036 {
3037 debug("Skipping unresolved relative_to. Let's hope it's not a circular one\n");
3038 $skipped++;
3039 }
3040 else
3041 {
304285simandl $rx = $this->nodes[$node->relative_to]->x;
3043 $ry = $this->nodes[$node->relative_to]->y;
30441simandl 
304585simandl if($node->polar)
3046 {
3047 // treat this one as a POLAR relative coordinate.
3048 // - draw rings around a node!
3049 $angle = $node->x;
3050 $distance = $node->y;
3051 $newpos_x = $rx + $distance * sin(deg2rad($angle));
3052 $newpos_y = $ry - $distance * cos(deg2rad($angle));
3053 debug("->$newpos_x,$newpos_y\n");
3054 $this->nodes[$node->name]->x = $newpos_x;
3055 $this->nodes[$node->name]->y = $newpos_y;
3056 $this->nodes[$node->name]->relative_resolved=TRUE;
3057 $set++;
3058 }
3059 else
3060 {
3061 
3062 // save the relative coords, so that WriteConfig can work
3063 // resolve the relative stuff
3064 
3065 $newpos_x = $rx + $this->nodes[$node->name]->x;
3066 $newpos_y = $ry + $this->nodes[$node->name]->y;
3067 debug("->$newpos_x,$newpos_y\n");
3068 $this->nodes[$node->name]->x = $newpos_x;
3069 $this->nodes[$node->name]->y = $newpos_y;
3070 $this->nodes[$node->name]->relative_resolved=TRUE;
3071 $set++;
3072 }
30731simandl }
3074 }
3075 else
3076 {
307785simandl warn("NODE ".$node->name." has a relative position to an unknown node! [WMWARN10]\n");
30781simandl }
3079 }
3080 }
308185simandl debug("Relative Positions Cycle $i - set $set and Skipped $skipped for unresolved dependencies\n");
30821simandl $i--;
3083 } while( ($set>0) && ($i!=0) );
308485simandl 
3085 if($skipped>0)
3086 {
3087 warn("There are Circular dependencies in relative POSITION lines for $skipped nodes. [WMWARN11]\n");
30881simandl }
3089 
309085simandl debug("-----------------------------------\n");
30911simandl 
309213simandl 
30931simandl debug("Running Pre-Processing Plugins...\n");
3094 foreach ($this->preprocessclasses as $pre_class)
3095 {
3096 debug("Running $pre_class"."->run()\n");
309785simandl $this->plugins['pre'][$pre_class]->run($this);
30981simandl }
3099 debug("Finished Pre-Processing Plugins...\n");
3100 
3101 return (TRUE);
3102}
3103 
310485simandlfunction ReadConfig_Commit(&$curobj)
3105{
3106 if(is_null($curobj)) return;
3107 
3108 $last_seen = $curobj->my_type();
3109 
3110 // first, save the previous item, before starting work on the new one
3111 if ($last_seen == "NODE")
3112 {
3113 $this->nodes[$curobj->name]=$curobj;
3114 debug ("Saving Node: " . $curobj->name . "\n");
3115 if($curobj->template == 'DEFAULT') $this->node_template_tree[ "DEFAULT" ][]= $curobj->name;
3116 }
3117 
3118 if ($last_seen == "LINK")
3119 {
3120 if (isset($curobj->a) && isset($curobj->b))
3121 {
3122 $this->links[$curobj->name]=$curobj;
3123 debug ("Saving Link: " . $curobj->name . "\n");
3124 }
3125 else
3126 {
3127 $this->links[$curobj->name]=$curobj;
3128 debug ("Saving Template-Only Link: " . $curobj->name . "\n");
3129 }
3130 if($curobj->template == 'DEFAULT') $this->link_template_tree[ "DEFAULT" ][]= $curobj->name;
3131 }
3132}
3133 
31341simandlfunction WriteConfig($filename)
3135{
3136 global $WEATHERMAP_VERSION;
3137 
3138 $fd=fopen($filename, "w");
3139 $output="";
3140 
3141 if ($fd)
3142 {
3143 $output.="# Automatically generated by php-weathermap v$WEATHERMAP_VERSION\n\n";
3144 
3145 if (count($this->fonts) > 0)
3146 {
3147 foreach ($this->fonts as $fontnumber => $font)
3148 {
3149 if ($font->type == 'truetype')
3150 $output.=sprintf("FONTDEFINE %d %s %d\n", $fontnumber, $font->file, $font->size);
3151 
3152 if ($font->type == 'gd')
3153 $output.=sprintf("FONTDEFINE %d %s\n", $fontnumber, $font->file);
3154 }
3155 
3156 $output.="\n";
3157 }
3158 
315985simandl $basic_params = array(
3160 array('background','BACKGROUND',CONFIG_TYPE_LITERAL),
3161 array('width','WIDTH',CONFIG_TYPE_LITERAL),
3162 array('height','HEIGHT',CONFIG_TYPE_LITERAL),
3163 array('htmlstyle','HTMLSTYLE',CONFIG_TYPE_LITERAL),
3164 array('kilo','KILO',CONFIG_TYPE_LITERAL),
3165 array('keyfont','KEYFONT',CONFIG_TYPE_LITERAL),
3166 array('timefont','TIMEFONT',CONFIG_TYPE_LITERAL),
3167 array('titlefont','TITLEFONT',CONFIG_TYPE_LITERAL),
3168 array('title','TITLE',CONFIG_TYPE_LITERAL),
3169 array('htmloutputfile','HTMLOUTPUTFILE',CONFIG_TYPE_LITERAL),
3170 array('htmlstylesheet','HTMLSTYLESHEET',CONFIG_TYPE_LITERAL),
3171 array('imageuri','IMAGEURI',CONFIG_TYPE_LITERAL),
3172 array('imageoutputfile','IMAGEOUTPUTFILE',CONFIG_TYPE_LITERAL)
3173 );
31741simandl 
317585simandl foreach ($basic_params as $param)
3176 {
3177 $field = $param[0];
3178 $keyword = $param[1];
31791simandl 
318085simandl if ($this->$field != $this->inherit_fieldlist[$field])
3181 {
3182 if($param[2] == CONFIG_TYPE_COLOR) $output.="$keyword " . render_colour($this->$field) . "\n";
3183 if($param[2] == CONFIG_TYPE_LITERAL) $output.="$keyword " . $this->$field . "\n";
3184 }
3185 }
31861simandl 
3187 if (($this->timex != $this->inherit_fieldlist['timex'])
3188 || ($this->timey != $this->inherit_fieldlist['timey'])
3189 || ($this->stamptext != $this->inherit_fieldlist['stamptext']))
3190 $output.="TIMEPOS " . $this->timex . " " . $this->timey . " " . $this->stamptext . "\n";
3191 
319285simandl if (($this->mintimex != $this->inherit_fieldlist['mintimex'])
3193 || ($this->mintimey != $this->inherit_fieldlist['mintimey'])
3194 || ($this->minstamptext != $this->inherit_fieldlist['minstamptext']))
3195 $output.="MINTIMEPOS " . $this->mintimex . " " . $this->mintimey . " " . $this->minstamptext . "\n";
3196 
3197 if (($this->maxtimex != $this->inherit_fieldlist['maxtimex'])
3198 || ($this->maxtimey != $this->inherit_fieldlist['maxtimey'])
3199 || ($this->maxstamptext != $this->inherit_fieldlist['maxstamptext']))
3200 $output.="MAXTIMEPOS " . $this->maxtimex . " " . $this->maxtimey . " " . $this->maxstamptext . "\n";
3201 
32021simandl if (($this->titlex != $this->inherit_fieldlist['titlex'])
3203 || ($this->titley != $this->inherit_fieldlist['titley']))
3204 $output.="TITLEPOS " . $this->titlex . " " . $this->titley . "\n";
3205 
3206 $output.="\n";
3207 
3208 foreach ($this->colours as $scalename=>$colours)
3209 {
3210 // not all keys will have keypos but if they do, then all three vars should be defined
321185simandl if ( (isset($this->keyx[$scalename])) && (isset($this->keyy[$scalename])) && (isset($this->keytext[$scalename]))
3212 && (($this->keytext[$scalename] != $this->inherit_fieldlist['keytext'])
32131simandl || ($this->keyx[$scalename] != $this->inherit_fieldlist['keyx'])
321485simandl || ($this->keyy[$scalename] != $this->inherit_fieldlist['keyy'])))
3215 {
3216 // sometimes a scale exists but without defaults. A proper scale object would sort this out...
3217 if($this->keyx[$scalename] == '') { $this->keyx[$scalename] = -1; }
3218 if($this->keyy[$scalename] == '') { $this->keyy[$scalename] = -1; }
3219 
32201simandl $output.="KEYPOS " . $scalename." ". $this->keyx[$scalename] . " " . $this->keyy[$scalename] . " " . $this->keytext[$scalename] . "\n";
322185simandl }
32221simandl 
3223 if ( (isset($this->keystyle[$scalename])) && ($this->keystyle[$scalename] != $this->inherit_fieldlist['keystyle']['DEFAULT']) )
3224 {
3225 $extra='';
3226 if ( (isset($this->keysize[$scalename])) && ($this->keysize[$scalename] != $this->inherit_fieldlist['keysize']['DEFAULT']) )
3227 {
3228 $extra = " ".$this->keysize[$scalename];
3229 }
3230 $output.="KEYSTYLE " . $scalename." ". $this->keystyle[$scalename] . $extra . "\n";
3231 }
323285simandl $locale = localeconv();
3233 $decimal_point = $locale['decimal_point'];
32341simandl 
3235 foreach ($colours as $k => $colour)
3236 {
323785simandl if (!isset($colour['special']) || ! $colour['special'] )
32381simandl {
323985simandl $top = rtrim(rtrim(sprintf("%f",$colour['top']),"0"),$decimal_point);
3240 $bottom= rtrim(rtrim(sprintf("%f",$colour['bottom']),"0"),$decimal_point);
32411simandl 
324285simandl if ($bottom > 1000) {
3243 $bottom = nice_bandwidth($colour['bottom'], $this->kilo);
3244 }
3245 
3246 if ($top > 1000) {
3247 $top = nice_bandwidth($colour['top'], $this->kilo);
3248 }
3249 
3250 $tag = (isset($colour['tag'])? $colour['tag']:'');
3251 
3252 if( ($colour['red1'] == -1) && ($colour['green1'] == -1) && ($colour['blue1'] == -1))
3253 {
3254 $output.=sprintf("SCALE %s %-4s %-4s none %s\n", $scalename,
3255 $bottom, $top, $tag);
3256 }
3257 elseif (!isset($colour['red2']))
3258 {
3259 $output.=sprintf("SCALE %s %-4s %-4s %3d %3d %3d %s\n", $scalename,
32601simandl $bottom, $top,
326185simandl $colour['red1'], $colour['green1'], $colour['blue1'],$tag);
3262 }
32631simandl else
326485simandl {
3265 $output.=sprintf("SCALE %s %-4s %-4s %3d %3d %3d %3d %3d %3d %s\n", $scalename,
32661simandl $bottom, $top,
3267 $colour['red1'],
3268 $colour['green1'], $colour['blue1'],
3269 $colour['red2'], $colour['green2'],
327085simandl $colour['blue2'], $tag);
3271 }
32721simandl }
3273 else { $output.=sprintf("%sCOLOR %d %d %d\n", $k, $colour['red1'], $colour['green1'],
3274 $colour['blue1']); }
3275 }
3276 $output .= "\n";
3277 }
3278 
3279 foreach ($this->hints as $hintname=>$hint)
3280 {
3281 $output .= "SET $hintname $hint\n";
3282 }
328385simandl 
3284 // this doesn't really work right, but let's try anyway
3285 if($this->has_includes)
3286 {
3287 $output .= "\n# Included files\n";
3288 foreach ($this->included_files as $ifile)
3289 {
3290 $output .= "INCLUDE $ifile\n";
3291 }
3292 }
32931simandl 
329485simandl $output.="\n# End of global section\n\n";
32951simandl 
3296 fwrite($fd, $output);
3297 
329885simandl ## fwrite($fd,$this->nodes['DEFAULT']->WriteConfig());
3299 ## fwrite($fd,$this->links['DEFAULT']->WriteConfig());
33001simandl 
330185simandl # fwrite($fd, "\n\n# Node definitions:\n");
33021simandl 
330385simandl foreach (array("template","normal") as $which)
3304 {
3305 if($which == "template") fwrite($fd,"\n# TEMPLATE-only NODEs:\n");
3306 if($which == "normal") fwrite($fd,"\n# regular NODEs:\n");
3307 
3308 foreach ($this->nodes as $node)
3309 {
3310 if(!preg_match("/^::\s/",$node->name))
3311 {
3312 if($node->defined_in == $this->configfile)
3313 {
33141simandl 
331585simandl if($which=="template" && $node->x === NULL) { debug("TEMPLATE\n"); fwrite($fd,$node->WriteConfig()); }
3316 if($which=="normal" && $node->x !== NULL) { fwrite($fd,$node->WriteConfig()); }
3317 }
3318 }
3319 }
3320 
3321 if($which == "template") fwrite($fd,"\n# TEMPLATE-only LINKs:\n");
3322 if($which == "normal") fwrite($fd,"\n# regular LINKs:\n");
3323 
3324 foreach ($this->links as $link)
3325 {
3326 if(!preg_match("/^::\s/",$link->name))
3327 {
3328 if($link->defined_in == $this->configfile)
3329 {
3330 if($which=="template" && $link->a === NULL) fwrite($fd,$link->WriteConfig());
3331 if($which=="normal" && $link->a !== NULL) fwrite($fd,$link->WriteConfig());
3332 }
3333 }
3334 }
3335 }
33361simandl 
333785simandl fwrite($fd, "\n\n# That's All Folks!\n");
33381simandl 
333985simandl fclose($fd);
33401simandl }
3341 else
3342 {
3343 warn ("Couldn't open config file $filename for writing");
3344 return (FALSE);
3345 }
3346 
3347 return (TRUE);
3348}
3349 
3350// pre-allocate colour slots for the colours used by the arrows
3351// this way, it's the pretty icons that suffer if there aren't enough colours, and
3352// not the actual useful data
3353// we skip any gradient scales
335485simandlfunction AllocateScaleColours($im,$refname='gdref1')
33551simandl{
3356 # $colours=$this->colours['DEFAULT'];
3357 foreach ($this->colours as $scalename=>$colours)
3358 {
3359 foreach ($colours as $key => $colour)
3360 {
336185simandl if ( (!isset($this->colours[$scalename][$key]['red2']) ) && (!isset( $this->colours[$scalename][$key][$refname] )) )
33621simandl {
3363 $r=$colour['red1'];
3364 $g=$colour['green1'];
3365 $b=$colour['blue1'];
336685simandl debug ("AllocateScaleColours: $scalename/$refname $key ($r,$g,$b)\n");
3367 $this->colours[$scalename][$key][$refname]=myimagecolorallocate($im, $r, $g, $b);
3368 }
33691simandl }
3370 }
3371}
3372 
337385simandlfunction DrawMap($filename = '', $thumbnailfile = '', $thumbnailmax = 250, $withnodes = TRUE, $use_via_overlay = FALSE, $use_rel_overlay=FALSE)
33741simandl{
337585simandl debug("Trace: DrawMap()\n");
3376 metadump("# start",true);
33771simandl $bgimage=NULL;
337885simandl if($this->configfile != "")
3379 {
3380 $this->cachefile_version = crc32(file_get_contents($this->configfile));
3381 }
3382 else
3383 {
3384 $this->cachefile_version = crc32("........");
3385 }
33861simandl 
3387 debug("Running Post-Processing Plugins...\n");
3388 foreach ($this->postprocessclasses as $post_class)
3389 {
3390 debug("Running $post_class"."->run()\n");
339185simandl //call_user_func_array(array($post_class, 'run'), array(&$this));
3392 $this->plugins['post'][$post_class]->run($this);
3393 
33941simandl }
3395 debug("Finished Post-Processing Plugins...\n");
3396 
339785simandl debug("=====================================\n");
3398 debug("Start of Map Drawing\n");
3399 
340013simandl $this->datestamp = strftime($this->stamptext, time());
3401 
34021simandl // do the basic prep work
3403 if ($this->background != '')
3404 {
3405 if (is_readable($this->background))
3406 {
3407 $bgimage=imagecreatefromfile($this->background);
3408 
3409 if (!$bgimage) { warn
3410 ("Failed to open background image. One possible reason: Is your BACKGROUND really a PNG?\n");
3411 }
3412 else
3413 {
3414 $this->width=imagesx($bgimage);
3415 $this->height=imagesy($bgimage);
3416 }
3417 }
3418 else { warn
3419 ("Your background image file could not be read. Check the filename, and permissions, for "
3420 . $this->background . "\n"); }
3421 }
3422 
342385simandl $image=wimagecreatetruecolor($this->width, $this->height);
34241simandl 
3425 # $image = imagecreate($this->width, $this->height);
3426 if (!$image) { warn
3427 ("Couldn't create output image in memory (" . $this->width . "x" . $this->height . ")."); }
3428 else
3429 {
3430 ImageAlphaBlending($image, true);
3431 # imageantialias($image,true);
3432 
3433 // by here, we should have a valid image handle
3434 
3435 // save this away, now
3436 $this->image=$image;
3437 
3438 $this->white=myimagecolorallocate($image, 255, 255, 255);
3439 $this->black=myimagecolorallocate($image, 0, 0, 0);
3440 $this->grey=myimagecolorallocate($image, 192, 192, 192);
3441 $this->selected=myimagecolorallocate($image, 255, 0, 0); // for selections in the editor
3442 
3443 $this->AllocateScaleColours($image);
3444 
3445 // fill with background colour anyway, in case the background image failed to load
344685simandl wimagefilledrectangle($image, 0, 0, $this->width, $this->height, $this->colours['DEFAULT']['BG']['gdref1']);
34471simandl 
3448 if ($bgimage)
3449 {
3450 imagecopy($image, $bgimage, 0, 0, 0, 0, $this->width, $this->height);
3451 imagedestroy ($bgimage);
3452 }
3453 
3454 // Now it's time to draw a map
3455 
345685simandl // do the node rendering stuff first, regardless of where they are actually drawn.
3457 // this is so we can get the size of the nodes, which links will need if they use offsets
3458 foreach ($this->nodes as $node)
3459 {
3460 // don't try and draw template nodes
3461 debug("Pre-rendering ".$node->name." to get bounding boxes.\n");
3462 if(!is_null($node->x)) $this->nodes[$node->name]->pre_render($image, $this);
3463 }
3464 
3465 $all_layers = array_keys($this->seen_zlayers);
3466 sort($all_layers);
34671simandl 
346885simandl foreach ($all_layers as $z)
3469 {
3470 $z_items = $this->seen_zlayers[$z];
3471 debug("Drawing layer $z\n");
3472 // all the map 'furniture' is fixed at z=1000
3473 if($z==1000)
3474 {
3475 foreach ($this->colours as $scalename=>$colours)
3476 {
3477 debug("Drawing KEY for $scalename if necessary.\n");
34781simandl 
347985simandl if( (isset($this->numscales[$scalename])) && (isset($this->keyx[$scalename])) && ($this->keyx[$scalename] >= 0) && ($this->keyy[$scalename] >= 0) )
3480 {
3481 if($this->keystyle[$scalename]=='classic') $this->DrawLegend_Classic($image,$scalename,FALSE);
3482 if($this->keystyle[$scalename]=='horizontal') $this->DrawLegend_Horizontal($image,$scalename,$this->keysize[$scalename]);
3483 if($this->keystyle[$scalename]=='vertical') $this->DrawLegend_Vertical($image,$scalename,$this->keysize[$scalename]);
3484 if($this->keystyle[$scalename]=='inverted') $this->DrawLegend_Vertical($image,$scalename,$this->keysize[$scalename],true);
3485 if($this->keystyle[$scalename]=='tags') $this->DrawLegend_Classic($image,$scalename,TRUE);
3486 }
3487 }
3488 
3489 $this->DrawTimestamp($image, $this->timefont, $this->colours['DEFAULT']['TIME']['gdref1']);
3490 if(! is_null($this->min_data_time))
3491 {
3492 $this->DrawTimestamp($image, $this->timefont, $this->colours['DEFAULT']['TIME']['gdref1'],"MIN");
3493 $this->DrawTimestamp($image, $this->timefont, $this->colours['DEFAULT']['TIME']['gdref1'],"MAX");
3494 }
3495 $this->DrawTitle($image, $this->titlefont, $this->colours['DEFAULT']['TITLE']['gdref1']);
3496 }
3497 
3498 if(is_array($z_items))
3499 {
3500 foreach($z_items as $it)
3501 {
3502 if(strtolower(get_class($it))=='weathermaplink')
3503 {
3504 // only draw LINKs if they have NODES defined (not templates)
3505 // (also, check if the link still exists - if this is in the editor, it may have been deleted by now)
3506 if ( isset($this->links[$it->name]) && isset($it->a) && isset($it->b))
3507 {
3508 debug("Drawing LINK ".$it->name."\n");
3509 $this->links[$it->name]->Draw($image, $this);
3510 }
3511 }
3512 if(strtolower(get_class($it))=='weathermapnode')
3513 {
3514 // if(!is_null($it->x)) $it->pre_render($image, $this);
3515 if($withnodes)
3516 {
3517 // don't try and draw template nodes
3518 if( isset($this->nodes[$it->name]) && !is_null($it->x))
3519 {
3520 # print "::".get_class($it)."\n";
3521 debug("Drawing NODE ".$it->name."\n");
3522 $this->nodes[$it->name]->NewDraw($image, $this);
3523 $ii=0;
3524 foreach($this->nodes[$it->name]->boundingboxes as $bbox)
3525 {
3526 # $areaname = "NODE:" . $it->name . ':'.$ii;
3527 $areaname = "NODE:N". $it->id . ":" . $ii;
3528 $this->imap->addArea("Rectangle", $areaname, '', $bbox);
3529 debug("Adding imagemap area");
3530 $ii++;
3531 }
3532 debug("Added $ii bounding boxes too\n");
3533 }
3534 }
3535 }
3536 }
3537 }
3538 }
3539 
3540 $overlay = myimagecolorallocate($image, 200, 0, 0);
3541 
3542 // for the editor, we can optionally overlay some other stuff
3543 if($this->context == 'editor')
3544 {
3545 if($use_rel_overlay)
35461simandl {
354785simandl # $overlay = myimagecolorallocate($image, 200, 0, 0);
3548 
3549 // first, we can show relatively positioned NODEs
355013simandl foreach ($this->nodes as $node) {
355185simandl if($node->relative_to != '')
3552 {
3553 $rel_x = $this->nodes[$node->relative_to]->x;
3554 $rel_y = $this->nodes[$node->relative_to]->y;
3555 imagearc($image,$node->x, $node->y,
3556 15,15,0,360,$overlay);
3557 imagearc($image,$node->x, $node->y,
3558 16,16,0,360,$overlay);
3559 
3560 imageline($image,$node->x, $node->y,
3561 $rel_x, $rel_y, $overlay);
3562 }
356313simandl }
35641simandl }
356585simandl 
3566 if($use_via_overlay)
35671simandl {
356885simandl // then overlay VIAs, so they can be seen
3569 foreach($this->links as $link)
35701simandl {
357185simandl foreach ($link->vialist as $via)
3572 {
3573 if(isset($via[2]))
3574 {
3575 $x = $this->nodes[$via[2]]->x + $via[0];
3576 $y = $this->nodes[$via[2]]->y + $via[1];
3577 }
3578 else
3579 {
3580 $x = $via[0];
3581 $y = $via[1];
3582 }
3583 imagearc($image, $x,$y, 10,10,0,360,$overlay);
3584 imagearc($image, $x,$y, 12,12,0,360,$overlay);
3585 }
35861simandl }
3587 }
358885simandl }
35891simandl 
359085simandl #$this->myimagestring($image, 3, 200, 100, "Test 1\nLine 2", $overlay,0);
3591 
3592# $this->myimagestring($image, 30, 100, 100, "Test 1\nLine 2", $overlay,0);
3593 #$this->myimagestring($image, 30, 200, 200, "Test 1\nLine 2", $overlay,45);
35941simandl 
3595 // Ready to output the results...
3596 
3597 if($filename == 'null')
3598 {
3599 // do nothing at all - we just wanted the HTML AREAs for the editor or HTML output
3600 }
3601 else
3602 {
3603 if ($filename == '') { imagepng ($image); }
3604 else {
3605 $result = FALSE;
3606 $functions = TRUE;
3607 if(function_exists('imagejpeg') && preg_match("/\.jpg/i",$filename))
3608 {
360985simandl debug("Writing JPEG file to $filename\n");
36101simandl $result = imagejpeg($image, $filename);
3611 }
3612 elseif(function_exists('imagegif') && preg_match("/\.gif/i",$filename))
3613 {
361485simandl debug("Writing GIF file to $filename\n");
36151simandl $result = imagegif($image, $filename);
3616 }
3617 elseif(function_exists('imagepng') && preg_match("/\.png/i",$filename))
3618 {
361985simandl debug("Writing PNG file to $filename\n");
36201simandl $result = imagepng($image, $filename);
3621 }
3622 else
3623 {
362485simandl warn("Failed to write map image. No function existed for the image format you requested. [WMWARN12]\n");
36251simandl $functions = FALSE;
3626 }
362785simandl 
36281simandl if(($result==FALSE) && ($functions==TRUE))
3629 {
3630 if(file_exists($filename))
3631 {
363285simandl warn("Failed to overwrite existing image file $filename - permissions of existing file are wrong? [WMWARN13]");
36331simandl }
3634 else
3635 {
363685simandl warn("Failed to create image file $filename - permissions of output directory are wrong? [WMWARN14]");
36371simandl }
3638 }
3639 }
3640 }
3641 
3642 if($this->context == 'editor2')
3643 {
364485simandl $cachefile = $this->cachefolder.DIRECTORY_SEPARATOR.dechex(crc32($this->configfile))."_bg.".$this->cachefile_version.".png";
36451simandl imagepng($image, $cachefile);
364685simandl $cacheuri = $this->cachefolder.'/'.dechex(crc32($this->configfile))."_bg.".$this->cachefile_version.".png";
36471simandl $this->mapcache = $cacheuri;
3648 }
3649 
3650 if (function_exists('imagecopyresampled'))
3651 {
3652 // if one is specified, and we can, write a thumbnail too
3653 if ($thumbnailfile != '')
3654 {
3655 $result = FALSE;
3656 if ($this->width > $this->height) { $factor=($thumbnailmax / $this->width); }
3657 else { $factor=($thumbnailmax / $this->height); }
3658 
365985simandl $this->thumb_width = $this->width * $factor;
3660 $this->thumb_height = $this->height * $factor;
36611simandl 
366285simandl $imagethumb=imagecreatetruecolor($this->thumb_width, $this->thumb_height);
3663 imagecopyresampled($imagethumb, $image, 0, 0, 0, 0, $this->thumb_width, $this->thumb_height,
36641simandl $this->width, $this->height);
3665 $result = imagepng($imagethumb, $thumbnailfile);
366613simandl imagedestroy($imagethumb);
36671simandl 
366885simandl 
3669 
36701simandl if(($result==FALSE))
3671 {
3672 if(file_exists($filename))
3673 {
367485simandl warn("Failed to overwrite existing image file $filename - permissions of existing file are wrong? [WMWARN15]");
36751simandl }
3676 else
3677 {
367885simandl warn("Failed to create image file $filename - permissions of output directory are wrong? [WMWARN16]");
36791simandl }
3680 }
3681 }
3682 }
3683 else
3684 {
368585simandl warn("Skipping thumbnail creation, since we don't have the necessary function. [WMWARN17]");
36861simandl }
3687 imagedestroy ($image);
3688 }
3689}
3690 
3691function CleanUp()
3692{
3693 // destroy all the images we created, to prevent memory leaks
3694 foreach ($this->nodes as $node) { if(isset($node->image)) imagedestroy($node->image); }
369513simandl #foreach ($this->nodes as $node) { unset($node); }
3696 #foreach ($this->links as $link) { unset($link); }
36971simandl 
3698}
3699 
3700function PreloadMapHTML()
3701{
370285simandl debug("Trace: PreloadMapHTML()\n");
37031simandl // onmouseover="return overlib('<img src=graph.png>',DELAY,250,CAPTION,'$caption');" onmouseout="return nd();"
3704 
370585simandl // find the middle of the map
37061simandl $center_x=$this->width / 2;
3707 $center_y=$this->height / 2;
3708 
370985simandl // loop through everything. Figure out along the way if it's a node or a link
3710 $allitems = array(&$this->nodes, &$this->links);
3711 reset($allitems);
3712 
3713 while( list($kk,) = each($allitems))
37141simandl {
371585simandl unset($objects);
3716 # $objects = &$this->links;
3717 $objects = &$allitems[$kk];
3718 
3719 reset($objects);
3720 while (list($k,) = each($objects))
37211simandl {
372285simandl unset($myobj);
3723 $myobj = &$objects[$k];
37241simandl 
372585simandl $type = $myobj->my_type();
3726 $prefix = substr($type,0,1);
37271simandl 
372885simandl $dirs = array();
3729 //print "\n\nConsidering a $type - ".$myobj->name.".\n";
3730 if($type == 'LINK') $dirs = array(IN=>array(0,2), OUT=>array(1,3));
3731 if($type == 'NODE') $dirs = array(IN=>array(0,1,2,3));
3732 
3733 // check to see if any of the relevant things have a value
3734 $change = "";
3735 foreach ($dirs as $d=>$parts)
37361simandl {
373785simandl //print "$d - ".join(" ",$parts)."\n";
3738 $change .= join('',$myobj->overliburl[$d]);
3739 $change .= $myobj->notestext[$d];
37401simandl }
374185simandl 
3742 if ($this->htmlstyle == "overlib")
37431simandl {
374485simandl //print "CHANGE: $change\n";
37451simandl 
374685simandl // skip all this if it's a template node
3747 if($type=='LINK' && ! isset($myobj->a->name)) { $change = ''; }
3748 if($type=='NODE' && ! isset($myobj->x)) { $change = ''; }
37491simandl 
375085simandl if($change != '')
3751 {
3752 //print "Something to be done.\n";
3753 if($type=='NODE')
3754 {
3755 $mid_x = $myobj->x;
3756 $mid_y = $myobj->y;
3757 }
3758 if($type=='LINK')
3759 {
3760 $a_x = $this->nodes[$myobj->a->name]->x;
3761 $a_y = $this->nodes[$myobj->a->name]->y;
37621simandl 
376385simandl $b_x = $this->nodes[$myobj->b->name]->x;
3764 $b_y = $this->nodes[$myobj->b->name]->y;
37651simandl 
376685simandl $mid_x=($a_x + $b_x) / 2;
3767 $mid_y=($a_y + $b_y) / 2;
3768 }
3769 $left=""; $above="";
3770 $img_extra = "";
3771 
3772 if ($myobj->overlibwidth != 0)
3773 {
3774 $left="WIDTH," . $myobj->overlibwidth . ",";
3775 $img_extra .= " WIDTH=$myobj->overlibwidth";
37761simandl 
377785simandl if ($mid_x > $center_x) $left.="LEFT,";
3778 }
3779 
3780 if ($myobj->overlibheight != 0)
3781 {
3782 $above="HEIGHT," . $myobj->overlibheight . ",";
3783 $img_extra .= " HEIGHT=$myobj->overlibheight";
37841simandl 
378585simandl if ($mid_y > $center_y) $above.="ABOVE,";
3786 }
3787 
3788 foreach ($dirs as $dir=>$parts)
3789 {
3790 $caption = ($myobj->overlibcaption[$dir] != '' ? $myobj->overlibcaption[$dir] : $myobj->name);
3791 $caption = $this->ProcessString($caption,$myobj);
37921simandl 
379385simandl $overlibhtml = "onmouseover=\"return overlib('";
37941simandl 
379585simandl $n = 0;
3796 if(sizeof($myobj->overliburl[$dir]) > 0)
3797 {
3798 // print "ARRAY:".is_array($link->overliburl[$dir])."\n";
3799 foreach ($myobj->overliburl[$dir] as $url)
3800 {
3801 if($n>0) { $overlibhtml .= '&lt;br /&gt;'; }
3802 $overlibhtml .= "&lt;img $img_extra src=" . $this->ProcessString($url,$myobj) . "&gt;";
3803 $n++;
3804 }
3805 }
3806 # print "Added $n for $dir\n";
3807 if(trim($myobj->notestext[$dir]) != '')
3808 {
3809 # put in a linebreak if there was an image AND notes
3810 if($n>0) $overlibhtml .= '&lt;br /&gt;';
3811 $note = $this->ProcessString($myobj->notestext[$dir],$myobj);
3812 $note = htmlspecialchars($note, ENT_NOQUOTES);
3813 $note=str_replace("'", "\\&apos;", $note);
3814 $note=str_replace('"', "&quot;", $note);
3815 $overlibhtml .= $note;
3816 }
3817 $overlibhtml .= "',DELAY,250,${left}${above}CAPTION,'" . $caption
3818 . "');\" onmouseout=\"return nd();\"";
3819 
3820 foreach ($parts as $part)
3821 {
3822 $areaname = $type.":" . $prefix . $myobj->id. ":" . $part;
3823 //print "INFOURL for $areaname - ";
3824 
3825 $this->imap->setProp("extrahtml", $overlibhtml, $areaname);
3826 }
3827 }
3828 } // if change
3829 } // overlib?
3830 
3831 // now look at inforurls
3832 foreach ($dirs as $dir=>$parts)
38331simandl {
383485simandl foreach ($parts as $part)
3835 {
3836 # $areaname = $type.":" . $myobj->name . ":" . $part;
3837 $areaname = $type.":" . $prefix . $myobj->id. ":" . $part;
3838 //print "INFOURL for $areaname - ";
3839 
3840 if ( ($this->htmlstyle != 'editor') && ($myobj->infourl[$dir] != '') ) {
3841 $this->imap->setProp("href", $this->ProcessString($myobj->infourl[$dir],$myobj), $areaname);
3842 //print "Setting.\n";
3843 }
3844 else
3845 {
3846 //print "NOT Setting.\n";
3847 }
3848 }
38491simandl }
385085simandl 
38511simandl }
3852 }
385385simandl 
38541simandl}
3855 
3856function asJS()
3857{
3858 $js='';
3859 
386085simandl $js .= "var Links = new Array();\n";
3861 $js .= "var LinkIDs = new Array();\n";
3862 # $js.=$this->defaultlink->asJS();
38631simandl 
3864 foreach ($this->links as $link) { $js.=$link->asJS(); }
3865 
386685simandl $js .= "var Nodes = new Array();\n";
3867 $js .= "var NodeIDs = new Array();\n";
3868 # $js.=$this->defaultnode->asJS();
38691simandl 
3870 foreach ($this->nodes as $node) { $js.=$node->asJS(); }
3871 
3872 return $js;
3873}
3874 
3875function asJSON()
3876{
3877 $json = '';
3878 
3879 $json .= "{ \n";
3880 
388185simandl $json .= "\"map\": { \n";
38821simandl foreach (array_keys($this->inherit_fieldlist)as $fld)
3883 {
3884 $json .= js_escape($fld).": ";
3885 $json .= js_escape($this->$fld);
3886 $json .= ",\n";
3887 }
3888 $json = rtrim($json,", \n");
3889 $json .= "\n},\n";
389085simandl 
3891 $json .= "\"nodes\": {\n";
38921simandl $json .= $this->defaultnode->asJSON();
3893 foreach ($this->nodes as $node) { $json .= $node->asJSON(); }
3894 $json = rtrim($json,", \n");
3895 $json .= "\n},\n";
3896 
3897 
3898 
389985simandl $json .= "\"links\": {\n";
39001simandl $json .= $this->defaultlink->asJSON();
3901 foreach ($this->links as $link) { $json .= $link->asJSON(); }
3902 $json = rtrim($json,", \n");
3903 $json .= "\n},\n";
3904 
3905 $json .= "'imap': [\n";
3906 $json .= $this->imap->subJSON("NODE:");
3907 // should check if there WERE nodes...
3908 $json .= ",\n";
3909 $json .= $this->imap->subJSON("LINK:");
3910 $json .= "\n]\n";
3911 $json .= "\n";
3912 
391385simandl $json .= ", 'valid': 1}\n";
39141simandl 
3915 return($json);
3916}
3917 
391885simandl// This method MUST run *after* DrawMap. It relies on DrawMap to call the map-drawing bits
3919// which will populate the ImageMap with regions.
3920//
3921// imagemapname is a parameter, so we can stack up several maps in the Cacti plugin with their own imagemaps
39221simandlfunction MakeHTML($imagemapname = "weathermap_imap")
3923{
392485simandl debug("Trace: MakeHTML()\n");
3925 // PreloadMapHTML fills in the ImageMap info, ready for the HTML to be created.
39261simandl $this->PreloadMapHTML();
3927 
3928 $html='';
3929 
393085simandl $html .= '<div class="weathermapimage" style="margin-left: auto; margin-right: auto; width: '.$this->width.'px;" >';
3931 if ( $this->imageuri != '') {
3932 $html.=sprintf(
3933 '<img id="wmapimage" src="%s" width="%d" height="%d" border="0" usemap="#%s"',
3934 $this->imageuri,
3935 $this->width,
3936 $this->height,
3937 $imagemapname
3938 );
3939 //$html .= 'alt="network weathermap" ';
3940 $html .= '/>';
3941 }
3942 else {
3943 $html.=sprintf(
3944 '<img id="wmapimage" src="%s" width="%d" height="%d" border="0" usemap="#%s"',
3945 $this->imagefile,
3946 $this->width,
3947 $this->height,
3948 $imagemapname
3949 );
3950 //$html .= 'alt="network weathermap" ';
3951 $html .= '/>';
3952 }
39531simandl $html .= '</div>';
3954 
395585simandl $html .= $this->SortedImagemap($imagemapname);
39561simandl 
395785simandl return ($html);
3958}
39591simandl 
396085simandlfunction SortedImagemap($imagemapname)
3961{
396289simandl $html='<map name="' . $imagemapname . '" id="' . $imagemapname . '">'. "\n";
39631simandl 
396485simandl # $html.=$this->imap->subHTML("NODE:",true);
3965 # $html.=$this->imap->subHTML("LINK:",true);
3966 
3967 $all_layers = array_keys($this->seen_zlayers);
3968 rsort($all_layers);
3969 
3970 debug("Starting to dump imagemap in reverse Z-order...\n");
3971 // this is not precisely efficient, but it'll get us going
3972 // XXX - get Imagemap to store Z order, or map items to store the imagemap
3973 foreach ($all_layers as $z)
3974 {
3975 debug("Writing HTML for layer $z\n");
3976 $z_items = $this->seen_zlayers[$z];
3977 if(is_array($z_items))
3978 {
3979 debug(" Found things for layer $z\n");
3980 
3981 // at z=1000, the legends and timestamps live
3982 if($z == 1000) {
3983 debug(" Builtins fit here.\n");
3984 $html .= $this->imap->subHTML("LEGEND:",true,($this->context != 'editor'));
3985 $html .= $this->imap->subHTML("TIMESTAMP",true,($this->context != 'editor'));
3986 }
3987 
3988 foreach($z_items as $it)
3989 {
3990 # print " " . $it->name . "\n";
3991 if($it->name != 'DEFAULT' && $it->name != ":: DEFAULT ::")
3992 {
3993 $name = "";
3994 if(strtolower(get_class($it))=='weathermaplink') $name = "LINK:L";
3995 if(strtolower(get_class($it))=='weathermapnode') $name = "NODE:N";
3996 $name .= $it->id . ":";
3997 debug(" Writing $name from imagemap\n");
3998 // skip the linkless areas if we are in the editor - they're redundant
3999 $html .= $this->imap->subHTML($name,true,($this->context != 'editor'));
4000 }
4001 }
4002 }
4003 }
4004 
4005 $html.='</map>';
4006 
4007 return($html);
40081simandl}
4009 
4010// update any editor cache files.
4011// if the config file is newer than the cache files, or $agelimit seconds have passed,
4012// then write new stuff, otherwise just return.
4013// ALWAYS deletes files in the cache folder older than $agelimit, also!
4014function CacheUpdate($agelimit=600)
4015{
401685simandl global $weathermap_lazycounter;
4017 
40181simandl $cachefolder = $this->cachefolder;
4019 $configchanged = filemtime($this->configfile );
4020 // make a unique, but safe, prefix for all cachefiles related to this map config
4021 // we use CRC32 because it makes for a shorter filename, and collisions aren't the end of the world.
4022 $cacheprefix = dechex(crc32($this->configfile));
4023 
4024 debug("Comparing files in $cachefolder starting with $cacheprefix, with date of $configchanged\n");
4025 
4026 $dh=opendir($cachefolder);
4027 
4028 if ($dh)
4029 {
4030 while ($file=readdir($dh))
4031 {
4032 $realfile = $cachefolder . DIRECTORY_SEPARATOR . $file;
4033 
4034 if(is_file($realfile) && ( preg_match('/^'.$cacheprefix.'/',$file) ))
4035 // if (is_file($realfile) )
4036 {
4037 debug("$realfile\n");
403885simandl if( (filemtime($realfile) < $configchanged) || ((time() - filemtime($realfile)) > $agelimit) )
40391simandl {
4040 debug("Cache: deleting $realfile\n");
4041 unlink($realfile);
4042 }
4043 }
4044 }
4045 closedir ($dh);
4046 
4047 foreach ($this->nodes as $node)
4048 {
4049 if(isset($node->image))
4050 {
4051 $nodefile = $cacheprefix."_".dechex(crc32($node->name)).".png";
4052 $this->nodes[$node->name]->cachefile = $nodefile;
4053 imagepng($node->image,$cachefolder.DIRECTORY_SEPARATOR.$nodefile);
4054 }
4055 }
4056 
405785simandl foreach ($this->keyimage as $key=>$image)
4058 {
4059 $scalefile = $cacheprefix."_scale_".dechex(crc32($key)).".png";
4060 $this->keycache[$key] = $scalefile;
4061 imagepng($image,$cachefolder.DIRECTORY_SEPARATOR.$scalefile);
4062 }
4063 
4064 
40651simandl $json = "";
4066 $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_map.json","w");
4067 foreach (array_keys($this->inherit_fieldlist)as $fld)
4068 {
4069 $json .= js_escape($fld).": ";
4070 $json .= js_escape($this->$fld);
4071 $json .= ",\n";
4072 }
4073 $json = rtrim($json,", \n");
4074 fputs($fd,$json);
4075 fclose($fd);
407685simandl 
4077 $json = "";
4078 $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_tree.json","w");
4079 $id = 10; // first ID for user-supplied thing
4080 
4081 $json .= "{ id: 1, text: 'SCALEs'\n, children: [\n";
4082 foreach ($this->colours as $scalename=>$colours)
4083 {
4084 $json .= "{ id: " . $id++ . ", text:" . js_escape($scalename) . ", leaf: true }, \n";
4085 }
4086 $json = rtrim($json,", \n");
4087 $json .= "]},\n";
4088 
4089 $json .= "{ id: 2, text: 'FONTs',\n children: [\n";
4090 foreach ($this->fonts as $fontnumber => $font)
4091 {
4092 if ($font->type == 'truetype')
4093 $json .= sprintf("{ id: %d, text: %s, leaf: true}, \n", $id++, js_escape("Font $fontnumber (TT)"));
40941simandl 
409585simandl if ($font->type == 'gd')
4096 $json .= sprintf("{ id: %d, text: %s, leaf: true}, \n", $id++, js_escape("Font $fontnumber (GD)"));
4097 }
4098 $json = rtrim($json,", \n");
4099 $json .= "]},\n";
4100 
4101 $json .= "{ id: 3, text: 'NODEs',\n children: [\n";
4102 $json .= "{ id: ". $id++ . ", text: 'DEFAULT', children: [\n";
4103 
4104 $weathemap_lazycounter = $id;
4105 // pass the list of subordinate nodes to the recursive tree function
4106 $json .= $this->MakeTemplateTree( $this->node_template_tree );
4107 $id = $weathermap_lazycounter;
4108 
4109 $json = rtrim($json,", \n");
4110 $json .= "]} ]},\n";
4111 
4112 $json .= "{ id: 4, text: 'LINKs',\n children: [\n";
4113 $json .= "{ id: ". $id++ . ", text: 'DEFAULT', children: [\n";
4114 $weathemap_lazycounter = $id;
4115 $json .= $this->MakeTemplateTree( $this->link_template_tree );
4116 $id = $weathermap_lazycounter;
4117 $json = rtrim($json,", \n");
4118 $json .= "]} ]}\n";
4119 
4120 fputs($fd,"[". $json . "]");
4121 fclose($fd);
4122 
41231simandl $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_nodes.json","w");
412485simandl $json = "";
4125// $json = $this->defaultnode->asJSON(TRUE);
4126 foreach ($this->nodes as $node) { $json .= $node->asJSON(TRUE); }
41271simandl $json = rtrim($json,", \n");
4128 fputs($fd,$json);
4129 fclose($fd);
4130 
413185simandl $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_nodes_lite.json","w");
4132 $json = "";
4133// $json = $this->defaultnode->asJSON(FALSE);
4134 foreach ($this->nodes as $node) { $json .= $node->asJSON(FALSE); }
4135 $json = rtrim($json,", \n");
4136 fputs($fd,$json);
4137 fclose($fd);
4138 
4139 
4140 
41411simandl $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_links.json","w");
414285simandl $json = "";
4143// $json = $this->defaultlink->asJSON(TRUE);
4144 foreach ($this->links as $link) { $json .= $link->asJSON(TRUE); }
41451simandl $json = rtrim($json,", \n");
4146 fputs($fd,$json);
4147 fclose($fd);
4148 
414985simandl $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_links_lite.json","w");
4150 $json = "";
4151// $json = $this->defaultlink->asJSON(FALSE);
4152 foreach ($this->links as $link) { $json .= $link->asJSON(FALSE); }
4153 $json = rtrim($json,", \n");
4154 fputs($fd,$json);
4155 fclose($fd);
4156 
4157 $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_imaphtml.json","w");
4158 $json = $this->imap->subHTML("LINK:");
4159 fputs($fd,$json);
4160 fclose($fd);
4161 
4162 
41631simandl $fd = fopen($cachefolder.DIRECTORY_SEPARATOR.$cacheprefix."_imap.json","w");
4164 $json = '';
4165 $nodejson = trim($this->imap->subJSON("NODE:"));
4166 if($nodejson != '')
4167 {
4168 $json .= $nodejson;
4169 // should check if there WERE nodes...
4170 $json .= ",\n";
4171 }
4172 $json .= $this->imap->subJSON("LINK:");
4173 fputs($fd,$json);
4174 fclose($fd);
4175 
4176 }
4177 else { debug("Couldn't read cache folder.\n"); }
4178}
417985simandl 
4180function MakeTemplateTree( &$tree_list, $startpoint="DEFAULT")
4181{
4182 global $weathermap_lazycounter;
4183 
4184 $output = "";
4185 foreach ($tree_list[$startpoint] as $subnode)
4186 {
4187 $output .= "{ id: " . $weathermap_lazycounter++ . ", text: " . js_escape($subnode);
4188 if( isset($tree_list[$subnode]))
4189 {
4190 $output .= ", children: [ \n";
4191 $output .= $this->MakeTemplateTree($tree_list, $subnode);
4192 $output = rtrim($output,", \n");
4193 $output .= "] \n";
4194 }
4195 else
4196 {
4197 $output .= ", leaf: true ";
4198 }
4199 $output .= "}, \n";
4200 }
4201 
4202 return($output);
4203}
4204 
4205function DumpStats($filename="")
4206{
4207 $report = "Feature Statistics:\n\n";
4208 foreach ($this->usage_stats as $key=>$val)
4209 {
4210 $report .= sprintf("%70s => %d\n",$key,$val);
4211 }
4212 
4213 if($filename == "") print $report;
4214}
4215 
42161simandl};
4217// vim:ts=4:sw=4:
4218?>

Powered by WebSVN 2.2.1