srsf/sisrscontrollerplugin/src/simodelbankdb.cpp
author Pat Downey <patd@symbian.org>
Wed, 01 Sep 2010 12:29:17 +0100
branchRCL_3
changeset 23 e36f3802f733
parent 0 bf1d17376201
permissions -rw-r--r--
Revert incorrect RCL_3 drop: Revision: 201033 Kit: 201035

/*
* Copyright (c) 2004-2008 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  This class handles the storage and access of user trained models
*               and utterances into a database.  It performs checksum verification
*               for the stored data.  It is also responsible for allocating memory
*               when loading the models into the recognizer.
*
*/


// INCLUDE FILES
#include <e32std.h>
#include <e32base.h>
#include <f32file.h>
#include "siresourcehandler.h"
#include "asrplugindataloader.h"
#include "simodelbankdb.h"
#include "rubydebug.h"

// CONSTANTS
const TInt KModelBankPackageType=3;
const TInt KModelBankLanguageType=0;
const TInt KModelBankStartPos=0;

// _LIT(KModelFileName,"c:\\system\\Apps\\model_data\\qhmms_fxp"); // Commented out to remove "not referenced" warning
// ============================ MEMBER FUNCTIONS ===============================

// -----------------------------------------------------------------------------
// CSIModelBankDB::CSIModelBankDB
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CSIModelBankDB::CSIModelBankDB( RDbNamedDatabase& aDatabase, 
                                RDbs& aDbSession,
                                TInt aDrive )
                               : CSICommonDB(aDatabase, aDbSession, aDrive ),
                                 iAcousticModelPtr(0,0,0)
    {
    }

 // -----------------------------------------------------------------------------
