package Cluster::Init::DFA::Process;
# 
# AUTOMATICALLY GENERATED by ./dot2dfa
# Fri Apr  4 11:40:29 2003

# DO NOT EDIT
#
#   Original .dot file contents included below __END__.
#
use strict;
use warnings;
require Exporter;
our @ISA = qw(Exporter);
our @EXPORT_OK = qw(DFA_ACTIONS CONFIGURED DONE FAIL PASS PAUSING RUNBG RUNFG RUNNING RUNTEST SETUP STOPPING TESTING _ANY_ START STOP CHLD WAIT TEST RESPAWN ONCE OFF STARTED EXITED EXECFAILED CONTINUE TOO_RAPID TIMEOUT PROCRUNNING RC_ZERO RC_NONZERO);         
our %EXPORT_TAGS = (constants => [qw(CONFIGURED DONE FAIL PASS PAUSING RUNBG RUNFG RUNNING RUNTEST SETUP STOPPING TESTING _ANY_ START STOP CHLD WAIT TEST RESPAWN ONCE OFF STARTED EXITED EXECFAILED CONTINUE TOO_RAPID TIMEOUT PROCRUNNING RC_ZERO RC_NONZERO)]);

my $debug = $ENV{DEBUG};

# Actions
#   (you need to implement these in caller)
#
#   Action       =>                   Value, # Events it can generate
#
use constant DFA_ACTIONS => (
    CKFREQ	 =>   '$self->ckfreq(@arg)', # CONTINUE TOO_RAPID
    CKMODE	 =>   '$self->ckmode(@arg)', # OFF ONCE RESPAWN TEST
					     # WAIT
    CKPID	 =>    '$self->ckpid(@arg)', # CHLD PROCRUNNING START
					     # STOP TIMEOUT
    CKRC	 =>	'$self->ckrc(@arg)', # RC_NONZERO RC_ZERO
    ERROR	 =>    '$self->error(@arg)', # 
    KILLPROC	 => '$self->killproc(@arg)', # PROCRUNNING TIMEOUT
    XEQ 	 =>	 '$self->xeq(@arg)', # EXECFAILED STARTED
);


my %const2act = DFA_ACTIONS;

# States
# use constant State      =>         Value; # Events it can handle     
#
use constant CONFIGURED   =>  'CONFIGURED'; # START
use constant DONE	  =>	    'DONE'; # EXITED OFF ONCE RESPAWN
					    # STOP WAIT
use constant FAIL	  =>	    'FAIL'; # START STOP
use constant PASS	  =>	    'PASS'; # START STOP
use constant PAUSING	  =>	 'PAUSING'; # CONTINUE STOP TOO_RAPID
use constant RUNBG	  =>	   'RUNBG'; # EXECFAILED EXITED
					    # STARTED STOP
use constant RUNFG	  =>	   'RUNFG'; # EXECFAILED EXITED
					    # STARTED STOP
use constant RUNNING	  =>	 'RUNNING'; # EXITED STOP
use constant RUNTEST	  =>	 'RUNTEST'; # EXECFAILED EXITED
					    # STARTED STOP
use constant SETUP	  =>	   'SETUP'; # OFF ONCE RESPAWN STOP
					    # TEST WAIT
use constant STOPPING	  =>	'STOPPING'; # EXITED PROCRUNNING
					    # TIMEOUT
use constant TESTING	  =>	 'TESTING'; # RC_NONZERO RC_ZERO STOP
use constant _ANY_	  =>	   '_ANY_'; # CHLD START STOP


# Events
# use constant Event      =>         Value; # States it can be accepted in
#
use constant START	  =>	   'START'; # CONFIGURED FAIL PASS
					    # _ANY_
use constant STOP	  =>	    'STOP'; # DONE FAIL PASS PAUSING
					    # RUNBG RUNFG RUNNING
					    # RUNTEST SETUP TESTING
					    # _ANY_
use constant CHLD	  =>	    'CHLD'; # _ANY_
use constant WAIT	  =>	    'WAIT'; # DONE SETUP
use constant TEST	  =>	    'TEST'; # SETUP
use constant RESPAWN	  =>	 'RESPAWN'; # DONE SETUP
use constant ONCE	  =>	    'ONCE'; # DONE SETUP
use constant OFF	  =>	     'OFF'; # DONE SETUP
use constant STARTED	  =>	 'STARTED'; # RUNBG RUNFG RUNTEST
use constant EXITED	  =>	  'EXITED'; # DONE RUNBG RUNFG
					    # RUNNING RUNTEST
					    # STOPPING
