/* FILE:		sub_supp.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"


#define ARC_COMPARE(x,y) (arc[x]->Compare(arc[y]))
#define ARC_COMPARE_REV(x,y) (arc[x]->CompareReverse(arc[y]))
#define ARC_COMPARE_MIN(x,y) (arc[x]->CompareForMin(arc[y]))


void SubGraph::SortLanguage ()
{
    int *sortList;

    if (numArc <= 1) {
        sortList= new int [numArc+2];
        sortList[0]= 0;
        if (forwardList)
            delete [] forwardList;
        forwardList= sortList;
        sortNum= numArc;
	    return;
    }
    SortLanguageAtIndices (-1, -1);
    return;
}

void SubGraph::SortLanguageAtIndices (int begIx, int endIx)
{
    int	ii, jj, hired, retd;
    int holdArc, *sortList;

    if (begIx < 0)
        begIx= 0;
    if (endIx < 0)
        endIx= numArc;

    if (endIx <= begIx)
	    return;

    sortList= new int [numArc+2];
    for (ii= 0; ii < sortNum && ii < numArc; ii++)
        sortList[ii]= forwardList[ii];
    for (ii= begIx; ii < endIx; ii++)
        sortList[ii]= ii;
    sortList--;

    /*  Hiring
    */
    hired= (numArc >> 1)+1;
    while (hired-- > 1) {
	    holdArc= sortList[hired];
	    ii= hired;
	    jj= hired << 1;
	    while (jj <= numArc) {
	        if (jj < numArc && ARC_COMPARE (sortList[jj], sortList[jj+1]) <= 0 )
		        jj++;
	        if (ARC_COMPARE (holdArc, sortList[jj]) < 0) {
		        sortList[ii]= sortList[jj];
		        ii= jj;
		        jj <<= 1;
	        }
	        else
		    break;
	    }
	    sortList[ii]= holdArc;
    }

    /*  Retiring
    */
    retd= numArc;
    while (retd > 0) {
	    holdArc= sortList[retd];
	    sortList[retd]= sortList[1];
	        if (--retd == 1) {
	            sortList[1]= holdArc;
	            break;
	        }
	    ii= 1;
	    jj= 2;
	    while (jj <= retd) {
	        if (jj < retd && ARC_COMPARE (sortList[jj], sortList[jj+1]) <= 0)
		        jj++;
	        if (ARC_COMPARE (holdArc, sortList[jj]) < 0) {
		        sortList[ii]= sortList[jj];
		        ii= jj;
		        jj <<= 1;
	        }
	        else
		        break;
	    }
	    sortList[ii]= holdArc;
    }
    sortList++;

    if (forwardList)
        delete [] forwardList;
    forwardList= sortList;
    sortNum= numArc;

    /*  Now carry out some checks
    */
    assert(CheckSort());

    return;
}

void SubGraph::SortLanguageAtSortIndices (int begIx, int endIx)
{
    int	ii, jj, hired, retd;
    int holdArc, *sortList;

    if (begIx < 0)
        begIx= 0;
    if (endIx < 0)
        endIx= numArc;

    if (endIx <= begIx)
	    return;

    sortList= forwardList;
    sortList--;

    /*  Hiring
    */
    hired= (numArc >> 1)+1;
    while (hired-- > 1) {
	    holdArc= sortList[hired];
	    ii= hired;
	    jj= hired << 1;
	    while (jj <= numArc) {
	        if (jj < numArc && ARC_COMPARE (sortList[jj], sortList[jj+1]) <= 0 )
		        jj++;
	        if (ARC_COMPARE (holdArc, sortList[jj]) < 0) {
		        sortList[ii]= sortList[jj];
		        ii= jj;
		        jj <<= 1;
	        }
	        else
		    break;
	    }
	    sortList[ii]= holdArc;
    }

    /*  Retiring
    */
    retd= numArc;
    while (retd > 0) {
	    holdArc= sortList[retd];
	    sortList[retd]= sortList[1];
	        if (--retd == 1) {
	            sortList[1]= holdArc;
	            break;
	        }
	    ii= 1;
	    jj= 2;
	    while (jj <= retd) {
	        if (jj < retd && ARC_COMPARE (sortList[jj], sortList[jj+1]) <= 0)
		        jj++;
	        if (ARC_COMPARE (holdArc, sortList[jj]) < 0) {
		        sortList[ii]= sortList[jj];
		        ii= jj;
		        jj <<= 1;
	        }
	        else
		        break;
	    }
	    sortList[ii]= holdArc;
    }
    sortList++;

    forwardList= sortList;

    /*  Now carry out some checks
    */
    assert(CheckSort());

    return;
}

