/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "networkinfo_s60.h"
#include "trace.h"

//This const is added as alternative for EPacketNotifyDynamicCapsChange in pcktcs.h
const TInt KPacketNofityDynamicCapsChange = 40021;

#ifdef ETELMM_SUPPORTED
CNetworkMode::CNetworkMode(MNetworkObserver *aObserver, RMobilePhone &aMobilePhone)
    : CActive(EPriorityNormal),
      iNetworkMode(RMobilePhone::ENetworkModeUnknown),
      iObserver(aObserver),
      iMobilePhone(aMobilePhone)
{
    CActiveScheduler::Add(this);

    TInt err = iMobilePhone.GetCurrentMode(iNetworkMode);
    TRACES(qDebug() << "Current Network mode in ctr" <<  iNetworkMode);

    if (!err)
        StartMonitoring();
}

CNetworkMode::~CNetworkMode()
{
    Cancel();
}

void CNetworkMode::DoCancel()
{
    TRACES ( qDebug() << "CNetworkMode::DoCancel<--" );
    iMobilePhone.CancelAsyncRequest(EMobilePhoneNotifyModeChange);
    TRACES ( qDebug() << "CNetworkMode::DoCancel-->" );
}

void CNetworkMode::RunL()
{
    TRACES(qDebug() << "CNetworkMode::RunL-Networkmode is<--:" << iNetworkMode);
    if (iStatus.Int() == KErrNone)
        iObserver->ChangedNetworkMode();
    StartMonitoring();
    TRACES(qDebug() << "CNetworkMode::RunL()--->");
}

void CNetworkMode::StartMonitoring()
{
    if (!IsActive()) {
        iMobilePhone.NotifyModeChange(iStatus, iNetworkMode);
        SetActive();
    }
    TRACES(qDebug() << "CNetworkMode::StartMonitoring--End");
}

RMobilePhone::TMobilePhoneNetworkMode CNetworkMode::GetMode() const
{
    return iNetworkMode;
}

CNetworkStatus::CNetworkStatus(MNetworkObserver *aObserver, RMobilePhone &aMobilePhone)
    : CActive(EPriorityNormal),
      iNetStatus(RMobilePhone::ERegistrationUnknown),
      iObserver(aObserver),
      iMobilePhone(aMobilePhone)
{
    TRACES (qDebug() << "CNetworkStatus::CNetworkStatus<----");
    CActiveScheduler::Add(this);

    TInt err = iMobilePhone.GetMultimodeCaps(iCapsPhone);
    if (!err) {
        TRequestStatus reqStatus;
        iMobilePhone.GetNetworkRegistrationStatus(reqStatus, iNetStatus);
        User::WaitForRequest(reqStatus);
        StartMonitoring();
    }
    TRACES (qDebug() << "CNetworkStatus::CNetworkStatus---->");
}

CNetworkStatus::~CNetworkStatus()
{
    TRACES (qDebug() << "CNetworkStatus::~CNetworkStatus");
    Cancel();
}

void CNetworkStatus::DoCancel()
{
    TRACES (qDebug() << "CNetworkStatus::DoCancel");
    iMobilePhone.CancelAsyncRequest(EMobilePhoneNotifyNetworkRegistrationStatusChange);
}

void CNetworkStatus::RunL()
{
    TRACES (qDebug() << "CNetworkStatus::RunL()<---");
    if (iStatus.Int() == KErrNone)
        iObserver->ChangedNetworkStatus();
    StartMonitoring();
    TRACES (qDebug() << "CNetworkStatus::RunL()--->");
}

void CNetworkStatus::StartMonitoring()
{
    TRACES (qDebug() << "CNetworkStatus::StartMonitoring");
    if (!IsActive()) {
        iMobilePhone.NotifyNetworkRegistrationStatusChange(iStatus,iNetStatus);
        SetActive();
    }
}

TUint32 CNetworkStatus::GetCapability() const
{
    return iCapsPhone;
}

RMobilePhone::TMobilePhoneRegistrationStatus CNetworkStatus::GetStatus() const
{
    return iNetStatus;
}

