/* FILE:		sub_grph.cpp
 *  DATE MODIFIED:	31-Aug-07
 *  DESCRIPTION:	Part of the  SREC graph compiler project source files.
 *
 *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
 *                                                                           *
 *  Licensed under the Apache License, Version 2.0 (the 'License');          *
 *  you may not use this file except in compliance with the License.         *
 *                                                                           *
 *  You may obtain a copy of the License at                                  *
 *      http://www.apache.org/licenses/LICENSE-2.0                           *
 *                                                                           *
 *  Unless required by applicable law or agreed to in writing, software      *
 *  distributed under the License is distributed on an 'AS IS' BASIS,        *
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 
 *  See the License for the specific language governing permissions and      *
 *  limitations under the License.                                           *
 *                                                                           *
 *---------------------------------------------------------------------------*/

#include <iostream>
#include <string>
#include <assert.h>
#include <cstdio>

#include "sub_grph.h"


static int checkEntry (int *itemList, int count, int item);

static int checkEntry (int *itemList, int count, int item)
{
    for (int ii= 0; ii < count; ii++)
        if (item == itemList[ii])
            return ii;
    return -1;
}

bool IsSlot (std::string label)
{
        int count= label.size();
        int fPos= label.find_first_of ("___");
        int lPos= label.find_last_of ("___") + 1;
	// std::cout << label << " " << count << " " << fPos << " " << lPos << std::endl;
        if (fPos >= 0 && lPos == count)
            return true;
        else
            return false;
}


void SubGraph::pushScope ()
{
    opStack[popOp++]= lastScope;
    opStack[popOp++]= startId;
    opStack[popOp++]= endId;
    opStack[popOp++]= lastId;
    opStack[popOp++]= arg1;
    opStack[popOp++]= arg2;
    opStack[popOp++]= numArc;
    return;
}

void SubGraph::popScope ()
{
    prevStartId= startId;
    prevEndId= endId;
    arcLoc= opStack[--popOp];
    arg2= opStack[--popOp];
    arg1= opStack[--popOp];
    lastId= opStack[--popOp];
    endId= opStack[--popOp];
    startId= opStack[--popOp];
    lastScope= opStack[--popOp];
    return;
}

void SubGraph::BeginScope (int scopeType, int newArg1, int newArg2)
//  Begin a new scope
//  Create nodes for item and /item but no transitions
{
    pushScope();

    arg1= newArg1;
    arg2= newArg2;
    lastScope= scopeType;
    arcLoc= numArc;

    startId= NewVertexId();

    switch (scopeType) {
    case SCOPE_ITEM:
    case SCOPE_RULE:
    case SCOPE_COUNT:
    case SCOPE_REPEAT:
    case SCOPE_OPT:
        endId= -1;
        lastId= startId;
        break;
    case SCOPE_ONEOF:
        endId= NewVertexId();
        lastId= endId;
        break;
    default:
        printf ("Shouldn't be getting here\n");
    }
    return;
}

void SubGraph::EndScope ()
//  End the current scope
{
    int closeId= CloseScope();
    lastId= ConnectLastScope (startId, closeId);
}

int SubGraph::ConnectLastScope (int beginScopeId, int endScopeId)
//  Connect up the child network to the parent
{
    int begLabel, endLabel, begOutLabel, endOutLabel;

    if (endId == -1)
        endId= lastId;
    if (lastScope == SCOPE_RULE) {
        begLabel= BEGINRULE_LABEL;
        begOutLabel= BEGINRULE_LABEL;
        endLabel= ENDRULE_LABEL;
        endOutLabel= arg1;  //  For inserting into closing brace
    }
    else {
        begLabel= BEGINSCOPE_LABEL;
        begOutLabel= BEGINRULE_LABEL;
        endLabel= ENDSCOPE_LABEL;
        endOutLabel= ENDSCOPE_LABEL;
    }

    popScope();

    switch (lastScope) {
    case SCOPE_ITEM:
    case SCOPE_COUNT:
    case SCOPE_REPEAT:
    case SCOPE_OPT:
        (void) CreateArc (begLabel, begOutLabel, lastId, beginScopeId);
        lastId= NewVertexId();
        (void) CreateArc (endLabel, endOutLabel, endScopeId, lastId);
        break;
    case SCOPE_ONEOF:
        (void) CreateArc (begLabel, begOutLabel, startId, beginScopeId);
        (void) CreateArc (endLabel, endOutLabel, endScopeId, endId);
        break;
    case SCOPE_RULE:
        (void) CreateArc (begLabel, begOutLabel, lastId, beginScopeId);
        lastId= NewVertexId();
        (void) CreateArc (endLabel, ruleId, endScopeId, lastId);
        break;
    case SCOPE_ROOT:
        (void) CreateArc (begLabel, begOutLabel, lastId, beginScopeId);
        lastId= NewVertexId();
        (void) CreateArc (endLabel, endOutLabel, endScopeId, lastId);
        break;
    default:
        printf ("Shouldn't be getting here\n");
    }
    return lastId;
}

