// $Id: b_state.cpp,v 1.4 2003/02/15 04:18:09 fukasawa Exp $

//=============================================================================
/**
 *  @file    b_state.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"

#define N_SEPARATOR  ('/')

EdgeState b_state::Null(_TX("Null"));

//------------------------------------------------------------------------------
//
// State
//
//------------------------------------------------------------------------------
int strRelation(const BCHAR * p1, const BCHAR * p2, int * retpos)
{
    int result;
    int i = 0;
    while ((*p1 == *p2) && (*p1 != '\0') && (*p2 != '\0'))
    {
        i++;
        p1++;
        p2++;
    }
    if ((*p1 == *p2) && (*p1 == '\0'))
    {
        result = b_state::SAME_STATE;
    }
    else if (i == 0)
    {
        result = b_state::OTHER_STATE;      // no relation
    }
    else if (*p1 == '\0')
    {
        result = b_state::DESCENT_STATE;   // p2 is descent of p1
    }
    else if (*p2 == '\0')
    {
        result = b_state::ANCESTOR_STATE;  // p2 is ancestor of p1
    }
    else
    {
        result = b_state::COUSIN_STATE;    // p2 is cousinhood of p1
    }

    if (retpos != NULL)
    {
        *retpos = i;
    }
    return result;
}

//------------------------------------------------------------------------------
// Check relationship of the destination state
//------------------------------------------------------------------------------
int b_state::relationship(b_state * dest, string& next)
{
    TRACE_FUNCTION(TRL_LOW, "b_state::relationship");

    int diffp;
    const BCHAR * selfptr = m_base->charName();
    const BCHAR * dstptr = dest->charName();
    int relation = strRelation(selfptr, dstptr, &diffp);
    if (relation == OTHER_STATE || relation == SAME_STATE)
    {
        next = dest->name();
    }
    else if (relation == COUSIN_STATE)
    {
        BCHAR * destslash = _tcschr(dstptr, N_SEPARATOR);
        BEEAssert(destslash != NULL);
        BCHAR * lastslash = _tcsrchr(selfptr, N_SEPARATOR);
        int  npos = lastslash - selfptr;
        next = m_base->name().substr(0, npos);
    }
    else if (relation == DESCENT_STATE)
    {
        BEEAssert(*(dstptr + diffp) == N_SEPARATOR ||
                  *(dstptr + diffp - 1) == N_SEPARATOR);
        BCHAR * firstslash = _tcschr(dstptr + diffp + 1, N_SEPARATOR);
        int  npos = firstslash - dstptr;
        next = dest->name().substr(0, npos);
    }
    else /* if (relation == ANCESTOR_STATE) */
    {
        BEEAssert(*(selfptr + diffp) == N_SEPARATOR ||
                  *(selfptr + diffp - 1) == N_SEPARATOR);
        BCHAR * lastslash = _tcsrchr(selfptr, N_SEPARATOR);
        int  npos = lastslash - selfptr;
        next = name().substr(0, npos);
    }
    return relation;
}

//------------------------------------------------------------------------------
bool b_state::isChild(const string& next)
{
    TRACE_FUNCTION(TRL_LOW, "b_state::isChild");

    int diffp;
    const BCHAR * selfptr = m_base->charName();
    const BCHAR * nextptr = next.c_str();
    int relation = strRelation(selfptr, nextptr, &diffp);
    if (relation != DESCENT_STATE)
    {
        return false;
    }

    BEEAssert(*(nextptr + diffp) == N_SEPARATOR ||
              *(nextptr + diffp - 1) == N_SEPARATOR);
    BCHAR * firstslash = _tcschr(nextptr + diffp + 1, N_SEPARATOR);
    if (firstslash != NULL)
    {
        return false;
    }
    return true;
}

//------------------------------------------------------------------------------
bool b_state::isDescendant(const string& next)
{
    TRACE_FUNCTION(TRL_LOW, "b_state::isDescendant");

    int diffp;
    const BCHAR * selfptr = m_base->charName();
    const BCHAR * nextptr = next.c_str();
    int relation = strRelation(selfptr, nextptr, &diffp);
    if (relation != DESCENT_STATE)
    {
        return false;
    }
    return true;
}

//------------------------------------------------------------------------------
// Dump
//------------------------------------------------------------------------------
void b_state::dump() const
{
    m_base->dump();
    ACE_DEBUG((LM_DEBUG, ACE_TEXT("m_parent = %s\n"),
              (this->m_parent != NULL) ? this->m_parent->name().c_str() : _TX("")));

}

