/usr/local/CPAN/Win32-CtrlGUI/Win32/CtrlGUI/State/multi.pm
###########################################################################
# Copyright 2000, 2001 Toby Everett. All rights reserved.
#
# This file is distributed under the Artistic License. See
# http://www.ActiveState.com/corporate/artistic_license.htm or
# the license that comes with your perl distribution.
#
# For comments, questions, bugs or general interest, feel free to
# contact Toby Everett at teverett@alascom.att.com
##########################################################################
use Win32::CtrlGUI;
use Win32::CtrlGUI::State;
use Win32::CtrlGUI::State::bookkeeper;
use strict;
package Win32::CtrlGUI::State::multi;
use vars qw($VERSION @ISA);
@ISA = ('Win32::CtrlGUI::State');
$VERSION='0.30';
sub _new {
my $class = shift;
$class eq 'Win32::CtrlGUI::State::multi' and die "$class is an abstract parent class.\n";
my $self = {
states => [],
state => 'init',
};
bless $self, $class;
while (my $i = shift) {
if (ref $i eq 'ARRAY') {
push(@{$self->{states}}, Win32::CtrlGUI::State::bookkeeper->new(Win32::CtrlGUI::State->new(@{$i})));
} elsif (UNIVERSAL::isa($i, 'Win32::CtrlGUI::State')) {
push(@{$self->{states}}, Win32::CtrlGUI::State::bookkeeper->new($i));
} else {
my $value = shift;
if (grep {$_ eq $i} $self->_options) {
$self->{$i} = $value;
} else {
ref $value eq 'ARRAY' or
die "$class demands ARRAY refs, Win32::CtrlGUI::State objects, or class => [] pairs.\n";
push(@{$self->{states}}, Win32::CtrlGUI::State::bookkeeper->new(Win32::CtrlGUI::State->new($i, $value)));
}
}
}
$self->{criteria} = $class;
$self->init;
return $self;
}
#### _options is a class method that returns a list of known "options" that the
#### class accepts - options are considered to be paired with their value.
sub _options {
return qw();
}
#### init gets called when a multi is initialized (i.e. by new) and when it is
#### reset. It should set the subclass statuses appropriately.
sub init {
my $self = shift;
die "Win32::CtrlGUI::State::multi::init is an abstract method.";
}
#### state_recognized gets called when a substate is recognized for the first
#### time. The state will be marked as active prior to the call, which is how
#### state_recognized can find it.
sub state_recognized {
my $self = shift;
die "Win32::CtrlGUI::State::multi::state_recognized is an abstract method.";
}
#### state_completed gets called when a substate is recognized for the first
#### time. The state will be marked as active prior to the call, which is how
#### state_completed can find it.
sub state_completed {
my $self = shift;
die "Win32::CtrlGUI::State::multi::state_completed is an abstract method.";
}
sub get_states {
my $self = shift;
my($status) = @_;
if ($status) {
my(@retstates);
if (ref $status eq 'Regexp') {
@retstates = grep {$_->bk_status =~ /$status/} @{$self->{states}};
} else {
@retstates = grep {$_->bk_status eq $status} @{$self->{states}};
}
if ($status eq 'active') {
scalar(@retstates) > 1 and die "Win32::CtrlGUI::State::multi::get_active_state error: more than one state is currently active.";
return $retstates[0];
}
return @retstates;
} else {
return @{$self->{states}};
}
}
sub is_recognized {
my $self = shift;
if ($self->state =~ /^init|srch$/) {
$self->state eq 'init' and $self->{state} = 'srch';
my $temp = $self->_is_recognized;
if ($temp && $self->state eq 'srch') {
$self->{state} = 'rcog';
}
return $temp;
} else {
return 1;
}
}
#### _is_recognized tells you whether the current state (which could be one of
#### many) is recognized
sub _is_recognized {
my $self = shift;
scalar($self->get_states('active')) and return 1;
my(@pcs_states) = $self->get_states('pcs');
if (scalar(@pcs_states)) {
foreach my $i (@pcs_states) {
if ($i->is_recognized) {
$i->bk_set_status('active');
$self->state_recognized;
return 1;
}
}
return 0;
} else {
if (scalar($self->get_states('pfs'))) {
die "Win32::CtrlGUI::State::multi::_is_recognized error: there should be no pfs states if there are no pcs states.";
} else {
$self->{state} = 'done';
return 0;
}
}
}
sub do_action_step {
my $self = shift;
$self->state eq 'rcog' and $self->{state} = 'actn';
while (1) {
$self->state eq 'actn' or return 0;
if ($self->_is_recognized) {
$self->get_states('active')->do_action_step;
if ($self->get_states('active')->state =~ /^done|fail$/) {
$self->get_states('active')->{executed}++;
$self->get_states('active')->bk_set_status('comp');
$self->state_completed;
next;
}
}
last;
}
}
sub reset {
my $self = shift;
$self->SUPER::reset;
foreach my $state (@{$self->{states}}) {
$state->reset;
}
$self->init;
}
1;