utilities/downloadmanager/src/oma2downloadbackend.cpp
author hgs
Fri, 15 Oct 2010 17:30:59 -0400
changeset 16 3c88a81ff781
permissions -rw-r--r--
201041

/**
   This file is part of CWRT package **

   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). **

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU (Lesser) General Public License as 
   published by the Free Software Foundation, version 2.1 of the License. 
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
   (Lesser) General Public License for more details. You should have 
   received a copy of the GNU (Lesser) General Public License along 
   with this program. If not, see <http://www.gnu.org/licenses/>.
*/

#include "oma2downloadbackend.h"
#include "omaddparser.h"
#include "downloadmanager.h"
#include "download.h"
#include "clientdownload.h"
#include "downloadcore.h"
#include "downloadevent.h"
#include <QCoreApplication>
#include <QFileInfo>

#ifdef Q_OS_LINUX
  #include <sys/statvfs.h>
#endif

#ifdef Q_OS_LINUX 
static double freeSpace(const char *path)
#else
static double freeSpace(const char* /*path*/)
#endif
{
#ifdef Q_OS_LINUX   
    struct statvfs fiData;
    if ((statvfs(path,&fiData)) < 0 ) 
        return 0;
    else {
        qint64 blockSize = fiData.f_bsize/1024;
        qint64 freeSize = (fiData.f_bavail)*blockSize;
        freeSize = freeSize/1024;
        return freeSize;
    }
#endif
    return 0;
}

// Constants
const char* const SuppressUserConfirmation_Never = "Never";

// private implementation
class OMA2DownloadBackendPrivate {
    DM_DECLARE_PUBLIC(OMA2DownloadBackend);
public:
    OMA2DownloadBackendPrivate();
    ~OMA2DownloadBackendPrivate();
    DownloadCore *m_downloadCore;
    ClientDownload *m_download;
    OMADownloadDescParser *m_parser; // for parsing oma descriptor
    OMADownloadDescriptor *m_downloadDesc;
    bool m_isMediaDownload; // flag to indicate if media download is happening  
    MediaDownloadList m_mediaDownloadList; // media downloads
    int m_currDownloadIndex;
    int m_currProductIndex;
    qint64 m_dlCompletedSize;
    QMap<int, int> m_mediaObjIdStateMap; // map to have the list of Media Objects' id and it's state.
    QList<QVariant> m_childIds;
    OMA2DownloadProduct *m_currProduct;
    OMA2DownloadMediaObj *m_currMediaObj;
};

OMA2DownloadBackendPrivate::OMA2DownloadBackendPrivate():m_downloadCore(0)
                                                        ,m_download(0)
                                                        ,m_parser(0)
                                                        ,m_downloadDesc(0)
                                                        ,m_isMediaDownload(false)
                                                        ,m_currDownloadIndex(-1)
                                                        ,m_currProductIndex(0)
                                                        ,m_dlCompletedSize(0)
{ }

OMA2DownloadBackendPrivate::~OMA2DownloadBackendPrivate()
{
    if (m_parser) {
        delete m_parser;
        m_parser = 0;
        m_downloadDesc = 0;
    }
    // In case of persistent storage
    if (m_downloadDesc) {
        delete m_downloadDesc;
        m_downloadDesc = 0;
    }
    
    int count = m_mediaDownloadList.count();
    for (int i = 0; i < count; i++)
        delete m_mediaDownloadList[i];
}

OMA2DownloadBackend::OMA2DownloadBackend(DownloadCore *dlCore, ClientDownload *dl)
    :DownloadBackend(dlCore, dl)
{
    DM_INITIALIZE(OMA2DownloadBackend);
    priv->m_downloadCore = dlCore;
    priv->m_download = dl;
}

OMA2DownloadBackend::~OMA2DownloadBackend()
{
    DM_UNINITIALIZE(OMA2DownloadBackend);
}

int OMA2DownloadBackend::pause()
{
    DM_PRIVATE(OMA2DownloadBackend);
    if (priv->m_isMediaDownload) {
        priv->m_mediaDownloadList[priv->m_currDownloadIndex]->pause();
        setDownloadState(DlPaused);
    }
    return 0;
}

