/**CFile****************************************************************

  FileName    [kLiveConstraints.c]

  SystemName  [ABC: Logic synthesis and verification system.]

  PackageName [Liveness property checking.]

  Synopsis    [Constraint analysis module for the k-Liveness algorithm
        invented by Koen Classen, Niklas Sorensson.]

  Author      [Sayak Ray]
  
  Affiliation [UC Berkeley]

  Date        [Ver. 1.0. Started - October 31, 2012.]

  Revision    [$Id: liveness.c,v 1.00 2009/01/01 00:00:00 alanmi Exp $]

***********************************************************************/

#include <stdio.h>
#include "base/main/main.h"
#include "aig/aig/aig.h"
#include "aig/saig/saig.h"
#include <string.h>
#include "base/main/mainInt.h"
#include "proof/pdr/pdr.h"

ABC_NAMESPACE_IMPL_START

Aig_Obj_t *createConstrained0LiveCone( Aig_Man_t *pNewAig, Vec_Ptr_t *signalList )
{
    Aig_Obj_t *pConsequent, *pConsequentCopy, *pAntecedent, *p0LiveCone, *pObj;
    int i, numSigAntecedent;
    
    numSigAntecedent = Vec_PtrSize( signalList ) - 1;

    pAntecedent = Aig_ManConst1( pNewAig );
    pConsequent = (Aig_Obj_t *)Vec_PtrEntry( signalList, numSigAntecedent );
    pConsequentCopy = Aig_NotCond( (Aig_Obj_t *)(Aig_Regular(pConsequent)->pData), Aig_IsComplement( pConsequent ) );

    for(i=0; i<numSigAntecedent; i++ )
    {
        pObj = (Aig_Obj_t *)Vec_PtrEntry( signalList, i );
        assert( Aig_Regular(pObj)->pData );
        pAntecedent = Aig_And( pNewAig, pAntecedent, Aig_NotCond((Aig_Obj_t *)(Aig_Regular(pObj)->pData), Aig_IsComplement(pObj)) );
    }

    p0LiveCone = Aig_Or( pNewAig, Aig_Not(pAntecedent), pConsequentCopy );

    return p0LiveCone;
}

Vec_Ptr_t *collectCSSignals( Abc_Ntk_t *pNtk, Aig_Man_t *pAig )
{
    int i;
    Aig_Obj_t *pObj, *pConsequent = NULL;
    Vec_Ptr_t *vNodeArray;

    vNodeArray = Vec_PtrAlloc(1);

    Saig_ManForEachPo( pAig, pObj, i )
    {
        if( strstr( Abc_ObjName(Abc_NtkPo( pNtk, i )), "csLiveConst_" ) != NULL )
            Vec_PtrPush( vNodeArray, Aig_NotCond((Aig_Obj_t *)Aig_ObjFanin0(pObj), Aig_ObjFaninC0(pObj)) );    
        else if( strstr( Abc_ObjName(Abc_NtkPo( pNtk, i )), "csLiveTarget_" ) != NULL )
            pConsequent = Aig_NotCond((Aig_Obj_t *)Aig_ObjFanin0(pObj), Aig_ObjFaninC0(pObj));
    }
    assert( pConsequent );
    Vec_PtrPush( vNodeArray, pConsequent );    
    return vNodeArray;
}

Aig_Man_t *createNewAigWith0LivePo( Aig_Man_t *pAig, Vec_Ptr_t *signalList, int *index0Live )
{
    Aig_Man_t *pNewAig;
    Aig_Obj_t *pObj, *pObjNewPoDriver;
    int i;

    //assert( Vec_PtrSize( signalList ) > 1 );

    //****************************************************************
    // Step1: create the new manager
    // Note: The new manager is created with "2 * Aig_ManObjNumMax(p)"
    // nodes, but this selection is arbitrary - need to be justified
    //****************************************************************
    pNewAig = Aig_ManStart( Aig_ManObjNumMax(pAig) );
    pNewAig->pName = (char *)malloc( strlen( pAig->pName ) + strlen("_0Live") + 1 );
    sprintf(pNewAig->pName, "%s_%s", pAig->pName, "0Live");
        pNewAig->pSpec = NULL;

    //****************************************************************
    // Step 2: map constant nodes
    //****************************************************************
        pObj = Aig_ManConst1( pAig );
        pObj->pData = Aig_ManConst1( pNewAig );

    //****************************************************************
        // Step 3: create true PIs
    //****************************************************************
        Saig_ManForEachPi( pAig, pObj, i )
    {
        pObj->pData = Aig_ObjCreateCi( pNewAig );
    }

    //****************************************************************
    // Step 5: create register outputs
    //****************************************************************
        Saig_ManForEachLo( pAig, pObj, i )
        {
        pObj->pData = Aig_ObjCreateCi( pNewAig );
        }

    //********************************************************************
    // Step 7: create internal nodes
    //********************************************************************
        Aig_ManForEachNode( pAig, pObj, i )
    {
        pObj->pData = Aig_And( pNewAig, Aig_ObjChild0Copy(pObj), Aig_ObjChild1Copy(pObj) );
    }

    Saig_ManForEachPo( pAig, pObj, i )
    {
        pObj->pData = Aig_ObjCreateCo( pNewAig, Aig_ObjChild0Copy(pObj) ); 
    }

    pObjNewPoDriver = createConstrained0LiveCone( pNewAig, signalList );
    Aig_ObjCreateCo( pNewAig, pObjNewPoDriver );
    *index0Live = i;

    Saig_ManForEachLi( pAig, pObj, i )
    {
        pObj->pData = Aig_ObjCreateCo( pNewAig, Aig_ObjChild0Copy(pObj) );
    }

    Aig_ManSetRegNum( pNewAig, Aig_ManRegNum(pAig) );
    Aig_ManCleanup( pNewAig );

    assert( Aig_ManCheck( pNewAig ) );
    return pNewAig;
}

Vec_Ptr_t *checkMonotoneSignal()
{
    return NULL;
}

Vec_Ptr_t *gatherMonotoneSignals(Aig_Man_t *pAig)
{
    int i;
    Aig_Obj_t *pObj;

    Aig_ManForEachNode( pAig, pObj, i )
    {
        Aig_ObjPrint( pAig, pObj );
        printf("\n");
    }
    
    return NULL;
}

Aig_Man_t *generateWorkingAig( Aig_Man_t *pAig, Abc_Ntk_t *pNtk, int *pIndex0Live )
{
    Vec_Ptr_t *vSignalVector;
    Aig_Man_t *pAigNew;

    vSignalVector = collectCSSignals( pNtk, pAig );    
    assert(vSignalVector);
    pAigNew = createNewAigWith0LivePo( pAig, vSignalVector, pIndex0Live );
    Vec_PtrFree(vSignalVector);

    return pAigNew;
}

ABC_NAMESPACE_IMPL_END