#ifdef ETELPACKETSERVICE_SUPPORTED
CPacketDataStatus::CPacketDataStatus(MNetworkObserver *aObserver, RPacketService &aPacketService)
    : CActive(EPriorityNormal),
      iObserver(aObserver),
      iPacketService(aPacketService),
      iPacketServiceStatus(RPacketService::EStatusUnattached),
      iDynCaps(0)
{
    CActiveScheduler::Add(this);

    TRACES (qDebug() << "CPacketDataStatus::CPacketDataStatus");

    iPacketService.GetStatus(iPacketServiceStatus);
    if (iPacketServiceStatus == RPacketService::EStatusActive)
        iPacketService.GetDynamicCaps(iDynCaps); //Initialize dynamic caps
    StartMonitoring();
}

CPacketDataStatus::~CPacketDataStatus()
{
    TRACES (qDebug() << "CPacketDataStatus::~CPacketDataStatus");
    Cancel();
}

TBool CPacketDataStatus::IsDynamicCapsSupported()
{
    iPacketService.GetStatus(iPacketServiceStatus);
    if (iPacketServiceStatus == RPacketService::EStatusActive) {
        if (iPacketService.GetDynamicCaps(iDynCaps) == KErrNone) //other than KErrNotSupported
            return ETrue;
    }
    return EFalse;
}

TUint CPacketDataStatus::DynamicCaps()
{
    TRACES (qDebug() << "CPacketDataStatus::DynamicCaps value:" << iDynCaps);
    return iDynCaps;
}

void CPacketDataStatus::DoCancel()
{
    TRACES (qDebug() << "CPacketDataStatus::DoCancel<---");
    iPacketService.CancelAsyncRequest(KPacketNofityDynamicCapsChange);
    TRACES (qDebug() << "CPacketDataStatus::DoCancel--->");
}

void CPacketDataStatus::RunL()
{
    TRACES (qDebug() << "CPacketDataStatus::RunL()<---");
    TRACES (qDebug() << "iStatus code:" << iStatus.Int());
    if (iStatus.Int() == KErrNone)
        iObserver->ChangedCellDataTechnology();
    StartMonitoring();
    TRACES(qDebug() << "CPacketDataStatus::RunL()--->");
}

void CPacketDataStatus::StartMonitoring()
{
    TRACES (qDebug() << "CPacketDataStatus::StartMonitoring<---");
    if (!IsActive()) {
        iPacketService.NotifyDynamicCapsChange(iStatus,iDynCaps);
        SetActive();
    }
    TRACES (qDebug() << "CPacketDataStatus::StartMonitoring--->");
}
#endif //ETELPACKETSERVICE_SUPPORTED
#endif //ETELMM_SUPPORTED

CNetworkInfo::CNetworkInfo()
    : iConstructed(false),
      iCellDataTechnology(KDefaultBearer),
      iPacketdataserviceCaps(true)
{
    Initialise();
}

CNetworkInfo::~CNetworkInfo()
{
#ifdef ETELMM_SUPPORTED
    delete iNetMode;
    delete iNetStat;
#ifdef ETELPACKETSERVICE_SUPPORTED
    delete iPacketDataStatus;
    iPacketService.Close();
#endif //ETELPACKETSERVICE_SUPPORTED
    iMobilePhone.Close();
    iTelServer.Close();
#endif //ETELMM_SUPPORTED
}

void CNetworkInfo::Initialise()
{
#ifdef ETELMM_SUPPORTED
    TRAPD(err, InitialiseL());
    if (err) {
        delete iNetMode;
        iNetMode = 0;
        delete iNetStat;
        iNetStat = 0;
#ifdef ETELPACKETSERVICE_SUPPORTED
        delete iPacketDataStatus;
        iPacketDataStatus = 0;
        iPacketService.Close();
#endif //ETELPACKETSERVICE_SUPPORTED
        iMobilePhone.Close();
        iTelServer.Close();
    } else {
        iConstructed = true;
    }
#else
    iConstructed = true;
#endif
}