int OMA2DownloadBackend::resume()
{
    DM_PRIVATE(OMA2DownloadBackend);
    if (priv->m_isMediaDownload)
        return (priv->m_mediaDownloadList[priv->m_currDownloadIndex]->resume());

    // Ready to download after the descriptor is parsed
    // capability check on the descriptor information
    if (checkDownloadDescriptor()) {
        ProductList product = priv->m_downloadDesc->productList();
        int count =  product[priv->m_currProductIndex]->mediaCount();
        
        for (int i=0; i < count; i++) {
            QUrl baseUrl = priv->m_downloadCore->url();
            QUrl relativeUrl = product[priv->m_currProductIndex]->mediaObjList()[i]->getAttribute(OMA2DownloadDescMediaObjServer).toString();
            QString url = baseUrl.resolved(relativeUrl).toString();
            // create download for media object
            // id's of media downloads are unique under its parent oma download
            ClientDownload *dl = new ClientDownload(priv->m_download->downloadManager(), url, (i+1), Parallel
                                                                                            , priv->m_download->id() );
            if (NULL == dl)
                return -1;
            // functions for persistent storage
            serializeData(dl, i);
            setValueForChild(DownloadInfo::EUrl, url, dl->id());
            setValueForChild(DownloadInfo::EDlState, DlCreated, dl->id());
            long state;
            getValue(DownloadInfo::EDlState, state);
            priv->m_mediaObjIdStateMap[dl->id()] = state;
            addtoDownloadList(dl);
        }
        setValue(DownloadInfo::EChildIdList, priv->m_childIds);
        qint64 tSize = product[priv->m_currProductIndex]->albumSize();
        setTotalSize(tSize);
        priv->m_currDownloadIndex = 0;
        priv->m_mediaDownloadList[priv->m_currDownloadIndex]->start();
        priv->m_isMediaDownload = true; 
        return 0;         
    }
    return -1;
}

int OMA2DownloadBackend::cancel()
{
    DM_PRIVATE(OMA2DownloadBackend);
    if (priv->m_isMediaDownload)
        priv->m_mediaDownloadList[priv->m_currDownloadIndex]->cancel();
    else
       DownloadBackend::cancel();
    return 0;
}

QVariant OMA2DownloadBackend::getAttribute(DownloadAttribute attr)
{
    DM_PRIVATE(OMA2DownloadBackend);
    // moIndex is zero because when product name is empty the name of 0th Mediaobject should be shown in dd and also the type is of the 0th Mediaobject
    const int moIndex = 0;
    QString text = "";
    ProductList product;
    if (priv->m_downloadDesc)
        product = priv->m_downloadDesc->productList();
    switch(attr) {
    case OMADownloadDescriptorName:
    {
        if (product[priv->m_currProductIndex]) {
            QString name = product[priv->m_currProductIndex]->getAttribute(OMA2DownloadDescProductName).toString();
            if (!name.isEmpty())
                return name;
            if (product[priv->m_currProductIndex]->mediaCount() > 0)
                return product[priv->m_currProductIndex]->mediaObjList()[moIndex]->getAttribute(OMA2DownloadDescMediaObjName);
            return text;
        }  
        return text;
    }

    case OMADownloadDescriptorType:
    {
        if (product[priv->m_currProductIndex]) {
            if (product[priv->m_currProductIndex]->mediaCount() > 0)
                return product[priv->m_currProductIndex]->mediaObjList()[moIndex]->getAttribute(OMA2DownloadDescMediaObjType);
            return text;
        }
        return text;
    }

    case OMADownloadDescriptorSize:
    {
        qint64 size = 0;
        if (product[priv->m_currProductIndex])
            return product[priv->m_currProductIndex]->albumSize();
        return size;
    }

    case OMADownloadDescriptorNextURL:
    {
        return priv->m_downloadDesc->getAttribute(OMADownloadDescNextURL);
    }

    case DlFileName:
    {
        if (!priv->m_isMediaDownload) {
            QString url = priv->m_downloadCore->url();
            QFileInfo fileUrl(url);
            return QVariant(fileUrl.fileName());
        }
        // If the product tag doesn't have a name then display the media object's name in the download list.
        // This is helpful for single OMA2 download and is done for better user readability
        if (product[priv->m_currProductIndex]) {
            QString name = product[priv->m_currProductIndex]->getAttribute(OMA2DownloadDescProductName).toString();
            if (!name.isEmpty())
                return name;
            if (product[priv->m_currProductIndex]->mediaCount() > 0)
                return product[priv->m_currProductIndex]->mediaObjList()[priv->m_currDownloadIndex]->getAttribute(OMA2DownloadDescMediaObjName);
            return text;
        }  
        return text;
    }

    case DlContentType:
    {
        if (!priv->m_isMediaDownload)
            return DownloadBackend::getAttribute(DlContentType);
        QString contentType = priv->m_mediaDownloadList[priv->m_currDownloadIndex]->getAttribute(DlContentType).toString();
        if (contentType != "")
            return contentType;
        QString mediaObjContentType;
        getValueForChild(DownloadInfo::EContentType, mediaObjContentType, priv->m_childIds[priv->m_currDownloadIndex].toInt());
        return mediaObjContentType;
    }

    default:
        return DownloadBackend::getAttribute(attr);
    }
    return QVariant();
}

