/*
 * MonitorWlasciwosci.h
 *
 * Autor: Pawe Gala
 */

#ifndef MONITORWLASCIWOSCI_H_
#define MONITORWLASCIWOSCI_H_

#include <e32base.h>        // CActive
#include <e32property.h>    // RProperty

/**
 * Klasa identyfikatora waciwoci
 */
class TIdWlasciwosci
    {
public:
    TUid iKategoria;
    TUint iKlucz;
    };

/**
 * Interfejs zwrotny
 */
class MMonitorWlasciwosci
    {
public:
    virtual void ZmianaWartosciL( const TIdWlasciwosci& aId, TInt aWartosc ) = 0;
    virtual void ZmianaWartosciL( const TIdWlasciwosci& aId, const TDesC8& aWartosc )= 0;
    virtual void ZmianaWartosciL( const TIdWlasciwosci& aId, const TDesC16& aWartosc ) = 0;
    
    /**
     * Metoda powinna zwrci ETrue, jeeli monitor ma kontynuowa obserwowanie
     * waciwoci. W przeciwnym wypadku musi zosta zwrcona warto EFalse.
     */
    virtual TBool Blad( const TIdWlasciwosci& aId, TInt aBlad ) = 0;
    };

class CMonitorWlasciwosci : public CActive
    {
public:
    // Definiujemy wasny typ waciwoci, aby mc odrni
    // EByteArray od ETekst oraz ELargeByteArray od ELargeText
    // (w enumeratorze RProperty::TType ich wartoci si powtarzaj).
    enum TTypWlasciwosci
        {
        ELiczbaCalkowita,
        ETablicaBajtow,
        ETekst,
        EDuzaTablicaBajtow,
        EDuzyTekst
        };
public:        // Konstruktor dwufazowy i destruktor
    static CMonitorWlasciwosci* NewL( const TIdWlasciwosci& aId,
                    TTypWlasciwosci aTyp,
                    MMonitorWlasciwosci& aMonitorWlasciwosci,
                    TBool aObserwujTeraz = EFalse );
    virtual ~CMonitorWlasciwosci();
    
public:
    TInt ObserwujTeraz();
    
protected:    // Konstruktory pierwszej i drugiej fazy
    CMonitorWlasciwosci( const TIdWlasciwosci& aId,
            TTypWlasciwosci aTyp,
            MMonitorWlasciwosci& aMonitorWlasciwosc );
    void ConstructL( TBool aObserwujTeraz );
    
private:    // Odziedziczone z CActive
    void DoCancel();
    void RunL();
    TInt RunError( TInt aError );
    
private:
    void OdczytajTabliceBajtowL( TInt aMaksRozmiar );
    void OdczytajTekstL( TInt aMaksRozmiar );
    
private:
    MMonitorWlasciwosci& iMonitorWlasciwosci;
    
    RProperty iWlasciwosc;
    TTypWlasciwosci iTyp;
    TIdWlasciwosci iId;
    };

#endif /* MONITORWLASCIWOSCI_H_ */


/*
 * MonitorWlasciwosci.cpp
 *
 * Autor: Pawe Gala
 */

#include "MonitorWlasciwosci.h"


CMonitorWlasciwosci* CMonitorWlasciwosci::NewL( const TIdWlasciwosci& aId,
                        TTypWlasciwosci aTyp,
                        MMonitorWlasciwosci& aMonitorWlasciwosci,
                        TBool aObserwujTeraz )
    {
    CMonitorWlasciwosci* self = new( ELeave ) CMonitorWlasciwosci( aId, 
aTyp,
                                    aMonitorWlasciwosci );
    CleanupStack::PushL( self );
    self->ConstructL( aObserwujTeraz );
    CleanupStack::Pop( self );
    return self;
    }
    
CMonitorWlasciwosci::CMonitorWlasciwosci( const TIdWlasciwosci& aId,
                        TTypWlasciwosci aTyp,
                        MMonitorWlasciwosci& aMonitorWlasciwosci )
:CActive( EPriorityStandard )
,iId( aId )
,iTyp( aTyp )
,iMonitorWlasciwosci( aMonitorWlasciwosci )
    {
    CActiveScheduler::Add( this );
    }
    
CMonitorWlasciwosci::~CMonitorWlasciwosci()
    {
    Cancel();
    iWlasciwosc.Close();
    }
    
void CMonitorWlasciwosci::ConstructL( TBool aObserwujTeraz )
    {    
    TInt blad = iWlasciwosc.Attach( iId.iKategoria, iId.iKlucz );
    if( blad == KErrNone && aObserwujTeraz )
        {
        blad = ObserwujTeraz();
        }
    User::LeaveIfError( blad );
    }
    
TInt CMonitorWlasciwosci::ObserwujTeraz()
    {
    TInt blad = KErrNone;
    if( IsActive() )
        {
        blad = KErrInUse;
        }
    else
        {
        iWlasciwosc.Subscribe( iStatus );
        SetActive();
        }
    return blad;
    }
    
