package Cluster::Init::DFA::Daemon;
# 
# AUTOMATICALLY GENERATED by ./dot2dfa
# Fri Apr  4 11:40:07 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 ACCEPT CLTAB HALT HALTING LISTEN READLINE START TELLING IDLE CLTAB_OK CLTAB_NOK SOCKETIO SOCKET_ERROR WRITETIME CLIENTIO TIMEOUT CMDERR TELL SHUTDOWN GROUP_NOK GROUPTOLD HALTED HALTTIME);         
our %EXPORT_TAGS = (constants => [qw(ACCEPT CLTAB HALT HALTING LISTEN READLINE START TELLING IDLE CLTAB_OK CLTAB_NOK SOCKETIO SOCKET_ERROR WRITETIME CLIENTIO TIMEOUT CMDERR TELL SHUTDOWN GROUP_NOK GROUPTOLD HALTED HALTTIME)]);

my $debug = $ENV{DEBUG};

# Actions
#   (you need to implement these in caller)
#
#   Action       =>                   Value, # Events it can generate
#
use constant DFA_ACTIONS => (
    BYE 	 =>	 '$self->bye(@arg)', # HALTTIME
    GETCMD	 =>   '$self->getcmd(@arg)', # CMDERR SHUTDOWN TELL
					     # TIMEOUT
    HALTALL	 =>  '$self->haltall(@arg)', # HALTED
    PUTRES	 =>   '$self->putres(@arg)', # HALTTIME SOCKET_ERROR
					     # WRITETIME
    READ_CLTAB	 => '$self->read_cltab(@arg)', # CLTAB_NOK CLTAB_OK
					     # IDLE
    START_LISTENER => '$self->start_listener(@arg)', # SOCKET_ERROR
					     # WRITETIME
    TELLGROUP	 => '$self->tellgroup(@arg)', # GROUPTOLD GROUP_NOK
					     # SHUTDOWN
    WATCH_CLIENT => '$self->watch_client(@arg)', # TIMEOUT
    WRITESTAT	 => '$self->writestat(@arg)', # SOCKET_ERROR
					     # WRITETIME
);


my %const2act = DFA_ACTIONS;

# States
# use constant State      =>         Value; # Events it can handle     
#
use constant ACCEPT	  =>	  'ACCEPT'; # CLIENTIO TIMEOUT
use constant CLTAB	  =>	   'CLTAB'; # CLTAB_NOK CLTAB_OK
use constant HALT	  =>	    'HALT'; # HALTTIME
use constant HALTING	  =>	 'HALTING'; # HALTED
use constant LISTEN	  =>	  'LISTEN'; # SOCKETIO SOCKET_ERROR
					    # WRITETIME
use constant READLINE	  =>	'READLINE'; # CMDERR SHUTDOWN TELL
					    # TIMEOUT
use constant START	  =>	   'START'; # CLTAB_NOK CLTAB_OK IDLE
use constant TELLING	  =>	 'TELLING'; # GROUPTOLD GROUP_NOK
					    # SHUTDOWN


# Events
# use constant Event      =>         Value; # States it can be accepted in
#
use constant IDLE	  =>	    'IDLE'; # START
use constant CLTAB_OK	  =>	'CLTAB_OK'; # CLTAB START
use constant CLTAB_NOK	  =>   'CLTAB_NOK'; # CLTAB START
use constant SOCKETIO	  =>	'SOCKETIO'; # LISTEN
use constant SOCKET_ERROR => 'SOCKET_ERROR'; # LISTEN
use constant WRITETIME	  =>   'WRITETIME'; # LISTEN
use constant CLIENTIO	  =>	'CLIENTIO'; # ACCEPT
use constant TIMEOUT	  =>	 'TIMEOUT'; # ACCEPT READLINE
use constant CMDERR	  =>	  'CMDERR'; # READLINE
use constant TELL	  =>	    'TELL'; # READLINE
use constant SHUTDOWN	  =>	'SHUTDOWN'; # READLINE TELLING
use constant GROUP_NOK	  =>   'GROUP_NOK'; # TELLING
use constant GROUPTOLD	  =>   'GROUPTOLD'; # TELLING
use constant HALTED	  =>	  'HALTED'; # HALTING
use constant HALTTIME	  =>	'HALTTIME'; # HALT


