#!/usr/local/bin/perl
use XML::Parser;
my $file = shift;
die "Can't find file \"$file\"" unless -f $file;
my $parser = new XML::Parser(Style => Tree, ErrorContext => 2);
my $pairref = $parser->parsefile($file);

# STATES specifies each STATE
$STATES='Behavioral_Elements\.State_Machines\.StateMachine\.top$';
$STATE = 'Behavioral_Elements\.State_Machines\.State$';
# each state specifies its OUTGOING TRANSITIONs
$OUTGOING = 'Behavioral_Elements\.State_Machines\.StateVertex\.outgoing$';
# TRANSITIONS specifies each TRANSITION
$TRANSITIONS='Behavioral_Elements\.State_Machines\.StateMachine\.transitions$';
$TRANSITION='Behavioral_Elements\.State_Machines\.Transition$';
# each TRANSITION has a TRIGGER which is an EVENT
$TRIGGER='Behavioral_Elements\.State_Machines\.Transition\.trigger';
$EVENT = 'Behavioral_Elements\.State_Machines\.SignalEvent$';
# and a TARGET which has a STATE
$TARGET = 'Behavioral_Elements\.State_Machines\.Transition\.target$';
# STATEs and EVENTs both have NAMEs
$NAME = 'Foundation\.Core\.ModelElement\.name$';

# wrap all the recursion data up to avoid dozens of params to recursive fns!
my $recdata = { states => undef,
		state => undef,
		outgoing => undef,
		transitions => undef,
		transition => undef,
		trigger => undef,
		target => undef,
		events => undef,
		event => undef };

mypair($recdata, @$pairref);
writeCWBinput($recdata);

sub mypair {
  my ($recdata, $tag, $content) = @_;
  return $content unless $tag; # deal with non-element nodes, i.e. text
  if ($tag=~/$STATES/) {
    $$recdata{states} = {}; # hash indexed by xmiid
    myarray($recdata, @$content); 
  }
  elsif ($tag=~/$STATE/ && $$recdata{target}) { 
    ${$$recdata{transition}}{target} = ${$$content[0]}{'xmi.idref'};
  }
  elsif ($tag=~/$STATE/) { 
    my $state = {}; 
    $$recdata{state} = $state;
    my $xmiid = ${$$content[0]}{'xmi.id'};
    $$state{xmiid} = $xmiid;
    myarray($recdata, @$content); # collect name, outgoing transitions
    ${$$recdata{states}}{$xmiid} = $state;
    undef $$recdata{state};
  }
  elsif ($tag=~/$NAME/ && $$recdata{state}){
    ${$$recdata{state}}{name} = @$content[2];
  }
  elsif ($tag=~/$NAME/ && $$recdata{event}){
    ${$$recdata{event}}{name} = @$content[2];
  }
  elsif ($tag=~/$OUTGOING/ && $$recdata{state}) {
    $$recdata{outgoing} = [];
    myarray($recdata, @$content); # get transition ids outgoing from state
    ${$$recdata{state}}{outgoing} = $$recdata{outgoing};
    undef $$recdata{outgoing};
  }
  elsif ($tag=~/$TRANSITION/ && $$recdata{outgoing}) {
    push @{$$recdata{outgoing}}, ${$$content[0]}{'xmi.idref'};
  }
  elsif ($tag=~/$TRANSITIONS/){
    $$recdata{transitions} = {}; # hash indexed by xmiid
    myarray($recdata, @$content); # get transition defs
  }
  elsif ($tag=~/$TRANSITION/ && $$recdata{transitions}) {
    my $xmiid = ${$$content[0]}{'xmi.id'};
    my $transition = {xmiid => $xmiid};
    $$recdata{transition} = $transition;
    myarray($recdata, @$content); # collect its event and target
    ${$$recdata{transitions}}{$xmiid} = $transition;
    undef $$recdata{transition};
  }
  elsif ($tag=~/$TRIGGER/ && $$recdata{transition}) {
    $$recdata{trigger} = {}; # just a marker, no interesting data
    myarray($recdata, @$content); # get its event
    undef $$recdata{trigger};
  }
  elsif ($tag=~/$EVENT/ && $$recdata{trigger}) {
    ${$$recdata{transition}}{eventid} = ${$$content[0]}{'xmi.idref'};
  }
  elsif ($tag=~/$EVENT/) { # it'll be the definition
    my $xmiid = ${$$content[0]}{'xmi.id'};
    my $event = {xmiid => $xmiid};
    $$recdata{event} = $event;
    myarray($recdata, @$content); # collect the event's name
    ${$$recdata{events}}{$xmiid} = $event;
    undef $$recdata{event};
  }
  elsif ($tag=~/$TARGET/ && $$recdata{transition}) { 
    $$recdata{target} = {}; # just a marker, no interesting data
    myarray($recdata, @$content); # collect the target state
  }
  else { myarray($recdata, @$content); }
}

sub myarray {
  my ($recdata, $attributes, @rest) = @_;
  while (@rest) {
    mypair ($recdata, shift @rest, shift @rest);
  }
}

sub writeCWBinput {
  my ($data) = @_; 
  for $state (values %{$$data{states}}) {
    @derivatives = ();
    next unless ($name = $$state{name});
    for $tr (@{$$state{outgoing}}) {
      $transition = ${$$data{transitions}}{$tr};
      $xmiidOfEvent = $$transition{eventid}; 
      $xmiidOfTarget = $$transition{target};
      $eventName = ${${$$data{events}}{$xmiidOfEvent}}{name};
      $targetName = ${${$$data{states}}{$xmiidOfTarget}}{name};
      $derivative = "$eventName.$targetName";
      push @derivatives, $derivative;
    }
    print "\nagent $name = ";
    if (@derivatives) { 
      print join ' + ', @derivatives;
      print ";\n";
    } else {
      print "0;\n"; 
    }
  }
}
