/*
* Copyright (c) 2002-2007 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: 
*
*/


#include "AknNotifyPlugin.h"
#include <AknNotifyStd.h>

#include <eikenv.h>
#include <eikspane.h>
#include <avkon.hrh>
#include <eikspane.h>
#include <aknappui.h>

#include <bautils.h> // For NearestLanguageFile
#include <aknnotpi.rsg>

#include <AknNotifySignature.h>
#include <s32mem.h>
#include <e32capability.h>
#include <eiksrvsp.h>
#include "aknstatuspanedatapublisher.h"

const TInt KIndicatorTap = 0xFFFF;

void CAknMediatorEvent::RaiseEvent(TInt aId, const TDesC8& aBuf )
    {
    TInt err(0);
    if (iImpl)
        {
        if (iArray.Find(aId) == KErrNotFound)
            {
            err = iImpl->RegisterEvent( 
                KMediatorSecondaryDisplayDomain,
                KAknSecondaryDisplayCategory, 
                aId,
                TVersion(0,0,0),
                TCapabilitySet(ECapabilityReadDeviceData));
                
            if (!err)                
                {
                err = iArray.Append(aId);
                }
            }
            
        if (!err)
            { // ignore possible errors from now on...
            iImpl->RaiseEvent( 
                KMediatorSecondaryDisplayDomain,
                KAknSecondaryDisplayCategory, 
                aId,
                TVersion(0,0,0), 
                aBuf);
            }
        }
    }

NONSHARABLE_CLASS(CAknIndicatorData): public CBase
    {
public:
    void HandleIndicatorChanged(TInt aIndicator, TInt aState)
        {
        TInt index = KErrNotFound;    
        for (TInt i = 0; i < iArray.Count(); i++)
            {
            if (iArray[i].iIndicator == aIndicator)
                {
                index = i;
                break;
                }
            }
        if (index == KErrNotFound)
            {
            const SAknSmallIndicatorData data=
                {
                aIndicator, aState
                };
            if (aState != EAknIndicatorStateOff)
                {
                iArray.Append(data); // ignore return value
                }
            }
        else
            {
            if (aState == EAknIndicatorStateOff)
                {
                iArray.Remove(index);
                }
            else
                {
                iArray[index].iIndicatorState = aState;
                }    
            }    
        }
        
    void ExternalizeL(RWriteStream& aStream) const
        {
        TInt count = iArray.Count();
        aStream.WriteInt16L(count);
        for (TInt i = 0; i < count; i++)
            {
            aStream.WriteInt32L(iArray[i].iIndicator);
            aStream.WriteInt32L(iArray[i].iIndicatorState);
            }
        }
        
    ~CAknIndicatorData()
        {
        iArray.Close();
        }

    RArray<SAknSmallIndicatorData> iArray;
    };


void CAknPopupNotifierSubject::Release()
    {
    delete this;
    }

CAknPopupNotifierSubject::TNotifierInfo CAknPopupNotifierSubject::RegisterL()
    {
    iInfo.iUid=KAknPopupNotifierUid;
    iInfo.iChannel=KAknPopupNotifierUid;            // made up uid
    iInfo.iPriority=ENotifierPriorityVHigh;
    return iInfo;
    }

CAknPopupNotifierSubject::TNotifierInfo CAknPopupNotifierSubject::Info() const
    {
    return iInfo;
    }

TPtrC8 CAknPopupNotifierSubject::StartL(const TDesC8& aBuffer)
    {
    PopupL(aBuffer);
    return KNullDesC8();
    }

void CAknPopupNotifierSubject::StartL(const TDesC8& aBuffer, TInt /*aReplySlot*/, 
    const RMessagePtr2& aMessage)
    {
    PopupL(aBuffer);
    aMessage.Complete(EEikNotExtRequestCompleted);
    }

void CAknPopupNotifierSubject::Cancel()
    {
    }

