package Graph::Template::Context; use strict; BEGIN { use vars qw(@ISA); @ISA = qw(Graph::Template::Base); use Graph::Template::Base; } # This is a helper object. It is not instantiated by the user, nor does it # represent an XML object. Rather, every container will use this object to # maintain the context for its children. my %isAbsolute = map { $_ => 1 } qw( ); sub new { my $class = shift; my $self = $class->SUPER::new(@_); $self->{PARAM_MAP} = [] unless UNIVERSAL::isa($self->{PARAM_MAP}, 'ARRAY'); $self->{STACK} = [] unless UNIVERSAL::isa($self->{STACK}, 'ARRAY'); return $self; } sub param { my $self = shift; my ($param, $depth) = @_; $param = uc $param; $depth ||= 0; my $val = undef; my $found = 0; for my $map (reverse @{$self->{PARAM_MAP}}) { next unless exists $map->{$param}; $depth--, next if $depth; $found = 1; $val = $map->{$param}; last; } die "Parameter '$param' not found\n" if !$found && $self->{DIE_ON_NO_PARAM}; return $val; } sub resolve { my $self = shift; my ($obj, $key, $depth) = @_; $key = uc $key; $depth ||= 0; my $obj_val = $obj->{$key}; $obj_val = $self->param($1) if $obj->{$key} =~ /^\$(\S+)$/o; #GGG Does this adequately test values to make sure they're legal?? # A value is defined as: # 1) An optional operator (+, -, *, or /) # 2) A decimal number #GGG Convert this to use //x my ($op, $val) = $obj_val =~ m!^\s*([\+\*\/\-])?\s*([\d.]*\d)\s*$!oi; # Unless it's a relative value, we have what we came for. return $obj_val unless $op; my $prev_val = $isAbsolute{$key} ? $self->{$key} : $self->get($obj, $key, $depth + 1); return $obj_val unless defined $prev_val; return $prev_val unless defined $obj_val; # Prevent divide-by-zero issues. return $val if $op eq '/' and $val == 0; my $new_val; for ($op) { /^\+$/ && do { $new_val = ($prev_val + $val); last; }; /^\-$/ && do { $new_val = ($prev_val - $val); last; }; /^\*$/ && do { $new_val = ($prev_val * $val); last; }; /^\/$/ && do { $new_val = ($prev_val / $val); last; }; die "Unknown operator '$op' in arithmetic resolve\n"; } return $new_val if defined $new_val; return; } sub enter_scope { my $self = shift; my ($obj) = @_; push @{$self->{STACK}}, $obj; for my $key (keys %isAbsolute) { next unless exists $obj->{$key}; $self->{$key} = $self->resolve($obj, $key); } return 1; } sub exit_scope { my $self = shift; my ($obj, $no_delta) = @_; unless ($no_delta) { my $deltas = $obj->deltas($self); $self->{$_} += $deltas->{$_} for keys %$deltas; } pop @{$self->{STACK}}; return 1; } sub get { my $self = shift; my ($dummy, $key, $depth) = @_; $depth ||= 0; $key = uc $key; return unless @{$self->{STACK}}; my $obj = $self->{STACK}[-1]; return $self->{$key} if $isAbsolute{$key}; my $val = undef; my $this_depth = $depth; foreach my $e (reverse @{$self->{STACK}}) { next unless exists $e->{$key}; next if $this_depth-- > 0; $val = $self->resolve($e, $key, $depth); last; } $val = $self->{$key} unless defined $val; return $val unless defined $val; return $self->param($1, $depth) if $val =~ /^\$(\S+)$/o; return $val; } sub plotted_graph { my $self = shift; $self->{PLOTTED_GRAPH} = $_[0] if @_; $self->{PLOTTED_GRAPH}; } sub graph { my $self = shift; $self->{GRAPH} = $_[0] if @_; $self->{GRAPH}; } sub format { my $self = shift; $self->{FORMAT} = $_[0] if @_; $self->{FORMAT}; } sub start_data { $_[0]{DATA} = []; $_[0]{DATA_AXIS} = 0; $_[0]{DATA_POINT} = 0; 1; } sub increment_data { $_[0]{DATA_AXIS} = 0; $_[0]{DATA_POINT}++; 1; } sub add_data { my $self = shift; my ($value) = @_; $value =~ s/\D//g if $self->{DATA_AXIS} > 0; $self->{DATA} ->[$self->{DATA_AXIS}++] ->[$self->{DATA_POINT}] = $value; return 1; } sub plot_data { $_[0]->plotted_graph($_[0]->graph->plot($_[0]->{DATA})) } #{ # my $self = shift; # # $self->plotted_graph($self->graph->plot($self->{DATA})); #} 1; __END__