# -*-Perl-*-

# instances allowed: one 

# (single instance modules would be silly to use more than one of
# anyway, so we use package local storage.  This is faster and places
# less artificial load on the machine than doing everything through
# the object hash)

package MGMmodule::cpustat;
use vars qw($numcpus $statcpus $xpath $graph @load @total @prevload 
	    @prevtotal $lastmod);

# class init
sub module_init{
    my$this=shift;
    my$xclass=$this->{"xclass"};

    # how many CPUs? Get this from /proc/cpuinfo then /proc/stat.
    # /proc/stat only sees multiple CPUs as of late 2.1, but we
    # at least want to mark the single bar as SMP under 2.0

    $lastmod=-1;
    $numcpus=0;
    $statcpus=1;
    if(defined($MGMmodule::helperST::proc{"cpu"}) &&
	       open(PROC,"</proc/cpuinfo")){
	while(<PROC>){
	    if(m/processor\s*:\s*(\d*)/){
		$numcpus=$1+1 if ($numcpus<$1+1);
	    }
	}
	close PROC;
	# now check /proc/stat to see how many cpus it reports
	$this->read_proc;
    }else{
	$this->{"toplevel"}->optionAdd("$xclass.active",0,21);
    }

    $this->{"toplevel"}->optionAdd("$xclass.order",     1,21);      
    $this;
}

# instance init
sub module_instance{
    my$this=shift;
    my$toplevel=$this->{"toplevel"};
    return undef if(defined($xpath));
    $xpath=$this->{"xpath"};

    ($minx,$miny)=MGM::Graph::calcxysize($this,100,'%',$statcpus);

    if($numcpus>1 && $statcpus==1){
	$toplevel->optionAdd("$xpath.bar.0.label", "cpus 0-".($numcpus-1),22);
    }else{
	for(my$i=0;$i<$numcpus;$i++){
	    $toplevel->optionAdd("$xpath.bar.$i.label", "cpu$i",22);
	}
    }

    $toplevel->optionAdd("$xpath.scalerefresh", 500,21); # faster
    $toplevel->optionAdd("$xpath.scalewidadj", 100*$statcpus,21);
    $toplevel->optionAdd("$xpath.scalelenadj", 100,21); 

    $toplevel->optionAdd("$xpath.minx",     $minx,21);      
    $toplevel->optionAdd("$xpath.miny",     $miny,21);      

    $this;
}

# instance widget build
sub module_run{
    my($this)=@_;
    if($statcpus==1){
	$graph=MGM::Graph->new($this,num=>1,fixed=>'1',
			       prompt=>"%",rangecurrent=>100*$numcpus,
			       rangesetting=>100*$numcpus);
    }else{
	$graph=MGM::Graph->new($this,num=>$statcpus,fixed=>'1',
			       prompt=>"%",rangecurrent=>100,
			       rangesetting=>100);

    }
    $lastmod=-1;
    $graph->{"widget"};        # must return widget
}

sub module_update{ 
    my$this=shift;
    
    if($lastmod!=$MGMmodule::helperST::lastmod){
	# don't update unless the helper has
	$lastmod=$MGMmodule::helperST::lastmod;

	$this->read_proc;
	
	if(defined(@prevload)){
	    my@vals;
	    
	    if($statcpus==1){
		my$tot=$total[0]-$prevtotal[0];
		if($tot>0){
		    $vals[0]=100*($load[0]-$prevload[0])/$tot;
		    $vals[0]=100*$numcpus if $vals[0]>100*$numcpus;
		}else{
		    $vals[0]=0;
		}
	    }else{
		for(my$i=0;$i<$statcpus;$i++){
		    my$tot=$total[$i+1]-$prevtotal[$i+1];
		    if($tot>0){
			$vals[$i]=100*($load[$i+1]-$prevload[$i+1])/$tot;
			$vals[$i]=100 if $vals[$i]>100;
		    }else{
			$vals[$i]=0;
		    }
		}
	    }
	    $graph->set(@vals);
	}
    
	@prevload=@load;
	@prevtotal=@total;
    }
}
    
sub read_proc{
    # now uses the 00helper to save on opens 
    
    # in late 2.1+ kernels, each CPU has an entry in /proc/stat along with
    # a common entry.  Earlier, only the common entry.
    
    # collective cpu entry
    $MGMmodule::helperST::proc{"cpu"}=~m/^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/;
    $load[0]=$1+$2+$3;
    $total[0]=$load[0]+$4;
    
    for(my$i=0;defined(my$line=$MGMmodule::helperST::proc{"cpu$i"});$i++){
	$line=~m/^(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/;
	# per-cpu entry
	$total[$i+1]=($load[$i+1]=$1+$2+$3)+$4;
	$numcpus=$statcpus=$i+1 if($i+1>$statcpus);
    }	
}

sub destroy{
    undef $xpath;
}

bless {};