TPtrC8 CAknPopupNotifierSubject::UpdateL(const TDesC8& aBuffer)
    {
    PopupL(aBuffer);
    return KNullDesC8();
    }

CAknPopupNotifierSubject* CAknPopupNotifierSubject::NewL()
    {
    CAknPopupNotifierSubject* self=new (ELeave) CAknPopupNotifierSubject();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

CAknPopupNotifierSubject::CAknPopupNotifierSubject()
    {
    }

void CAknPopupNotifierSubject::ConstructL()
    {
    }

void CAknPopupNotifierSubject::PopupL(const TDesC8& aBuffer)
    {
    TPtrC msg(reinterpret_cast<const TUint16*>(aBuffer.Ptr()), aBuffer.Length()/2);
    CEikonEnv::Static()->InfoWinL(_L("popup"), msg);
    }

void CAknSignalNotifierSubject::Release()
    {
    delete this;
    }

CAknSignalNotifierSubject::TNotifierInfo CAknSignalNotifierSubject::RegisterL()
    {
    iInfo.iUid=KAknSignalNotifierUid;
    iInfo.iChannel=KAknSignalNotifierUid;
    iInfo.iPriority=ENotifierPriorityVHigh;
    return iInfo;
    }

CAknSignalNotifierSubject::TNotifierInfo CAknSignalNotifierSubject::Info() const
    {
    return iInfo;
    }

TPtrC8 CAknSignalNotifierSubject::StartL(const TDesC8& aBuffer)
    {
    HandleSignalMessageL(aBuffer);
    return KNullDesC8();
    }

void CAknSignalNotifierSubject::StartL(const TDesC8& aBuffer, TInt /*aReplySlot*/, 
    const RMessagePtr2& aMessage)
    {
    HandleSignalMessageL(aBuffer);
    aMessage.Complete(EEikNotExtRequestCompleted);
    }

void CAknSignalNotifierSubject::Cancel()
    {
    }

TPtrC8 CAknSignalNotifierSubject::UpdateL(const TDesC8& aBuffer)
    {
    HandleSignalMessageL(aBuffer);
    return KNullDesC8();
    }

CAknSignalNotifierSubject* CAknSignalNotifierSubject::NewL(CAknMediatorEvent* aEvent)
    {
    CAknSignalNotifierSubject* self=new (ELeave) CAknSignalNotifierSubject();
    CleanupStack::PushL(self);
    self->iEvent = aEvent;
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

CAknSignalNotifierSubject::CAknSignalNotifierSubject()
    {
    }

CAknSignalNotifierSubject::~CAknSignalNotifierSubject()
    {
    }

void CAknSignalNotifierSubject::ConstructL()
    {
    }

void CAknSignalNotifierSubject::HandleSignalMessageL(const TDesC8& aBuffer)
    {
    SAknNotifierPackage<SAknSignalNotifyParams>* params = 
        (SAknNotifierPackage<SAknSignalNotifyParams>*)aBuffer.Ptr();
        
    if ( aBuffer.Length() < 0 
        || (TUint)aBuffer.Length() < sizeof(SAknNotifierPackage<SAknSignalNotifyParams>) 
        || params->iSignature != KAKNNOTIFIERSIGNATURE )
        {
        User::Leave( KErrArgument );
        }
    SAknSignalNotifyParams sParams = params->iParamData; //  safe

    CEikServStatusPane* ssp = static_cast<CEikServStatusPane*>(CEikStatusPaneBase::Current());
    CAknStatusPaneDataPublisher* publisher = ssp->iDataPublisher;
    
    if ( sParams.iValue != EAknSignalStateNotChanged )
        {
        publisher->SetSignalLevel(params->iParamData.iValue);
        }
        
    if ( sParams.iGprsState != EAknSignalGprsIndicatorBgTypeWipe && 
         sParams.iGprsState != EAknNaviPaneBackgroundTypeSolid &&
         sParams.iGprsState >= 0 )    
        {               
        publisher->SetSignalIcon( sParams.iGprsState );       
        }   
        
    publisher->PublishDataL();  

    TPckgBuf<SAknSignalNotifyParams> buf(sParams);
    iEvent->RaiseEvent(EAknSignalIndicatorSDInfo, buf );
    }

void CAknBatteryNotifierSubject::Release()
    {
    delete this;
    }

CAknBatteryNotifierSubject::TNotifierInfo CAknBatteryNotifierSubject::RegisterL()
    {
    iInfo.iUid=KAknBatteryNotifierUid;
    iInfo.iChannel=KAknBatteryNotifierUid;
    iInfo.iPriority=ENotifierPriorityVHigh;
    return iInfo;
    }

CAknBatteryNotifierSubject::TNotifierInfo CAknBatteryNotifierSubject::Info() const
    {
    return iInfo;
    }

TPtrC8 CAknBatteryNotifierSubject::StartL(const TDesC8& aBuffer)
    {
    HandleBatteryMessageL(aBuffer);
    return KNullDesC8();
    }

void CAknBatteryNotifierSubject::StartL(const TDesC8& aBuffer, TInt /*aReplySlot*/, 
    const RMessagePtr2& aMessage)
    {
    HandleBatteryMessageL(aBuffer);
    aMessage.Complete(EEikNotExtRequestCompleted);
    }

void CAknBatteryNotifierSubject::Cancel()
    {
    }

TPtrC8 CAknBatteryNotifierSubject::UpdateL(const TDesC8& aBuffer)
    {
    HandleBatteryMessageL(aBuffer);
    return KNullDesC8();
    }

CAknBatteryNotifierSubject* CAknBatteryNotifierSubject::NewL(CAknMediatorEvent* aEvent)
    {
    CAknBatteryNotifierSubject* self=new (ELeave) CAknBatteryNotifierSubject();
    CleanupStack::PushL(self);
    self->iEvent = aEvent;
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

CAknBatteryNotifierSubject::CAknBatteryNotifierSubject()
    {
    }

CAknBatteryNotifierSubject::~CAknBatteryNotifierSubject()
    {
    }

void CAknBatteryNotifierSubject::ConstructL()
    {
    }

void CAknBatteryNotifierSubject::HandleBatteryMessageL(const TDesC8& aBuffer)
    {
    SAknNotifierPackage<SAknBatteryNotifyParams>* params = 
        (SAknNotifierPackage<SAknBatteryNotifyParams>*)aBuffer.Ptr();

    if ( aBuffer.Length() < 0 
        || (TUint)aBuffer.Length() < sizeof(SAknNotifierPackage<SAknBatteryNotifyParams>) 
        || params->iSignature != KAKNNOTIFIERSIGNATURE )
        {
        User::Leave( KErrArgument );
        }

    CEikServStatusPane* ssp = static_cast<CEikServStatusPane*>(CEikStatusPaneBase::Current());
    CAknStatusPaneDataPublisher* publisher = ssp->iDataPublisher;
    switch ( params->iParamData.iType )
        {
        case SAknBatteryNotifyParams::ESetValue:
            {
            publisher->SetBatteryLevel(params->iParamData.iValue);
            break;
            }
        case SAknBatteryNotifyParams::ERecharge:
            {
            publisher->SetRecharge(ETrue);
            break;
            }
        case SAknBatteryNotifyParams::EStopRecharge:
            {
            publisher->SetRecharge(EFalse);
            break;
            }
        case SAknBatteryNotifyParams::ENoRecharge:
            {
            publisher->SetRecharge(EFalse);
            break;
            }
        case SAknBatteryNotifyParams::ESetState:
            {
            publisher->SetBatteryIcon( params->iParamData.iBatteryState );
            break;
            }
        default:
            break;
        }
    publisher->PublishDataL();  

    TPckgBuf<SAknBatteryNotifyParams> buf(params->iParamData );
    iEvent->RaiseEvent(EAknBatteryIndicatorSDInfo, buf);
    }

TInt CAknBatteryNotifierSubject::TickerCallback(TAny* aThis)
    {
    return static_cast<CAknBatteryNotifierSubject*>(aThis)->DoTick();
    }

TInt CAknBatteryNotifierSubject::DoTick()
    {
    return ETrue;
    }

void CAknSmallIndicatorSubject::Release()
    {
    delete this;
    }

CAknSmallIndicatorSubject::TNotifierInfo CAknSmallIndicatorSubject::RegisterL()
    {
    iInfo.iUid=KAknSmallIndicatorUid;
    iInfo.iChannel=KAknSmallIndicatorUid;
    iInfo.iPriority=ENotifierPriorityVHigh;
    return iInfo;
    }

CAknSmallIndicatorSubject::TNotifierInfo CAknSmallIndicatorSubject::Info() const
    {
    return iInfo;
    }

TPtrC8 CAknSmallIndicatorSubject::StartL(const TDesC8& aBuffer)
    {
    HandleIndicatorMessageL(aBuffer);
    return KNullDesC8();
    }

void CAknSmallIndicatorSubject::StartL(const TDesC8& aBuffer, TInt /*aReplySlot*/, 
    const RMessagePtr2& aMessage)
    {
    HandleIndicatorMessageL(aBuffer);
    aMessage.Complete(EEikNotExtRequestCompleted);
    }

void CAknSmallIndicatorSubject::Cancel()
    {
    }

TPtrC8 CAknSmallIndicatorSubject::UpdateL(const TDesC8& aBuffer)
    {
    HandleIndicatorMessageL(aBuffer);
    return KNullDesC8();
    }

CAknSmallIndicatorSubject* CAknSmallIndicatorSubject::NewL(CAknMediatorEvent* aEvent)
    {
    CAknSmallIndicatorSubject* self=new (ELeave) CAknSmallIndicatorSubject();
    CleanupStack::PushL(self);
    self->ConstructL();
    self->iEvent = aEvent; // do not store until leaving methods are clear
    CleanupStack::Pop();
    return self;
    }

CAknSmallIndicatorSubject::CAknSmallIndicatorSubject()
    {
    }

CAknSmallIndicatorSubject::~CAknSmallIndicatorSubject()
    {
    delete iIndicatorSDData;
    delete iEvent; // bit nasty, but does not have really effect even if not deleted at all
    }


void CAknSmallIndicatorSubject::ConstructL()
    {
    iIndicatorSDData = new (ELeave) CAknIndicatorData();
    }

void CAknSmallIndicatorSubject::HandleIndicatorMessageL(const TDesC8& aBuffer)
    {
    SAknNotifierPackage<SAknSmallIndicatorParams>* params = 
        (SAknNotifierPackage<SAknSmallIndicatorParams>*)aBuffer.Ptr();

    if ( aBuffer.Length() < 0 
        || (TUint)aBuffer.Length() < sizeof(SAknNotifierPackage<SAknSmallIndicatorParams>) 
        || params->iSignature != KAKNNOTIFIERSIGNATURE )
        {
        User::Leave( KErrArgument );
        }

    CEikServStatusPane* ssp = static_cast<CEikServStatusPane*>(CEikStatusPaneBase::Current());
    CAknStatusPaneDataPublisher* publisher = ssp->iDataPublisher;

    if (params->iParamData.iValue == KIndicatorTap)
        {
        publisher->HandleIndicatorTapL(params->iParamData.iSmallIndicatorUid);  
        }
    else
        {           
        publisher->SetIndicatorState(params->iParamData.iSmallIndicatorUid, params->iParamData.iValue);         
        publisher->PublishDataL();  

        // publish current indicator status to coverui    
        iIndicatorSDData->HandleIndicatorChanged(
            params->iParamData.iSmallIndicatorUid.iUid, 
            params->iParamData.iValue);
            
        CBufFlat* buf = CBufFlat::NewL(5);
        CleanupStack::PushL(buf);
        RBufWriteStream stream;
        stream.Open(*buf);
        CleanupClosePushL(stream);
        stream << *iIndicatorSDData;
        stream.CommitL();
        CleanupStack::PopAndDestroy();  // close stream           
        
        iEvent->RaiseEvent(EAknSmallIndicatorSDInfo, buf->Ptr(0) );
        CleanupStack::PopAndDestroy(buf);                    
        }
    }

void CAknIncallBubbleSubject::Release()
    {
    delete this;
    }


CAknIncallBubbleSubject::TNotifierInfo CAknIncallBubbleSubject::RegisterL()
    {
    iInfo.iUid=KAknIncallBubbleUid;
    iInfo.iChannel=KAknIncallBubbleUid;
    iInfo.iPriority=ENotifierPriorityVHigh;
    return iInfo;
    }

CAknIncallBubbleSubject::TNotifierInfo CAknIncallBubbleSubject::Info() const
    {
    return iInfo;
    }

TPtrC8 CAknIncallBubbleSubject::StartL(const TDesC8& aBuffer)
    {
    HandleIndicatorMessageL( aBuffer, 0 );
    return KNullDesC8();
    }

void CAknIncallBubbleSubject::StartL(const TDesC8& aBuffer, TInt /*aReplySlot*/, 
    const RMessagePtr2& aMessage)
    {
    RThread clientThread;
    TUint64 clientId = 0;
    if ( KErrNone == aMessage.Client( clientThread ) )
        {
        clientId = clientThread.Id().Id();
        }
    clientThread.Close();
    HandleIndicatorMessageL( aBuffer, clientId );
    aMessage.Complete(EEikNotExtRequestCompleted);
    }

void CAknIncallBubbleSubject::Cancel()
    {
    }

TPtrC8 CAknIncallBubbleSubject::UpdateL(const TDesC8& aBuffer)
    {
    HandleIndicatorMessageL(aBuffer,0);
    return KNullDesC8();
    }

CAknIncallBubbleSubject* CAknIncallBubbleSubject::NewL()
    {
    CAknIncallBubbleSubject* self=new (ELeave) CAknIncallBubbleSubject();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop();
    return self;
    }

CAknIncallBubbleSubject::CAknIncallBubbleSubject()
    {
    }

void CAknIncallBubbleSubject::ConstructL()
    {
    }

void CAknIncallBubbleSubject::HandleIndicatorMessageL( const TDesC8& aBuffer , const TUint64& aClientId  )
    {
    SAknNotifierPackage<SAknIncallBubbleParams>* params = 
        (SAknNotifierPackage<SAknIncallBubbleParams>*)aBuffer.Ptr();

    if ( aBuffer.Length() < 0 
        || (TUint)aBuffer.Length() < sizeof(SAknNotifierPackage<SAknIncallBubbleParams>) 
        || params->iSignature != KAKNNOTIFIERSIGNATURE )
        {
        User::Leave( KErrArgument );
        }
    
    CEikServStatusPane* ssp = static_cast<CEikServStatusPane*>(CEikStatusPaneBase::Current());
    CAknStatusPaneDataPublisher* publisher = ssp->iDataPublisher;
    TInt flags = params->iParamData.iIncallBubbleFlags;
    if ( flags & EAknStatusBubbleReservedInternal ) 
        {
        if (flags & 4)
            {
            publisher->SetIncallBubbleAllowedInUsual( ETrue , aClientId );
            }
        else if (flags & 2)
            {
            publisher->SetIncallBubbleAllowedInUsual( EFalse , aClientId );
            }
        else if (flags & 1)
            {
            publisher->SetIncallBubbleAllowedInIdle( ETrue );
            }
        else
            { 
            publisher->SetIncallBubbleAllowedInIdle( EFalse );
            }
        }
    else
        {
        publisher->SetIncallBubbleFlags( flags );
        }    

    publisher->PublishDataL();  
    }


