/*
 *
 * VRML to RW converter plug-in
 */

/****************************************************************************
 *    
 * VRML 2.0 to RW3.0 Converter
 * Copyright (C) 1997 Criterion Technologies
 *
 * Author  : Damian Scallan 
 *
 * Module  : Symtable.c
 *                                                                         
 * Purpose : Used to implement Vrml DEF & USE 
 *          Places symbol in table along with its AbstractNode pointer
 *          for later instancing with USE
 *          
 ****************************************************************************/

/****************************************************************************
 Includes
 */

#include "rpplugin.h"
#include "symtable.h"
#include "abstractnode.h"
#include "llinklist.h"
#include "rpvrmlanim.h"
#include "rpvrml.h"
#include "route.h"

static const char __RWUNUSED__ rcsid[] =
    "@@(#)$Id: symtable.c,v 1.26 2001/01/26 12:11:00 johns Exp $";

/****************************************************************************
 Local Types
 */

typedef struct symbolEnt symbolEnt;
struct symbolEnt
{
    RwChar             *name;
    AbstractNode       *an;
};

typedef struct symbolRouteEnt symbolRouteEnt;
struct symbolRouteEnt
{
    RwChar             *fromName;
    RwChar             *eventOutName;
    RwChar             *toName;
    RwChar             *eventInName;
};

/****************************************************************************
 Local (Static) Prototypes
 */

static symbolEnt   *SymbolEnt_Create(const RwChar * name,
                                     AbstractNode * an);
static RwBool       SymbolEnt_Destroy(symbolEnt * se);

static symbolRouteEnt *SymbolRouteEnt_Create(const RwChar * fromName,
                                             const RwChar *
                                             eventOutName,
                                             const RwChar * toName,
                                             const RwChar *
                                             eventInName);
static RwBool       SymbolRouteEnt_Destroy(symbolRouteEnt * sre);

/****************************************************************************
 Local Defines
 */

/****************************************************************************
 Local (static) Globals
 */

static LLinkList    symbolsList;
static LLinkList    symbolsRouteList;

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    SymTable methods

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

void
SymTab_Create(void)
{
    RWFUNCTION(RWSTRING("SymTab_Create"));

    LLinkList_Init(&symbolsList);
    LLinkList_Init(&symbolsRouteList);

    RWRETURNVOID();
}

void
SymTab_Destroy(void)
{
    RWFUNCTION(RWSTRING("SymTab_Destroy"));

    LLinkList_Destroy(&symbolsList, (linkCallback) SymbolEnt_Destroy);
    LLinkList_Destroy(&symbolsRouteList,
                      (linkCallback) SymbolRouteEnt_Destroy);

    RWRETURNVOID();
}

RwBool
SymTab_AddEntry(const RwChar * name, AbstractNode * an)
{
    RWFUNCTION(RWSTRING("SymTab_AddEntry"));
    RWASSERT(name);

    if (name)
    {
        symbolEnt          *se;

        if (!an)
        {
            RWRETURN(FALSE);
        }

        /* should check for previous entries with same name */
        /* but this will do for now... */

        se = SymbolEnt_Create(name, an);
        if (!se)
        {
            RWRETURN(FALSE);
        }

        if (!LLinkList_AddData(&symbolsList, se))
        {
            SymbolEnt_Destroy(se);

            RWRETURN(FALSE);
        }

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_NULLP));
    RWRETURN(FALSE);
}

AbstractNode       *
SymTab_GetEntry(const RwChar * name)
{
    RWFUNCTION(RWSTRING("SymTab_GetEntry"));
    RWASSERT(name);

    if (name)
    {
        symbolEnt          *se;

        LLinkList_IteratorReset(&symbolsList);
        while ((se =
                (symbolEnt *) LLinkList_IteratorNext(&symbolsList)))
        {
            if (rwstrcmp(se->name, name) == 0)
            {
                RWRETURN(se->an);
            }
        }

        RWRETURN(NULL);
    }

    RWERROR((E_RW_NULLP));
    RWRETURN(FALSE);
}

RwBool
SymTab_ProtoInstance(void)
{
    symbolEnt          *se;

    RWFUNCTION(RWSTRING("SymTab_ProtoInstance"));

    LLinkList_IteratorReset(&symbolsList);
    while ((se = (symbolEnt *) LLinkList_IteratorNext(&symbolsList)))
    {
        AbstractNode       *an;

        an = se->an;

#if (0)
        if (an->userProto)
#endif /* (0) */
        {
            AbstractNodeTree_InstanceProto(an);
        }
    }

    RWRETURN(TRUE);
}

