/*
* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "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:  class implementation
*
*/


#include "sysinfoservice.h"
#include "sysconnectionrequest.h"
#include "sysrequest.h"

const TInt KGranularity(2);

// --------------------------------------------------------------------
// CConnection::CConnection()
// C++ default constructor.
// --------------------------------------------------------------------
//
CConnection::CConnection( TSysRequest::TRequestType aReqType, TInt32 aTransID,
                            ISystemObserver* aObsrver):
                            CActiveRequest(aReqType,aTransID,aObsrver),
                            iConnectionCount(0), iConnectionIndex(1),
                            iConnectionInfoArray(KGranularity),	
                            iConnectionInit(ETrue)
    {
    }

// --------------------------------------------------------------------
// CConnection::~CConnection()
// Destructor.
// --------------------------------------------------------------------
//
CConnection::~CConnection()
    {
    Cancel();

    iConnectionInfoArray.Close();
    iConnMonitor.Close();

    delete iReadConnectionInfo;

    delete iEntity;
    delete iKey;
    }

// --------------------------------------------------------------------
// CConnection::NewL
// Two-phased constructor, returns instance of this class.
// --------------------------------------------------------------------
//
CConnection* CConnection::NewL(const TSysRequest& aRequest)
    {
    CConnection* self;
    self = new (ELeave) CConnection(aRequest.RequestType(),
                            aRequest.TransactionID(), aRequest.Observer());

    CleanupStack::PushL(self);
    self->ConstructL (aRequest);
    CleanupStack::Pop(self);

    return self;
    }

// --------------------------------------------------------------------
// CConnection::ConstructL
// 2nd Phase constructor to allocate required resources for this obj.
// --------------------------------------------------------------------
//
void CConnection::ConstructL(const TSysRequest& aRequest)
    {
    //connect
    User::LeaveIfError(iConnMonitor.ConnectL());

    // Make local copy of SA.
    iEntity = aRequest.Entity().AllocL();

    iKey	= aRequest.Key().AllocL();
    }
	
// --------------------------------------------------------------------
// CConnection::Request
// Issues connection request.
// --------------------------------------------------------------------
//
TInt CConnection::Request()
    {
    TInt err = KErrNone;
    if( !IsActive() )
        {
        //Retrieve all connections.		
        iConnMonitor.GetConnectionCount(iConnectionCount, iStatus);
        SetActive();
        if(TSysRequest::ENotification == RequestType())
            TRAP(err,iConnMonitor.NotifyEventL(*this));
        }
    return err;
    }

// --------------------------------------------------------------------
// CConnection::RunL
// Gets called in event of request completion or error situation.
// --------------------------------------------------------------------
//
void CConnection::RunL()
    {
    TSysRequest::TRequestType ReqType = RequestType();
    TInt32 transId = this->TransactionID();
    TInt error(iStatus.Int());

    if(error >= KErrNone)
        {
        // Read All Connected Connection IDs.
        for(TInt i=1; i<=iConnectionCount; i++)
            {
            TUint	ConnectioID,IgnoreSubConnects;
            iConnMonitor.GetConnectionInfo(i, ConnectioID, IgnoreSubConnects);
            iConnectionIds[i-1] = ConnectioID;
            }

        // read if thr are connections.
        if ( iConnectionCount > 0 )
            {
            //read the connections.
            ReadNextConnectionL();
            }
        else if( ReqType == TSysRequest::EASyncONESHOT )
            {	
            //create a copy of SA for response.
            CConnectionList* connList = CConnectionList::
                                            NewL(iConnectionInfoArray);
            //call observer.
            TRAP_IGNORE(SystemObserver()->HandleResponseL(*iEntity,*iKey,
                                    connList,transId,RequestType(),error));
            //remove this from active store.
            ActiveStore::RemoveRequest(transId);
            }
        }
    else // in case error.
        {
        //call observer.
        TRAP_IGNORE(SystemObserver()->HandleResponseL(*iEntity,*iKey,
                                    NULL,transId,RequestType(),error));
        }
    }