int OMA2DownloadBackend::setAttribute(DownloadAttribute attr, const QVariant& value)
{
    return DownloadBackend::setAttribute(attr, value);
}

// stores the data in storage
void OMA2DownloadBackend::store(QByteArray /*data*/, bool /*lastChunk=false*/)
{
    return;
}

// deletes the storage
void OMA2DownloadBackend::deleteStore()
{
    return;
}

// returns the size of stored data
qint64 OMA2DownloadBackend::storedDataSize()
{
    return 0;
}

void OMA2DownloadBackend::bytesRecieved(qint64 /*bytesRecieved*/, qint64 /*bytesTotal*/)
{
     //Do nothing. This is here to avoid this signal to reach to base class' slot.
     return;
}

void OMA2DownloadBackend::bytesUploaded(qint64 bytesUploaded, qint64 bytesTotal)
{
    DM_PRIVATE(OMA2DownloadBackend);
    // once data is uploaded, cancel the transaction
    if (bytesUploaded == bytesTotal)
        priv->m_downloadCore->abort() ;

}

void OMA2DownloadBackend::handleFinished()
{
     DM_PRIVATE(OMA2DownloadBackend);
     QString contentType = priv->m_downloadCore->contentType();
     if (contentType == OMA2_CONTENT_TYPE) {
         bool bSucceeded = parseDownloadDescriptor();
         priv->m_downloadDesc = priv->m_parser->downloadDescriptor();
         if (bSucceeded) {
             ProductList product = priv->m_downloadDesc->productList();
             int count =  product[priv->m_currProductIndex]->mediaCount();
             if (count == 0) {
                 priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("906 Invalid descriptor"));
                 priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
                 priv->m_downloadCore->setLastErrorString(tr("Invalid Descriptor"));
                 setDownloadState(DlFailed);
                 postEvent(Error, NULL);
                 return;
             }
             for (int i=0; i < count; i++) {
                 QString server = product[priv->m_currProductIndex]->mediaObjList()[i]->getAttribute(OMA2DownloadDescMediaObjServer).toString();
                 QString size = product[priv->m_currProductIndex]->mediaObjList()[i]->getAttribute(OMA2DownloadDescMediaObjSize).toString();
                 QString type = product[priv->m_currProductIndex]->mediaObjList()[i]->getAttribute(OMA2DownloadDescMediaObjType).toString();
                 if (server.isEmpty() || size.isEmpty() || type.isEmpty()) {
                     QString string;
                     string = product[priv->m_currProductIndex]->mediaObjList()[i]->getAttribute(OMA2DownloadDescMediaObjInstallNotifyURI).toString();
                     priv->m_downloadCore->post(string, QByteArray("905 Attribute Mismatch"));
                     priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
                     priv->m_downloadCore->setLastErrorString(tr("Invalid Descriptor"));
                     setDownloadState(DlFailed);
                     postEvent(Error, NULL);
                     return;
                 }
             }
             // if download is restarted OR suppressUserConfirmation is true, do not show descriptor
             if (suppressUserConfirmation() || (DlDescriptorUpdated == downloadState())) {
                 resume();
             } else {
                 setDownloadState(DlPaused);
                 postEvent(OMADownloadDescriptorReady, NULL);
             }
         } else {
             priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("906 Invalid descriptor"));
             priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
             priv->m_downloadCore->setLastErrorString(tr("Invalid Descriptor"));
             setDownloadState(DlFailed);
             postEvent(Error, NULL);
        }
    }
}
          