use constant EXECFAILED   =>  'EXECFAILED'; # RUNBG RUNFG RUNTEST
use constant CONTINUE	  =>	'CONTINUE'; # PAUSING
use constant TOO_RAPID	  =>   'TOO_RAPID'; # PAUSING
use constant TIMEOUT	  =>	 'TIMEOUT'; # STOPPING
use constant PROCRUNNING  => 'PROCRUNNING'; # STOPPING
use constant RC_ZERO	  =>	 'RC_ZERO'; # TESTING
use constant RC_NONZERO   =>  'RC_NONZERO'; # TESTING


use constant GRAPH => {
  CONFIGURED => {
                  START => { action => "CKMODE", newstate => "SETUP" },
                  STOP  => { action => "", newstate => "CONFIGURED" },
                },
  DONE       => {
                  CHLD    => { action => "CKPID", newstate => "DONE" },
                  EXITED  => { action => "CKMODE", newstate => "DONE" },
                  OFF     => { action => "", newstate => "STOPPING" },
                  ONCE    => { action => "", newstate => "DONE" },
                  RESPAWN => { action => "CKFREQ", newstate => "PAUSING" },
                  START   => { action => "", newstate => "DONE" },
                  STOP    => { action => "", newstate => "STOPPING" },
                  WAIT    => { action => "", newstate => "DONE" },
                },
  FAIL       => {
                  START => { action => "CKMODE", newstate => "SETUP" },
                  STOP  => { action => "", newstate => "CONFIGURED" },
                },
  PASS       => {
                  START => { action => "CKMODE", newstate => "SETUP" },
                  STOP  => { action => "", newstate => "CONFIGURED" },
                },
  PAUSING    => {
                  CHLD => { action => "CKPID", newstate => "PAUSING" },
                  CONTINUE => { action => "XEQ", newstate => "RUNBG" },
                  START => { action => "", newstate => "PAUSING" },
                  STOP => { action => "", newstate => "STOPPING" },
                  TOO_RAPID => { action => "", newstate => "PAUSING" },
                },
  RUNBG      => {
                  CHLD       => { action => "CKPID", newstate => "RUNBG" },
                  EXECFAILED => { action => "ERROR", newstate => "CONFIGURED" },
                  EXITED     => { action => "CKMODE", newstate => "DONE" },
                  START      => { action => "", newstate => "RUNBG" },
                  STARTED    => { action => "", newstate => "DONE" },
                  STOP       => { action => "", newstate => "STOPPING" },
                },
  RUNFG      => {
                  CHLD       => { action => "CKPID", newstate => "RUNFG" },
                  EXECFAILED => { action => "ERROR", newstate => "CONFIGURED" },
                  EXITED     => { action => "CKMODE", newstate => "DONE" },
                  START      => { action => "", newstate => "RUNFG" },
                  STARTED    => { action => "", newstate => "RUNNING" },
                  STOP       => { action => "", newstate => "STOPPING" },
                },
  RUNNING    => {
                  CHLD   => { action => "CKPID", newstate => "RUNNING" },
                  EXITED => { action => "CKMODE", newstate => "DONE" },
                  START  => { action => "", newstate => "RUNNING" },
                  STOP   => { action => "", newstate => "STOPPING" },
                },
  RUNTEST    => {
                  CHLD       => { action => "CKPID", newstate => "RUNTEST" },
                  EXECFAILED => { action => "ERROR", newstate => "CONFIGURED" },
                  EXITED     => { action => "CKRC", newstate => "TESTING" },
                  START      => { action => "", newstate => "RUNTEST" },
                  STARTED    => { action => "", newstate => "RUNTEST" },
                  STOP       => { action => "", newstate => "STOPPING" },
                },
  SETUP      => {
                  OFF     => { action => "", newstate => "CONFIGURED" },
                  ONCE    => { action => "XEQ", newstate => "RUNBG" },
                  RESPAWN => { action => "XEQ", newstate => "RUNBG" },
                  START   => { action => "", newstate => "SETUP" },
                  STOP    => { action => "", newstate => "CONFIGURED" },
                  TEST    => { action => "XEQ", newstate => "RUNTEST" },
                  WAIT    => { action => "XEQ", newstate => "RUNFG" },
                },
  STOPPING   => {
                  CHLD        => { action => "CKPID", newstate => "STOPPING" },
                  EXITED      => { action => "", newstate => "CONFIGURED" },
                  PROCRUNNING => { action => "KILLPROC", newstate => "STOPPING" },
                  START       => { action => "", newstate => "STOPPING" },
                  STOP        => { action => "", newstate => "STOPPING" },
                  TIMEOUT     => { action => "CKPID", newstate => "STOPPING" },
                },
  TESTING    => {
                  RC_NONZERO => { action => "", newstate => "FAIL" },
                  RC_ZERO => { action => "", newstate => "PASS" },
                  START => { action => "", newstate => "TESTING" },
                  STOP => { action => "", newstate => "CONFIGURED" },
                },
  _ANY_      => {
                  CHLD  => { action => "CKPID", newstate => "_ANY_" },
                  START => { action => "", newstate => "_ANY_" },
                  STOP  => { action => "", newstate => "_ANY_" },
                },
};