// --------------------------------------------------------------------
// CConnection::HandleConnectionInfoL
// Gets called when an ConnectionID Connection information is read.
// --------------------------------------------------------------------
//
void CConnection::HandleConnectionInfoL(CConnectionInfo*& aInfo,TInt error)
    {
    TInt32 transId = this->TransactionID();
    iReadConnectionInfo = NULL;

    if(TSysRequest::ENotification == RequestType())
        {
        iConnectionInfoArray.AppendL(aInfo);
        if( !iConnectionInit )
            {
            CConnectionInfo* conninfo = aInfo->CopyL();
            TRAP_IGNORE(SystemObserver()->HandleResponseL(*iEntity, *iKey,
                                    conninfo, transId, RequestType(), error));
            }
        }
    else
        {
        //Inc index.
        ++iConnectionIndex;

        //Add connection info to RArrayPointer.
        if( !error ) 
            iConnectionInfoArray.AppendL(aInfo);

        // check if some more connections exists.
        if( iConnectionIndex <= iConnectionCount)
            {
            ReadNextConnectionL();
            // don't send response.
            return;
            }

        //create a ConnectionList object.
        CConnectionList* connList = CConnectionList::NewL(iConnectionInfoArray);
        //call observer.
        TRAP_IGNORE(SystemObserver()->HandleResponseL(*iEntity, *iKey,
                                 connList, transId, RequestType(), error));

        // Remove this from active store.
        ActiveStore::RemoveRequest(TransactionID());
        }
    }

// --------------------------------------------------------------------
// CConnection::ReadNextConnectionL
// Creates CReadConnectionInfo request for an ConnectionID.
// --------------------------------------------------------------------
//
void CConnection::ReadNextConnectionL()
    {
    iReadConnectionInfo = CReadConnectionInfo::NewL(iConnMonitor,
                                    iConnectionIds[iConnectionIndex-1],
                                    this,CConnectionInfo::EConnected,
                                    TSysRequest::EASyncONESHOT);

    iReadConnectionInfo->Request();
    }

// --------------------------------------------------------------------
// CConnection::DoCancel
// cancel any notificatons.
// --------------------------------------------------------------------
//
void CConnection::DoCancel()
    {
    TSysRequest::TRequestType ReqType = RequestType();
    if(ReqType ==TSysRequest::ENotification )
        iConnMonitor.CancelNotifications();		
    }

// --------------------------------------------------------------------
// CConnection::EventL
// gets called whenever there is change in connections.
// --------------------------------------------------------------------
//
void CConnection::EventL(const CConnMonEventBase& aEvent)
    {
    TUint connectionId =0;
    CReadConnectionInfo* rdConnectionInfo = NULL;
    switch( aEvent.EventType() )
        {
        case EConnMonCreateConnection:
            iConnectionInit = EFalse;
            CConnMonCreateConnection* eventCreate; 
            eventCreate = (CConnMonCreateConnection*)& aEvent;
            connectionId = eventCreate->ConnectionId();	
            rdConnectionInfo = CReadConnectionInfo::NewL(iConnMonitor,
            					connectionId,
            					this,
            					CConnectionInfo::EConnected,
            					TSysRequest::ENotification);
            CleanupStack::PushL(rdConnectionInfo);
            // get connection details.
            User::LeaveIfError(rdConnectionInfo->Request());
            CleanupStack::Pop(rdConnectionInfo);
            break;

        case EConnMonDeleteConnection:
            CConnMonDeleteConnection* eventDelete; 
            eventDelete = (CConnMonDeleteConnection*)& aEvent;
            connectionId  = eventDelete->ConnectionId();

            for(TInt i=0; i<iConnectionInfoArray.Count(); i++)
                {
                CConnectionInfo* conninfo = iConnectionInfoArray[i];
                if( connectionId == conninfo->ConnectionId() )
                    {
                    CConnectionInfo* info = conninfo->CopyL();
                    info->SetConnectionState(CConnectionInfo::EDisconnected);
                    TRAP_IGNORE(SystemObserver()->HandleResponseL(
                                    *iEntity,*iKey,info,TransactionID(),
                                    RequestType(),KErrNone));
                                    
                    iConnectionInfoArray.Remove(i);
                    delete conninfo;
                    break;
                    }
                }
            break;

        default:
            break;
        }
    }
    
// --------------------------------------------------------------------
// CReadConnectionInfo::CReadConnectionInfo
// C++ default constructor.
// --------------------------------------------------------------------
//
CReadConnectionInfo::CReadConnectionInfo( RConnectionMonitor& aConnMon,
                        TUint aConnId, MConnectInfoCallback* aCallBack, 
                        CConnectionInfo::TConnectionState aState,
                        TSysRequest::TRequestType aReqType ) :
                        CActive(EPriorityNormal), iConnectionID(aConnId),
                        iCallBack(aCallBack), iConnMon(aConnMon),
                        iState(EInitial), iConnState(aState),iReqType(aReqType)
    {
    CActiveScheduler::Add(this);
    }

// --------------------------------------------------------------------
// CReadConnectionInfo::~CReadConnectionInfo
// Destructor.
// --------------------------------------------------------------------
//
CReadConnectionInfo::~CReadConnectionInfo()
    {
    Cancel();
    delete iIAPName;
    delete iNetworkName;
    delete iConnectionName;
    }