bool OMA2DownloadBackend::parseDownloadDescriptor()
{
    DM_PRIVATE(OMA2DownloadBackend);
    priv->m_parser = new OMADownloadDescParser();
    QXmlInputSource source(priv->m_downloadCore->reply());
    QXmlSimpleReader reader;
    reader.setContentHandler(priv->m_parser);
    reader.setErrorHandler(priv->m_parser);
    return reader.parse(source);
}

// capability check on the descriptor
bool OMA2DownloadBackend::checkDownloadDescriptor()
{
#ifdef Q_OS_LINUX
    DM_PRIVATE(OMA2DownloadBackend); 
    ProductList product = priv->m_downloadDesc->productList();
    double fileSize = product[priv->m_currProductIndex]->albumSize();
    double mbFactor = 1024*1024;
    fileSize = fileSize/mbFactor; //fileSize in MB
    double spaceLeft = freeSpace(ROOT_PATH); //spaze left in MB
    
    if (fileSize > spaceLeft) {
        priv->m_downloadCore->post(priv->m_downloadDesc->getAttribute(OMADownloadDescInstallNotifyURI).toString(), QByteArray("901 Insufficient memory"));
        priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
        priv->m_downloadCore->setLastErrorString(tr("901 Insufficient Memory"));
        setDownloadState(DlFailed);
        postEvent(Error, NULL);
        return false;       
    } 
#endif
    return true;
}

bool OMA2DownloadBackend::event(QEvent *event)
{
    DM_PRIVATE(OMA2DownloadBackend);
    ProductList product = priv->m_downloadDesc->productList();
    DownloadEvent* downloadEvent =  dynamic_cast<DownloadEvent*>(event);
    DEventType type = (DEventType)event->type();
    switch(type) {
    case Started:
        break;
    case HeaderReceived:
    {
        int dlId = ((DownloadEvent*)event)->getId();
        if (downloadEvent) {
            int statusCode = downloadEvent->getAttribute(HeaderReceivedStatusCode).toInt();
            handleStatusCode(statusCode);
        }
        ClientDownload *dl = findDownload(dlId);
        // Check the mismatch in total size returned by server with the size given in the descriptor.
        //This piece of code is commented as-of-now. when needed in future , will be uncommented
        /*qint64 totalSize = dl->getAttribute(DlTotalSize).toInt();
        if(product[priv->m_currProductIndex]->mediaObjList()[priv->m_currDownloadIndex]->getAttribute(OMA2DownloadDescMediaObjSize).toInt() != totalSize) {
            postInstallNotifyEvent("905 Attribut Mismatch");
            priv->m_mediaObjIdStateMap[downloadEvent->getId()] = DlFailed;
        } */
        // Check the mismatch in content type returned by server with the content type given in the descriptor.
        QString contentType = dl->getAttribute(DlContentType).toString();
        if(product[priv->m_currProductIndex]->mediaObjList()[priv->m_currDownloadIndex]->getAttribute(OMA2DownloadDescMediaObjType).toString() != contentType) {
            postInstallNotifyEvent("905 Attribute Mismatch");
            priv->m_mediaObjIdStateMap[downloadEvent->getId()] = DlFailed;
            if (priv->m_currDownloadIndex < product[priv->m_currProductIndex]->mediaCount()-1) {
                priv->m_currDownloadIndex++;
                priv->m_mediaDownloadList[priv->m_currDownloadIndex]->start();
            }
       }        
        break;
    }

    case Progress:
    {        
        QVariant curDlsize = priv->m_mediaDownloadList[priv->m_currDownloadIndex]->getAttribute(DlDownloadedSize);
        qint64 currentDlSize =  priv->m_dlCompletedSize + (curDlsize.toInt());
        setDownloadedDataSize(currentDlSize);
        setDownloadState(DlInprogress);
        priv->m_mediaObjIdStateMap[downloadEvent->getId()] = DlInprogress;
        setValueForChild(DownloadInfo::EDlState, DlInprogress, downloadEvent->getId());
        postEvent(Progress, NULL);
        break;
    }
    case Paused:
    {
        setDownloadState(DlPaused);
        priv->m_mediaObjIdStateMap[downloadEvent->getId()] = DlPaused;
        setValueForChild(DownloadInfo::EDlState, DlPaused, downloadEvent->getId());
        postEvent(Paused, NULL);
        break;
    }
    case NetworkLoss:
    {
        postEvent(NetworkLoss, NULL);
        break;
    }
    case Cancelled:
    {
        postInstallNotifyEvent("902 User Cancelled");
        priv->m_mediaObjIdStateMap[downloadEvent->getId()] = DlCancelled;
        setValueForChild(DownloadInfo::EDlState, DlCancelled, downloadEvent->getId());
        setDownloadState(DlCancelled);
        postEvent(Cancelled, NULL);
        break;
    }
    case Completed:
    {
        postInstallNotifyEvent("900 Success");
        priv->m_mediaObjIdStateMap[downloadEvent->getId()] = DlCompleted;
        setValueForChild(DownloadInfo::EDlState, DlCompleted, downloadEvent->getId());
        QVariant curDlsize = priv->m_mediaDownloadList[priv->m_currDownloadIndex]->getAttribute(DlDownloadedSize);
        priv->m_dlCompletedSize = priv->m_dlCompletedSize + (curDlsize.toInt());
        if (priv->m_currDownloadIndex < product[priv->m_currProductIndex]->mediaCount()-1) {
            priv->m_currDownloadIndex++;
            priv->m_mediaDownloadList[priv->m_currDownloadIndex]->start();
        } else if (priv->m_currDownloadIndex == product[priv->m_currProductIndex]->mediaCount()-1) 
            verifyDownloads();
        break;
    }        
    case Error:
    {
        priv->m_downloadCore->setLastError(QNetworkReply::UnknownContentError);
        priv->m_downloadCore->setLastErrorString(tr("905 Attribute Mismatch"));
        setDownloadState(DlFailed);
        postEvent(Error, NULL);
        priv->m_mediaObjIdStateMap[downloadEvent->getId()] = DlFailed;
        setValueForChild(DownloadInfo::EDlState, DlFailed, downloadEvent->getId());
        break;
    } 
    default:
        break;
    }
    return true;
}