my $num2str = {
  "1"         => "CONFIGURED",
  "1024"      => "STOPPING",
  "1048576"   => "OFF",
  "128"       => "RUNNING",
  "131072"    => "TEST",
  "134217728" => "PROCRUNNING",
  "16"        => "PAUSING",
  "16384"     => "STOP",
  "16777216"  => "CONTINUE",
  "2"         => "DONE",
  "2048"      => "TESTING",
  "2097152"   => "STARTED",
  "256"       => "RUNTEST",
  "262144"    => "RESPAWN",
  "268435456" => "RC_ZERO",
  "32"        => "RUNBG",
  "32768"     => "CHLD",
  "33554432"  => "TOO_RAPID",
  "4"         => "FAIL",
  "4096"      => "_ANY_",
  "4194304"   => "EXITED",
  "512"       => "SETUP",
  "524288"    => "ONCE",
  "536870912" => "RC_NONZERO",
  "64"        => "RUNFG",
  "65536"     => "WAIT",
  "67108864"  => "TIMEOUT",
  "8"         => "PASS",
  "8192"      => "START",
  "8388608"   => "EXECFAILED",
};

my $str2num = {
  CHLD        => 32_768,
  CONFIGURED  => 1,
  CONTINUE    => 16_777_216,
  DONE        => 2,
  EXECFAILED  => 8_388_608,
  EXITED      => 4_194_304,
  FAIL        => 4,
  OFF         => 1_048_576,
  ONCE        => 524_288,
  PASS        => 8,
  PAUSING     => 16,
  PROCRUNNING => 134_217_728,
  RC_NONZERO  => 536_870_912,
  RC_ZERO     => 268_435_456,
  RESPAWN     => 262_144,
  RUNBG       => 32,
  RUNFG       => 64,
  RUNNING     => 128,
  RUNTEST     => 256,
  SETUP       => 512,
  START       => 8192,
  STARTED     => 2_097_152,
  STOP        => 16_384,
  STOPPING    => 1024,
  TEST        => 131_072,
  TESTING     => 2048,
  TIMEOUT     => 67_108_864,
  TOO_RAPID   => 33_554_432,
  WAIT        => 65_536,
  _ANY_       => 4096,
};

my %num2str = %$num2str;
my %str2num = %$str2num;

sub new
{
  my $class=shift;
  my $self = { @_ };
  bless $self, ref($class) || $class;
  $self->{graph}=GRAPH;
  $self->{except}=\&except unless $self->{except};
  $self->{entersuf} = "_enter" unless $self->{entersuf};
  $self->{leavesuf} = "_leave" unless $self->{leavesuf};
  $self->init() if $self->can('init');
  return $self;
}

# set state blindly, running only the enter routine -- for use at startup
sub state
{
  my ($self,$state)=@_;
  if ($state)
  {
    die __PACKAGE__.": invalid state: ".$state."\n" 
    unless $self->{graph}{$state};
    $self->{state}=$state;
    my $enter = $state.$self->{entersuf};
    $self->$enter($state) if $self->can($enter);
  }
  return $self->{state};
}

# feed event into state engine, then execute leave, action, and enter
# routines
sub tick
{
  my ($self,$event,@arg) = @_;
  die "usage: \$obj->tick(\$event[,\@arg])\n" unless $event;
  @arg=() unless @arg;
  my $numeric=0;
  # $numeric = 1 if $event =~ /^\d+$/;
  # $event=$num2str{$event} if $numeric;
  my $graph = $self->{graph};
  my $oldstate = $self->{state};
  die __PACKAGE__.": initial state not set\n" unless $oldstate;
  unless ($graph->{$oldstate}{$event})
  {
    return (&{$self->{except}}($oldstate,$event),'');
  }
  my $node = $graph->{$oldstate}{$event};
  my $newstate = $node->{newstate};
  my $action = $node->{action} || "";
  my $statechg = ($newstate ne $oldstate);
  $self->{state}=$newstate if $statechg;
  my $leave = $oldstate.$self->{leavesuf};
  my $enter = $newstate.$self->{entersuf};
  $self->$leave($oldstate,$newstate,$action,@arg) 
    if $statechg && $self->can($leave);
  $self->transit($oldstate,$newstate,$action,@arg) 
    if $self->can('transit');
  $self->$enter($oldstate,$newstate,$action,@arg) 
    if $statechg && $self->can($enter);
  return ($newstate,$action);
}