// --------------------------------------------------------------------
// CReadConnectionInfo::NewL
// Two-phased constructor, returns instance of this class.
// --------------------------------------------------------------------
//
CReadConnectionInfo* CReadConnectionInfo::NewL(RConnectionMonitor& aConnMon,
                            TUint aConnId,MConnectInfoCallback* aCallBack,
                            CConnectionInfo::TConnectionState aState,
                            TSysRequest::TRequestType aReqType )
    {
    CReadConnectionInfo* self = new (ELeave) CReadConnectionInfo(aConnMon,
                                        aConnId, aCallBack, aState, aReqType);
    return self;
    }

// --------------------------------------------------------------------
// CReadConnectionInfo::Request
// Issues ConnectionInfo read request.
// --------------------------------------------------------------------
//
TInt CReadConnectionInfo::Request()
    {
    if(!IsActive())
        {
        TRequestStatus* status = &iStatus;
        User::RequestComplete(status,KErrNone);
        SetActive();
        }
    return KErrNone;
    }

// --------------------------------------------------------------------
// CReadConnectionInfo::RunL
// Gets called in event of request completion or error situation.
// --------------------------------------------------------------------
//
void CReadConnectionInfo::RunL()
    {
    CConnectionInfo* connectionInfo=NULL;

    TInt error(iStatus.Int());
    if(error >= KErrNone)
        {
        switch(iState)
            {
            case EInitial:
                iConnMon.GetUintAttribute(iConnectionID, 0, KIAPId, iIAPId, iStatus);
                iState = EIAPId;
                break;

            case EIAPId:
                iConnMon.GetIntAttribute(iConnectionID, 0, KBearer,iBearerType, iStatus);
                iState = EBearerType;
                break;

            case EBearerType:
                iConnMon.GetStringAttribute(iConnectionID, 0, KIAPName, iNameBuf, iStatus);
                iState = EIAPName; 
                break;

            case EIAPName:
                iIAPName = iNameBuf.AllocL();
                iNameBuf.Zero();

                if(iBearerType == EBearerWLAN )
                    {
                    iConnMon.GetStringAttribute(iConnectionID, 0, 
                                        KNetworkName, iNameBuf, iStatus);
                    iState = ENetworkName;
                    }
                else
                    {
                    iConnMon.GetStringAttribute(iConnectionID, 0, 
                                    KAccessPointName, iNameBuf, iStatus);	
                    iState = EIAPConnectionName;
                    }
                break;

            case ENetworkName :
                iNetworkName = iNameBuf.AllocL();
                iNameBuf.Zero();
                connectionInfo = CConnectionInfo::NewL(iConnectionID, iIAPId,
                                        iBearerType, iConnState, *iIAPName,
                                        *iNetworkName, KNullDesC);

                iState = EComplete;
                break;

            case EIAPConnectionName:
                iConnectionName = iNameBuf.AllocL();	
                iNameBuf.Zero();

                connectionInfo = CConnectionInfo::NewL(iConnectionID, iIAPId,
                                        iBearerType, iConnState, *iIAPName,
                                        KNullDesC, *iConnectionName);
                iState = EComplete;	
            }
        }
    else
        {
        if (iState == EIAPConnectionName || iState == ENetworkName) 
            {
            connectionInfo = CConnectionInfo::NewL(iConnectionID, iIAPId,
                                    iBearerType, iConnState, *iIAPName,
                                    KNullDesC, KNullDesC);
            error = KErrNone;
            }
        iState = EComplete;
        }

    //if not complete read next attribute.
    if(iState != EComplete)
        SetActive();
    else
        {
        iCallBack->HandleConnectionInfoL(connectionInfo,error);
        delete this;
        }
    }

// --------------------------------------------------------------------
// CReadConnectionInfo::DoCancel
// cancels any ongoing request.
// --------------------------------------------------------------------
//
void CReadConnectionInfo::DoCancel()
    {
    if( IsActive() )
        {
        switch(iState)
            {
            case EIAPId:
                iConnMon.CancelAsyncRequest(EConnMonGetUintAttribute);
                break;
            case EBearerType: 
                iConnMon.CancelAsyncRequest(EConnMonGetIntAttribute);
                break;
            case EIAPName:
            case ENetworkName:
            case EIAPConnectionName:
                iConnMon.CancelAsyncRequest(EConnMonGetStringAttribute);
                break;

            default:
                iConnMon.CancelNotifications();
                break;
            }
        }
    }

// End of file
