// $Id: b_statenode.cpp,v 1.4 2003/03/16 14:51:00 fukasawa Exp $

//=============================================================================
/**
 *  @file    b_statenode.cpp
 *
 *  @author Fukasawa Mitsuo
 *
 *
 *    Copyright (C) 1998-2003 BEE Co.,Ltd. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
//=============================================================================

#define BEE_BUILD_DLL

#include "state/b_context.h"
#include "state/b_statenode.h"
#include "state/b_trigger.h"

//------------------------------------------------------------------------------
// Constructor/Destractor
//------------------------------------------------------------------------------
b_statenode::b_statenode(b_statype * base, b_context * root)
            : b_state(base, root)
{
    m_current = base->defState();
    m_next = base->defState();
    m_before = base->defState();
    m_nodeNum = -1;
}

//------------------------------------------------------------------------------
// Transit
//------------------------------------------------------------------------------
int b_statenode::transit(b_state * prev, b_state * dest)
{
    TRACE_FUNCTION(TRL_LOW, "b_statenode::transit");
    string next;
    string dest_next;
    int prev_relate = this->relationship(prev, next);
    int dest_relate = this->relationship(dest, dest_next);
    if ((prev_relate == DESCENT_STATE && dest_relate == SAME_STATE) ||
        (prev_relate == ANCESTOR_STATE && dest_relate == SAME_STATE))
    {
        m_current = m_base->name();
    }
    else if (prev_relate == DESCENT_STATE && dest_relate == DESCENT_STATE)
    {
        m_current = dest->name();
#if 1
        if (prev->relationship(dest, next) == DESCENT_STATE)
        {
            TRACE_DEBUG((_TX("Inconsistency logic: %s : %s\n"),
                         prev->charName(), dest->charName()));
        }
#endif
    }
    else if ((prev_relate == DESCENT_STATE && dest_relate == ANCESTOR_STATE) ||
             (prev_relate == ANCESTOR_STATE && dest_relate == DESCENT_STATE) ||
             (prev_relate == DESCENT_STATE && dest_relate == COUSIN_STATE))
    {
        m_current = dest_next;
    }
    else
    {
        TRACE_ERROR((_TX("Illegal transit states(%d/%d): %s : %s : %s\n"),
                     prev_relate, dest_relate, prev->charName(), charName(),
                     dest->charName()));
    }

    return BEE_SUCCESS;
}


//------------------------------------------------------------------------------
// Dump
//------------------------------------------------------------------------------
void b_statenode::dump() const
{
    ACE_DEBUG((LM_DEBUG, ACE_TEXT("\nstate node name = %s\n"),
                         this->name().c_str()));
    b_states::const_iterator iter = m_substates.begin();
    for ( ; iter != m_substates.end(); iter++)
    {
        b_state * state = *iter;
        state->dump();
    }
}

//-----------------------------------------------------------------------------
//
// Condition Node
//
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
//
// History Node
//
//-----------------------------------------------------------------------------
const BCHAR * b_histnode::next(b_trigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "b_histnode::next");
    ACE_UNUSED_ARG(trigger);

    m_current = m_before;
    b_state * state = m_root->state(m_current);
    BEEAssert(state != NULL);
    return state->charName();
}


//-----------------------------------------------------------------------------
//
// Fixed Node
//
//------------------------------------------------------------------------------
int b_fixnode::begin(b_state * prev, b_trigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "b_fixnode::begin");
    ACE_UNUSED_ARG(trigger);

    m_current = m_base->defState();
    b_state * state = m_root->state(m_current);
    BEEAssert(state != NULL);
    return state->begin(prev, trigger);
}

//-----------------------------------------------------------------------------
const BCHAR * b_fixnode::next(b_trigger * event)
{
    TRACE_FUNCTION(TRL_LOW, "b_fixnode::next");
    ACE_UNUSED_ARG(event);

    b_state * state = m_root->state(m_next);
    BEEAssert(state != NULL);
    return state->charName();
}


//-----------------------------------------------------------------------------
//
// And Node
//
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// begin method
//-----------------------------------------------------------------------------
int b_andnode::begin(b_state * prev, b_trigger * trigger)
{
    TRACE_FUNCTION(TRL_LOW, "b_andnode::begin");
    int result;
    for (size_t i = 0; i < m_substates.size(); i++)
    {
        b_state * node = m_substates[i];
        result = node->begin(prev, trigger);
        if (result < 0)
        {
            break;
        }
    }
    return result;
}

//------------------------------------------------------------------------------
// Get current state name
//------------------------------------------------------------------------------
const string& b_andnode::current(int num) const
{
    TRACE_FUNCTION(TRL_LOW, "b_andnode::current");
    b_statenode * node;
    if (num >= (int)m_substates.size())
    {
        TRACE_ERROR(("Illegal state number: %d\n", num));
        node = (b_statenode *)m_substates[0];
    }
    else
    {
        node = (b_statenode *)m_substates[num];
    }
    return node->current();

}

//-----------------------------------------------------------------------------
//
// Root Node
//
//-----------------------------------------------------------------------------
static RootState  _st_root(_TX("/"));
static b_rootnode _root(&_st_root, NULL);

//------------------------------------------------------------------------------
// Constructor/Destractor
//------------------------------------------------------------------------------
b_rootnode::b_rootnode(b_statype * base, b_context * root)
        : b_statenode(base, root)
{
    m_states.push_back(this->name());
}

//------------------------------------------------------------------------------
// Get current state name
//------------------------------------------------------------------------------
const string& b_rootnode::current(int num) const
{
    TRACE_FUNCTION(TRL_LOW, "b_rootnode::current");
    if (num >= (int)m_states.size())
    {
        TRACE_ERROR((_TX("Illegal state number: %d\n"), num));
        return m_states[0];
    }
    return m_states[num];
}

//------------------------------------------------------------------------------
// Change current state
//------------------------------------------------------------------------------
void b_rootnode::change(b_state * state)
{
    TRACE_FUNCTION(TRL_LOW, "b_rootnode::change");
    m_states.erase(m_states.begin(), m_states.end());  // Erase all state names
    if (state->isAnd())
    {   // And node
        b_andnode * andnd = (b_andnode *)state;
        b_states::iterator iter = andnd->m_substates.begin();
        for ( ; iter != andnd->m_substates.end(); iter++)
        {
            b_statenode * node = (b_statenode *)(*iter);
            m_states.push_back(node->current());
        }
    }
    else
    {
        m_states.push_back(state->name());
    }
}