int SubGraph::CloseScope ()
//  Closes the transitions and returns to the previous scope
//  Special case for count and repeats
{
    int ii, finalId, endLoc, blockCount;

    switch (lastScope) {
    case SCOPE_ITEM:
    case SCOPE_RULE:
    case SCOPE_ONEOF:
        break;
    case SCOPE_OPT:
        (void) CreateArc (NONE_LABEL, NONE_LABEL, startId, lastId);  // start to end
        break;
    case SCOPE_COUNT:
        endLoc= numArc;
        blockCount= numVertex - startId - 1;
	    //  Special case, min-count= 0

        for (ii= 1; ii < arg1; ii++)
            CopyFastArcs (this, arcLoc, endLoc, ii * blockCount, -1, -1, -1, -1);
        finalId= lastId + (arg2 - 1) * blockCount;
        for ( ; ii < arg2; ii++) {
            CopyFastArcs (this, arcLoc, endLoc, ii * blockCount, -1, -1, -1, -1);
            (void) CreateArc (NONE_LABEL, NONE_LABEL, lastId + (ii - 1) * blockCount, finalId);
        }
	    if (arg1 <= 0)
	        (void) CreateArc (NONE_LABEL, NONE_LABEL, startId, finalId);  // start to end

        UpdateVertexCount (endLoc);
        lastId= finalId;
        break;
    case SCOPE_REPEAT:
        endLoc= numArc;
        blockCount= numVertex - startId - 1;
#if 1
        for (ii= 1; ii < arg1; ii++)
            CopyFastArcs (this, arcLoc, endLoc, ii * blockCount, -1, -1, -1, -1);
        finalId= lastId + (arg1 - 1) * blockCount;

        // loop
        CopyFastArcs (this, arcLoc, endLoc, blockCount, startId, finalId, lastId, finalId);

        // start to end
        if (arg1 == 0)
            (void) CreateArc (NONE_LABEL, NONE_LABEL, startId, finalId);
#else
        // loop
        CopyFastArcs (this, arcLoc, endLoc, blockCount, startId, lastId, lastId, lastId);
        UpdateVertexCount (endLoc);

        // second part
        blockCount= numVertex - startId;
        CopyFastArcs (this, arcLoc, endLoc, blockCount, startId, lastId, lastId, -1);
        UpdateVertexCount (endLoc);

        // once
        finalId= lastId + blockCount;
        blockCount= numVertex - startId;
        if (arg1 <= 1)
            CopyFastArcs (this, arcLoc, endLoc, blockCount, startId, startId, lastId, finalId);

        // start to end
        if (arg1 == 0)
            (void) CreateArc (NONE_LABEL, NONE_LABEL, startId, finalId);
#endif

        UpdateVertexCount (endLoc);
        lastId= finalId;
        break;
    default:
        printf ("Shouldn't be getting here\n");
    }
    return lastId;
}

int SubGraph::AddItem (int inputLabel, int tagLabel)
{
    int newId;

    switch (lastScope) {
    case SCOPE_RULE:
        arg1= tagLabel;
    case SCOPE_ITEM:
    case SCOPE_OPT:
    case SCOPE_COUNT:
    case SCOPE_REPEAT:
        newId= NewVertexId();
        (void) CreateArc (inputLabel, tagLabel, lastId, newId);
        lastId= newId;
        break;
    case SCOPE_ONEOF:
        (void) CreateArc (inputLabel, tagLabel, startId, endId);
        lastId= endId;
        break;
    default: ;
        printf ("Shouldn't be getting here\n");
    }
    return lastId;
}

int SubGraph::AddTag (int tagLabel)
{
    int newId;

    switch (lastScope) {
    case SCOPE_RULE:
    case SCOPE_ITEM:
    case SCOPE_OPT:
    case SCOPE_COUNT:
    case SCOPE_REPEAT:
        newId= NewVertexId();
        (void) CreateArc (TAG_LABEL, tagLabel, lastId, newId);
        lastId= newId;
        break;
    case SCOPE_ONEOF:
        (void) CreateArc (TAG_LABEL, tagLabel, startId, endId);
        lastId= endId;
        break;
    default:
        printf ("Shouldn't be getting here\n");
    }
    return lastId;
}