// CSIModelBankDB::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::ConstructL()
    {
    RUBY_DEBUG_BLOCK( "CSIModelBankDB::ConstructL" );

    // Resource handler 
    CSIResourceHandler* resourceHandler = CSIResourceHandler::NewL();
    CleanupStack::PushL(resourceHandler);
    //  Data loader
    iDataLoader = CDataLoader::NewL( 
        *(resourceHandler->iDataFilenamePrefix), 
        *(resourceHandler->iDataFilenameSeperator),
        *(resourceHandler->iDataFilenamePostfix) );
    CleanupStack::PopAndDestroy(1); //resourceHandler
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CSIModelBankDB* CSIModelBankDB::NewL( RDbNamedDatabase& aDatabase, 
                                      RDbs& aDbSession,
                                      TInt aDrive )
    {
    RUBY_DEBUG_BLOCK( "CSIModelBankDB::NewL" );
    
    CSIModelBankDB* self 
        = new( ELeave ) CSIModelBankDB( aDatabase, aDbSession, aDrive );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop();	
    return self;
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::~CSIModelBankDB
// Destructor
// -----------------------------------------------------------------------------
//
CSIModelBankDB::~CSIModelBankDB()
{
	// Delete all elements of the array before deleting the array
	iModelBankArray.ResetAndDestroy();
	iModelBankArray.Close();
	
 	delete iDataLoader;
}

// -----------------------------------------------------------------------------
// CSIModelBankDB::GetAllAcousticModelsL
// 
// -----------------------------------------------------------------------------
//
const CSIModelBank* CSIModelBankDB::GetAllAcousticModelsL( TSIModelBankID aModelBankID ) 
    {
    
    // Construct the table name using the provided model bank ID
    TBuf<40> KModelBankName(KSIModelBankTable);
    KModelBankName.AppendNumUC(aModelBankID);
    
    TBuf<100> KSQLStatement;
    // Declare a literal string to hold the SQL statement
    // SELECT  KHmmColumn, KHmmChecksumColumn FROM KModelBankName
    _LIT(KSQLSelect1, "SELECT ");
    _LIT(KSQLSelect2, " FROM ");
    
    KSQLStatement = KSQLSelect1;
    KSQLStatement.Append(KHmmColumn);
    KSQLStatement.Append(KNext);
    KSQLStatement.Append(KHmmChecksumColumn);
    KSQLStatement.Append(KSQLSelect2);
    KSQLStatement.Append(KModelBankName);
    
    RDbView view;
    CleanupClosePushL(view);
    User::LeaveIfError(view.Prepare(iDb, TDbQuery(KSQLStatement, EDbCompareNormal)));
    User::LeaveIfError(view.EvaluateAll());
    
    // Get column set for column ordinals
    CDbColSet* columns = view.ColSetL();
    TDbColNo hmm_col = columns->ColNo(KHmmColumn);
    TDbColNo hmmchecksum_col = columns->ColNo(KHmmChecksumColumn);
    delete columns;
    
    // Create a model bank object
    CSIModelBank* modelBank = CSIModelBank::NewLC(aModelBankID);
    
    TSIModelID modelID=KModelID;
    TInt length;
    TInt32 checksum;
    // After evaluation, the first call to NextL() is equivalent to FirstL()
    while ( view.NextL() )
        {
        // Retrieve the current row
        view.GetL();
        length = view.ColLength(hmm_col);
        checksum = view.ColUint32(hmmchecksum_col);
        
        // Read the acoustic model into a buffer
        TUint8* hmmBuf = new (ELeave) TUint8[length];
        CleanupStack::PushL(hmmBuf);
        TPtr8 hmmPtr(hmmBuf, 0, length);
        RDbColReadStream colReadStrm;
       	colReadStrm.OpenLC(view, hmm_col);
       	colReadStrm.ReadL(hmmPtr, length);
        // Cleanup colReadStrm
        CleanupStack::PopAndDestroy();
        
        if ( VerifyChecksum( hmmPtr, checksum) )
            {
            CSIModel* model = CSIModel::NewLC(modelID);
            HBufC8* aAcousticModel=HBufC8::NewL(length); 
            *aAcousticModel=hmmPtr;
            model->SetAcousticModel(aAcousticModel);
            modelBank->AddL((CSIModel*)model);
            //!
            // Cleanup aAcousticModel and hmmBuf
            CleanupStack::Pop();
            CleanupStack::PopAndDestroy();
            
            }
        else
            {
            User::Leave( KErrCorrupt );
            }
        }
    
    // Keep the reference of the modelBank
    //User::LeaveIfError(iModelBankArray.Append(modelBank));
    // Cleanup modelBank
    CleanupStack::Pop();
    
    // Cleanup view
    CleanupStack::PopAndDestroy();
    
    return modelBank;
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::AllAcousticModelsL
// Loads all acoustic models within the specified model bank into a model bank
// object, which is loaded into recognizer during recognition session.
// -----------------------------------------------------------------------------
//
const CSIModelBank* CSIModelBankDB::AllAcousticModelsL( TSIModelBankID aModelBankID )
    {
    // Construct the table name using the provided model bank ID
    TBuf<40> KModelBankName(KSIModelBankTable);
    KModelBankName.AppendNumUC(aModelBankID);
    
    TBuf<100> KSQLStatement;
    // Declare a literal string to hold the SQL statement
    // SELECT  KHmmColumn, KHmmChecksumColumn FROM KModelBankName
    _LIT(KSQLSelect1, "SELECT * ");
    _LIT(KSQLSelect2, " FROM ");
    
    KSQLStatement = KSQLSelect1;
    //	KSQLStatement.Append(KHmmColumn);
    //	KSQLStatement.Append(KNext);
    //	KSQLStatement.Append(KHmmChecksumColumn);
    KSQLStatement.Append(KSQLSelect2);
    KSQLStatement.Append(KModelBankName);
    RDbView view;
    CleanupClosePushL(view);
    User::LeaveIfError(view.Prepare(iDb, TDbQuery(KSQLStatement, EDbCompareNormal)));
    User::LeaveIfError(view.EvaluateAll());
    
    // Get column set for column ordinals
    CDbColSet* columns = view.ColSetL();
    TDbColNo hmm_col = columns->ColNo(KHmmColumn);
    TDbColNo hmmchecksum_col = columns->ColNo(KHmmChecksumColumn);
    delete columns;
    
    // Create a model bank object
    CSIModelBank* modelBank = CSIModelBank::NewLC(aModelBankID);
    
    TSIModelID modelID=KModelID;
    TInt length;
    TInt32 checksum;
    // After evaluation, the first call to NextL() is equivalent to FirstL()
    while ( view.NextL() )
        {
        // Retrieve the current row
        view.GetL();
        length = view.ColLength(hmm_col);
        checksum = view.ColUint32(hmmchecksum_col);
        
        // Read the acoustic model into a buffer
        TUint8* hmmBuf = new (ELeave) TUint8[length];
        CleanupStack::PushL(hmmBuf);
        TPtr8 hmmPtr(hmmBuf, 0, length);
        RDbColReadStream colReadStrm;
       	colReadStrm.OpenLC(view, hmm_col);
       	colReadStrm.ReadL(hmmPtr, length);
        // Cleanup colReadStrm
        CleanupStack::PopAndDestroy();

#ifdef __SIND_HMMS_TO_FILE
        {
        TInt error( KErrNone );
        RFile sampleFile; 
        RFs fileSession; 
        User::LeaveIfError( fileSession.Connect() );

        _LIT( KCDrive,"c:\\" ); 
        _LIT( KFileName, "data\\rec\\hmm_%08d.raw" ); 
        _LIT( KStartOfYear, "20060101:000000.000000" ); 
        TTime startOfYear( KStartOfYear ); 
        TTimeIntervalSeconds secondsSince; 
        TTime nowtime; 
        nowtime.UniversalTime(); 
        nowtime.SecondsFrom( startOfYear, secondsSince );

        TFileName fileName; 
        fileName.Append( KCDrive ); 
        fileName.AppendFormat( KFileName, secondsSince.Int() ); 
        error = sampleFile.Replace( fileSession, fileName, EFileWrite );
        if ( !error ) 
            {
            TPtr8 ptr( hmmBuf, length ); 
            ptr.SetLength( length ); 
            sampleFile.Write( ptr );
            sampleFile.Close();
            }   
        fileSession.Close();
        }
#endif
        
        if ( VerifyChecksum( hmmPtr, checksum) )
            {
            CSIModel* model = CSIModel::NewLC(modelID);
            HBufC8* aAcousticModel=HBufC8::NewL(length); 
            *aAcousticModel=hmmPtr;
            SetAcousticModelL(aAcousticModel->Des());
            model->SetAcousticModel(aAcousticModel);
            modelBank->AddL((CSIModel*)model);
            //!
            // Cleanup aAcousticModel and hmmBuf
            CleanupStack::Pop();
            CleanupStack::PopAndDestroy();
            }
        else
            {
            User::Leave( KErrCorrupt );
            }
        }
    
    // Keep the reference of the modelBank
    User::LeaveIfError(iModelBankArray.Append(modelBank));
    // Cleanup modelBank
    CleanupStack::Pop();
    // Cleanup view
    CleanupStack::PopAndDestroy();
    
    return modelBank;
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::AllModelCountL
// Returns the total number of models in the system (all model banks).
// -----------------------------------------------------------------------------
//
TInt CSIModelBankDB::AllModelCountL()
    {
    TBuf<100> KSQLStatement;
    // Declare a literal string to hold the SQL statement
    // SELECT KCounterColumn FROM KModelBankIdTable WHERE KUsedColumn = KUsed
    _LIT(KSQLSelect1, "SELECT ");
    _LIT(KSQLSelect2, " FROM ");
    _LIT(KSQLSelect3, " WHERE ");
    
    KSQLStatement = KSQLSelect1;
    KSQLStatement.Append(KCounterColumn);
    KSQLStatement.Append(KSQLSelect2);
    KSQLStatement.Append(KModelBankIdTable);
    KSQLStatement.Append(KSQLSelect3);
    KSQLStatement.Append(KUsedColumn);
    KSQLStatement.Append(KEqual);
    KSQLStatement.AppendNum(KUsed);
    
    RDbView view;
    CleanupClosePushL(view);
    User::LeaveIfError(view.Prepare(iDb, TDbQuery(KSQLStatement, EDbCompareNormal)));
    User::LeaveIfError(view.EvaluateAll());
    
    // Get column set for column ordinals
    CDbColSet* columns = view.ColSetL();
    
    delete columns;
    
    TInt counter = 0;
    // After evaluation, the first call to NextL() is equivalent to FirstL()
    while ( view.NextL() )
        {
        // Retrieve the current row
        view.GetL();
        //counter += view.ColInt(counter_col);
        //!
        counter ++;//=view.ColInt(used_col); 
        }
    
    // Cleanup view
    CleanupStack::PopAndDestroy();
    
    return counter;
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::CreateIDTableL
// Creates a new model bank ID table in the database.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::CreateIDTableL()
    {
    // Invoke function in the base class CSICommonDB.
    CSICommonDB::CreateIDTableL(KModelBankIdTable, KModelBankIdColumn, KModelBankIndex);
    };

// -----------------------------------------------------------------------------
// CSIModelBankDB::CreateModelBankL
// Creates a new model bank table in the database.
// -----------------------------------------------------------------------------
//
TSIModelBankID CSIModelBankDB::CreateModelBankL( TUid aClientUid )
    {
    RUBY_DEBUG_BLOCK( "CSIModelBankDB::CreateModelBankL" );
    
    // Model bank is already exist in the 
    RArray<TSIModelBankID> aExistModelBankIDs;
    CleanupClosePushL( aExistModelBankIDs );
    GetAllClientModelBankIDsL(aClientUid,aExistModelBankIDs);
    
    
    if(aExistModelBankIDs.Count()>0) {
        TSIModelBankID aExistModelBankID=aExistModelBankIDs[0];	
        CleanupStack::PopAndDestroy( &aExistModelBankIDs );
        return aExistModelBankID;
        }
    CleanupStack::PopAndDestroy( &aExistModelBankIDs );
    
    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, sizeof( CSIModelBank ) ) );
    
    // Generate a new model bank ID
    TSIModelBankID modelBankID = STATIC_CAST(TSIModelBankID,CreateNewIDL(KModelBankIdTable, KModelBankIdColumn, aClientUid));
    // Construct the table name using the new model bank ID
    TBuf<40> KModelBankName(KSIModelBankTable);
    KModelBankName.AppendNumUC(modelBankID);
    // Create a table definition
    CDbColSet* columns=CDbColSet::NewLC();
    
    // add the columns  
    // 1) Binary data, 2) binary data size
    columns->AddL(TDbCol(KHmmColumn,EDbColLongBinary));
    columns->AddL(TDbCol(KHmmChecksumColumn,EDbColUint32));
    
    // Create a table
    TInt err =iDb.CreateTable(KModelBankName,*columns);
    
    if ( err != KErrNone )
        {
        // Failed to create the table.
        // Need to release the new ModelBank ID and leave.
        ReleaseIdL(KModelBankIdTable, KModelBankIdColumn, modelBankID);
        User::Leave(err);
        }
    
    // cleanup the column set
    CleanupStack::PopAndDestroy();
    
    // Put and empty Modelbank inside
        {
        //!!! Use the default model file to construct	
        //!
        HBufC8 *bf=NULL;		
        bf= iDataLoader->LoadData( KModelBankPackageType,KModelBankLanguageType,KModelBankStartPos,KMaxTUint32);
        // Modelbank file does not exist;
        if(bf==NULL)
            User::Leave(KErrNotFound);
        CleanupStack::PushL(bf);
        
        iAcousticModelPtr.Set(bf->Des());
        //.Set(_L8("empty"));
        //iAcousticModelPtr=(_L8("empty"));
        // Always 1 for each model bank
        //TSIModelID modelID=KModelID; 
        
        TInt32 hmmChecksum = CalculateChecksum(iAcousticModelPtr);
        
        // Open model bank table
        RDbTable dbTable;		// Provides access to table data as a rowset
        User::LeaveIfError(dbTable.Open(iDb, KModelBankName, RDbTable::EUpdatable));
        CleanupClosePushL(dbTable);
        
        // Get column set for column ordinals
        columns = dbTable.ColSetL();
        TDbColNo hmm_col = columns->ColNo(KHmmColumn);
        TDbColNo hmmchecksum_col = columns->ColNo(KHmmChecksumColumn);
        delete columns;
        
        // 		 No, insert new row
        dbTable.InsertL();
        dbTable.SetColL(hmm_col, iAcousticModelPtr);
        
        dbTable.SetColL(hmmchecksum_col, hmmChecksum);
        
        // Write the updated row
        TRAPD(err, dbTable.PutL());
        if( err != KErrNone )
            {
            // Error: cancel update
            dbTable.Cancel();
            dbTable.Reset();
            User::Leave(err);
            }
        
        // Cleanup bf dbTable 
        CleanupStack::PopAndDestroy(2);
        // Free up resources
        Reset();
        }
        
    iDbSession.FreeReservedSpace( iDrive );
        
    //AllAcousticModelsL(modelBankID);
    return modelBankID;
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::GetAllClientModelBankIDsL
// This function returns all model bank IDs owned by the specified client.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::GetAllClientModelBankIDsL( TUid aClientUid,
                                                RArray<TSIModelBankID>& aModelBankIDs )
    {
    // This is a hack to get the id aligned to 4-byte boundary,
    // for some reason this does not happen in winscw build if 
    // TSIModelBankID is taken from stack.
    TSIModelBankID* id = new (ELeave) TSIModelBankID;
    CleanupStack::PushL( id );
    
    RArray<TUint32> ix;
    ix.Reset();
    GetAllClientIDsL(KModelBankIdTable, KModelBankIdColumn, aClientUid, ix);
    for(TInt i=0;i<ix.Count();i++) 
        {
        *id = STATIC_CAST( TSIModelBankID, ix[i] );
        aModelBankIDs.Append( *id );
        }
    ix.Close();
    CleanupStack::PopAndDestroy( id );
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::GetAllModelBankIDsL
// This function returns all model bank IDs in the database.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::GetAllModelBankIDsL( RArray<TSIModelBankID>& aModelBankIDs )
    {
    // This is a hack to get the id aligned to 4-byte boundary,
    // for some reason this does not happen in winscw build if 
    // TSIModelBankID is taken from stack.
    TSIModelBankID* id = new ( ELeave ) TSIModelBankID;
    CleanupStack::PushL( id );
    
    RArray<TUint32> ix;
    ix.Reset();
    GetAllIDsL( KModelBankIdTable, KModelBankIdColumn, ix );
    for ( TInt i = 0; i < ix.Count(); i++ ) 
        { 
        *id = STATIC_CAST( TSIModelBankID, ix[i] );
        aModelBankIDs.Append( *id );
        }
    ix.Close();
    CleanupStack::PopAndDestroy( id );
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::GetAllModelIDsL
// This function returns all model IDs within the specified model bank. It's
// expected that the client has already done allocation on aModelIDs array object.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::GetAllModelIDsL( TSIModelBankID /*aModelBankID*/,
                                     RArray<TSIModelID>& aModelIDs )
    {
    // Only one id , and it is KModelID
    aModelIDs.Append(KModelID);	
    }
	
// -----------------------------------------------------------------------------
// CSIModelBankDB::IsModelBankValidL
// Checks if the specified model bank table exists in the database and also verify
// ownership.
// -----------------------------------------------------------------------------
//
TBool CSIModelBankDB::IsModelBankValidL( TUid aClientUid,
                                         TSIModelBankID aModelBankID )
    {
    VerifyOwnershipL(aClientUid, KModelBankIdTable, KModelBankIndex, aModelBankID);
    return ETrue;
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::IsModelValidL
// Checks if the specified model exists in the specified model bank table.
// -----------------------------------------------------------------------------
//
TBool CSIModelBankDB::IsModelValidL( TSIModelBankID /*aModelBankID*/,
                                     TSIModelID aModelID )
    {
    // Assume that ModelBankd ID is valid
    if (aModelID==KModelID)
        {
        return ETrue;
        }
    else
        {
        return EFalse;
        }
    }
    
// -----------------------------------------------------------------------------
// CSIModelBankDB::UpdateModelBankIfInvalidL
// Validate the adapted model bank against ROM version and update if not valid.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::UpdateModelBankIfInvalidL( TSIModelBankID aModelBankID )
    {    
    RUBY_DEBUG_BLOCK( "CSIModelBankDB::UpdateModelBankIfInvalidL" );
    
    const TUint KModelBankHeaderSize(20);
    
    HBufC8 *bf = iDataLoader->LoadData( KModelBankPackageType,
                                        KModelBankLanguageType,
                                        KModelBankStartPos,
                                        KMaxTUint32 );
    
    if( bf == NULL )
        {
        // Modelbank file does not exist;
        User::Leave( KErrNotFound );
        }
        
    CleanupStack::PushL( bf );
    
    TPtr8 origModelPtr( bf->Des() );

    // Compare phoneme definitions
    TBool areEqual( EFalse );
    
    TRAPD( error, 
        const CSIModelBank* adaptedModelBank = GetAllAcousticModelsL( aModelBankID );
        CleanupStack::PushL( (CSIModelBank*)adaptedModelBank );

        TPtrC8 adaptedModelPtr = adaptedModelBank->AtL(0).AcousticModel();
        
        // 1. Compare size of phoneme definition
        TInt adaptedSize = adaptedModelPtr[18];
        adaptedSize |= adaptedModelPtr[19] << 8;
            
        TInt origSize = origModelPtr[18];
        origSize |= origModelPtr[19] << 8;
        
        if ( adaptedSize == origSize )
            {
            // 2. compare content of phoneme definitions
            TInt size = origSize + KModelBankHeaderSize;
            if ( Mem::Compare( origModelPtr.Ptr(), size, adaptedModelPtr.Ptr(), size ) == 0 )
                {
                areEqual = ETrue;
                }
            }

        CleanupStack::PopAndDestroy( (CSIModelBank*)adaptedModelBank );
    );
    
    // GetAllAcousticModelsL will leave with KErrCorrupt if checksum doesn't match
    // This case should be handled by updating model bank
    if ( error != KErrNone && error != KErrCorrupt )
        {
        User::Leave( error );
        }
    
    if ( !areEqual )
        {
        // replace the adapted model bank with the original model bank
        RUBY_DEBUG0("phoneme definitions changed or model bank corrupted, update models" );
        
        SetAcousticModelL( origModelPtr );
        SaveModelL( aModelBankID );
        }

    CleanupStack::PopAndDestroy( bf );
    }
    
// -----------------------------------------------------------------------------
// CSIModelBankDB::GetUtteranceDurationL
//
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::GetUtteranceDurationL( TSIModelBankID /*aModelBankID*/, 
                                            TSIModelID /*aModelID*/,
                                            TTimeIntervalMicroSeconds32& /*aDuration*/ )
    {
    User::Leave(KErrNotSupported);
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::ModelCountL
// Returns the number of models in the specified model bank.
// -----------------------------------------------------------------------------
//
TInt CSIModelBankDB::ModelCountL( TSIModelBankID /*aModelBankID*/ )
    {
    
    //User::Leave(KErrNotSupported);
    return 1;
    // one model per modelbank by defination
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::RemoveModelBankL
// Deletes a model bank table from the database.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::RemoveModelBankL( TUid aClientUid,
                                       TSIModelBankID aModelBankID )
    {
    VerifyOwnershipL(aClientUid, KModelBankIdTable, KModelBankIndex, aModelBankID);
    
    TInt diskSpace = ( ModelCountL(aModelBankID) * sizeof( CSIModel ) )
        + sizeof( CSIModelBank );
    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, diskSpace ) );
    
    // Construct the table name using the provided model bank ID
    TBuf<40> KModelBankName(KSIModelBankTable);
    KModelBankName.AppendNumUC(aModelBankID);
    
    TBuf<50> KSQLStatement;
    // Declare a literal string to hold the SQL statement
    // DROP TABLE KModelBankName
    _LIT(KSQLDelete1, "DROP TABLE ");
    
    KSQLStatement = KSQLDelete1;
    KSQLStatement.Append(KModelBankName);
    
    User::LeaveIfError(iDb.Execute(KSQLStatement));
    
    // Release the ModelBank ID
    ReleaseIdL(KModelBankIdTable, KModelBankIdColumn, aModelBankID);
    
    // Cancel free disk space request
    iDbSession.FreeReservedSpace( iDrive );
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::RemoveModelL
// Removes a model from the model bank table by marking it as "not used".
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::RemoveModelL( TUid /*aClientUid*/,
                                   TSIModelBankID /*aModelBankID*/,
                                   TSIModelID /*aModelID*/ )
    {
    User::Leave(KErrNotSupported);
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::Reset
// Deallocates the temporary memory allocated during training.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::Reset()
    {
    iAcousticModelPtr.Set(0,0,0);
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::Reset
// Deallocates the temporary memory allocated during recognition.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::ResetAndDestroy()
    {
    iModelBankArray.ResetAndDestroy();
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::SaveModelL
// Saves the trained model in the temporary memory into the database.
// -----------------------------------------------------------------------------
//
TSIModelID CSIModelBankDB::SaveModelL( TSIModelBankID aModelBankID )
    {
    if ( iAcousticModelPtr.Length() <= 0 )
        {
        User::Leave(KErrNotReady);
        }

    User::LeaveIfError( iDbSession.ReserveDriveSpace( iDrive, sizeof( CSIModel ) ) );
    
    // Always 1 for each model bank
    TSIModelID modelID=KModelID; 
    // Construct the table name using the provided model bank ID
    TBuf<40> KModelBankName(KSIModelBankTable);
    KModelBankName.AppendNumUC(aModelBankID);
    
    TInt32 hmmChecksum = CalculateChecksum(iAcousticModelPtr);
    
    // Open model bank table
    RDbTable dbTable;		// Provides access to table data as a rowset
    User::LeaveIfError(dbTable.Open(iDb, KModelBankName, RDbTable::EUpdatable));
    CleanupClosePushL(dbTable);
    
    // Get column set for column ordinals
    CDbColSet* columns = dbTable.ColSetL();
    TDbColNo hmm_col = columns->ColNo(KHmmColumn);
    TDbColNo hmmchecksum_col = columns->ColNo(KHmmChecksumColumn);
    delete columns;
    
    // 		Update it
    dbTable.FirstL(); 	
    dbTable.UpdateL();
    
    dbTable.SetColL(hmm_col, iAcousticModelPtr);
    dbTable.SetColL(hmmchecksum_col, hmmChecksum);
    
    // Write the updated row
    TRAPD(err, dbTable.PutL());
    if( err != KErrNone )
        {
        // Error: cancel update
        dbTable.Cancel();
        dbTable.Reset();
        User::Leave(err);
        }
    iDbSession.FreeReservedSpace( iDrive );
    // Cleanup dbTable
    CleanupStack::PopAndDestroy();
    // Free up resources
    Reset();
    
    return modelID;
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::SetAcousticModelL
// Saves the acoustic model into a temporary memory during training.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::SetAcousticModelL( const TPtr8& aAcousticModelBuf )
    {
    if ( aAcousticModelBuf.Length() <= 0 )
        {
        User::Leave(KErrNotReady);
        }
    
    iAcousticModelPtr.Set(aAcousticModelBuf);
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::SetUtteranceDurationL
// Saves the utterance duration of a trained model in temporary memory during
// training.
// -----------------------------------------------------------------------------
//
void CSIModelBankDB::SetUtteranceDurationL( TInt /*aUtteranceDuration*/ )
    {
    User::Leave( KErrNotSupported );
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::CalculateChecksum
// Calculates a checksum value for the given buffer.
// -----------------------------------------------------------------------------
//
TInt32 CSIModelBankDB::CalculateChecksum( const TPtr8& aBuf )
    {
    TInt32 checksum = 0;
    TInt length = aBuf.Length();
    
    for( TInt i = 0; i < length; i++ )
        {
        checksum += aBuf[i];
        }
    return checksum;
    }

// -----------------------------------------------------------------------------
// CSIModelBankDB::VerifyChecksum
// Verifies the checksum value for the given buffer by comparing it with the
// provided aChecksum value.
// -----------------------------------------------------------------------------
//
TBool CSIModelBankDB::VerifyChecksum( const TPtr8& aBuf,
                                      TInt32 aChecksum )
    {
    TInt32 checksum = CalculateChecksum(aBuf);
    return (checksum == aChecksum);
    }


// -----------------------------------------------------------------------------
// Unit Test only
// -----------------------------------------------------------------------------
//
#ifdef __CONSOLETEST__
// Returns array of loaded model banks
RPointerArray<CSIModelBank>& CSIModelBankDB::ModelBankArray()
    {
    return iModelBankArray;
    }

#endif

//  End of File