void CMonitorWlasciwosci::DoCancel()
    {
    iWlasciwosc.Cancel();
    }

void CMonitorWlasciwosci::RunL()
    {
    // Metoda RunL() wywoana zostanie w dwch przypadkach:
    // 1. jeli utworzona zostanie waciwo, ktra ma by obserwowana;
    // 2. jeli zmieni si warto obserwowanej waciwoci.
    
    TInt blad = iStatus.Int();
    
    if( blad == KErrNone && ( iTyp < 0 || iTyp >= RProperty::ETypeLimit) )
        {
        // Nigdy nie powinno si zdarzy.
        blad = KErrGeneral;
        }
    
    if( blad )
        {
        if( !iMonitorWlasciwosci.Blad( iId, blad ) )
            {
            return;
            }
        }
    
    // Musimy jak najszybciej uruchomi usug powiadamiania, tak aby adna
    // zmiana wartoci obserwowanej wasnoci nam nie umkna.
    ObserwujTeraz();
    
    // Jeeli wystpi bd, to nie ma sensu pobiera wartoci waciwoci.
    if( blad )
        {
        return;
        }
    
    // Obsugujemy zmian wartoci waciwoci.
    switch( iTyp )
        {
        case ELiczbaCalkowita:
            {
            TInt wartosc = 0;
            User::LeaveIfError( RProperty::Get( iId.iKategoria, iId.iKlucz, wartosc ) );
            iMonitorWlasciwosci.ZmianaWartosciL( iId, wartosc );
            }
            break;
        case ETablicaBajtow:
            {            
            OdczytajTabliceBajtowL( RProperty::KMaxPropertySize );
            }
            break;
        case ETekst:
            {                
            OdczytajTekstL( RProperty::KMaxPropertySize / 2 );
            }
            break;
        case EDuzaTablicaBajtow:
            {
            OdczytajTabliceBajtowL( RProperty::KMaxLargePropertySize );
            }
            break;
        case EDuzyTekst:
            {                
            OdczytajTekstL( RProperty::KMaxLargePropertySize / 2 );
            }
            break;
        }
    }

TInt CMonitorWlasciwosci::RunError( TInt aError )
    {
    // Nastpio wyjcie w metodzie RunL() - raportujemy bd.
    if( !iMonitorWlasciwosci.Blad( iId, aError ) )
        {
        // Przerywamy obserwowanie waciwoci.
        Cancel();
        }
    
    // Bd zosta obsuony - nie chcemy, aby Zarzdca Aktywnoci nas
    // spanikowa, wic zwracamy KErrNone.
    return KErrNone;
    }

void CMonitorWlasciwosci::OdczytajTabliceBajtowL( TInt aMaksRozmiar )
    {
    HBufC8* desk8 = HBufC8::NewLC( aMaksRozmiar );
    TPtr8 desk8Wsk = desk8->Des();
    
    User::LeaveIfError( RProperty::Get( iId.iKategoria, iId.iKlucz, desk8Wsk ) );
    iMonitorWlasciwosci.ZmianaWartosciL( iId, *desk8 );
    
    CleanupStack::PopAndDestroy( desk8 );
    }

void CMonitorWlasciwosci::OdczytajTekstL( TInt aMaksRozmiar )
    {
    HBufC16* desk16 = HBufC16::NewLC( aMaksRozmiar );
    TPtr16 desk16Wsk = desk16->Des();
    
    User::LeaveIfError( RProperty::Get( iId.iKategoria, iId.iKlucz, desk16Wsk ) );
    iMonitorWlasciwosci.ZmianaWartosciL( iId, *desk16 );
    
    CleanupStack::PopAndDestroy( desk16 );
    }
    

// ----------------
// Uycie klasy CMonitorWlasciwosci
// ----------------

// Definiujemy kategori oraz klucz waciwoci.
TUid kategoria( RProcess().SecureId() );
const TUint KKluczWlasciwosciInt = 1;

// Definiujemy waciwo.
TInt blad = RProperty::Define( kategoria, KKluczWlasciwosciInt, RProperty::EInt );
if( blad != KErrNone && blad != KErrAlreadyExists )
    {
    // Obsuga bdu
    User::Leave( blad );
    }

// Zapisujemy peny identyfikator waciwoci.
iIdWl.iKategoria = kategoria;
iIdWl.iKlucz = KKluczWlasciwosciInt;

// Tworzymy monitor i uruchamiamy monitor waciwoci.
iMonitorWl = CMonitorWlasciwosci::NewL( iIdWl, CMonitorWlasciwosci::ELiczbaCalkowita, *this, ETrue );

// ...
// Gdzie w programie zmieniamy warto waciwoci na 100:
RProperty::Set( iIdWl.iKategoria, iIdWl.iKlucz, 100 );