void SubGraph::ExpandRules (SubGraph **subList, int *lookupList, int numSubs)
{
    int initialId, finalId, ruleId, pos;

    for (int ii= 0; ii < numArc; ii++) {
        ruleId= arc[ii]->GetInput();
        if (ruleId < 0 && ruleId > NONE_LABEL) {
            initialId= arc[ii]->GetFromId();
            finalId= arc[ii]->GetToId();
            ruleId= checkEntry (lookupList, numSubs, -ruleId);
            assert (ruleId >= 0);
	    // printf ("Expanding rule (%d) %s\n", -ruleId, subList[ruleId]->title);

            arc[ii]->AssignInput (DISCARD_LABEL);       //  Clear down the rule
	    // printf ("------------------------");
	    // subList[ruleId]->SortLanguage();
	    // subList[ruleId]->Print();
	    // printf ("------------------------////");
	    pos= numArc;
            CopyFastArcs (subList[ruleId], 0, subList[ruleId]->numArc, numVertex,
                        subList[ruleId]->startId, initialId, subList[ruleId]->lastId, finalId);
	    UpdateVertexCount (pos);
        }
    }
    UpdateVertexCount (0);
    SortLanguage ();
    return;
}

void SubGraph::UpdateVertexCount (int startLoc)
{
    int vertId, maxVertId;

    maxVertId= -1;
    for (int ii= startLoc; ii < numArc; ii++) {
        vertId= arc[ii]->GetFromId();
        if (maxVertId < vertId)
            maxVertId= vertId;
        vertId= arc[ii]->GetToId();
        if (maxVertId < vertId)
            maxVertId= vertId;
    }
    maxVertId++;
    if (startLoc <= 0)       //  i.e. a fresh start
        numVertex= maxVertId;
    else if (numVertex < maxVertId)
        numVertex= maxVertId;
    return;
}

void SubGraph::AddTerminalConnections ()
{
    //  Add terminal transition
    (void) CreateArc (TERMINAL_LABEL, NONE_LABEL, lastId, TERMINAL_LABEL);
    return;
}

void SubGraph::RemoveRuleConnections ()
{
    AddTerminalConnections ();
    RemoveTagConnections (-1, -1);
    RemoveRuleStarts (-1, -1);
    RemoveRuleEnds (-1, -1);
    RemoveNulls (-1, -1);
    ClearRuleIds ();

    ClearDuplicateArcs ();
    RemoveUnvisitedArcs (startId, lastId);
    RemoveDiscardedArcs ();
    RenumberNodes ();
    UpdateVertexCount (0);

    SortLanguage ();
    return;
}

void SubGraph::RemoveRuleStarts (int startPoint, int endPoint)
{
    if (startPoint == -1 && endPoint == -1) {
        startPoint= startId;
        endPoint= lastId;
    }

    int *nodeList= new int [numVertex];
    int *visitList= new int [numVertex];
    for (int ii= 0; ii < numVertex; ii++)
        visitList[ii]= 0;

    SortLanguage ();
    ProcessBegins (startPoint, endPoint, BEGINRULE_LABEL, nodeList, 0, visitList, numVertex);
    ClearLabelledConnections (BEGINRULE_LABEL);

    delete [] nodeList;
    delete [] visitList;
    return;
}

void SubGraph::RemoveRuleEnds (int startPoint, int endPoint)
{
    if (startPoint == -1 && endPoint == -1) {
        startPoint= startId;
        endPoint= lastId;
    }

    int *nodeList= new int [numVertex];
    int *visitList= new int [numVertex];
    for (int ii= 0; ii < numVertex; ii++)
        visitList[ii]= 0;

    SortLanguageReverse ();
    ProcessEnds (endPoint, startPoint, ENDRULE_LABEL, nodeList, 0, visitList, numVertex);
    ClearLabelledConnections (ENDRULE_LABEL);

    delete [] nodeList;
    delete [] visitList;
    return;
}