RwBool
SymTab_AddRouteEntry(const RwChar * fromName,
                     const RwChar * eventOutName, const RwChar * toName,
                     const RwChar * eventInName)
{
    RWFUNCTION(RWSTRING("SymTab_AddRouteEntry"));
    RWASSERT(fromName);
    RWASSERT(eventOutName);
    RWASSERT(toName);
    RWASSERT(eventInName);

    if (fromName && eventOutName && toName && eventInName)
    {
        symbolRouteEnt     *sre;

        sre = SymbolRouteEnt_Create(fromName, eventOutName, toName,
                                    eventInName);
        if (!sre)
        {
            RWRETURN(FALSE);
        }

        if (!LLinkList_AddData(&symbolsRouteList, sre))
        {
            SymbolRouteEnt_Destroy(sre);

            RWRETURN(FALSE);
        }

        Route_Set(sre->fromName, sre->eventOutName, sre->toName,
                  sre->eventInName);

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_NULLP));
    RWRETURN(FALSE);
}

/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

    private SymbolEnt methods

   !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */

static symbolEnt   *
SymbolEnt_Create(const RwChar * name, AbstractNode * an)
{
    RWFUNCTION(RWSTRING("SymbolEnt_Create"));
    RWASSERT(name);
    RWASSERT(an);

    if (name && an)
    {
        symbolEnt          *se = NULL;

        if ((se = (symbolEnt *) RwMalloc(sizeof(symbolEnt))))
        {
            rwstrdup(se->name, name);
            se->an = AbstractNode_AddRef(an);
            AbstractNode_SetSymName(an, name);
        }

        RWRETURN(se);
    }

    RWERROR((E_RW_NULLP));
    RWRETURN(NULL);
}

static              RwBool
SymbolEnt_Destroy(symbolEnt * se)
{
    RWFUNCTION(RWSTRING("SymbolEnt_Destroy"));
    RWASSERT(se);

    if (se)
    {
        RwFree(se->name);
        AbstractNode_Destroy(se->an);

        RwFree(se);

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_NULLP));
    RWRETURN(FALSE);
}

static symbolRouteEnt *
SymbolRouteEnt_Create(const RwChar * fromName,
                      const RwChar * eventOutName,
                      const RwChar * toName, const RwChar * eventInName)
{
    RWFUNCTION(RWSTRING("SymbolRouteEnt_Create"));
    RWASSERT(fromName);
    RWASSERT(eventOutName);
    RWASSERT(toName);
    RWASSERT(eventInName);

    if (fromName && eventOutName && toName && eventInName)
    {
        symbolRouteEnt     *sre = NULL;

        if ((sre = (symbolRouteEnt *) RwMalloc(sizeof(symbolRouteEnt))))
        {
            rwstrdup(sre->fromName, fromName);
            if (!sre->fromName)
            {
                SymbolRouteEnt_Destroy(sre);

                RWRETURN(NULL);
            }

            rwstrdup(sre->eventOutName, eventOutName);
            if (!sre->eventOutName)
            {
                SymbolRouteEnt_Destroy(sre);

                RWRETURN(NULL);
            }

            rwstrdup(sre->toName, toName);
            if (!sre->toName)
            {
                SymbolRouteEnt_Destroy(sre);

                RWRETURN(NULL);
            }

            rwstrdup(sre->eventInName, eventInName);
            if (!sre->eventInName)
            {
                SymbolRouteEnt_Destroy(sre);

                RWRETURN(NULL);
            }
        }

        RWRETURN(sre);
    }

    RWERROR((E_RW_NULLP));
    RWRETURN(FALSE);
}

static              RwBool
SymbolRouteEnt_Destroy(symbolRouteEnt * sre)
{
    RWFUNCTION(RWSTRING("SymbolRouteEnt_Destroy"));
    RWASSERT(sre);

    if (sre)
    {
        if (sre->fromName)
        {
            RwFree(sre->fromName);
        }

        if (sre->eventOutName)
        {
            RwFree(sre->eventOutName);
        }

        if (sre->toName)
        {
            RwFree(sre->toName);
        }

        if (sre->eventInName)
        {
            RwFree(sre->eventInName);
        }

        RwFree(sre);

        RWRETURN(TRUE);
    }

    RWERROR((E_RW_NULLP));
    RWRETURN(FALSE);
}

RwBool
SymbolRouteEnt_Set(void)
{
    symbolRouteEnt     *sre;

    RWFUNCTION(RWSTRING("SymbolRouteEnt_Set"));

    LLinkList_IteratorReset(&symbolsRouteList);
    while ((sre =
            (symbolRouteEnt *)
            LLinkList_IteratorNext(&symbolsRouteList)))
    {
        if (!Route_Set(sre->fromName, sre->eventOutName, sre->toName,
                       sre->eventInName))
        {
            RWRETURN(FALSE);
        }
    }

    RWRETURN(TRUE);
}