void OMA2DownloadBackend::getChildren(QList<Download*>& list)
{
    DM_PRIVATE(OMA2DownloadBackend);
    for (int i = 0; i < priv->m_mediaDownloadList.count(); i++) 
        list.append(priv->m_mediaDownloadList[i]);

}

bool OMA2DownloadBackend::suppressUserConfirmation()
{
    DM_PRIVATE(OMA2DownloadBackend);

    ProductList productList = priv->m_downloadDesc->productList();
    QString suppressValue = productList[priv->m_currProductIndex]->getAttribute(OMA2DownloadDescProductSuppressConfirmation).toString();
    QString suppressUserConfirmNever(SuppressUserConfirmation_Never);

    // If suppressUserConfirmation attribute is present for Product tag, use it and don't check media objects
    // for this attribute
    if (!suppressValue.isEmpty()) {
        if (suppressValue == suppressUserConfirmNever)
            return false;
        return true;
    }
    
    int mediaCount = productList[priv->m_currProductIndex]->mediaCount();
    // If suppressUserConfirmation is present and it is NOT "Never" for even a single media object,
    // then treat this as true and do not display user confirmation.
    QString suppressConfirmMediaObj = "";

    for (int i=0; i<mediaCount; ++i) {
        // If the mediaObject element in DD file has this attribute
        suppressValue = productList[priv->m_currProductIndex]->mediaObjList()[i]->getAttribute(OMA2DownloadDescMediaObjSuppressConfirmation).toString();
        if (!suppressValue.isEmpty()) {
            // Check if two or more mediObjects have different values for this attribute.
            // If so, then this is an invalid case. Hence we ignore this attribute.
            if (suppressConfirmMediaObj.isEmpty())
                suppressConfirmMediaObj = suppressValue;
            else if (suppressConfirmMediaObj != suppressValue) {
                // Two mediaObjects have different values of suppressUserConfirmation attribute.
                // Ignore this attribute.
                return false;
            }
        }
    }
    
    // If string is empty OR its value is "Never", return false.
    if (suppressConfirmMediaObj.isEmpty() || (suppressConfirmMediaObj == suppressUserConfirmNever))
        return false;
    
    return true;
}

void OMA2DownloadBackend::handleStatusCode(const int& statusCode)
{
    HttpStatusCode status = (HttpStatusCode)statusCode;
    switch(status) {
    case HttpPreconditionFailed:    // Precondition Failed
    {
        handlePreconditionFailed();
        postEvent(DescriptorUpdated, NULL);
        return;
    }
    
    default:
        return;
    }
}