void SubGraph::RemoveNulls (int startPoint, int endPoint)
{
    if (startPoint == -1 && endPoint == -1) {
        startPoint= startId;
        endPoint= lastId;
    }

    int *nodeList= new int [numVertex];
    int *visitList= new int [numVertex];
    for (int ii= 0; ii < numVertex; ii++)
        visitList[ii]= 0;

    SortLanguage ();
    ProcessBegins (startPoint, endPoint, NONE_LABEL, nodeList, 0, visitList, numVertex);
    ClearLabelledConnections (NONE_LABEL);

    delete [] nodeList;
    delete [] visitList;
    return;
}

void SubGraph::RemoveInternalConnections ()
{
    RemoveForwardConnections (-1, -1);
    RemoveBackwardConnections (-1, -1);
    ClearDuplicateArcs ();
    RemoveUnvisitedArcs (startId, lastId);
    RemoveDiscardedArcs ();
    RenumberNodes ();
    UpdateVertexCount (0);

    SortLanguage ();
    return;
}

void SubGraph::RemoveForwardConnections (int startPoint, int endPoint)
{
    //  Code to pull up nodes for forward connecting transitions

    if (startPoint == -1 && endPoint == -1) {
        startPoint= startId;
        endPoint= lastId;
    }

    int *nodeList= new int [numVertex];
    int *visitList= new int [numVertex];
    for (int ii= 0; ii < numVertex; ii++)
        visitList[ii]= 0;

    SortLanguage ();
    ProcessBegins (startPoint, endPoint, BEGINSCOPE_LABEL, nodeList, 0, visitList, numVertex);
    ClearLabelledConnections (BEGINSCOPE_LABEL);
    RemoveDiscardedArcs ();

    delete [] nodeList;
    delete [] visitList;
    return;
}

void SubGraph::PullUpBegins (int currId, int baseId, int finalId, int procLabel,
                             int *nodeList, int currNum, int maxNum)
{
    int rix;

    nodeList[currNum]= currId;
    rix= FindFromIndex (currId);
    if (rix < 0)
        return;
    while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) {
        if (arc[forwardList[rix]]->GetInput() == procLabel) {
            PullUpBegins (arc[forwardList[rix]]->GetToId(), baseId,
                                finalId, procLabel, nodeList, currNum+1, maxNum);
        }
        else if (arc[forwardList[rix]]->GetInput() != DISCARD_LABEL)
            InheritArc (arc[forwardList[rix]], baseId);
        rix++;
    }
    return;
}

void SubGraph::ProcessBegins (int currId, int finalId, int procLabel,
                              int *nodeList, int currNum, int *visitMark, int maxNum)
{
    int rix, nextId;

    nodeList[currNum]= currId;
    rix= FindFromIndex (currId);
    if (rix < 0) {
	    visitMark[currId]= 1;
        return;
    }
    while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) {
        if (arc[forwardList[rix]]->GetInput() == procLabel) {
            PullUpBegins (arc[forwardList[rix]]->GetToId(), currId,
                        finalId, procLabel, nodeList, currNum, maxNum);
        }

        nextId= arc[forwardList[rix]]->GetToId();
        if (nextId >= 0 && nextId != finalId && checkEntry (nodeList, currNum, nextId) < 0
         && visitMark[nextId] == 0)
            ProcessBegins (nextId, finalId, procLabel, nodeList, currNum+1, visitMark, maxNum);
        rix++;
    }
    visitMark[currId]= 1;
    return;
}

void SubGraph::RemoveBackwardConnections (int startPoint, int endPoint)
{
    //  Code to push back nodes for reverse connecting transitions

    if (startPoint == -1 && endPoint == -1) {
        startPoint= startId;
        endPoint= lastId;
    }

    int *nodeList= new int [numVertex];
    int *visitList= new int [numVertex];
    for (int ii= 0; ii < numVertex; ii++)
        visitList[ii]= 0;

    SortLanguageReverse ();
    ProcessEnds (endPoint, startPoint, ENDSCOPE_LABEL, nodeList, 0, visitList, numVertex);
    ClearLabelledConnections (ENDSCOPE_LABEL);
    RemoveDiscardedArcs ();

    delete [] nodeList;
    delete [] visitList;
    return;
}

void SubGraph::PullUpEnds (int currId, int baseId, int initialId, int procLabel,
                           int *nodeList, int currNum, int maxNum)
{
    int rix;

    nodeList[currNum]= currId;
    rix= FindToIndex (currId);
    if (rix < 0)
        return;
    while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) {
        if (arc[backwardList[rix]]->GetInput() == procLabel) {
            PullUpEnds (arc[backwardList[rix]]->GetFromId(), baseId,
                                initialId, procLabel, nodeList, currNum+1, maxNum);
        }
        else if (arc[backwardList[rix]]->GetInput() != DISCARD_LABEL)
            InheritReverseArc (arc[backwardList[rix]], baseId);
        rix++;
    }
    return;
}