# default exception handler
sub except
{
  my ($state,$event) = @_;
  warn __PACKAGE__.": state '$state': unhandled event: ".$event."\n" if $debug;
  return $state;
}

sub num2str
{
  my $self=shift;
  my $num=shift;
  return $num2str{$num};
}

1;
__END__
digraph "Cluster::Init::DFA::Process"
{

  size="7.5,10";
  //rankdir=LR;
  ratio=fill;

  // _ANY_ -> _ANY_ [label="update/ckent"];
  _ANY_ -> _ANY_ [label="start/"];
  _ANY_ -> _ANY_ [label="stop/"];
  // _ANY_ -> _ANY_ [label="restart/"];
  _ANY_ -> _ANY_ [label="chld/ckpid"];

  //async: start stop 
  configured -> setup [label="start/ckmode"];
  // configured -> retired [label="retire/destruct"];

  // sequencing -> setup [label="ready/ckmode"];
  // sequencing -> sequencing [label="idle/ckseq"];
  // sequencing -> configured [label="stop/"];
  // sequencing -> retired [label="retire/destruct"];

  setup -> runfg [label="wait/xeq"];
  setup -> runtest [label="test/xeq"];
  setup -> runbg [label="respawn/xeq"];
  setup -> runbg [label="once/xeq"];
  setup -> configured [label="stop/"];
  setup -> configured [label="off/"];
  // setup -> retired [label="retire/destruct"];

  //async: start stop chld exited

  runfg -> running [label="started/"];
  runfg -> done [label="exited/ckmode"];
  runfg -> configured [label="execfailed/error"];
  runfg -> stopping [label="stop/"];
  // runfg -> restarting [label="restart/"];
  // runfg -> retiring [label="retire/"];

  runtest -> runtest [label="started/"];
  runtest -> testing [label="exited/ckrc"];
  runtest -> configured [label="execfailed/error"];
  runtest -> stopping [label="stop/"];

  runbg -> done [label="started/"];
  runbg -> done [label="exited/ckmode"];
  runbg -> configured [label="execfailed/error"];
  runbg -> stopping [label="stop/"];
  // runbg -> restarting [label="restart/"];
  // runbg -> retiring [label="retire/"];

  running -> done [label="exited/ckmode"];
  running -> stopping [label="stop/"];
  // running -> restarting [label="restart/"];
  // running -> retiring [label="retire/"];

  done -> done [label="exited/ckmode"];
  done -> done [label="wait/"];
  // done -> testing [label="test/ckrc"];
  done -> pausing [label="respawn/ckfreq"];
  done -> done [label="once/"];
  done -> stopping [label="stop/"];
  done -> stopping [label="off/"];
  // done -> restarting [label="restart/"];
  // done -> retiring [label="retire/"];

  pausing -> runbg [label="continue/xeq"];
  pausing -> pausing [label="too_rapid/"];
  pausing -> stopping [label="stop/"];

  stopping -> stopping [label="timeout/ckpid"];
  stopping -> stopping [label="procrunning/killproc"];
  stopping -> configured [label="exited/"];

  // restarting -> restarting [label="idle/ckpid"];
  // restarting -> restarting [label="procrunning/"];
  // restarting -> restarting [label="restart/"];
  // restarting -> stopping [label="stop/"];
  // restarting -> setup [label="procstopped/ckseq"];
  // restarting -> setup [label="exited/ckseq"];
  // restarting -> retiring [label="retire/"];

  // retiring -> retiring [label="idle/ckpid"];
  // retiring -> retiring [label="procrunning/"];
  // retiring -> retired [label="procstopped/destruct"];
  // retiring -> retired [label="exited/destruct"];
  // retiring -> retiring [label="retire/"];

  //async: start stop 
  testing -> pass [label="rc_zero/"];
  testing -> fail [label="rc_nonzero/"];
  testing -> configured [label="stop/"];
  // testing -> restarting [label="restart/"];
  // testing -> retired [label="retire/destruct"];

  pass -> setup [label="start/ckmode"];
  pass -> configured [label="stop/"];
  // pass -> restarting [label="restart/"];
  // pass -> retired [label="retire/destruct"];

  fail -> setup [label="start/ckmode"];
  fail -> configured [label="stop/"];
  // fail -> restarting [label="restart/"];
  // fail -> retired [label="retire/destruct"];

}

