source: branches/0.4/web/addons/job_monarch/libtoga.php @ 753

Last change on this file since 753 was 752, checked in by ramonb, 11 years ago
  • minor optimization
  • Property svn:keywords set to Id
File size: 71.2 KB
Line 
1<?php
2/*
3 *
4 * This file is part of Jobmonarch
5 *
6 * Copyright (C) 2006-2013  Ramon Bastiaans
7 *
8 * Jobmonarch is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * Jobmonarch is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 *
22 * SVN $Id: libtoga.php 752 2013-03-26 14:55:23Z ramonb $
23 *
24 */
25
26
27class HTTPVariables
28{
29    var $clustername, $metricname;
30    var $restvars, $httpvars;
31
32    function HTTPVariables( $httpvars, $getvars )
33    {
34        $this->restvars        = array();
35
36        $this->clustername    = isset( $httpvars["c"] ) ? $httpvars["c"] : $getvars["c"];
37        $this->metricname    = isset( $httpvars["m"] ) ? $httpvars["m"] : $getvars["m"];
38
39        if( count( $httpvars ) > 0 )
40        {
41            foreach( $httpvars as $httpvar => $httpval )
42            {
43                if( $httpval )
44                {
45                    $this->restvars[$httpvar] = $httpval;
46                }
47            }
48        }
49
50        if( count( $getvars ) > 0 )
51        {
52            foreach( $getvars as $getvar => $getval )
53            {
54                if( $getval )
55                {
56                    $this->restvars[$getvar] = $getval;
57                }
58            }
59        }
60    }
61
62    function getClusterName()
63    {
64        return $this->clustername;
65    }
66
67    function getMetricName()
68    {
69        return $this->metricname;
70    }
71
72    function getHttpVar( $var )
73    {
74        if( isset( $this->restvars[$var] ) )
75        {
76            return $this->restvars[$var];
77        }
78        else
79        {
80            return null;
81        }
82    }
83}
84
85$CLUSTER_CONFS    = array();
86
87ini_set("memory_limit","500M");
88set_time_limit(0);
89
90// Monarch's conf
91//
92include_once "./conf.php";
93include_once "./version.php";
94
95global $GANGLIA_PATH;
96global $RRDTOOL;
97global $JOB_ARCHIVE_DIR;
98global $JOB_ARCHIVE_DBASE;
99global $skan_str;
100global $x_first, $y_first;
101global $CLUSTER_CONFS;
102
103$my_dir = getcwd();
104
105// Load Ganglia's PHP
106chdir( $GANGLIA_PATH );
107
108include_once "./eval_conf.php";
109include_once "./functions.php";
110include_once "./get_context.php";
111
112global $GLOBALS, $conf, $metrics, $version, $rrdtool_version, $context;
113
114// ganglia start
115$metrics = array();
116$version = array();
117
118$version["webfrontend"] = $GLOBALS["ganglia_version"];
119
120# Get rrdtool version
121$rrdtool_version = array();
122exec($conf['rrdtool'], $rrdtool_version);
123$rrdtool_version = explode(" ", $rrdtool_version[0]);
124$rrdtool_version = $rrdtool_version[1];
125$version["rrdtool"] = "$rrdtool_version";
126
127// ganglia end
128
129$context = 'cluster';
130
131// Back to our PHP
132chdir( $my_dir );
133
134global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH, $DATA_SOURCE, $HTTP_GET_VARS, $_GET;
135$httpvars = new HTTPVariables( $HTTP_GET_VARS, $_GET );
136
137// Set cluster context so that Ganglia will
138// provide us with the correct metrics array
139//
140global $context, $clustername, $reports;
141
142global $default_metric;
143
144// Ganglia's array of host metrics
145//
146global $hosts_up;
147global $start;
148
149global $DATETIME_FORMAT;
150
151function makeDate( $time )
152{
153    global $DATETIME_FORMAT;
154    return strftime( $DATETIME_FORMAT, $time );
155}
156
157
158class TarchDbase
159{
160    var $ip, $dbase, $conn;
161
162    function TarchDbase( $ip = null, $dbase = null )
163    {
164        global $CLUSTER_CONFS, $clustername;
165        global $JOB_ARCHIVE_DBASE;
166
167        // Import cluster specific settings
168        //
169        foreach( $CLUSTER_CONFS as $confcluster => $conffile )
170        {
171            if( strtolower( trim($this->clustername) ) == strtolower(trim($confcluster)) )
172            {
173                include_once $conffile;
174            }
175        }
176
177        $db_fields = explode( '/', $JOB_ARCHIVE_DBASE );
178
179        $this->ip    = $db_fields[0];
180        $this->dbase    = $db_fields[1];
181        $this->conn    = null;
182    }
183
184    function connect()
185    {
186        if( $this->ip == null )
187            $this->conn = pg_connect( "dbname=".$this->dbase );
188        else
189            $this->conn = pg_connect( "host=".$this->ip." dbname=".$this->dbase );
190    }
191
192    function searchDbase( $id = null, $queue = null, $owner = null, $name = null, $start_from_time = null, $start_to_time = null, $end_from_time = null, $end_to_time = null )
193    {
194        global $SEARCH_RESULT_LIMIT;
195
196        if( $id )
197        {
198            $select_query = "SELECT job_id FROM jobs WHERE job_id = '$id' AND job_status = 'F'";
199            $this->resultcount = 1;
200        }
201        else
202        {
203            $query_args = array();
204           
205            if( $queue )
206            {
207                $query_args[] = "job_queue ='$queue'";
208            }
209            if( $owner )
210            {
211                $query_args[] = "job_owner ='$owner'";
212            }
213            if( $name )
214            {
215                $query_args[] = "job_name = '$name'";
216            }
217            if( $start_from_time )
218            {
219                $query_args[] = "job_start_timestamp >= $start_from_time";
220            }
221            if( $start_to_time )
222            {
223                $query_args[] = "job_start_timestamp <= $start_to_time";
224            }
225            if( $end_from_time )
226            {
227                $query_args[] = "job_stop_timestamp >= $end_from_time";
228            }
229            if( $end_to_time )
230            {
231                $query_args[] = "job_stop_timestamp <= $end_to_time";
232            }
233
234            $query = "FROM jobs WHERE job_status = 'F' AND ";
235            $extra_query_args = '';
236
237            foreach( $query_args as $myquery )
238            {
239                if( $extra_query_args == '' )
240                {
241                    $extra_query_args = $myquery;
242                }
243                else
244                {
245                    $extra_query_args .= " AND ".$myquery;
246                }
247            }
248            $query .= $extra_query_args;
249
250            $count_result_idname = "COUNT(job_id)";
251            $select_result_idname = "job_id";
252
253            $count_query = "SELECT " . $count_result_idname . " " . $query;
254
255            $count_result = $this->queryDbase( $count_query );
256            $this->resultcount = (int) $count_result[0]['count'];
257
258            $select_query = "SELECT " . $select_result_idname . " " . $query . " ORDER BY job_id DESC LIMIT " . $SEARCH_RESULT_LIMIT;
259        }
260
261        $ids = $this->queryDbase( $select_query );
262
263        $ret = array();
264
265        foreach( $ids as $crow)
266        {
267            $ret[] = $crow['job_id'];
268        }
269
270        return $ret;
271    }
272
273    function getNodesForJob( $jobid )
274    {
275        $result = $this->queryDbase( "SELECT node_id FROM job_nodes WHERE job_id = '$jobid'" );
276
277        $nodes = array();
278
279        foreach( $result as $result_row ) 
280        {
281            $nodes[] = $this->getNodeArray( $result_row['node_id'] );
282        }
283
284        return $nodes;
285    }
286
287    function getJobsForNode( $nodeid )
288    {
289        $result = $this->queryDbase( "SELECT job_id FROM job_nodes WHERE node_id = '$nodeid'" );
290
291        $jobs = array();
292
293        foreach( $result as $result_row )
294        {
295            $jobs[] = $this->getJobArray( $result_row['job_id'] );
296        }
297        return $jobs;
298    }
299
300    function getJobArray( $id )
301    {
302        $result = $this->queryDbase( "SELECT * FROM jobs WHERE job_id = '$id'" );
303
304        return ( $this->makeArray( $result[0] ) );
305    }
306
307    function getNodeArray( $id )
308    {
309        $result = $this->queryDbase( "SELECT * FROM nodes WHERE node_id = '$id'" );
310
311        return ( $this->makeArray( $result[0] ) );
312    }
313
314    function makeArray( $result_row )
315    {
316        $myar = array();
317
318        foreach( $result_row as $mykey => $myval )
319        {
320            $map_key = explode( '_', $mykey );
321
322            $rmap_key = array_reverse( $map_key );
323            array_pop( $rmap_key );
324            $map_key = array_reverse( $rmap_key );
325           
326            $newkey = implode( '_', $map_key );
327           
328            $myar[$newkey] = $result_row[$mykey];
329        }
330
331        return $myar;
332    }
333
334    function queryDbase( $query )
335    {
336        $result_rows = array();
337   
338        if( !$this->conn )
339        {
340            $this->connect();
341        }
342
343        $result = pg_query( $this->conn, $query );
344
345        while ($row = pg_fetch_assoc($result))
346        {
347            $result_rows[] = $row;
348        }
349
350        return $result_rows;
351    }
352}
353
354class TarchRrdGraph
355{
356    var $rrdbin, $rrdvalues, $clustername, $hostname, $tempdir, $tarchdir, $metrics;
357
358    function TarchRrdGraph( $clustername, $hostname )
359    {
360        global $conf;
361        global $JOB_ARCHIVE_DIR;
362
363        $this->rrdbin        = $conf['rrdtool'];
364        $this->rrdvalues    = array();
365        $this->tarchdir        = $JOB_ARCHIVE_DIR;
366        $this->clustername    = $clustername;
367        $this->hostname        = $hostname;
368    }
369
370    function doCmd( $command )
371    {
372        $pipe = popen( $command . ' 2>&1', 'r' );
373
374        if (!$pipe)
375        {
376            print "pipe failed.";
377            return "";
378        }
379
380        $output = '';
381
382        while(!feof($pipe))
383        {
384            $output .= fread($pipe, 1024);
385        }
386
387        pclose($pipe);
388
389        $output = explode( "\n", $output );
390
391        return $output;
392    }
393
394    function dirList( $dir )
395    {
396        $dirlist = array();
397
398        if ($handle = opendir( $dir ))
399        {
400            while (false !== ($file = readdir($handle)))
401            {
402                if ($file != "." && $file != "..")
403                {
404                    $dirlist[] = $file;
405                }
406            }
407            closedir($handle);
408        }
409
410        return $dirlist;
411    }
412
413    function getTimePeriods( $start, $end )
414    {
415        $times = array();
416        $dirlist = $this->dirList( $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname );
417
418        $first = 0;
419        $last = 9999999999999;
420
421        foreach( $dirlist as $dir )
422        {
423            if( $dir > $first and $dir <= $start )
424            {
425                $first = $dir;
426            }
427            if( $dir < $last and $dir >= $end )
428            {
429                $last = $dir;
430            }
431        }
432
433        foreach( $dirlist as $dir )
434        {
435            if( $dir >= $first and $dir <= $last and !array_key_exists( $dir, $times ) )
436            {
437                $times[] = $dir;
438            }
439        }
440
441        sort( $times );
442
443        return $times;
444    }
445
446    function getRrdDirs( $start, $stop )
447    {
448        $timess = $this->getTimePeriods( $start, $stop );
449
450        $rrd_files = array();
451
452        foreach( $timess as $time )
453        {
454            $rrd_files[] = $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname. '/'.$time;
455        }
456
457        return $rrd_files;
458    }
459
460    function getRrdFiles( $metric, $start, $stop )
461    {
462        $times = $this->getTimePeriods( $start, $stop );
463
464        $rrd_files = array();
465
466        foreach( $times as $time )
467        {
468            $rrd_files[] = $this->tarchdir . '/' . $this->clustername . '/' . $this->hostname . '/' .$time. '/' . $metric. '.rrd';
469        }
470
471        return $rrd_files;
472    }
473}
474
475class DataSource
476{
477    var $data, $ip, $port;
478
479    function DataSource()
480    {
481        global $DATA_SOURCE, $clustername;
482
483        $ds_fields     = explode( ':', $DATA_SOURCE );
484
485        $ds_ip         = $ds_fields[0];
486        $ds_port       = $ds_fields[1];
487
488        $this->ip       = $ds_ip;
489        $this->port     = $ds_port;
490        $this->clustername = $clustername;
491    }
492
493    function getData()
494    {
495        $errstr        = '';
496        $errno         = 0;
497        $timeout       = 3;
498
499        $fp = fsockopen( $this->ip, $this->port, $errno, $errstr, $timeout );
500
501        if( !$fp )
502        {
503            echo 'Unable to connect to '.$this->ip.':'.$this->port;
504            return;
505        }
506
507        if( $this->port == '8652' )
508        {
509            $request = "/" . $this->clustername . "\n";
510            $rc = fputs($fp, $request);
511            if (!$rc)
512            {
513                $error = "Could not sent request to gmetad: $errstr";
514                if ($debug) print "<br/>DEBUG: $error\n";
515                   return FALSE;
516            }
517        }
518
519        stream_set_timeout( $fp, 30 );
520
521        while ( !feof( $fp ) )
522        {
523            $data .= fread( $fp, 16384 );
524        }
525
526        fclose( $fp );
527
528        return $data;
529    }
530}
531
532class DataGatherer
533{
534    var $xmlhandler, $data, $httpvars;
535
536    function DataGatherer( $cluster )
537    {
538        $this->cluster    = $cluster;
539        $this->httpvars = $httpvars;
540    }
541
542    function parseXML( $data )
543    {
544
545        $this->parser         = xml_parser_create();
546        $this->xmlhandler     = new TorqueXMLHandler( $this->cluster );
547
548        xml_parser_set_option( $this->parser, XML_OPTION_CASE_FOLDING, 0 );
549        xml_set_element_handler( $this->parser, array( &$this->xmlhandler, 'startElement' ), array( &$this->xmlhandler, 'stopElement' ) );
550
551        if ( !xml_parse( $this->parser, $data ) )
552        {
553            $error = sprintf( 'XML error: %s at %d', xml_error_string( xml_get_error_code( $this->parser ) ), xml_get_current_line_number( $this->parser ) );
554        }
555        $handler = &$this->xmlhandler;
556        $handler->finishUp();
557    }
558
559    function printInfo()
560    {
561        $handler = $this->xmlhandler;
562        $handler->printInfo();
563    }
564
565    function getUsingFQDN()
566    {
567        $handler = $this->xmlhandler;
568        return $handler->getUsingFQDN();
569    }
570
571    function getMetrics()
572    {
573        $handler = $this->xmlhandler;
574        return $handler->getMetrics();
575    }
576    function getNodes()
577    {
578        $handler = $this->xmlhandler;
579        return $handler->getNodes();
580    }
581
582    function getNode( $node )
583    {
584        $handler = $this->xmlhandler;
585        return $handler->getNode( $node );
586    }
587
588    function getCpus()
589    {
590        $handler = $this->xmlhandler;
591        return $handler->getCpus();
592    }
593
594    function getJobs()
595    {
596        $handler = $this->xmlhandler;
597        return $handler->getJobs();
598    }
599
600    function getJob( $job )
601    {
602        $handler = $this->xmlhandler;
603        return $handler->getJob( $job );
604    }
605
606    function getHeartbeat()
607    {
608        $handler = $this->xmlhandler;
609        return $handler->getHeartbeat();
610    }
611
612    function isJobmonRunning()
613    {
614        $handler = $this->xmlhandler;
615        return $handler->isJobmonRunning();
616    }
617}
618
619class TorqueXMLHandler
620{
621    var $clusters, $heartbeat, $nodes, $jobs, $clustername, $proc_cluster;
622
623    function TorqueXMLHandler( $clustername )
624    {
625        $this->jobs        = array();
626        $this->clusters     = array();
627        $this->nodes         = array();
628        $this->metrics      = array();
629        $this->heartbeat     = array();
630        $this->down_nodes    = array();
631        $this->offline_nodes    = array();
632        $this->clustername    = $clustername;
633        $this->proc_cluster = null;
634        $this->proc_hostname = null;
635        $this->fqdn        = 1;
636    }
637
638    function getUsingFQDN()
639    {
640        return $this->fqdn;
641    }
642
643    function getCpus()
644    {
645        $cpus = 0;
646
647        if( isset( $this->jobs ) && count( $this->jobs ) > 0 )
648        {
649            foreach( $this->jobs as $jobid=>$jobattrs )
650            {
651                $nodes    = count( $jobattrs['nodes'] );
652                $ppn    = (int) $jobattrs['ppn'] ? $jobattrs['ppn'] : 1;
653                $mycpus    = $nodes * $ppn;
654
655                $cpus    = $cpus + $mycpus;
656            }
657        }
658    }
659
660    function isJobmonRunning()
661    {
662        if (isset( $this->heartbeat['time'] ))
663        {
664            return 1;
665        }
666        else
667        {
668            return 0;
669        }
670    }
671
672    function makeHostname( $thostname, $tdomain=null )
673    {
674        // Should hostname be FQDN or short w/o domain
675        //
676        $nodes = &$this->nodes;
677
678        $fqdn = 1;
679
680        //$tdomain = explode( '.', $thostname );
681        //
682        // TODO?: extract domain from hostname or something?
683
684        if( $tdomain )
685        {
686            $domain_len    = 0 - strlen( $tdomain );
687
688            // Let's see if Ganglia use's FQDN or short hostnames
689            //
690            foreach( $nodes as $hostname => $nimage )
691            {
692                if( strpos( $hostname, $tomdain ) !== false )
693                {
694                    $fqdn    = 0;
695                }
696            }
697        }
698        else
699        {
700            $fqdn    = 0;
701        }
702   
703        if( $tdomain && $fqdn )
704        {
705            if( strpos( $thostname, $tdomain ) !== false )
706            {
707                $thostname = $thostname . '.'.$tdomain;
708            } 
709            else
710            {
711                $thostname = $thostname;
712            }
713        }
714
715        return $thostname;
716    }
717
718    function startElement( $parser, $name, $attrs )
719    {
720        global $cluster, $metrics;
721
722        $jobid = null;
723
724        if( $name == 'CLUSTER' )
725        {
726            // ganglia start
727            $cluster = $attrs;
728            // ganglia end
729
730            $this->proc_cluster = $attrs['NAME'];
731            //printf("set proc cluster to %s\n", $attrs['NAME'] );
732            return null;
733        }
734        if( $this->proc_cluster != $this->clustername )
735        {
736            //printf("cluster does not match: %s\n", $this->clustername );
737            return null;
738        }
739
740        if( $name == 'HOST' )
741        {
742            // ganglia start
743            $hostname = $attrs['NAME'];
744            $this->proc_hostname = $hostname;
745
746            # Pseudo metrics - add useful HOST attributes like gmond_started & last_reported to the metrics list:
747            $metrics[$hostname]['gmond_started']['NAME'] = "GMOND_STARTED";
748            $metrics[$hostname]['gmond_started']['VAL'] = $attrs['GMOND_STARTED'];
749            $metrics[$hostname]['gmond_started']['TYPE'] = "timestamp";
750            $metrics[$hostname]['last_reported']['NAME'] = "REPORTED";
751            $metrics[$hostname]['last_reported']['VAL'] = $attrs['REPORTED'];
752            $metrics[$hostname]['last_reported']['TYPE'] = "string";
753            $metrics[$hostname]['last_reported_timestamp']['NAME'] = "REPORTED TIMESTAMP";
754            $metrics[$hostname]['last_reported_timestamp']['VAL'] = $attrs['REPORTED'];
755            $metrics[$hostname]['last_reported_timestamp']['TYPE'] = "uint32";
756            $metrics[$hostname]['ip_address']['NAME'] = "IP";
757            $metrics[$hostname]['ip_address']['VAL'] = $attrs['IP'];
758            $metrics[$hostname]['ip_address']['TYPE'] = "string";
759            $metrics[$hostname]['location']['NAME'] = "LOCATION";
760            $metrics[$hostname]['location']['VAL'] = $attrs['LOCATION'];
761            $metrics[$hostname]['location']['TYPE'] = "string";
762            // ganglia end
763
764            //printf( "host %s\n", $hostname );
765            //$location = $attrs['LOCATION'];
766
767            if( !isset( $this->nodes[$hostname] ) )
768            {
769                $this->nodes[$hostname] = new NodeImage( $this->proc_cluster, $hostname );
770            }
771            return null;
772        }
773
774        if( $name == 'METRIC' )
775        {
776            $hostname = $this->proc_hostname;
777
778            // ganglia start
779            $metricname = rawurlencode($attrs['NAME']);
780            $metrics[$hostname][$metricname] = $attrs;
781            // ganglia end
782
783            if ( strpos( $attrs['NAME'], 'zplugin_monarch' ) === false )
784            {
785                return null;
786            }
787
788            if( strpos( $attrs['NAME'], 'zplugin_monarch_heartbeat' ) !== false )
789            {
790                $this->heartbeat['time'] = $attrs['VAL'];
791                return;
792            }
793            else if( strpos( $attrs['NAME'], 'zplugin_monarch_down' ) !== false )
794            {
795                $fields        = explode( ' ', $attrs['VAL'] );
796
797                $nodes_down    = array();
798                $down_domain    = null;
799
800                foreach( $fields as $f )
801                {
802                    $togavalues    = explode( '=', $f );
803
804                    $toganame    = $togavalues[0];
805                    $togavalue    = $togavalues[1];
806
807                    if( $toganame == 'nodes' )
808                    {
809                        $mynodes = explode( ';', $togavalue );
810
811                        foreach( $mynodes as $node )
812                        {
813                            $nodes_down[] = $node;
814                        }
815                    }
816                    else if( $toganame == 'domain' )
817                    {
818                        $down_domain = $togavalue;
819                    }
820                    else if( $toganame == 'reported' )
821                    {
822                        if( !isset( $this->down_nodes['heartbeat'] ) )
823                        {
824                            $this->down_nodes[$togavalue]    = array( $nodes_down, $down_domain );
825                        }
826                    }
827                }
828                return;
829            }
830            else if( strpos( $attrs['NAME'], 'zplugin_monarch_offline' ) !== false )
831            {
832                $fields        = explode( ' ', $attrs['VAL'] );
833
834                $nodes_offline    = array();
835                $offline_domain    = null;
836
837                foreach( $fields as $f )
838                {
839                    $togavalues    = explode( '=', $f );
840
841                    $toganame    = $togavalues[0];
842                    $togavalue    = $togavalues[1];
843
844                    if( $toganame == 'nodes' )
845                    {
846                        $mynodes = explode( ';', $togavalue );
847
848                        foreach( $mynodes as $node )
849                        {
850                            $nodes_offline[] = $node;
851                        }
852                    }
853                    else if( $toganame == 'domain' )
854                    {
855                        $offline_domain = $togavalue;
856                    }
857                    else if( $toganame == 'reported' )
858                    {
859                        if( !isset( $this->offline_nodes['heartbeat'] ) )
860                        {
861                            $this->offline_nodes[$togavalue] = array( $nodes_offline, $offline_domain );
862                        }
863                    }
864                }
865                return;
866            }
867            else if( strpos( $attrs['NAME'], 'zplugin_monarch_job' ) !== false )
868            {
869                sscanf( $attrs['NAME'], 'zplugin_monarch_job_%d_%s$', $monincr, $jobid );
870
871                if( !isset( $this->jobs[$jobid] ) )
872                {
873                    $this->jobs[$jobid] = array();
874                }
875
876                $fields = explode( ' ', $attrs['VAL'] );
877
878                foreach( $fields as $f )
879                {
880                    $togavalues = explode( '=', $f );
881
882                    $toganame = $togavalues[0];
883                    $togavalue = $togavalues[1];
884
885                    if( $toganame == 'nodes' )
886                    {
887                        if( $this->jobs[$jobid]['status'] == 'R' )
888                        {
889                            if( !isset( $this->jobs[$jobid][$toganame] ) )
890                            {
891                                $this->jobs[$jobid][$toganame] = array();
892                            }
893
894                            $mynodes = explode( ';', $togavalue );
895
896                            foreach( $mynodes as $node )
897                            {
898                                if( !in_array( $node, $this->jobs[$jobid][$toganame] ) )
899                                {
900                                    array_push( $this->jobs[$jobid][$toganame], $node );
901                                }
902                            }
903
904                        }
905                        else if( $this->jobs[$jobid]['status'] == 'Q' )
906                        {
907                            $this->jobs[$jobid][$toganame] = $togavalue;
908                        }
909                    }
910                    else
911                    {
912                        $this->jobs[$jobid][$toganame] = $togavalue;
913                    }
914                }
915
916                if( isset( $this->jobs[$jobid]['nodes'] ) )
917                {
918                    $nr_nodes = count( $this->jobs[$jobid]['nodes'] );
919       
920                    if( $this->jobs[$jobid]['status'] == 'R' )
921                    {
922
923                        if( isset( $this->jobs[$jobid]['domain'] ) )
924                        {
925                            $domain        = $this->jobs[$jobid]['domain'];
926                            $domain_len    = 0 - strlen( $domain );
927
928                            $first_host    = key( array_slice($this->nodes, 0, 1, true) );
929
930                            // Let's see if Ganglia use's FQDN or short hostnames
931                            //
932                            if( strpos( $first_host, $domain ) === false )
933                            {
934                                $this->fqdn    = 0;
935                            }
936                        }
937                        else
938                        {
939                            $this->fqdn    = 0;
940                        }
941
942                        foreach( $this->jobs[$jobid]['nodes'] as $node )
943                        {
944
945                            // Only add domain name to the hostname if Ganglia is doing that too
946                            //
947                            if( $this->fqdn && isset( $this->jobs[$jobid]['domain'] ) )
948                            {
949                                if( strpos( $node, $domain ) === false )
950                                {
951                                    $host = $node. '.'.$domain;
952                                } else
953                                {
954                                    $host = $node;
955                                }
956                            }
957                            else
958                            {
959                                $host    = $node;
960                            }
961
962                            if( !isset( $this->nodes[$host] ) )
963                            {
964                                $my_node = new NodeImage( $this->proc_cluster, $host );
965                            }
966                            else
967                            {
968                                $my_node = $this->nodes[$host];
969                            }
970
971                            if( !$my_node->hasJob( $jobid ) )
972                            {
973                                if( isset( $jobs[$jobid]['ppn'] ) )
974                                {
975                                    $my_node->addJob( $jobid, ((int) $jobs[$jobid]['ppn']) );
976                                }
977                                else
978                                {
979                                    $my_node->addJob( $jobid, 1 );
980                                }
981                            }
982
983                            $this->nodes[$host] = $my_node;
984                        }
985                    }
986                }
987            }
988            return;
989        }
990    }
991
992    function finishUp( )
993    {
994        $nodes    = $this->nodes;
995
996        if( sizeof( $this->down_nodes ) > 0 )
997        {
998            foreach( $this->down_nodes as $reported => $dnodes )
999            {
1000                if( $reported == $this->heartbeat['time'] )
1001                {
1002                    $domain = $dnodes[1];
1003
1004                    foreach( $dnodes[0] as $downhost )
1005                    {
1006                        $downhost = $this->makeHostname( $downhost, $domain );
1007
1008                        if( isset( $nodes[$downhost] ) )
1009                        {
1010                            // OMG PHP4 is fking stupid!
1011                            // $nodes[$downhost]->setDown( 1 ) won't work here..
1012                            //
1013                            $mynode = $nodes[$downhost];
1014                            $mynode->setDown( 1 );
1015                            $nodes[$downhost] = $mynode;
1016                        }
1017                    }
1018                }
1019            }
1020        }
1021
1022        if( sizeof( $this->offline_nodes ) > 0 )
1023        {
1024            foreach( $this->offline_nodes as $reported => $onodes )
1025            {
1026                if( $reported == $this->heartbeat['time'] )
1027                {
1028                    $domain = $onodes[1];
1029
1030                    foreach( $onodes[0] as $offlinehost )
1031                    {
1032                        $offlinehost = $this->makeHostname( $offlinehost, $domain );
1033
1034                        if( isset( $nodes[$offlinehost] ) )
1035                        {
1036                            // OMG PHP4 is fking stupid!
1037                            // $nodes[$offlinehost]->setDown( 1 ) won't work here..
1038                            //
1039                            $mynode = $nodes[$offlinehost];
1040                            $mynode->setOffline( 1 );
1041                            $nodes[$offlinehost] = $mynode;
1042                        }
1043                    }
1044                }
1045            }
1046        }
1047
1048        $this->nodes = $nodes;
1049    }
1050
1051    function stopElement( $parser, $name )
1052    {
1053    }
1054
1055    function printInfo()
1056    {
1057        $jobs = &$this->jobs;
1058
1059        printf( "---jobs---\n" );
1060
1061        foreach( $jobs as $jobid => $job )
1062        {
1063            printf( "job %s\n", $jobid );
1064
1065            if( isset( $job['nodes'] ) )
1066            {
1067                foreach( $job['nodes'] as $node )
1068                {
1069                    $mynode = $this->nodes[$node];
1070                    $hostname = $mynode->getHostname();
1071                    $location = $mynode->getLocation();
1072
1073                    printf( "\t- node %s\tlocation %s\n", $hostname, $location );
1074                }
1075            }
1076        }
1077
1078        printf( "---nodes---\n" );
1079
1080        $nodes = &$this->nodes;
1081
1082        foreach( $nodes as $node )
1083        {
1084            $hostname = $node->getHostname();
1085            $location = $node->getLocation();
1086            $jobs = implode( ' ', $node->getJobs() );
1087            printf( "* node %s\tlocation %s\tjobs %s\n", $hostname, $location, $jobs );
1088        }
1089    }
1090
1091    function getNodes()
1092    {
1093        return $this->nodes;
1094    }
1095
1096    function getNode( $node )
1097    {
1098        $nodes = &$this->nodes;
1099
1100        if( isset( $nodes[$node] ) )
1101        {
1102            return $nodes[$node];
1103        }
1104        else
1105        {
1106            return NULL;
1107        }
1108    }
1109
1110    function getJobs()
1111    {
1112        return $this->jobs;
1113    }
1114
1115    function getJob( $job )
1116    {
1117        $jobs = &$this->jobs;
1118
1119        if( isset( $jobs[$job] ) )
1120        {
1121            return $jobs[$job];
1122        }
1123        else
1124        {
1125            return NULL;
1126        }
1127    }
1128
1129    function getHeartbeat()
1130    {
1131        return $this->heartbeat['time'];
1132    }
1133}
1134
1135class NodeImage
1136{
1137    var $image, $x, $y, $hostname, $jobs, $tasks, $showinfo;
1138
1139    function NodeImage( $cluster, $hostname )
1140    {
1141        global $SMALL_CLUSTERIMAGE_NODEWIDTH;
1142
1143        $this->jobs        = array();
1144        $this->tasks        = 0;
1145        $this->hostname        = $hostname;
1146        $this->clustername    = $cluster;
1147        $this->showinfo        = 1;
1148        $this->size        = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1149        $this->down        = 0;
1150        $this->offline        = 0;
1151    }
1152
1153    function addJob( $jobid, $cpus )
1154    {
1155        $jobs        = &$this->jobs;
1156        $jobs[]        = $jobid;
1157        $this->jobs    = $jobs;
1158
1159        $this->addTask( $cpus );
1160    }
1161
1162    function hasJob( $jobid )
1163    {
1164        $jobfound = 0;
1165
1166        if( count( $this->jobs ) > 0 )
1167        {
1168            foreach( $this->jobs as $job )
1169            {
1170                if( $job == $jobid )
1171                {
1172                    $jobfound = 1;
1173                }
1174            }
1175        }
1176
1177        return $jobfound;
1178    }
1179
1180    function addTask( $cpus )
1181    {
1182        $this->tasks = $this->tasks + $cpus;
1183    }
1184    function setDown( $down )
1185    {
1186        $this->down = $down;
1187    }
1188    function isDown()
1189    {
1190        return $this->down;
1191    }
1192    function setOffline( $offline )
1193    {
1194        $this->offline = $offline;
1195    }
1196    function isOffline()
1197    {
1198        return $this->offline;
1199    }
1200    function setImage( $image )
1201    {
1202        $this->image = $image;
1203    }
1204    function setCoords( $x, $y )
1205    {
1206        $this->x = $x;
1207        $this->y = $y;
1208    }
1209    function getX()
1210    {
1211        return $this->x;
1212    }
1213    function getY()
1214    {
1215        return $this->y;
1216    }
1217
1218    function getImagemapArea()
1219    {
1220        $area_topleft        = $this->x . "," . $this->y;
1221        $area_bottomright    = ($this->x + $this->size) . "," . ($this->y + $this->size);
1222        $area_coords        = $area_topleft . "," . $area_bottomright;
1223
1224        $area_href        = "./?c=" . $this->clustername . "&h=" . $this->hostname;
1225
1226        $area_tooltip        = $this->hostname;
1227
1228        if( $this->down)
1229        {
1230            $area_tooltip        = $area_tooltip . ": DOWN";
1231        }
1232        else if( $this->offline )
1233        {
1234            $area_tooltip        = $area_tooltip . ": OFFLINE";
1235        }
1236
1237        $area_tooltip        = $area_tooltip . ": " . implode( " ", $this->jobs );
1238
1239        $tag_href        = "HREF=\"" . $area_href . "\"";
1240        $tag_coords        = "COORDS=\"" . $area_coords . "\"";
1241        $tag_tooltip1        = "ALT=\"" . $area_tooltip . "\"";
1242        $tag_tooltip2        = "TITLE=\"" . $area_tooltip . "\"";
1243
1244        return ("<AREA SHAPE=\"RECT\" " . $tag_coords . " " . $tag_href . " " . $tag_tooltip1 . " " . $tag_tooltip2 . ">");
1245    }
1246
1247    function colorHex( $color )
1248    {
1249        $my_color = imageColorAllocate( $this->image, hexdec( substr( $color, 0, 2 )), hexdec( substr( $color, 2, 2 )), hexdec( substr( $color, 4, 2 )) );
1250
1251        return $my_color;
1252    }
1253
1254    function setLoad( $load )
1255    {
1256        $this->load = $load;
1257    }
1258
1259    function setHostname( $hostname )
1260    {
1261        $this->hostname = $hostname;
1262    }
1263
1264    function getHostname()
1265    {
1266        return $this->hostname;
1267    }
1268
1269    function getJobs()
1270    {
1271        return $this->jobs;
1272    }
1273
1274    function setShowinfo( $showinfo )
1275    {
1276        $this->showinfo = $showinfo;
1277    }
1278
1279    function drawSmall()
1280    {
1281        global $SMALL_CLUSTERIMAGE_NODEWIDTH;
1282
1283        $this->size    = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1284
1285        $this->draw();
1286    }
1287
1288    function drawBig()
1289    {
1290        global $BIG_CLUSTERIMAGE_NODEWIDTH;
1291
1292        $this->size    = $BIG_CLUSTERIMAGE_NODEWIDTH;
1293
1294        $this->draw();
1295    }
1296
1297    function draw()
1298    {
1299        global $JOB_NODE_MARKING, $NODE_DOWN_MARKING, $NODE_OFFLINE_MARKING;
1300
1301        $black_color = imageColorAllocate( $this->image, 0, 0, 0 );
1302        $size = $this->size;
1303
1304        imageFilledRectangle( $this->image, $this->x, $this->y, $this->x+($size), $this->y+($size), $black_color );
1305
1306        if( $this->showinfo)
1307        {
1308            $this->load = $this->determineLoad();
1309
1310            if( !isset( $this->image ) or !isset( $this->x ) or !isset( $this->y ) )
1311            {
1312                printf( "aborting\n" );
1313                printf( "x %d y %d load %f\n", $this->x, $this->y, $load );
1314                return;
1315            }
1316
1317            // Convert Ganglias Hexadecimal load color to a Decimal one
1318            //
1319            $load = $this->determineLoad();   
1320            $usecolor = $this->colorHex( load_color($load) );
1321            imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
1322            if( $this->down )
1323            {
1324                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $NODE_DOWN_MARKING, $black_color );
1325            }
1326            else if( $this->offline )
1327            {
1328                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $NODE_OFFLINE_MARKING, $black_color );
1329            }
1330            else if( count( $this->jobs ) > 0 )
1331            {
1332                imageString( $this->image, 1, $this->x+(($size/2)-1), $this->y+(($size/2)-4), $JOB_NODE_MARKING, $black_color );
1333            }
1334        }
1335        else
1336        {
1337            // White
1338            $usecolor = imageColorAllocate( $this->image, 255, 255, 255 );
1339            imageFilledRectangle( $this->image, $this->x+1, $this->y+1, $this->x+($size-1), $this->y+($size-1), $usecolor );
1340        }
1341    }
1342
1343    function determineLoad()
1344    {
1345        global $metrics;
1346
1347        $cpus = $metrics[$this->hostname]['cpu_num']['VAL'];
1348        if (!$cpus)
1349        {
1350            $cpus=1;
1351        }
1352
1353        $load_one    = $metrics[$this->hostname]['load_one']['VAL'];
1354        $load        = ((float) $load_one)/$cpus;
1355
1356        return $load;
1357    }
1358}
1359
1360class ClusterImage
1361{
1362    var $dataget, $image, $clustername;
1363    var $filtername, $filters;
1364
1365    function ClusterImage( $data, $clustername )
1366    {
1367        $this->dataget        = new DataGatherer( $clustername );
1368        $this->data        = $data;
1369        $this->clustername    = $clustername;
1370        $this->filters        = array();
1371        $this->size        = 's';
1372        $this->width        = 0;
1373        $this->height        = 0;
1374        $this->output        = 1;
1375        $this->jobs         = null;
1376        $this->nodes        = null;
1377    }
1378
1379    function getWidth()
1380    {
1381        return $this->width;
1382    }
1383    function getHeight()
1384    {
1385        return $this->height;
1386    }
1387    function setSmall()
1388    {
1389        $this->size    = 's';
1390    }
1391    function setBig()
1392    {
1393        $this->size    = 'b';
1394    }
1395    function setNoimage()
1396    {
1397        $this->output    = 0;
1398    }
1399    function setJobs($jobs )
1400    {
1401        $this->jobs     = &$jobs;
1402    }
1403    function getJobs()
1404    {
1405        if( $this->jobs == null )
1406        {
1407            $mydatag = $this->dataget;
1408            $mydatag->parseXML( $this->data );
1409            $this->jobs = $mydatag->getJobs();
1410        }
1411
1412        return $this->jobs;
1413    }
1414    function getNodes()
1415    {
1416        if( $this->nodes== null )
1417        {
1418            $mydatag = $this->dataget;
1419            $mydatag->parseXML( $this->data );
1420            $this->nodes = $mydatag->getNodes();
1421        }
1422
1423        return $this->nodes;
1424    }
1425    function setNodes($nodes)
1426    {
1427        $this->nodes    = &$nodes;
1428    }
1429    function isSmall()
1430    {
1431        return ($this->size == 's');
1432    }
1433    function isBig()
1434    {
1435        return ($this->size == 'b');
1436    }
1437    function setFilter( $filtername, $filtervalue )
1438    {
1439        $this->filters[$filtername] = $filtervalue;
1440    }
1441
1442    function filterNodes( $jobs, $nodes )
1443    {
1444        $filtered_nodes = array();
1445
1446        //print_r( $nodes );
1447
1448        foreach( $nodes as $node )
1449        {
1450            $hostname = $node->getHostname();
1451
1452            $addhost = 1;
1453
1454            if( count( $this->filters ) > 0 )
1455            {
1456                $mynjobs = $node->getJobs();
1457
1458                if( count( $mynjobs ) > 0 )
1459                {
1460                    foreach( $mynjobs as $myjob )
1461                    {
1462                        foreach( $this->filters as $filtername => $filtervalue )
1463                        {
1464                            if( $filtername!=null && $filtername!='' )
1465                            {
1466                                if( $filtername == 'jobid' && !$node->hasJob( $filtervalue) )
1467                                {
1468                                    $addhost = 0;
1469                                }
1470                                else if( $filtername != 'jobid' )
1471                                {
1472                                    if( $jobs[$myjob][$filtername] != $filtervalue )
1473                                    {
1474                                        $addhost = 0;
1475                                    }
1476                                }
1477                            }
1478                        }
1479                    }
1480                }
1481                else
1482                {
1483                    $addhost = 0;
1484                }
1485            }
1486
1487            if( $addhost )
1488            {
1489                $filtered_nodes[] = $hostname;
1490            }
1491        }
1492
1493        return $filtered_nodes;
1494    }
1495
1496    function draw()
1497    {
1498        global $SMALL_CLUSTERIMAGE_MAXWIDTH, $SMALL_CLUSTERIMAGE_NODEWIDTH;
1499        global $BIG_CLUSTERIMAGE_MAXWIDTH, $BIG_CLUSTERIMAGE_NODEWIDTH;
1500        global $CLUSTER_CONFS, $confcluster, $SHOW_EMPTY_COLUMN, $SHOW_EMPTY_ROW;
1501
1502        global $SORTBY_HOSTNAME, $SORT_ORDER, $skan_str;
1503        global $x_first, $y_first;
1504
1505        foreach( $CLUSTER_CONFS as $confcluster => $conffile )
1506        {
1507            if( strtolower( trim($this->clustername) ) == strtolower(trim($confcluster)) )
1508            {
1509                include_once $conffile;
1510            }
1511        }
1512
1513        if( $this->isSmall() )
1514        {
1515            $max_width    = $SMALL_CLUSTERIMAGE_MAXWIDTH;
1516            $node_width    = $SMALL_CLUSTERIMAGE_NODEWIDTH;
1517        }
1518        else if( $this->isBig() )
1519        {
1520            $max_width    = $BIG_CLUSTERIMAGE_MAXWIDTH;
1521            $node_width    = $BIG_CLUSTERIMAGE_NODEWIDTH;
1522        }
1523
1524        $nodes        = $this->getNodes();
1525        $nodes_hosts    = array_keys( $nodes );
1526
1527        $nodes_nr    = count( $nodes );
1528
1529        $nodes_size    = $nodes_nr*$node_width;
1530        $node_rows    = 0;
1531
1532        if( $nodes_size > $max_width )
1533        {
1534            $nodes_per_row = ( (int) ($max_width/$node_width) );
1535        }
1536        else
1537        {
1538            $nodes_per_row = $nodes_size;
1539            $node_rows = 1;
1540        }
1541
1542        if( $nodes_per_row < $nodes_nr )
1543        {
1544            $node_rows = ( (int) ($nodes_nr/$nodes_per_row) );
1545            $node_rest = fmod( $nodes_nr, $nodes_per_row );
1546
1547            if( $node_rest > 0 )
1548            {
1549                $node_rows++;
1550            }
1551        }
1552
1553        $y_offset    = 0;
1554        $font         = 2;
1555        $fontwidth    = ImageFontWidth( $font );
1556        $fontheight    = ImageFontHeight( $font );
1557        $fontspaceing    = 2;
1558        $y_offset    = $fontheight + (2 * $fontspaceing);
1559
1560        $this->width    = $max_width;
1561        $this->height    = ($y_offset + (($node_rows*$node_width)+1) );
1562
1563        $jobs = $this->getJobs();
1564        $filtered_nodes = $this->filterNodes( $jobs, $nodes );
1565
1566        if( $SORTBY_HOSTNAME != "" )
1567        {
1568                $sorted     = array();
1569
1570            $x_first    = 0;
1571            $y_first    = 0;
1572
1573            $skan_str    = $SORTBY_HOSTNAME;
1574
1575            global $x_present, $y_present;
1576            $x_present    = false;
1577            $y_present    = false;
1578
1579            // Should we scan by X, Y or both
1580            //
1581            if(strpos( $SORTBY_HOSTNAME, "{x}" ) != false )
1582            {
1583                $x_str        = "{x}";
1584                $x_present    = true;
1585            }
1586            else if(strpos( $SORTBY_HOSTNAME, "{X}" ) != false )
1587            {
1588                $x_str        = "{X}";
1589                $x_present    = true;
1590            }
1591            if(strpos( $SORTBY_HOSTNAME, "{y}" ) != false )
1592            {
1593                $y_str        = "{y}";
1594                $y_present    = true;
1595            }
1596            else if(strpos( $SORTBY_HOSTNAME, "{Y}" ) != false )
1597            {
1598                $y_str        = "{Y}";
1599                $y_present    = true;
1600            }
1601
1602            // If we should scan for both X and Y: see which one is first
1603            //
1604            if(( strpos( $SORTBY_HOSTNAME, $x_str ) < strpos( $SORTBY_HOSTNAME, $y_str ) ) && ( $x_present && $y_present ))
1605            {
1606                $x_first    = 1;
1607            }
1608            else if(( strpos( $SORTBY_HOSTNAME, $x_str ) > strpos( $SORTBY_HOSTNAME, $y_str ) ) && ( $x_present && $y_present ))
1609            {
1610                $y_first    = 1;
1611       
1612            }
1613            else if( $x_present )
1614            {
1615                $x_first    = 1;
1616            }
1617            else if( $y_present )
1618            {
1619                $y_first    = 1;
1620            }
1621
1622            // Now replace our {x} and {y} with %d for sscanf parsing
1623            //
1624            if(( $x_first ) && ( $x_present && $y_present ) )
1625            {
1626                $skan_str    = str_replace( $x_str, "%d", $skan_str );
1627                $skan_str    = str_replace( $y_str, "%d", $skan_str );
1628            } 
1629            else if( $x_present)
1630            {
1631                $skan_str    = str_replace( $x_str, "%d", $skan_str );
1632            }
1633            else if( $y_present)
1634            {
1635                $skan_str    = str_replace( $y_str, "%d", $skan_str );
1636            }
1637
1638            $x_min        = null;
1639            $x_max        = null;
1640            $y_min        = null;
1641            $y_max        = null;
1642
1643            $x_columns    = array();
1644            $y_rows        = array();
1645
1646            // Now let's walk through all our nodes and see which one are valid for our scan pattern
1647            //
1648            foreach( $nodes as $hostname => $node )
1649            {
1650                $x    = null;
1651                $y    = null;
1652
1653                if( $x_present && $y_present )
1654                {
1655                    if( $x_first )
1656                    {
1657                        $n = sscanf( $hostname, $skan_str, $x, $y );
1658                    }
1659                    else if( $y_first )
1660                    {
1661                        $n = sscanf( $hostname, $skan_str, $y, $x );
1662                    }
1663
1664                    // Remove nodes that don't match
1665                    //
1666                    if( $n < 2 )
1667                    {
1668                        // This node hostname has no match for: {x} and {y}
1669                        //
1670                        unset( $nodes[$hostname] );
1671                    }
1672                }
1673                else if( $x_present && !$y_present )
1674                {
1675                    $n = sscanf( $hostname, $skan_str, $x );
1676
1677                    // Remove nodes that don't match
1678                    //
1679                    if( $n < 1 )
1680                    {
1681                        // This node hostname has no match for: {x}
1682                        //
1683                        unset( $nodes[$hostname] );
1684                    }
1685                    $y    = 1;
1686                }
1687                else if( $y_present && !$x_present )
1688                {
1689                    $n = sscanf( $hostname, $skan_str, $y );
1690
1691                    // Remove nodes that don't match
1692                    //
1693                    if( $n < 1 )
1694                    {
1695                        // This node hostname has no match for: {y}
1696                        //
1697                        unset( $nodes[$hostname] );
1698                    }
1699                    $x    = 1;
1700                }
1701
1702                // Determine the lowest value of {x} that exists in all node hostnames
1703                //
1704                if( !$x_min && $x != null )
1705                {
1706                    $x_min    = $x;
1707                }
1708                else if( $x < $x_min && $x != null )
1709                {
1710                    $x_min    = $x;
1711                }
1712
1713                // Determine the highest value of {x} that exists in all node hostnames
1714                //
1715                if( !$x_max && $x != null )
1716                {
1717                    $x_max    = $x;
1718                }
1719                else if( $x > $x_max && $x != null )
1720                {
1721                    $x_max    = $x;
1722                }
1723
1724                // Determine the lowest value of {y} that exists in all node hostnames
1725                //
1726                if( !$y_min && $y != null )
1727                {
1728                    $y_min    = $y;
1729                }
1730                else if( $y < $y_min && $y != null )
1731                {
1732                    $y_min    = $y;
1733                }
1734
1735                // Determine the highest value of {y} that exists in all node hostnames
1736                //
1737                if( !$y_max && $y != null )
1738                {
1739                    $y_max    = $y;
1740                }
1741                else if( $y > $y_max && $y != null )
1742                {
1743                    $y_max    = $y;
1744                }
1745
1746                // Store which non-empty columns and rows we found
1747                //
1748                if( !in_array( $x, $x_columns ) )
1749                {
1750                    $x_columns[] = $x;
1751                }
1752                if( !in_array( $y, $y_rows ) )
1753                {
1754                    $y_rows[] = $y;
1755                }
1756            }
1757
1758            // Sort all the nodes (alpha and numerically)
1759            // 1: gb-r1n1, 2: gb-r1n2, 3: gb-r2n1, etc
1760            //
1761            $sorted_nodes    = usort( $nodes, "cmp" );
1762
1763            //print_r( $x_columns ) ;
1764
1765            $cur_node    = 0;
1766
1767            $x_offset    = 0;
1768            $y_offset    = 0;
1769            $font         = 2;
1770            $fontwidth    = ImageFontWidth( $font );
1771            $fontheight    = ImageFontHeight( $font );
1772            $fontspaceing    = 2;
1773
1774            if( $this->isSmall() ) 
1775            {
1776                $y_offset    = $y_offset + (2 * $fontspaceing) + $fontheight;
1777            }
1778
1779            if( $this->isBig() ) 
1780            {
1781                $y_offset    = ($fontheight * (1 + strlen( $x_max) ) ) + ((2 + strlen( $x_max)) * $fontspaceing);
1782                $x_offset    = ($fontwidth * (1 + strlen( $y_max) ) ) + ((2 + strlen( $y_max)) * $fontspaceing);
1783            }
1784
1785            $image_width    = $x_offset + ($node_width * ($x_max-$x_min+2));
1786
1787            if( $this->isSmall() ) 
1788            {
1789                $image_width    = $max_width;
1790            }
1791            else if( $this->isBig() ) 
1792            {
1793                $image_width    = ($image_width < $max_width) ? $image_width : $max_width;
1794            }
1795            $image_height    = $y_offset + ($node_width * ($y_max-$y_min+2));
1796
1797            $this->width    = $image_width;
1798            $this->heigth    = $image_heigth;
1799
1800            $image        = imageCreateTrueColor( $image_width, $image_height );
1801            $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
1802
1803            imageFill( $image, 0, 0, $colorwhite );
1804
1805            if( $this->isSmall() )
1806            {
1807                // Draw a fancy little header text to explain what it is
1808                //
1809                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1810
1811                imageString( $image, $font, 2, 2, "Monarch Joblist - cluster: ".$this->clustername, $colorblue );
1812            }
1813
1814            if( $this->isBig() && ( isset( $SORT_XLABEL ) || isset( $SORT_YLABEL ) ) )
1815            {
1816                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1817
1818                if( isset( $SORT_XLABEL ) )
1819                {
1820                    // Print the {x} label: rack
1821                    //
1822                    imageString( $image, $font, $x_offset, $fontspaceing, $SORT_XLABEL, $colorblue );
1823                }
1824
1825                if( isset( $SORT_YLABEL ) )
1826                {
1827                    // Stupid php without imageStringDown function... we'll make one ourself
1828                    //
1829
1830                    // Print the {y} label: node
1831                    //
1832                    imageStringDown( $image, $font, $fontspaceing, $y_offset, $SORT_YLABEL, $colorblue );
1833                }
1834            }
1835
1836            $previous_n    = 0;
1837            $previous_m    = 0;
1838            $x_empty_count    = 0;
1839            $y_empty_count    = 0;
1840
1841            // Let's start assigning x,y coordinates now
1842            //
1843            for( $n = $x_min; $n <= $x_max; $n++ )
1844            {
1845                for( $m = $y_min; $m <= $y_max; $m++ )
1846                {
1847                    if( $x_min > 0 )
1848                    {
1849                        $x    = $x_offset + ( ($n-$x_min) * $node_width ) - ($x_empty_count * $node_width);
1850                    }
1851                    if( $y_min > 0 )
1852                    {
1853                        $y    = $y_offset + ( ($m-$y_min) * $node_width ) - ($y_empty_count * $node_width);
1854                    }
1855
1856                    // Don't show empty rows/columns if option enabled
1857                    //
1858                    if( !in_array( $n, $x_columns ) && !$SHOW_EMPTY_COLUMN )
1859                    {
1860                        // Skip to next iteration: we don't want a empty column
1861                        //
1862                        if( $n > $previous_n )
1863                        {
1864                            $previous_n = $n;
1865                            $x_empty_count++;
1866                        }
1867                        continue;
1868                    }
1869                    if( !in_array( $m, $y_rows ) && !$SHOW_EMPTY_ROW )
1870
1871                    {
1872                        // Skip to next iteration: we don't want a empty column
1873                        //
1874                        if( $m > $previous_m )
1875                        {
1876                            $previous_m = $m;
1877                            $y_empty_count++;
1878                        }
1879                        continue;
1880                    }
1881
1882                    if( $this->isBig() ) 
1883                    {
1884                        // Draw y(node) column number header
1885                        //
1886                        if(( $n == $x_min ) && ( isset($SORT_YLABEL) ) )
1887                        {
1888                            $mfontspacing    = 1;
1889
1890                            $ylabel_x    = $x - ( $fontwidth * strlen( $y_max ) ) - $mfontspacing;
1891                            $ylabel_y    = $y;
1892
1893                            imageString( $image, $font, $ylabel_x, $ylabel_y, strval( $m ), $colorblue );
1894
1895                            $xmin_hit[$n]    = true;
1896                        }
1897
1898                        // Draw x(rack) column number header
1899                        //
1900                        if(( $m == $y_min ) && ( isset($SORT_XLABEL) ) )
1901                        {
1902                            $mfontspacing    = 2;
1903                            $xlabel_y    = $y - ( $fontheight * strlen( $x_max ) );
1904                            $xlabel_x    = $x + $mfontspacing; 
1905
1906                            imageStringDown( $image, $font, $xlabel_x, $xlabel_y, strval( $n ), $colorblue );
1907                        }
1908                    }
1909
1910                    if( isset( $nodes[$cur_node] ) ) 
1911                    {
1912                        $host    = $nodes[$cur_node]->getHostname();
1913
1914                        if( $x_present && $y_present )
1915                        {
1916                            if( $x_first )
1917                            {
1918                                $nn = sscanf( $host, $skan_str, $rx, $ry );
1919                            }
1920                            else if( $y_first )
1921                            {
1922                                $nn = sscanf( $host, $skan_str, $ry, $rx );
1923                            }
1924                            if ( $nn < 2 )
1925                            {
1926                                //printf( "skipping node %s - y present & x present + <2 x,y matchs\n", $host);
1927                                continue;
1928                            }
1929                            if( intval( $rx ) > $n )
1930                            {
1931                                // If x(rack) is higher than current x, skip to next x(rack)
1932                                //
1933                                $m        = $y_max + 1;
1934
1935                                continue;
1936                            }
1937                            if( intval( $ry ) > $m )
1938                            {
1939                                // If y(node) is higher than current y, skip to next y(node)
1940                                //
1941                                continue;
1942                            }
1943                        }
1944                        else if( $x_present )
1945                        {
1946                            $nn = sscanf( $host, $skan_str, $rx );
1947                        }
1948                        else if( $y_present )
1949                        {
1950                            $nn = sscanf( $host, $skan_str, $ry );
1951                        }
1952
1953                        if( !in_array( $host, $filtered_nodes ) )
1954                        {
1955                            // This node has been filtered out: we only want to see certain nodes
1956                            //
1957                            $nodes[$cur_node]->setShowinfo( 0 );
1958                        }
1959
1960                        $nodes[$cur_node]->setCoords( $x, $y );
1961                        $nodes[$cur_node]->setImage( $image );
1962
1963                        if( $this->isSmall() )
1964                        {
1965                            $nodes[$cur_node]->drawSmall();
1966                        }
1967                        else if( $this->isBig() )
1968                        {
1969                            $nodes[$cur_node]->drawBig();
1970                        }
1971
1972                        $cur_node++;
1973                    }
1974                }
1975            }
1976
1977        }
1978        else
1979        {
1980            if( $this->isSmall() )
1981            {
1982                $image        = imageCreateTrueColor( $max_width, ($y_offset + (($node_rows*$node_width)+1) ) );
1983            }
1984            else if( $this->isBig() )
1985            {
1986                $image_width    = ($node_width * $nodes_nr) + 2;
1987                $image_width    = ($image_width < $max_width) ? $image_width : $max_width;
1988                $image        = imageCreateTrueColor( $image_width, ($y_offset + (($node_rows*$node_width)+1) ) );
1989            }
1990            $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
1991
1992            imageFill( $image, 0, 0, $colorwhite );
1993
1994            if( $this->isSmall() )
1995            {
1996                $colorblue    = imageColorAllocate( $image, 0, 0, 255 );
1997
1998                imageString( $image, $font, 2, 2, "Monarch Joblist - cluster: ".$this->clustername, $colorblue );
1999            }
2000
2001            for( $n = 0; $n < $node_rows; $n++ )
2002            {
2003                for( $m = 0; $m < $nodes_per_row; $m++ )
2004                {
2005                    $x = ($m * $node_width);
2006                    $y = $y_offset + ($n * $node_width);
2007
2008                    $cur_node = ($n * $nodes_per_row) + ($m);
2009                    $host = isset( $nodes_hosts[$cur_node] ) ? $nodes_hosts[$cur_node] : '';
2010
2011                    if( isset( $nodes[$host] ) )
2012                    {
2013                        $nodes[$host]->setCoords( $x, $y );
2014                        $nodes[$host]->setImage( $image );
2015
2016                        if( !in_array( $host, $filtered_nodes ) )
2017                        {
2018                            $nodes[$host]->setShowinfo( 0 );
2019                        }
2020
2021                        if( $this->isSmall() )
2022                        {
2023                            $nodes[$host]->drawSmall();
2024                        }
2025                        else if( $this->isBig() )
2026                        {
2027                            $nodes[$host]->drawBig();
2028                        }
2029                    }
2030                }
2031            }
2032        }
2033   
2034        $this->nodes    = &$nodes;
2035
2036        if ($this->output)
2037        {
2038            header( 'Content-type: image/png' );
2039            imagePNG( $image );
2040            imageDestroy( $image );
2041        }
2042    }
2043
2044    function getImagemapArea()
2045    {
2046        $clusterimage_map    = "";
2047
2048        foreach( $this->nodes as $hostname => $node )
2049        {
2050            $node_map        = $node->getImagemapArea();
2051            $clusterimage_map    .= $node_map;
2052        }
2053
2054        return $clusterimage_map;
2055    }
2056}
2057
2058class EmptyImage
2059{
2060    function draw()
2061    {
2062        $image        = imageCreateTrueColor( 1, 1 );
2063        $colorwhite    = imageColorAllocate( $image, 255, 255, 255 );
2064        imageFill( $image, 0, 0, $colorwhite );                         
2065
2066        header( 'Content-type: image/png' );
2067        imagePNG( $image );
2068        imageDestroy( $image );
2069    }
2070}
2071
2072class HostImage
2073{
2074    var $data_gather, $cluster, $host, $node, $image;
2075    var $headerstrlen;
2076
2077    function HostImage( $data_gather, $cluster, $host )
2078    {
2079        $this->data_gather     = $data_gather;
2080        $this->cluster        = $cluster;
2081        $this->host        = $host;
2082        $this->y_offset        = 0;
2083        $this->font        = 2;
2084        $this->fontspaceing    = 2;
2085        $this->headerstrlen    = array();
2086
2087        $this->fontheight    = ImageFontHeight( $this->font );
2088        $this->fontwidth    = ImageFontWidth( $this->font );
2089
2090        $dg            = &$this->data_gather;
2091        $this->node        = &$dg->getNode( $this->host );
2092        $n            = &$this->node;
2093        $this->njobs        = $n->getJobs();
2094    }
2095
2096    function drawJobs()
2097    {
2098        $dg                     = &$this->data_gather;
2099        $colorblack        = imageColorAllocate( $this->image, 0, 0, 0 );
2100
2101        for( $n = 0; $n < count( $this->njobs ); $n++ )
2102        {
2103            $jobid            = $this->njobs[$n];
2104            $jobinfo        = $dg->getJob( $jobid );
2105
2106            $xoffset        = 5;
2107            imageString( $this->image, $this->font, $xoffset, $this->y_offset, strval( $jobid ), $colorblack );
2108
2109            foreach( $this->headerstrlen as $headername => $headerlen )
2110            {
2111                if( $headername == 'nodes' )
2112                {
2113                    $attrval    = strval( count( $jobinfo['nodes'] ) );
2114                }
2115                else if( $headername == 'cpus' )
2116                {
2117                    if( !isset( $jobinfo['ppn'] ) )
2118                    {
2119                        $jobinfo['ppn'] = 1;
2120                    }
2121
2122                    $attrval    = strval( count( $jobinfo['nodes'] ) * intval( $jobinfo['ppn'] ) );
2123                }
2124                else if( $headername == 'runningtime' )
2125                {
2126                    $attrval    = makeTime( intval( $jobinfo['reported'] ) - intval( $jobinfo['start_timestamp'] ) );
2127                }
2128                else
2129                {
2130                    $attrval    = strval( $jobinfo[$headername] );
2131                }
2132
2133                imageString( $this->image, $this->font, $xoffset, $this->y_offset, $attrval, $colorblack );
2134       
2135                $xoffset    = $xoffset + ($this->fontwidth * ( $headerlen + 1 ) );
2136            }
2137           
2138            $this->newLineOffset();
2139        }
2140    }
2141
2142    function drawHeader()
2143    {
2144        $dg                     = &$this->data_gather;
2145
2146        for( $n = 0; $n < count( $this->njobs ); $n++ )
2147        {
2148            $jobid            = $this->njobs[$n];
2149            $jobinfo        = $dg->getJob( $jobid );
2150
2151            if( !isset( $this->headerstrlen['id'] ) )
2152            {
2153                $this->headerstrlen['id']    = strlen( strval( $jobid ) );
2154            }
2155            else if( strlen( strval( $jobid ) ) > $this->headerstrlen['id'] )
2156            {
2157                $this->headerstrlen['id']    = strlen( strval( $jobid ) );
2158            }
2159
2160            if( !isset( $this->headerstrlen['owner'] ) )
2161            {
2162                $this->headerstrlen['owner']    = strlen( strval( $jobinfo['owner'] ) );
2163            }
2164            else if( strlen( strval( $jobinfo['owner'] ) ) > $this->headerstrlen['owner'] )
2165            {
2166                $this->headerstrlen['owner']    = strlen( strval( $jobinfo['owner'] ) );
2167            }
2168
2169            if( !isset( $this->headerstrlen['queue'] ) )
2170            {
2171                $this->headerstrlen['queue']    = strlen( strval( $jobinfo['queue'] ) );
2172            }
2173            else if( strlen( strval( $jobinfo['queue'] ) ) > $this->headerstrlen['queue'] )
2174            {
2175                $this->headerstrlen['queue']    = strlen( strval( $jobinfo['queue'] ) );
2176            }
2177
2178            if( !isset( $jobinfo['ppn'] ) )
2179            {
2180                $jobinfo['ppn'] = 1;
2181            }
2182
2183            $cpus            = count( $jobinfo['nodes'] ) * intval( $jobinfo['ppn'] );
2184
2185            if( !isset( $this->headerstrlen['cpus'] ) )
2186            {
2187                $this->headerstrlen['cpus']    = strlen( strval( $cpus ) );
2188            }
2189            else if( strlen( strval( $cpus ) ) > $this->headerstrlen['cpus'] )
2190            {
2191                $this->headerstrlen['cpus']    = strlen( strval( $cpus ) );
2192            }
2193
2194            $nodes            = count( $jobinfo['nodes'] );
2195
2196            if( !isset( $this->headerstrlen['nodes'] ) )
2197            {
2198                $this->headerstrlen['nodes']    = strlen( strval( $nodes ) );
2199            }
2200            else if( strlen( strval( $nodes) ) > $this->headerstrlen['nodes'] )
2201            {
2202                $this->headerstrlen['nodes']    = strlen( strval( $nodes ) );
2203            }
2204
2205            $runningtime        = makeTime( intval( $jobinfo[reported] ) - intval( $jobinfo['start_timestamp'] ) );
2206
2207            if( !isset( $this->headerstrlen['runningtime'] ) )
2208            {
2209                $this->headerstrlen['runningtime']    = strlen( strval( $runningtime) );
2210            }
2211            else if( strlen( strval( $runningtime) ) > $this->headerstrlen['runningtime'] )
2212            {
2213                $this->headerstrlen['runningtime']    = strlen( strval( $runningtime) );
2214            }
2215
2216            if( !isset( $this->headerstrlen['name'] ) )
2217            {
2218                $this->headerstrlen['name']    = strlen( strval( $jobinfo['name'] ) );
2219            }
2220            else if( strlen( strval( $jobinfo['name'] ) ) > $this->headerstrlen['name'] )
2221            {
2222                $this->headerstrlen['name']    = strlen( strval( $jobinfo['name'] ) );
2223            }
2224        }
2225
2226        $xoffset    = 5;
2227
2228        foreach( $this->headerstrlen as $headername => $headerlen )
2229        {
2230            $colorgreen    = imageColorAllocate( $this->image, 0, 200, 0 );
2231
2232            if( $headerlen < strlen( $headername ) )
2233            {
2234                $this->headerstrlen[$headername]    = strlen( $headername );
2235            }
2236
2237            imageString( $this->image, $this->font, $xoffset, $this->y_offset, ucfirst( $headername ), $colorgreen );
2238
2239            $xoffset    = $xoffset + ($this->fontwidth * ( $this->headerstrlen[$headername] + 1 ) );
2240        }
2241        $this->newLineOffset();
2242    }
2243
2244    function newLineOffset()
2245    {
2246        $this->y_offset        = $this->y_offset + $this->fontheight + $this->fontspaceing;
2247    }
2248
2249    function draw()
2250    {
2251        $xlen        = 450;
2252        $ylen        = ( count( $this->njobs ) * ( $this->fontheight + $this->fontspaceing ) ) + (3 * $this->fontheight);
2253
2254        $this->image    = imageCreateTrueColor( $xlen, $ylen );
2255        $colorwhite    = imageColorAllocate( $this->image, 255, 255, 255 );
2256        imageFill( $this->image, 0, 0, $colorwhite );                         
2257
2258        $colorblue    = imageColorAllocate( $this->image, 0, 0, 255 );
2259
2260        imageString( $this->image, $this->font, 1, $this->y_offset, "Monarch Joblist - host: ".$this->host, $colorblue );
2261        $this->newLineOffset();
2262
2263        $this->drawHeader();
2264        $this->drawJobs();
2265
2266        header( 'Content-type: image/png' );
2267        imagePNG( $this->image );
2268        imageDestroy( $this->image );
2269    }
2270}
2271
2272function imageStringDown( &$image, $font, $x, $y, &$s, &$col )
2273{
2274    $fw    = imagefontwidth( $font);
2275    $fh    = imagefontheight( $font);
2276   
2277    $fontspacing = 0;
2278
2279    $fx    = $x;
2280    $fy    = $y;
2281
2282    for( $n=0; $n<strlen( $s ); $n++ )
2283    {
2284        $myc    = $s{$n};
2285
2286        imagestring( $image, $font, $fx, $fy, $myc, $col );
2287
2288        $fy    += ($fontspacing + $fh );
2289    }
2290}
2291
2292function array_rem( $val, &$arr )
2293{
2294    // Delete val from arr
2295    //
2296    $i    = array_search( $val, $arr );
2297
2298    if( $i == false ) return false;
2299
2300    $arr    = array_merge( array_slice( $arr, 0, $i ), array_slice( $arr, $i+1, count( $arr ) ) );
2301
2302    return true;
2303}
2304
2305function cmp( $a, $b ) 
2306{
2307    global $SORT_ORDER;
2308    global $skan_str;
2309    global $x_first, $y_first;
2310    global $x_present, $y_present;
2311
2312    $a_node        = $a;
2313    $b_node        = $b;
2314    $a        = $a_node->getHostname();
2315    $b        = $b_node->getHostname();
2316
2317    if( $a == $b ) return 0;
2318
2319    $a_x        = 0;
2320    $b_x        = 0;
2321    $a_y        = 0;
2322    $b_y        = 0;
2323
2324    if( $x_present && $y_present )
2325    {
2326        if( $x_first )
2327        {
2328            $n = sscanf( $a, $skan_str, $a_x, $a_y );
2329            $n = sscanf( $b, $skan_str, $b_x, $b_y );
2330        }
2331        else if( $y_first )
2332        {
2333            $n = sscanf( $a, $skan_str, $a_y, $a_x );
2334            $n = sscanf( $b, $skan_str, $b_y, $b_x );
2335        }
2336    } 
2337    else if( $x_present && !$y_present )
2338    {
2339        $n = sscanf( $a, $skan_str, $a_x );
2340        $n = sscanf( $b, $skan_str, $b_x );
2341    }
2342    else if( $y_present && !$x_present )
2343    {
2344        $n = sscanf( $a, $skan_str, $a_y );
2345        $n = sscanf( $b, $skan_str, $b_y );
2346    }
2347
2348    if ( $SORT_ORDER=="desc" )
2349    {
2350
2351        if( $x_present && $y_present )
2352        {
2353            // 1  = a < b
2354            // -1 = a > b
2355            //
2356            if ($a_x == $b_x)
2357            {
2358                if ($a_y < $b_y)
2359                {
2360                    return 1;
2361                }
2362                else if ($a_y > $b_y)
2363                {
2364                    return -1;
2365                }
2366            }
2367            else if ($a_x < $b_x)
2368            {
2369                return 1;
2370            }
2371            else if ($a_x > $b_x)
2372            {
2373                return -1;
2374            }
2375        } 
2376        else if( $x_present && !$y_present )
2377        {
2378            if ($a_x < $b_x)
2379            {
2380                return 1;
2381            }
2382            else if ($a_x > $b_x)
2383            {
2384                return -1;
2385            }
2386        }
2387        else if( $y_present && !$x_present )
2388        {
2389            if ($a_y < $b_y)
2390            {
2391                return 1;
2392            }
2393            else if ($a_y > $b_y)
2394            {
2395                return -1;
2396            }
2397        }
2398    }
2399    else if ( $SORT_ORDER == "asc" )
2400    {
2401
2402        if( $x_present && $y_present )
2403        {
2404            // 1  = a > b
2405            // -1 = a < b
2406            //
2407            if ($a_x == $b_x)
2408            {
2409                if ($a_y > $b_y)
2410                {
2411                    return 1;
2412                }
2413                else if ($a_y < $b_y)
2414                {
2415                    return -1;
2416                }
2417            }
2418            else if ($a_x > $b_x)
2419            {
2420                return 1;
2421            }
2422            else if ($a_x < $b_x)
2423            {
2424                return -1;
2425            }
2426        }
2427        else if( $x_present && !$y_present )
2428        {
2429            if ($a_x > $b_x)
2430            {
2431                return 1;
2432            }
2433            else if ($a_x < $b_x)
2434            {
2435                return -1;
2436            }
2437        }
2438        else if( $y_present && !$x_present )
2439        {
2440            if ($a_y > $b_y)
2441            {
2442                return 1;
2443            }
2444            else if ($a_y < $b_y)
2445            {
2446                return -1;
2447            }
2448        }
2449    }
2450}
2451function makeTime( $time )
2452{
2453        $days = intval( $time / 86400 );
2454        $time = ($days>0) ? $time % ($days * 86400) : $time;
2455
2456        $date_str = '';
2457        $day_str = '';
2458
2459        if( $days > 0 )
2460        {
2461            if( $days > 1 )
2462            {
2463                $day_str .= $days . ' days';
2464            }
2465            else
2466            {
2467                $day_str .= $days . ' day';
2468            }
2469        }
2470
2471        $hours = intval( $time / 3600 );
2472        $time = $hours ? $time % ($hours * 3600) : $time;
2473
2474        if( $hours > 0 )
2475        {
2476             $date_str .= $hours . ':';
2477             $date_unit = 'hours'; 
2478        }
2479
2480        $minutes = intval( $time / 60 );
2481        $seconds = $minutes ? $time % ($minutes * 60) : $time;
2482
2483        if( $minutes > 0 )
2484        {
2485            if( $minutes >= 10 )
2486            {
2487                $date_str .= $minutes . ':';
2488            }
2489            else
2490            {
2491                $date_str .= '0' . $minutes . ':';
2492            }
2493                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
2494        }
2495        else
2496        {
2497            if($hours > 0 )
2498            {
2499                $date_str .= '00:';
2500                $date_unit = (!isset($date_unit)) ? 'minutes' : $date_unit;
2501            }
2502        }
2503
2504        $date_unit = (!isset($date_unit)) ? 'seconds' : $date_unit;
2505
2506        if( $seconds > 0 )
2507        {
2508            if( $seconds >= 10 )
2509            {
2510                $date_str .= $seconds . ' ' . $date_unit;
2511            }
2512            else
2513            {
2514                $date_str .= '0' . $seconds . ' ' . $date_unit;
2515            }
2516        }
2517        else if ( $hours > 0 or $minutes > 0 )
2518        {
2519            $date_str .= '00 ' . $date_unit;
2520        }
2521
2522        if( $days > 0)
2523        {
2524            if( $hours > 0 or $minutes > 0 or $seconds > 0 )
2525            {
2526                $date_str = $day_str . ' - ' . $date_str;
2527            }
2528            else
2529            {
2530                $date_str = $day_str;
2531            }
2532        }
2533        return $date_str;
2534}
2535?>
Note: See TracBrowser for help on using the repository browser.