int SubGraph::FindFromIndex (int element)
{
    int rix, rix_low, rix_high, direction;

    rix_low= -1;
    rix_high= sortNum;
    while ((rix_high - rix_low) > 1) {
	    rix= (rix_high + rix_low) >> 1;
	    direction= element - arc[forwardList[rix]]->GetFromId();
	    if (direction < 0)
	        rix_high= rix;
	    else if (direction > 0)
	        rix_low= rix;
	    else {
            assert (arc[forwardList[rix]]->GetFromId() == element);
	        while (rix > 0 && arc[forwardList[rix-1]]->GetFromId() == element)
		        rix--;
            assert (arc[forwardList[rix]]->GetFromId() == element);
            assert (rix < sortNum);
	        return (rix);
	    }
    }
    return (-1);
}

void SubGraph::SortLanguageReverse ()
{
    int	ii, jj, hired, retd;
    int holdArc, *sortList;

    if (numArc <= 1) {
        sortList= new int [numArc+2];
        sortList[0]= 0;
        if (backwardList)
            delete [] backwardList;
        backwardList= sortList;
        sortRevNum= numArc;
	    return;
    }

    sortList= new int [numArc+2];
    for (ii= 0; ii < numArc; ii++)
        sortList[ii]= ii;
    sortList--;

    /*  Hiring
    */
    hired= (numArc >> 1)+1;
    while (hired-- > 1) {
	    holdArc= sortList[hired];
	    ii= hired;
	    jj= hired << 1;
	    while (jj <= numArc) {
	        if (jj < numArc && ARC_COMPARE_REV (sortList[jj], sortList[jj+1]) <= 0 )
		        jj++;
	        if (ARC_COMPARE_REV (holdArc, sortList[jj]) < 0) {
		        sortList[ii]= sortList[jj];
		        ii= jj;
		        jj <<= 1;
	        }
	        else
		    break;
	    }
	    sortList[ii]= holdArc;
    }

    /*  Retiring
    */
    retd= numArc;
    while (retd > 0) {
	    holdArc= sortList[retd];
	    sortList[retd]= sortList[1];
	        if (--retd == 1) {
	            sortList[1]= holdArc;
	            break;
	        }
	    ii= 1;
	    jj= 2;
	    while (jj <= retd) {
	        if (jj < retd && ARC_COMPARE_REV (sortList[jj], sortList[jj+1]) <= 0)
		        jj++;
	        if (ARC_COMPARE_REV (holdArc, sortList[jj]) < 0) {
		        sortList[ii]= sortList[jj];
		        ii= jj;
		        jj <<= 1;
	        }
	        else
		        break;
	    }
	    sortList[ii]= holdArc;
    }
    sortList++;

    if (backwardList)
        delete [] backwardList;
    backwardList= sortList;
    sortRevNum= numArc;

    /*  Now carry out some checks
    */
    assert(CheckSortReverse());

    return;
}

int SubGraph::FindToIndex (int element)
{
    int rix, rix_low, rix_high, direction;

    rix_low= -1;
    rix_high= sortRevNum;
    while ((rix_high - rix_low) > 1) {
	    rix= (rix_high + rix_low) >> 1;
	    direction= element - arc[backwardList[rix]]->GetToId();
	    if (direction < 0)
	        rix_high= rix;
	    else if (direction > 0)
	        rix_low= rix;
	    else {
            assert (arc[backwardList[rix]]->GetToId() == element);
	        while (rix > 0 && arc[backwardList[rix-1]]->GetToId() == element)
		        rix--;
            assert (arc[backwardList[rix]]->GetToId() == element);
            assert (rix < sortRevNum);
	        return (rix);
	    }
    }
    return (-1);
}

void SubGraph::UpdateSortForLanguage ()
{
    SortLanguageAtIndices (sortNum, numArc);
}

bool SubGraph::CheckSort ()
{
    for (int ii= 1; ii < numArc; ii++) {
	    if (ARC_COMPARE (forwardList[ii-1], forwardList[ii]) > 0)
            return false;
    }
    return true;
}

bool SubGraph::CheckSortReverse ()
{
    for (int ii= 1; ii < numArc; ii++) {
	if (ARC_COMPARE_REV (backwardList[ii-1], backwardList[ii]) > 0) {
	    printf ("Failed at %d\n", ii);
            return false;
	}
    }
    return true;
}

void SubGraph::ClearDuplicateArcs ()
{
    int currId;

    SortLanguage();
    currId= 0;
    for (int ii= 1; ii < numArc; ii++) {
        if (arc[forwardList[ii]]->GetInput() != DISCARD_LABEL)
            if (ARC_COMPARE (forwardList[currId], forwardList[ii]) == 0)
                arc[forwardList[ii]]->AssignInput (DISCARD_LABEL);
            else
                currId= ii;
    }
    return;
}