void SubGraph::ProcessEnds (int currId, int initialId, int procLabel,
                            int *nodeList, int currNum, int *visitMark, int maxNum)
{
    int rix, nextId;

    nodeList[currNum]= currId;
    rix= FindToIndex (currId);
    if (rix < 0) {
	visitMark[currId]= 1;
        return;
    }
    while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) {
        if (arc[backwardList[rix]]->GetInput() == procLabel) {
            PullUpEnds (arc[backwardList[rix]]->GetFromId(), currId,
                        initialId, procLabel, nodeList, currNum, maxNum);
        }
        nextId= arc[backwardList[rix]]->GetFromId();
        if (nextId != initialId && checkEntry (nodeList, currNum, nextId) < 0
         && visitMark[nextId] == 0)
            ProcessEnds (nextId, initialId, procLabel, nodeList, currNum+1, visitMark, maxNum);
        rix++;
    }
    visitMark[currId]= 1;
    return;
}

void SubGraph::RemoveUnreachedConnections (int startPoint, int endPoint)
{
    //  Obtain nodes with real transitions
    //  Code to pull up nodes for forward connecting transitions
    //  Code to push back nodes for reverse connecting transitions

    if (startPoint == -1 && endPoint == -1) {
        startPoint= startId;
        endPoint= lastId;
    }

    ClearDuplicateArcs ();
    RemoveUnvisitedArcs (startPoint, endPoint);
    RemoveDiscardedArcs ();
    RenumberNodes ();
    UpdateVertexCount (0);

    return;
}

void SubGraph::RemoveUnreachedConnectionsDebug (int startPoint, int endPoint)
{
    //  Obtain nodes with real transitions
    //  Code to pull up nodes for forward connecting transitions
    //  Code to push back nodes for reverse connecting transitions

    if (startPoint == -1 && endPoint == -1) {
        startPoint= startId;
        endPoint= lastId;
    }

    // ClearDuplicateArcs ();
    RemoveUnvisitedArcs (startPoint, endPoint);
    RemoveDiscardedArcs ();
    // RenumberNodes ();
    UpdateVertexCount (0);

    return;
}

void SubGraph::ReduceArcsByEquivalence ()
{
    int ii, *equivMap, *depthMap;

    //  Sort by Input, Output and to nodes
    SortLanguage ();
    SortLanguageReverse ();

    //  Calculate depth
    depthMap= new int [numVertex];
    for (ii= 0; ii < numVertex; ii++)
        depthMap[ii]= MAXNUM;
    if (lastId >= 0)
        ReverseDepthData (lastId, depthMap, 1);
    ReverseDepthOnTerminal (depthMap);
    for (ii= 0; ii < numVertex; ii++)
        if (depthMap[ii] == MAXNUM)
            depthMap[ii]= -1;

    //  Create equivalence list
    equivMap= new int [numVertex];
    for (ii= 0; ii < numVertex; ii++)
        equivMap[ii]= ii;

    //  Equivalence test to use equivalence list, duplicate transitions ignored
    //  Test nodes with same equivalence
    IdentifyEquivalence (depthMap, equivMap);

    //  On identification of an equivalence
    //      Update equivalence entry
    MapGraphVertices (equivMap);
    RemoveDiscardedArcs ();

    //  Sort for general access
    SortLanguage ();

    delete [] depthMap;
    delete [] equivMap;
    return;
}

void SubGraph::DeterminizeArcs ()
{
    int ii;
    bool allDone;

    SortLanguage ();
    DetCache *cache= new DetCache;

    SetupVisitationCache ();
    assert (VisitationConsistencyCheck () == 0);
    printf ("Determinization\n");
    allDone= false;
    while (!allDone) {
        allDone= true;
        for (ii= 0; ii < numVertex; ii++) {
	    if (QueryMinProperty(ii) == false) {
                if (startId == ii || QueryNodeProperty(ii) > 0) {
                    DeterminizeAtVertex (ii, cache);
		    SetMinProperty (ii);
        	    allDone= false;
	            //printf ("    Node %d, Total %d, Arcs %d\n", ii, numVertex, numArc);
	        }
                assert (VisitationConsistencyCheck () == 0);
		// hmm .. this seems harmless but ..
		// printf("assert(0) in SubGraph::DeterminizeArcs() ii=%d allDone=%d\n", ii, allDone);
		// assert (0);
            }
        }
    }

    ClearVisitationCache ();

    delete cache;
    return;
}

