/**@@@+++@@@@******************************************************************
**
** Microsoft Windows Media
** Copyright (C) Microsoft Corporation. All rights reserved.
**
***@@@---@@@@******************************************************************
*/


#include <drmcommon.h>
#include <drmutilities.h>
#include <drmcontextsizes.h>
#include <drmsyncstore.h>
#include <drmlicstore.h>
#include <drmhds.h>

#if DRM_SUPPORT_CLEANUP 
static const DRM_DWORD g_dwPercentageTimeForDefrag = 10;

#define _REPORT_STATUS \
{\
    ++iLicense;\
    if ( pfnCallback && (iLicense % cLicBetweenCBInterval) == 0 ) \
    {\
        ChkDR( pfnCallback( pvCallerData, iLicense, cLicenses));\
    }\
}
#endif

/******************************************************************************
** 
** Function :   DRM_LST_Clean
** 
** Synopsis :   For PC (if DRM_SUPPORT_CLEANUP is defined), it will remove 
**              unusable licenses from the License store, and then "defrag" the 
**              store. For devices, it will only defrag the store
** 
** Arguments :  pbLicEvalCtxt
**              pbLicStoreCtxt
**              pbBuffer    - User supplied buffer for storing license
**              cbBuffer    - # of bytes in license buffer
**              pvCallerData- Caller data to be passed in the ReportProgress 
**                            callback
**              dwCallbackInterval - % completion after which 
**                  Callback (if any) should be invoked. 
**                  e.g. if dwCallbackInterval = 5, callback will be 
**                  invoked after 5%, 10%, 15%...completion
**              pfnCallback - Callback function to report progress
**              poHdsContext- HDS context
**
** Returns :    
** 
** Notes :      
** 
******************************************************************************/
DRM_RESULT DRM_API DRM_LST_Clean (
    IN       DRM_BYTE                *pbLicEvalCtxt,
    IN       DRM_BYTE                *pbLicStoreCtxt,
    IN       DRM_BYTE                *pbBuffer,
    IN       DRM_DWORD                cbBuffer,
    IN const DRM_VOID                *pvCallerData,
    IN       DRM_DWORD                dwCallbackInterval,
    IN       pfnStoreCleanupProgress  pfnCallback,
    IN       DRM_HDS_CONTEXT         *poHdsContext)
{
    DRM_RESULT                  dr = DRM_SUCCESS;
    
#if DRM_SUPPORT_CLEANUP    
    DRM_KID                     oKID;
    DRM_LID                     oLID;
    DRM_BOOL                    fDelete = FALSE;
    DRM_DWORD                   cLicenses = 0;  
    DRM_DWORD                   iLicense = 0;
    DRM_DWORD                   cLicBetweenCBInterval = 0;
    DRM_DWORD                   cbLicense = 0;
    DRM_LICEVAL_CONTEXT*        pLicEvalCtxt = (DRM_LICEVAL_CONTEXT *)
                                                    pbLicEvalCtxt;
#endif

    /*  Check input */
    ChkArg(pbLicEvalCtxt && pbLicStoreCtxt && pbBuffer && poHdsContext);

#if DRM_SUPPORT_CLEANUP     
    /*  Query for all licenses  */
    ChkDR( DRM_LST_InitEnum( 
            (DRM_LICSTORE_CONTEXT *)pbLicStoreCtxt, 
            NULL, 
            FALSE, 
            pLicEvalCtxt->pLicStoreEnumContext
            ) );

    if (pfnCallback)
    {
        /*  Count the number of licenses in the store   */
        ChkDR(DRM_LST_LicCount(
                pLicEvalCtxt->pLicStoreEnumContext,
                &cLicenses
                ));

        /*  Callback to confirm whether cleanup should be started */
        /*  Caller returns an error to indicate that cleanup should */
        /*  be aborted  */
        ChkDR( pfnCallback( pvCallerData, 0, cLicenses ) );
        
        cLicBetweenCBInterval = 
            (dwCallbackInterval * cLicenses * 
                    (100 + g_dwPercentageTimeForDefrag)) / (100*100);

        /*  For certain values of callbackinterval and size of the  */
        /*  store, this value might become zero                     */
        /*  Make sure that this value is reset to 1                 */
        if (0 == cLicBetweenCBInterval)
        {
            cLicBetweenCBInterval = 1;  
        }
        
        /*  Query for all licenses  */
        ChkDR( DRM_LST_InitEnum( 
                (DRM_LICSTORE_CONTEXT *)pbLicStoreCtxt, 
                NULL, 
                FALSE, 
                pLicEvalCtxt->pLicStoreEnumContext
                ) );        
    }
    
    while( TRUE ) /*    Loop will break when DRM_E_NOMORE is hit */
    {
        DRM_HDS_SLOT_HINT slotHint;

        cbLicense = 0;
        dr = DRM_LST_EnumNext( 
                pLicEvalCtxt->pLicStoreEnumContext,
                &oKID, &oLID, 
                &slotHint,
                &cbLicense
                ); 
        if( DRM_E_NOMORE == dr )
        {
            dr = DRM_SUCCESS;
            break;
        }
        ChkDR(dr);

        if (cbLicense > cbBuffer)
        {
            /*
            **  License size is greater than size of buffer available
            **  Ignore this license 
            */
            continue;           
        }

        /*  Use buffer provided by user */ 
        dr =  DRM_LST_GetLicense( (DRM_LICSTORE_CONTEXT *)pbLicStoreCtxt,
                                  &oKID, 
                                  &oLID, 
                                  &slotHint,
                                  pbBuffer, 
                                  &cbLicense );  
        if ( DRM_FAILED(dr) )
        {
            /*  Nevermind - continue deleting other licenses  */
            dr = DRM_SUCCESS;
            _REPORT_STATUS;
            continue;
        }

        /* Add info about this license to the license evaluator obj */
        DSTR_FROM_PB( &pLicEvalCtxt->dstrContentLicense, pbBuffer, cbLicense );
        pLicEvalCtxt->fUseCachedAttribs = FALSE;
        
        /* Talk to BB to get the secstore password for this license */
        ChkDR( DRM_SST_CreateLicenseStatePassword( &oLID, pbBuffer, (DRM_BYTE*)pLicEvalCtxt->pcontextBBX ) );

        dr = DRM_SST_OpenKeyTokens( pLicEvalCtxt->pcontextSSTLicense,
                                    &oLID,
                                    NULL,
                                    pbBuffer,
                                    0,
                                    SECURE_STORE_LICENSE_DATA,
                                    poHdsContext );     
        /*  
        **  Note there is no need to close this store.  
        **  We don't care to report actions we just peek inside 
        */

        if ( dr == DRM_E_FILENOTFOUND )
        {
            /* Data corruption - delete this license    */
            dr = DRM_SUCCESS;
            (void)DRM_LST_EnumDelete( pLicEvalCtxt->pLicStoreEnumContext );
            _REPORT_STATUS;
            continue;
        } 
        else if ( DRM_FAILED(dr) )
        {
            /*  Ignore this license */
            dr = DRM_SUCCESS;
            _REPORT_STATUS;
            continue;
        }

        /*  Save the store context  */
        pLicEvalCtxt->pcontextHDS = poHdsContext;                
               
        fDelete = FALSE;
        dr = DRM_LEVL_IsLicenseReadyForDeletion( pLicEvalCtxt, &fDelete );
        if ( !fDelete || DRM_FAILED(dr) )
        {
            /* Ignore this license    */
            dr = DRM_SUCCESS;
            _REPORT_STATUS;
            continue;
        }
        
        (void)DRM_LST_EnumDelete( pLicEvalCtxt->pLicStoreEnumContext );
        _REPORT_STATUS;                        
        
    }   /*  End of while(TRUE) loop   */   

#endif 

    /*  Defrag the license store    */
    ChkDR( DRM_HDS_CleanupStore(poHdsContext, TRUE) );    
                 
ErrorExit:
    return dr;
}