void CNetworkInfo::InitialiseL()
{
    TInt err = 0;
    TRACES(qDebug() << "CNetworkInfo::ConstructL<---");

    if (iConstructed)
        return;

#ifdef ETELMM_SUPPORTED
    err = iTelServer.Connect();
    TRACES(qDebug() << "Err val for RTelServer::Connect" << err);
    User::LeaveIfError(err);

    err = iTelServer.GetPhoneInfo( 0, iPhoneInfo );
    TRACES(qDebug() << "Err val for RTelServer::GetPhoneInfo =" << err);
    User::LeaveIfError(err);

    err = iMobilePhone.Open(iTelServer,iPhoneInfo.iName);
    TRACES(qDebug() << "Err val for RMobilePhone::Open =" << err);
    User::LeaveIfError(err);

    err = iMobilePhone.Initialise();
    TRACES(qDebug() << "Err val for RMobilePhone::Initialise =" << err);
    User::LeaveIfError(err);

    // Create active objects for monitoring statuses
    iNetMode = new (ELeave) CNetworkMode(this, iMobilePhone);
    iNetStat = new (ELeave) CNetworkStatus(this, iMobilePhone);

#ifdef ETELPACKETSERVICE_SUPPORTED
    TInt packetserviceerr = iPacketService.Open(iMobilePhone);
    if (packetserviceerr != KErrNone)
        iPacketdataserviceCaps = false;
    TRACES(qDebug() << "Err val for iPacketService.Open =" << packetserviceerr);

    if (iPacketdataserviceCaps)
        iPacketDataStatus = new (ELeave) CPacketDataStatus(this, iPacketService);

#endif //ETELPACKETSERVICE_SUPPORTED
#endif //ETELMM_SUPPORTED
    TRACES(qDebug() << "CNetworkInfo::ConstructL--->");
}

bool CNetworkInfo::IsInitialised()
{
    return iConstructed;
}

#ifdef ETELMM_SUPPORTED
RMobilePhone::TMobilePhoneNetworkMode CNetworkInfo::GetMode() const
{
    if (iConstructed)
        return iNetMode->GetMode();
    else
        return RMobilePhone::ENetworkModeUnknown;
}

RMobilePhone::TMobilePhoneRegistrationStatus CNetworkInfo::GetStatus() const
{
    if (iConstructed)
        return iNetStat->GetStatus();
    else
        return RMobilePhone::ERegistrationUnknown;
}
#endif

TUint32 CNetworkInfo::GetCapability() const
{
#ifdef ETELMM_SUPPORTED
    if (iConstructed)
        return iNetStat->GetCapability();
#endif

    return 0;
}

void CNetworkInfo::addObserver(MNetworkInfoObserver *aObserver)
{
    iObservers.append(aObserver);
}

void CNetworkInfo::removeObserver(MNetworkInfoObserver *aObserver)
{
    iObservers.removeOne(aObserver);
}

void CNetworkInfo::ChangedNetworkMode()
{
    foreach (MNetworkInfoObserver *observer, iObservers)
        observer->changedNetworkMode();
}

void CNetworkInfo::ChangedNetworkStatus()
{
    foreach (MNetworkInfoObserver *observer, iObservers)
        observer->changedNetworkStatus();
}

void CNetworkInfo::ChangedCellDataTechnology()
{
    TRACES (qDebug() << "CNetworkInfo::ChangedCellDataTechnology");
    TUint celldatatech = CellDataTechnology();
    if (celldatatech != iCellDataTechnology) {
        TRACES (qDebug() << "Notify observers");
        foreach (MNetworkInfoObserver *observer, iObservers)
            observer->changedCellDataTechnology();
    }
    iCellDataTechnology = celldatatech;
}

TUint CNetworkInfo::CellDataTechnology()
{
#if defined(ETELMM_SUPPORTED) && defined(ETELPACKETSERVICE_SUPPORTED)
    TRACES (qDebug() << "CNetworkInfo::CellDataTechnology<---");
    if (!iConstructed || !iPacketdataserviceCaps)
        return KDefaultBearer;
    TUint dynamicCaps = 0;
    if (iPacketDataStatus->IsDynamicCapsSupported())
        dynamicCaps = iPacketDataStatus->DynamicCaps();

    RMobilePhone::TMobilePhoneNetworkMode networkMode = iNetMode->GetMode();

    if ((dynamicCaps & RPacketService::KCapsHSUPA) || (dynamicCaps & RPacketService::KCapsHSDPA)) {
        TRACES ( qDebug() << "KHsdpaBearer" );
        return KHsdpaBearer;
    } else if ( dynamicCaps & RPacketService::KCapsEGPRS ) {
        TRACES ( qDebug() << "KEGprsBearer" );
        return KEGprsBearer;
    } else {
        if (networkMode == RMobilePhone::ENetworkModeGsm) {
            TRACES ( qDebug() << "KGprsBearer" );
            return KGprsBearer;
        } else if (networkMode == RMobilePhone::ENetworkModeWcdma) {
            TRACES ( qDebug() << "KUmtsBearer" );
            return KUmtsBearer;
        } else {
            TRACES ( qDebug() << "KDefaultBearer" );
            return KDefaultBearer;
        }
    }
#else
    return KDefaultBearer;
#endif
}