void OMA2DownloadBackend::handlePreconditionFailed()
{
    DM_PRIVATE(OMA2DownloadBackend);
    QString updatedDDUri = priv->m_downloadDesc->getAttribute(OMA2DownloadDescUpdatedDDURI).toString();
    if (updatedDDUri.isEmpty())
        return;

    DownloadManager* dlMgr = priv->m_download->downloadManager();
    if (!dlMgr)
        return;

    // Delete all media objects
    priv->m_isMediaDownload = false;
    ProductList productList = priv->m_downloadDesc->productList();
    int count =  productList[priv->m_currProductIndex]->mediaCount();

    // Remove all media objects
    for(int i=0; i<count; ++i) {
        ClientDownload* dl = priv->m_mediaDownloadList[i];
        QCoreApplication::removePostedEvents(this);
        dl->unregisterEventReceiver(this);
        priv->m_mediaDownloadList.removeOne(dl);
        dlMgr->removeOne(dl);
    }
    
    // start download of updated DD
    priv->m_downloadCore->changeUrl(updatedDDUri);
    priv->m_downloadCore->doDownload();
    setDownloadState(DlDescriptorUpdated);
}

void OMA2DownloadBackend::addtoDownloadList(ClientDownload* dl)
{
    DM_PRIVATE(OMA2DownloadBackend); 
    dl->registerEventReceiver(this);
    priv->m_childIds.append(dl->id());
    priv->m_mediaDownloadList.append(dl);
}

ClientDownload* OMA2DownloadBackend::findDownload(int id)
{
    DM_PRIVATE(OMA2DownloadBackend);
    for (int i = 0; i < priv->m_mediaDownloadList.size(); ++i) {
        if (priv->m_mediaDownloadList[i]->id() == id)
            return priv->m_mediaDownloadList[i];
    }
    return 0; 
}

void OMA2DownloadBackend::postInstallNotifyEvent(const char* statusMessage)
{
    DM_PRIVATE(OMA2DownloadBackend);
    ProductList product = priv->m_downloadDesc->productList();
    QString string;
    string = product[priv->m_currProductIndex]->mediaObjList()[priv->m_currDownloadIndex]->getAttribute(OMA2DownloadDescMediaObjInstallNotifyURI).toString();
    priv->m_downloadCore->post(string, QByteArray(statusMessage));   
}

void OMA2DownloadBackend::verifyDownloads()
{
    DM_PRIVATE(OMA2DownloadBackend);
    // go throught the mediaObjmap of id, state value pair and if any dl is failed then set the state of parent as paused.
    ProductList product = priv->m_downloadDesc->productList();
    int counter = 0;
    for (int i=0; i < priv->m_childIds.count(); i++) {
        if (priv->m_mediaObjIdStateMap[priv->m_childIds[i].toInt()] == DlCompleted)
            counter++;
        else if (priv->m_mediaObjIdStateMap[priv->m_childIds[i].toInt()] == DlFailed) {
            setDownloadState(DlFailed);
            postEvent(Error, NULL);
            break;
        }
    }
    if (counter == priv->m_childIds.count()) {
        setDownloadState(DlCompleted);
        postEvent(Completed, NULL);
    }
}

int OMA2DownloadBackend::currentIndex()
{
    // If a download is in progress and closed,  a track in an album is either paused or created.
    // This function as part of persistant storage,returns the index of the download which is either in paused or created state
    DM_PRIVATE(OMA2DownloadBackend);
    ProductList product = priv->m_downloadDesc->productList();
    for (int i=0; i < priv->m_childIds.count(); i++) {
        if (priv->m_mediaObjIdStateMap[priv->m_childIds[i].toInt()] == DlPaused
            || priv->m_mediaObjIdStateMap[priv->m_childIds[i].toInt()] == DlCreated) {
            priv->m_currDownloadIndex = i;
            break;
        }
    }
    return priv->m_currDownloadIndex;
}