int SubGraph::IsDeterminized (int currId)
{
    int count, rix, lastInput;

    count= 0;
    lastInput= -1;
    rix= FindFromIndex (currId);
    if (rix < 0)
        return -1;
    while (rix < sortNum && arc[forwardList[rix]]->GetFromId() == currId) {
        if (lastInput >= 0 && lastInput == arc[forwardList[rix]]->GetInput())
            count++;
        else
            lastInput= arc[forwardList[rix]]->GetInput();
        rix++;
    }
    return count;
}

void SubGraph::ReverseGraphForOutput ()
{
    int     ii, incId, outId;

    assert (startId == 0);
    UpdateVertexCount (0);
    for (ii= 0; ii < numArc; ii++) {
        incId= arc[ii]->GetFromId();
        outId= arc[ii]->GetToId();
        if (outId == TERMINAL_LABEL) {
            arc[ii]->AssignFromId (0);
            arc[ii]->AssignInput (NONE_LABEL);
            arc[ii]->AssignOutput (NONE_LABEL);
            arc[ii]->AssignToId (incId);
        }
        else {
            arc[ii]->AssignFromId (outId);
            if (incId == 0)
                arc[ii]->AssignToId (numVertex);
            else
                arc[ii]->AssignToId (incId);
        }
    }
    (void) CreateArc (TERMINAL_LABEL, NONE_LABEL, numVertex, TERMINAL_LABEL);  //  Add terminal transition
    numVertex++;

    return;
}

void SubGraph::RemoveTagConnections (int startPoint, int endPoint)
{
    //  Code to push back nodes for reverse connecting transitions

    if (startPoint == -1 && endPoint == -1) {
        startPoint= startId;
        endPoint= lastId;
    }

    int *nodeList= new int [numVertex];
    int *visitList= new int [numVertex];
    for (int ii= 0; ii < numVertex; ii++)
        visitList[ii]= 0;

    SortLanguageReverse ();
    ProcessTags (endPoint, startPoint, nodeList, 0, visitList, numVertex);
    ClearLabelledConnections (TAG_LABEL);
    RemoveDiscardedArcs ();

    delete [] nodeList;
    delete [] visitList;
    return;
}

bool SubGraph::PullUpTags (int currId, int baseId, int initialId,
                           int outTag, int *nodeList, int currNum, int maxNum)
{
    int rix;
    bool hasCascade= false;

    nodeList[currNum]= currId;
    rix= FindToIndex (currId);
    if (rix < 0)
        return hasCascade;
    while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) {
        if (arc[backwardList[rix]]->GetInput() == TAG_LABEL) {
            if (PullUpTags (arc[backwardList[rix]]->GetFromId(), baseId, initialId,
                arc[backwardList[rix]]->GetOutput(), nodeList, currNum+1, maxNum))
                CreateCopyWithOutput (arc[backwardList[rix]], NONE_LABEL);
            hasCascade= true;
        }
        else if (arc[backwardList[rix]]->GetInput() != DISCARD_LABEL)
            InheritReverseArcWithTag (arc[backwardList[rix]], baseId, outTag);
        rix++;
    }
    return hasCascade;
}

void SubGraph::ProcessTags (int currId, int initialId, int *nodeList, int currNum,
                            int *visitMark, int maxNum)
{
    int rix, nextId;

    nodeList[currNum]= currId;
    rix= FindToIndex (currId);
    if (rix < 0) {
	    visitMark[currId]= 1;
        return;
    }
    while (rix < sortRevNum && arc[backwardList[rix]]->GetToId() == currId) {
        if (arc[backwardList[rix]]->GetInput() == TAG_LABEL) {
            if (PullUpTags (arc[backwardList[rix]]->GetFromId(), currId, initialId,
                arc[backwardList[rix]]->GetOutput(), nodeList, currNum, maxNum))
                CreateCopyWithOutput (arc[backwardList[rix]], NONE_LABEL);
        }
        nextId= arc[backwardList[rix]]->GetFromId();
        if (nextId != initialId && checkEntry (nodeList, currNum, nextId) < 0
         && visitMark[nextId] == 0)
            ProcessTags (nextId, initialId, nodeList, currNum+1, visitMark, maxNum);
        rix++;
    }
    visitMark[currId]= 1;
    return;
}