/* ====================================================================
* The Vovida Software License, Version 1.0
*
* Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The names "VOCAL", "Vovida Open Communication Application Library",
* and "Vovida Open Communication Application Library (VOCAL)" must
* not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact vocal@vovida.org.
*
* 4. Products derived from this software may not be called "VOCAL", nor
* may "VOCAL" appear in their name, without prior written
* permission of Vovida Networks, Inc.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
* NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
* NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
* IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*
* ====================================================================
*
* This software consists of voluntary contributions made by Vovida
* Networks, Inc. and many individuals on behalf of Vovida Networks,
* Inc. For more information on Vovida Networks, Inc., please see
* .
*
*/
static const char* const StateInterface_cxx_Version =
"$Id: StateInterface.cxx,v 1.2 2001/08/10 04:02:04 icahoon Exp $";
#include "global.h"
#include
#include "StateInterface.hxx"
#include "Stimulus.hxx"
#include "Action.hxx"
#include "VLog.hxx"
using Vocal::Behavioral::StateInterface;
using Vocal::Behavioral::Stimulus;
using Vocal::Behavioral::Action;
using Vocal::Logging::VLog;
using Vocal::ReturnCode;
StateInterface::StateInterface(
const char * name,
Action * onEntry,
Action * onExit
)
: myName(name ? name : "NullState"),
myEntry(onEntry),
myExit(onExit)
{
const string fn("StateInterface::StateInterface");
VLog log(fn);
VDEBUG(log) << fn << ": " << *this << VDEBUG_END(log);
}
StateInterface::~StateInterface()
{
const string fn("StateInterface::~StateInterface");
VLog log(fn);
VDEBUG(log) << fn << ": " << myName << VDEBUG_END(log);
}
void
StateInterface::addAction(
const Stimulus & stimulus,
Action & action,
StateInterface & nextState
)
{
const string fn("StateInterface::addAction");
VLog log(fn);
bool rc = stimulusTable_.insert(
StimulusPair(stimulus, StimulusData(action, nextState, 0))
).second;
assert( rc );
VDEBUG(log) << fn
<< "\n\tState :\t" << myName
<< "\n\tStimulus :\t" << stimulus
<< "\n\tAction :\t" << action
<< "\n\tNextState :\t" << nextState.name()
<< VDEBUG_END(log);
}
void
StateInterface::addAction(
const Stimulus & stimulus,
Action & action,
StateInterface & nextState,
StateInterface & nextStateOnFail
)
{
const string fn("StateInterface::addAction");
VLog log(fn);
bool rc = stimulusTable_.insert(
StimulusPair(stimulus, StimulusData(action, nextState, &nextStateOnFail))
).second;
assert( rc );
VDEBUG(log) << fn
<< "\n\tState :\t" << myName
<< "\n\tStimulus :\t" << stimulus
<< "\n\tAction :\t" << action
<< "\n\tNextState :\t" << nextState.name()
<< "\n\tNextStateOnFail:\t" << nextStateOnFail.name()
<< VDEBUG_END(log);
}
void
StateInterface::entryAction(Action & onEntry)
{
myEntry = &onEntry;
}
void
StateInterface::exitAction(Action & onExit)
{
myExit = &onExit;
}
void
StateInterface::enter() throw ()
{
const string fn("StateInterface::enter");
VLog log(fn);
if ( myEntry )
{
VDEBUG(log) << fn << ": State: " << myName
<< ": Action: " << *myEntry << VDEBUG_END(log);
myEntry->action();
}
}
StateInterface &
StateInterface::stimulate(
const Stimulus & stimulus
) throw ()
{
const string fn("StateInterface::stimuluate");
VLog log(fn);
VDEBUG(log) << fn
<< "\n\tState: " << myName
<< ",\t\tStimulus: " << stimulus
<< VDEBUG_END(log);
// Lookup the stimulus in the stimulus table.
//
StimulusTable::iterator it = stimulusTable_.find(stimulus);
// If it doesn't exist, do nothing.
//
if ( it == stimulusTable_.end() )
{
VDEBUG(log) << fn
<< "\n\tState: " << myName
<< ",\t\tAction: No Action"
<< VDEBUG_END(log);
return ( *this );
}
// If the stimulus exists first perform the exit action on this state,
// then perform the action associated with the stimulus, and finally
// perform the entry action on the next state.
//
// Note that the exit action, the action associated with this stimulus,
// and the entry action of the next state may throw an exception.
//
exit();
Action & action = (*it).second.action_;
VDEBUG(log) << fn
<< "\n\tState: " << myName
<< ",\t\tAction: " << action
<< VDEBUG_END(log);
ReturnCode rc = action.action(stimulus);
StateInterface & nextState =
( rc != SUCCESS && (*it).second.nextStateOnFail_
? *(*it).second.nextStateOnFail_
: (*it).second.nextState_
);
VDEBUG(log) << fn
<< "\n\tState: " << myName
<< ",\t\tNext State: " << nextState.name()
<< VDEBUG_END(log);
nextState.enter();
return ( nextState );
}
void
StateInterface::exit() throw ()
{
const string fn("StateInterface::enter");
VLog log(fn);
if ( myExit )
{
VDEBUG(log) << fn
<< "\n\tState: " << myName
<< ",\t\tAction: " << *myExit
<< VDEBUG_END(log);
myExit->action();
}
}
ostream &
StateInterface::writeTo(ostream & out) const
{
out << name()
<< "\n\tEntry:\t" << ( myEntry ? *myEntry : Action() )
<< "\n\tExit:\t" << ( myExit ? *myExit : Action() )
<< "\n\tStimuli:\n\t{";
for ( StimulusTable::const_iterator it = stimulusTable_.begin();
it != stimulusTable_.end();
it++
)
{
out << "\n\t\tStimulus :\t" << (*it).first
<< "\n\t\tAction :\t" << (*it).second.action_
<< "\n\t\tNextState :\t" << (*it).second.nextState_.name();
if ( (*it).second.nextStateOnFail_ )
{
out << "\n\t\tNextStateOnFail:\t" << (*it).second.nextStateOnFail_->name();
}
out << '\n';
}
return ( out << "\n\t}" );
}
const string &
StateInterface::name() const
{
return ( myName );
}
StateInterface::StimulusData::StimulusData(
Action & action,
StateInterface & nextState,
StateInterface * nextStateOnFail
)
: action_(action),
nextState_(nextState),
nextStateOnFail_(nextStateOnFail)
{
}