use constant GRAPH => {
  ACCEPT   => {
                CLIENTIO => { action => "GETCMD", newstate => "READLINE" },
                TIMEOUT  => { action => "PUTRES", newstate => "LISTEN" },
              },
  CLTAB    => {
                CLTAB_NOK => { action => "PUTRES", newstate => "LISTEN" },
                CLTAB_OK  => { action => "TELLGROUP", newstate => "TELLING" },
              },
  HALT     => { HALTTIME => { action => "BYE", newstate => "HALT" } },
  HALTING  => { HALTED => { action => "PUTRES", newstate => "HALT" } },
  LISTEN   => {
                SOCKETIO     => { action => "WATCH_CLIENT", newstate => "ACCEPT" },
                SOCKET_ERROR => { action => "", newstate => "HALT" },
                WRITETIME    => { action => "WRITESTAT", newstate => "LISTEN" },
              },
  READLINE => {
                CMDERR   => { action => "PUTRES", newstate => "LISTEN" },
                SHUTDOWN => { action => "HALTALL", newstate => "HALTING" },
                TELL     => { action => "READ_CLTAB", newstate => "CLTAB" },
                TIMEOUT  => { action => "PUTRES", newstate => "LISTEN" },
              },
  START    => {
                CLTAB_NOK => { action => "", newstate => "HALT" },
                CLTAB_OK => { action => "START_LISTENER", newstate => "LISTEN" },
                IDLE => { action => "READ_CLTAB", newstate => "START" },
              },
  TELLING  => {
                GROUPTOLD => { action => "PUTRES", newstate => "LISTEN" },
                GROUP_NOK => { action => "PUTRES", newstate => "LISTEN" },
                SHUTDOWN  => { action => "HALTALL", newstate => "HALTING" },
              },
  _ANY_    => {},
};

my $num2str = {
  "1"       => "ACCEPT",
  "1024"    => "CLTAB_NOK",
  "1048576" => "GROUPTOLD",
  "128"     => "TELLING",
  "131072"  => "TELL",
  "16"      => "LISTEN",
  "16384"   => "CLIENTIO",
  "2"       => "CLTAB",
  "2048"    => "SOCKETIO",
  "2097152" => "HALTED",
  "256"     => "IDLE",
  "262144"  => "SHUTDOWN",
  "32"      => "READLINE",
  "32768"   => "TIMEOUT",
  "4"       => "HALT",
  "4096"    => "SOCKET_ERROR",
  "4194304" => "HALTTIME",
  "512"     => "CLTAB_OK",
  "524288"  => "GROUP_NOK",
  "64"      => "START",
  "65536"   => "CMDERR",
  "8"       => "HALTING",
  "8192"    => "WRITETIME",
};

my $str2num = {
  ACCEPT       => 1,
  CLIENTIO     => 16_384,
  CLTAB        => 2,
  CLTAB_NOK    => 1024,
  CLTAB_OK     => 512,
  CMDERR       => 65_536,
  GROUPTOLD    => 1_048_576,
  GROUP_NOK    => 524_288,
  HALT         => 4,
  HALTED       => 2_097_152,
  HALTING      => 8,
  HALTTIME     => 4_194_304,
  IDLE         => 256,
  LISTEN       => 16,
  READLINE     => 32,
  SHUTDOWN     => 262_144,
  SOCKETIO     => 2048,
  SOCKET_ERROR => 4096,
  START        => 64,
  TELL         => 131_072,
  TELLING      => 128,
  TIMEOUT      => 32_768,
  WRITETIME    => 8192,
};

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::Daemon"
{
  
  size="7.5,10";
  //rankdir=LR;
  //ratio=fill;


  //async: 
  start -> start [label="idle/read_cltab"];
  start -> listen [label="cltab_ok/start_listener"];
  //async: socketio
  start -> halt [label="cltab_nok/"];
  listen -> accept [label="socketio/watch_client"];
  //async: socketio clientio
  listen -> halt [label="socket_error/"];
  listen -> listen [label="writetime/writestat"];
  accept -> readline [label="clientio/getcmd"];
  accept -> listen [label="timeout/putres"];
  readline -> listen [label="timeout/putres"];
  readline -> listen [label="cmderr/putres"];
  readline -> cltab [label="tell/read_cltab"];
  readline -> halting [label="shutdown/haltall"];
  cltab -> listen [label="cltab_nok/putres"];
  cltab -> telling [label="cltab_ok/tellgroup"];
  telling -> listen [label="group_nok/putres"];
  telling -> listen [label="grouptold/putres"];
  telling -> halting [label="shutdown/haltall"];
  halting -> halt [label="halted/putres"];
  halt -> halt [label="halttime/bye"];

}