void OMA2DownloadBackend::init()
{
    DM_PRIVATE(OMA2DownloadBackend);
    priv->m_isMediaDownload = true; // since init() is called during restoring the persistent info, the flag should be set to true.

    priv->m_downloadDesc = new OMADownloadDescriptor();
    priv->m_currProduct = new OMA2DownloadProduct();
    priv->m_downloadDesc->addProduct(priv->m_currProduct);
    // populating the product map
    QString productName;
    getValue(DownloadInfo::EFileName, productName);
    priv->m_currProduct->setAttribute("name", QVariant(productName));

    QList<QVariant> id;
    getValue(DownloadInfo::EChildIdList, id);
    QString oma2ContentType,mediaObjName,mediaObjUrl,mediaObjContentType;
    long mediaObjSize;
    long state;
    priv->m_currProductIndex = 0;
    for(int i=0; i<id.size(); i++) {
        //populating the mediaobj map
        priv->m_currMediaObj = new OMA2DownloadMediaObj();
        priv->m_currProduct->addMediaObject(priv->m_currMediaObj);
        
        // getting all the values related to media object for populating descriptor's mediaobj map        
        getValueForChild(DownloadInfo::EFileName, mediaObjName, id[i].toInt());
        getValueForChild(DownloadInfo::ETotalSize, mediaObjSize, id[i].toInt());
        getValueForChild(DownloadInfo::EUrl, mediaObjUrl, id[i].toInt());
        getValueForChild(DownloadInfo::EContentType, mediaObjContentType, id[i].toInt());
        getValueForChild(DownloadInfo::EDlState, state, id[i].toInt());
        priv->m_mediaObjIdStateMap[id[i].toInt()] = state;

        // creaating downloads for the media objects
        ClientDownload *dl = NULL;
        if (state == DlCreated) {
            dl = new ClientDownload(priv->m_download->downloadManager(), mediaObjUrl, id[i].toInt(), Parallel
                                                                                                   , priv->m_download->id() );
        }
        else
            dl = new ClientDownload(priv->m_download->downloadManager(), id[i].toInt(), priv->m_download->id());

        setValueForChild(DownloadInfo::EDlState, priv->m_mediaObjIdStateMap[id[i].toInt()], id[i].toInt());
        addtoDownloadList(dl);
        // re-constructing descriptor's mediaobj map
        priv->m_currMediaObj->setAttribute("name", QVariant(mediaObjName));
        int size = mediaObjSize;
        priv->m_currMediaObj->setAttribute("size", QVariant(size));
        priv->m_currMediaObj->setAttribute("type", QVariant(mediaObjContentType));
        priv->m_currMediaObj->setAttribute("server",QVariant(mediaObjUrl));
    }
    ProductList product = priv->m_downloadDesc->productList();
    getValue(DownloadInfo::EDlState,state);
    if(state == DlCompleted)
        priv->m_currDownloadIndex = product[priv->m_currProductIndex]->mediaCount()-1;
    else
        priv->m_currDownloadIndex = currentIndex();
}

void OMA2DownloadBackend::serializeData(ClientDownload* dl, int index)
{
    DM_PRIVATE(OMA2DownloadBackend);
    ProductList product = priv->m_downloadDesc->productList();
    // set OMA2 parent values in QSettings.
    QString productName = product[priv->m_currProductIndex]->getAttribute(OMA2DownloadDescProductName).toString(); // contenttype,url being written in dlbackend's constructor
    setValue(DownloadInfo::EFileName, productName);

    // set minimal MediaObject attributes in QSettings like name, size, url and contentType as these are the ones required for persistent storage.
    QString mediaObjName = product[priv->m_currProductIndex]->mediaObjList()[index]->getAttribute(OMA2DownloadDescMediaObjName).toString();
    setValueForChild(DownloadInfo::EFileName, mediaObjName, dl->id());
    long mediaObjSize = product[priv->m_currProductIndex]->mediaObjList()[index]->getAttribute(OMA2DownloadDescMediaObjSize).toInt();
    setValueForChild(DownloadInfo::ETotalSize, mediaObjSize, dl->id());
    QString mediaObjContentType = product[priv->m_currProductIndex]->mediaObjList()[index]->getAttribute(OMA2DownloadDescMediaObjType).toString();
    setValueForChild(DownloadInfo::EContentType, mediaObjContentType, dl->id());
    QString destPath = (download()->attributes().value(DlDestPath)).toString();
    setValueForChild(DownloadInfo::EFinalPath, destPath, dl->id());
    setValueForChild(DownloadInfo::EETag, priv->m_downloadCore->entityTag(), dl->id()); //not getting set check later
}