void SubGraph::RenumberNodes ()
{
  int  ii, id, count;

    UpdateVertexCount (0);
    if (numVertex > 0) {
        int *mapList= new int [numVertex];
        for (ii= 0; ii < numVertex; ii++)
            mapList[ii]= -1;

        for (ii= 0; ii < numArc; ii++) {
            id= arc[ii]->GetFromId();
            mapList[id]= 1;
            id= arc[ii]->GetToId();
            if (id >= 0)
                mapList[id]= 1;
        }

        count= 0;
        for (ii= 0; ii < numVertex; ii++)
            if (mapList[ii] > 0) {
                mapList[ii]= count;
                count++;
            }

        for (ii= 0; ii < numArc; ii++) {
            id= arc[ii]->GetFromId();
            arc[ii]->AssignFromId(mapList[id]);
            id= arc[ii]->GetToId();
            if (id >= 0)
                arc[ii]->AssignToId(mapList[id]);
        }
        startId= mapList[startId];
        if (lastId >= 0)
            lastId= mapList[lastId];
        delete [] mapList;
    }
    else {
        startId= 0;
        lastId= -1;
        endId= -1;
    }
    return;
}

void SubGraph::RemoveDuplicatesAtNode (int rixBegin, int rixEnd)
//  Works only within one node/vertex
{
    int rix, lastRix;
    bool needSort;

    SortLanguageAtSortIndices (rixBegin, rixEnd);

    //  Check for duplicate transitions
    needSort= false;
    lastRix= rixBegin;
    for (rix= rixBegin+1; rix < rixEnd; rix++) {
        assert (arc[forwardList[lastRix]]->GetFromId() == arc[forwardList[rix]]->GetFromId());
        if (ARC_COMPARE (forwardList[lastRix], forwardList[rix]) == 0) {
            arc[forwardList[rix]]->AssignInput (DISCARD_LABEL);
            needSort= true;
        }
        else
            lastRix= rix;
    }

    //  Resort
    if (needSort)
        SortLanguageAtSortIndices (rixBegin, rixEnd);

    return;
}

void SubGraph::SortLanguageForMin ()
{
    int *sortList;

    if (numArc <= 1) {
        sortList= new int [numArc+2];
        sortList[0]= 0;
        if (forwardList)
            delete [] forwardList;
        forwardList= sortList;
        sortNum= numArc;
	    return;
    }
    SortLanguageAtIndicesForMin (-1, -1);
    return;
}

void SubGraph::SortLanguageAtIndicesForMin (int begIx, int endIx)
{
    int	ii, jj, hired, retd;
    int holdArc, *sortList;

    if (begIx < 0)
        begIx= 0;
    if (endIx < 0)
        endIx= numArc;

    if (endIx <= begIx)
	    return;

    sortList= new int [numArc+2];
    for (ii= 0; ii < sortNum && ii < numArc; ii++)
        sortList[ii]= forwardList[ii];
    for (ii= begIx; ii < endIx; ii++)
        sortList[ii]= ii;
    sortList--;

    /*  Hiring
    */
    hired= (numArc >> 1)+1;
    while (hired-- > 1) {
	    holdArc= sortList[hired];
	    ii= hired;
	    jj= hired << 1;
	    while (jj <= numArc) {
	        if (jj < numArc && ARC_COMPARE_MIN (sortList[jj], sortList[jj+1]) <= 0 )
		        jj++;
	        if (ARC_COMPARE_MIN (holdArc, sortList[jj]) < 0) {
		        sortList[ii]= sortList[jj];
		        ii= jj;
		        jj <<= 1;
	        }
	        else
		    break;
	    }
	    sortList[ii]= holdArc;
    }

    /*  Retiring
    */
    retd= numArc;
    while (retd > 0) {
	    holdArc= sortList[retd];
	    sortList[retd]= sortList[1];
	        if (--retd == 1) {
	            sortList[1]= holdArc;
	            break;
	        }
	    ii= 1;
	    jj= 2;
	    while (jj <= retd) {
	        if (jj < retd && ARC_COMPARE_MIN (sortList[jj], sortList[jj+1]) <= 0)
		        jj++;
	        if (ARC_COMPARE_MIN (holdArc, sortList[jj]) < 0) {
		        sortList[ii]= sortList[jj];
		        ii= jj;
		        jj <<= 1;
	        }
	        else
		        break;
	    }
	    sortList[ii]= holdArc;
    }
    sortList++;

    if (forwardList)
        delete [] forwardList;
    forwardList= sortList;
    sortNum= numArc;

    /*  Now carry out some checks
    */
    int checkSort = CheckSort();
    if(checkSort == 0) {
      // printf("assert(0) in SubGraph::CheckSort %d\n", checkSort);
      // hmm .. this seems harmless but ...!
      // assert(checkSort);
    }

    return;
}