/* ============================================================
 *
 * This file is a part of kipi-plugins project
 * http://www.kipi-plugins.org
 *
 * Date        : 2005-07-07
 * Description : a kipi plugin to export images to Flickr web service
 *
 * Copyright (C) 2005-2008 by Vardhman Jain <vardhman at gmail dot com>
 * Copyright (C) 2008 by Gilles Caulier <caulier dot gilles at gmail dot com>
 *
 * This program is free software; you can redistribute it
 * and/or modify it under the terms of the GNU General
 * Public License as published by the Free Software Foundation;
 * either version 2, or (at your option) any later version.
 *
 * 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 General Public License for more details.
 *
 * ============================================================ */

// C++ includes.

#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <string>

// TQt includes.

#include <tqcstring.h>
#include <tqtextstream.h>
#include <tqfile.h>
#include <tqimage.h>
#include <tqstringlist.h>
#include <tqlineedit.h>
#include <tqmessagebox.h>
#include <tqdom.h>
#include <tqmap.h>
#include <tqfileinfo.h>
#include <tqprogressdialog.h>

// KDE includes.

#include <tdelocale.h>
#include <kdebug.h>
#include <kmimetype.h>
#include <kstandarddirs.h>
#include <kmdcodec.h>
#include <tdeapplication.h>
#include <tdemessagebox.h>

// LibKExiv2 includes.

#include <libkexiv2/kexiv2.h>

// LibKDcraw includes.

#include <libkdcraw/version.h>
#include <libkdcraw/kdcraw.h>

#if KDCRAW_VERSION < 0x000106
#include <libkdcraw/dcrawbinary.h>
#endif

// Local includes.

#include "pluginsversion.h"
#include "mpform.h"
#include "flickritem.h"
#include "flickrwindow.h"
#include "flickrtalker.h"
#include "flickrtalker.moc"

namespace KIPIFlickrExportPlugin
{

FlickrTalker::FlickrTalker(TQWidget* parent)
{
    m_parent = parent;
    m_job    = 0;
    m_apikey = "49d585bafa0758cb5c58ab67198bf632";
    m_secret = "34b39925e6273ffd";

    connect(this, TQ_SIGNAL(signalAuthenticate()),
            this, TQ_SLOT(slotAuthenticate()));
}

FlickrTalker::~FlickrTalker()
{
    if (m_job)
        m_job->kill();
}

/** Compute MD5 signature using url queries keys and values following Flickr notice:
    http://www.flickr.com/services/api/auth.spec.html
*/
TQString FlickrTalker::getApiSig(const TQString& secret, const KURL& url)
{
    TQMap<TQString, TQString> queries = url.queryItems();
    TQString compressed(secret);

    // NOTE: iterator TQMap iterator will sort alphabetically items based on key values.
    for (TQMap<TQString, TQString>::iterator it = queries.begin() ; it != queries.end(); ++it)
    {
        compressed.append(it.key());
        compressed.append(it.data());
    }

    KMD5 context(compressed.utf8());
    return context.hexDigest().data();
}

/**get the Api sig and send it to the server server should return a frob.
*/
void FlickrTalker::getFrob()
{
    if (m_job)
    {
        m_job->kill();
        m_job = 0;
    }

    KURL url("http://www.flickr.com/services/rest/");
    url.addQueryItem("method", "flickr.auth.getFrob");
    url.addQueryItem("api_key", m_apikey);
    TQString md5 = getApiSig(m_secret, url);
    url.addQueryItem("api_sig", md5);
    kdDebug() << "Get frob url: " << url << endl;
    TQByteArray tmp;
    TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false);

    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded");

    connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
            this, TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));

    connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
            this, TQ_SLOT(slotResult(TDEIO::Job *)));

    m_state = FE_GETFROB;
    m_authProgressDlg->setLabelText(i18n("Getting the Frob"));
    m_authProgressDlg->setProgress(1, 4);
    m_job   = job;
    m_buffer.resize(0);
    emit signalBusy(true);
}

void FlickrTalker::checkToken(const TQString& token) 
{
    if (m_job)
    {
        m_job->kill();
        m_job = 0;
    }

    KURL url("http://www.flickr.com/services/rest/");
    url.addQueryItem("method", "flickr.auth.checkToken");
    url.addQueryItem("api_key", m_apikey);
    url.addQueryItem("auth_token", token);
    TQString md5 = getApiSig(m_secret, url);
    url.addQueryItem("api_sig", md5);
    kdDebug() << "Check token url: " << url << endl;
    TQByteArray tmp;
    TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false);

    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded");

    connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
            this, TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));

    connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
            this, TQ_SLOT(slotResult(TDEIO::Job *)));

    m_state = FE_CHECKTOKEN;
    m_authProgressDlg->setLabelText(i18n("Checking if previous token is still valid"));
    m_authProgressDlg->setProgress(1, 4);
    m_job   = job;
    m_buffer.resize(0);
    emit signalBusy( true );
}

void FlickrTalker::slotAuthenticate()
{
    if (m_job)
    {
        m_job->kill();
        m_job = 0;
    }

    KURL url("http://www.flickr.com/services/auth/");
    url.addQueryItem("api_key", m_apikey);
    url.addQueryItem("frob", m_frob);
    url.addQueryItem("perms", "write");
    TQString md5 = getApiSig(m_secret, url);
    url.addQueryItem("api_sig", md5);
    kdDebug() << "Authenticate url: " << url << endl;

    TDEApplication::kApplication()->invokeBrowser(url.url());
    int valueOk = KMessageBox::questionYesNo(kapp->activeWindow(),
                  i18n("Please Follow through the instructions in the browser window and "
                       "return back to press ok if you are authenticated or press No"),
                  i18n("Flickr Service Web Authorization"));

    if( valueOk == KMessageBox::Yes)
    {
        getToken();
        m_authProgressDlg->setLabelText(i18n("Authenticating the User on web"));
        m_authProgressDlg->setProgress(2, 4);
        emit signalBusy(false);
    }
    else 
    {
        kdDebug() << "User didn't proceed with getToken Authorization, cannot proceed further, aborting" << endl;
        cancel();
    }
}

void FlickrTalker::getToken()
{
    if (m_job)
    {
        m_job->kill();
        m_job = 0;
    }

    KURL url("http://www.flickr.com/services/rest/");
    url.addQueryItem("api_key", m_apikey);
    url.addQueryItem("method", "flickr.auth.getToken");
    url.addQueryItem("frob", m_frob);
    TQString md5 = getApiSig(m_secret, url);
    url.addQueryItem("api_sig", md5);
    kdDebug() << "Get token url: " << url << endl;
    TQByteArray tmp;
    TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false);
    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded");

    connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
            this, TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));

    connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
            this, TQ_SLOT(slotResult(TDEIO::Job *)));

    m_state = FE_GETTOKEN;
    m_job   = job;
    m_buffer.resize(0);
    emit signalBusy(true);
    m_authProgressDlg->setLabelText(i18n("Getting the Token from the server"));
    m_authProgressDlg->setProgress(3, 4);
}

void FlickrTalker::listPhotoSets()
{
    KURL url("http://www.flickr.com/services/rest/");
    url.addQueryItem("api_key", m_apikey);
    url.addQueryItem("method", "flickr.photosets.getList");
    url.addQueryItem("user_id", m_userId);
    TQString md5 = getApiSig(m_secret, url);
    url.addQueryItem("api_sig", md5);
    kdDebug() << "List photo sets url: " << url << endl;
    TQByteArray tmp;
    TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false);
    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded" );

    connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
            this, TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));

    connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
            this, TQ_SLOT(slotResult(TDEIO::Job *)));

    m_state = FE_LISTPHOTOSETS;
    m_job   = job;
    m_buffer.resize(0);
    emit signalBusy(true);
}

void FlickrTalker::getPhotoProperty(const TQString& method, const TQStringList& argList)
{
    if (m_job)
    {
        m_job->kill();
        m_job = 0;
    }

    KURL url("http://www.flickr.com/services/rest/");
    url.addQueryItem("api_key", m_apikey);
    url.addQueryItem("method", method);
    url.addQueryItem("frob", m_frob);

    for (TQStringList::const_iterator it = argList.begin(); it != argList.end(); ++it)
    {
        TQStringList str = TQStringList::split("=", (*it));
        url.addQueryItem(str[0], str[1]);
    }

    TQString md5 = getApiSig(m_secret, url);
    url.addQueryItem("api_sig", md5);
    kdDebug() << "Get photo property url: " << url << endl;
    TQByteArray tmp;
    TDEIO::TransferJob* job = TDEIO::http_post(url, tmp, false);
    job->addMetaData("content-type", "Content-Type: application/x-www-form-urlencoded" );

    connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
            this, TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));

    connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
            this, TQ_SLOT(slotResult(TDEIO::Job *)));

    m_state = FE_GETPHOTOPROPERTY;
    m_job   = job;
    m_buffer.resize(0);
    emit signalBusy( true );

//  m_authProgressDlg->setLabelText("Getting the Token from the server");
//  m_authProgressDlg->setProgress(3,4);
}
void FlickrTalker::listPhotos(const TQString& /*albumName*/)
{
    // TODO
}

void FlickrTalker::createAlbum(const TQString& /*parentAlbumName*/, const TQString& /*albumName*/,
                               const TQString& /*albumTitle*/, const TQString& /*albumCaption*/)
{
    //TODO: The equivalent for Album is sets.
}

bool FlickrTalker::addPhoto(const TQString& photoPath, const FPhotoInfo& info,
                            bool rescale, int maxDim, int imageQuality)
{
    if (m_job)
    {
        m_job->kill();
        m_job = 0;
    }

    KURL    url("http://www.flickr.com/services/upload/");
    TQString path = photoPath;
    MPForm  form;

    form.addPair("auth_token", m_token);
    url.addQueryItem("auth_token", m_token);

    form.addPair("api_key", m_apikey);
    url.addQueryItem("api_key", m_apikey);

    TQString ispublic = (info.is_public == 1) ? "1" : "0";
    form.addPair("is_public", ispublic);
    url.addQueryItem("is_public", ispublic);

    TQString isfamily = (info.is_family == 1) ? "1" : "0";
    form.addPair("is_family", isfamily);
    url.addQueryItem("is_family", isfamily);

    TQString isfriend = (info.is_friend == 1) ? "1" : "0";
    form.addPair("is_friend", isfriend);
    url.addQueryItem("is_friend", isfriend);

    TQString tags = info.tags.join(" ");
    if(tags.length() > 0)
    {
        form.addPair("tags", tags);
        url.addQueryItem("tags", tags);
    }

    if (!info.title.isEmpty())
    {
        form.addPair("title", info.title);
        url.addQueryItem("title", info.title);
    }

    if (!info.description.isEmpty())
    {
        form.addPair("description", info.description);
        url.addQueryItem("description", info.description);
    }

    TQString md5 = getApiSig(m_secret, url);
    form.addPair("api_sig", md5);
    url.addQueryItem("api_sig", md5);
    TQImage image;

    // Check if RAW file.
#if KDCRAW_VERSION < 0x000106
    TQString rawFilesExt(KDcrawIface::DcrawBinary::instance()->rawFiles());
#else
    TQString rawFilesExt(KDcrawIface::KDcraw::rawFiles());
#endif
    TQFileInfo fileInfo(photoPath);
    if (rawFilesExt.upper().contains(fileInfo.extension(false).upper()))
        KDcrawIface::KDcraw::loadDcrawPreview(image, photoPath);
    else
        image.load(photoPath);

    kdDebug() << "Add photo query: " << url << endl;

    if (!image.isNull())
    {
        path = locateLocal("tmp", TQFileInfo(photoPath).baseName().stripWhiteSpace() + ".jpg");

        if (rescale && (image.width() > maxDim || image.height() > maxDim))
            image = image.smoothScale(maxDim, maxDim, TQImage::ScaleMin);

        image.save(path, "JPEG", imageQuality);

        // Restore all metadata.

        KExiv2Iface::KExiv2 exiv2Iface;

        if (exiv2Iface.load(photoPath))
        {
            exiv2Iface.setImageDimensions(image.size());

            // NOTE: see B.K.O #153207: Flickr use IPTC keywords to create Tags in web interface
            //       As IPTC do not support UTF-8, we need to remove it.
            exiv2Iface.removeIptcTag("Iptc.Application2.Keywords", false);

            exiv2Iface.setImageProgramId(TQString("Kipi-plugins"), TQString(kipiplugins_version));
            exiv2Iface.save(path);
        }
        else
        {
            kdWarning(51000) << "(flickrExport::Image doesn't have metdata)" << endl;
        }

        kdDebug() << "Resizing and saving to temp file: " << path << endl;
    }

    if (!form.addFile("photo", path))
        return false;

    form.finish();

    TDEIO::TransferJob* job = TDEIO::http_post(url, form.formData(), false);
    job->addMetaData("content-type", form.contentType());

    connect(job, TQ_SIGNAL(data(TDEIO::Job*, const TQByteArray&)),
            this, TQ_SLOT(data(TDEIO::Job*, const TQByteArray&)));

    connect(job, TQ_SIGNAL(result(TDEIO::Job *)),
            this, TQ_SLOT(slotResult(TDEIO::Job *)));

    m_state = FE_ADDPHOTO;
    m_job   = job;
    m_buffer.resize(0);
    emit signalBusy(true);
    return true;
}

TQString FlickrTalker::getUserName()
{
    return m_username;
}

TQString FlickrTalker::getUserId()
{
    return m_userId;
}

void FlickrTalker::cancel()
{
    if (m_job)
    {
        m_job->kill();
        m_job = 0;
    }

    if (m_authProgressDlg && !m_authProgressDlg->isHidden()) 
        m_authProgressDlg->hide();
}

void FlickrTalker::data(TDEIO::Job*, const TQByteArray& data)
{
    if (data.isEmpty())
        return;

    int oldSize = m_buffer.size();
    m_buffer.resize(m_buffer.size() + data.size());
    memcpy(m_buffer.data()+oldSize, data.data(), data.size());
}

void FlickrTalker::slotError(const TQString& error)
{
    TQString transError;
    int errorNo = atoi(error.latin1());

    switch (errorNo)
    {
        case 2: 
            transError = i18n("No photo specified");
            break;
        case 3: 
            transError = i18n("General upload failure");
            break;
        case 4: 
            transError = i18n("Filesize was zero");
            break;
        case 5: 
            transError = i18n("Filetype was not recognised");
            break;
        case 6:
            transError = i18n("User exceeded upload limit");
            break;
        case 96:
            transError = i18n("Invalid signature");
            break;
        case 97:
            transError = i18n("Missing signature"); 
            break;
        case 98:
            transError = i18n("Login Failed / Invalid auth token"); 
            break;
        case 100: 
            transError = i18n("Invalid API Key"); 
            break;
        case 105:
            transError = i18n("Service currently unavailable");
            break;
        case 108:
            transError = i18n("Invalid Frob");
            break;
        case 111: 
            transError = i18n("Format \"xxx\" not found"); 
            break;
        case 112:
            transError = i18n("Method \"xxx\" not found"); 
            break;
        case 114:
            transError = i18n("Invalid SOAP envelope");
            break;
        case 115:
            transError = i18n("Invalid XML-RPC Method Call");
            break;
        case 116:
            transError = i18n("The POST method is now required for all setters"); 
            break;
        default:
            transError = i18n("Unknown error");
            break;
    };

    KMessageBox::error(kapp->activeWindow(),
                 i18n("Error Occured: %1\n We can not proceed further").arg(transError));

//  kdDebug() << "Not handling the error now will see it later" << endl;
}

void FlickrTalker::slotResult(TDEIO::Job *job)
{
    m_job = 0;
    emit signalBusy(false);

    if (job->error())
    {
        if (m_state == FE_ADDPHOTO)
            emit signalAddPhotoFailed( job->errorString());
        else
            job->showErrorDialog(m_parent);
        return;
    }

    switch(m_state)
    {
        case(FE_LOGIN):
            //parseResponseLogin(m_buffer);
            break;
        case(FE_LISTPHOTOSETS):
            parseResponseListPhotoSets(m_buffer);
            break;
        case(FE_GETFROB):
            parseResponseGetFrob(m_buffer);
            break;
        case(FE_GETTOKEN):
            parseResponseGetToken(m_buffer);
            break;
        case(FE_CHECKTOKEN):
            parseResponseCheckToken(m_buffer);
            break;
        case(FE_GETAUTHORIZED):
            //parseResponseGetToken(m_buffer);
            break;
        case(FE_LISTPHOTOS):
            parseResponseListPhotos(m_buffer);
            break;
        case(FE_GETPHOTOPROPERTY):
            parseResponsePhotoProperty(m_buffer);
            break;
        case(FE_ADDPHOTO):
            parseResponseAddPhoto(m_buffer);
            break;
    }
    /*
        if (m_state == FE_LOGIN && m_loggedIn)
        {
    //  listAlbums();
    }*/
}

void FlickrTalker::parseResponseGetFrob(const TQByteArray& data)
{
    bool success = false;
    TQString errorString;
    TQDomDocument doc("mydocument");

    if (!doc.setContent(data)) 
    {
        return;
    }

    TQDomElement docElem = doc.documentElement();
    TQDomNode node       = docElem.firstChild();

    while(!node.isNull())
    {
        if (node.isElement() && node.nodeName() == "frob")
        {
            TQDomElement e = node.toElement();    // try to convert the node to an element.
            kdDebug() << "Frob is" << e.text() << endl; 
            m_frob        = e.text();            // this is what is obtained from data.
            success       = true;
        }

        if (node.isElement() && node.nodeName() == "err")
        {
            kdDebug() << "Checking Error in response" << endl;
            errorString = node.toElement().attribute("code");
            kdDebug() << "Error code=" << errorString << endl;
            kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl;	
        }
        node = node.nextSibling();
    }

    kdDebug() << "GetFrob finished" << endl;
    m_authProgressDlg->setProgress(2, 4);
    m_state = FE_GETAUTHORIZED;
    if(success)
        emit signalAuthenticate();
    else
        emit signalError(errorString);
}

void FlickrTalker::parseResponseCheckToken(const TQByteArray& data)
{
    bool         success = false;
    TQString      errorString;
    TQString      username;
    TQString      transReturn;
    TQDomDocument doc("checktoken");

    if (!doc.setContent(data)) 
    {
        return;
    }

    TQDomElement docElem = doc.documentElement();
    TQDomNode node       = docElem.firstChild();
    TQDomElement e;

    while(!node.isNull())
    {
        if (node.isElement() && node.nodeName() == "auth")
        {
            e                = node.toElement(); // try to convert the node to an element.
            TQDomNode details = e.firstChild();

            while(!details.isNull())
            {
                if(details.isElement())
                {
                    e = details.toElement();

                    if(details.nodeName() == "token")
                    {
                        kdDebug() << "Token=" << e.text() << endl; 
                        m_token = e.text();//this is what is obtained from data.
                    }

                    if(details.nodeName() == "perms")
                    {
                        kdDebug() << "Perms=" << e.text() << endl; 
                        TQString	perms = e.text();//this is what is obtained from data.

                        if(perms == "write")
                            transReturn = i18n("As in the persmission to", "write");
                        else if(perms == "read")
                            transReturn = i18n("As in the permission to", "read");
                        else if(perms == "delete")
                            transReturn = i18n("As in the permission to", "delete");
                    }

                    if(details.nodeName() == "user")
                    {
                        kdDebug() << "nsid=" << e.attribute("nsid") << endl; 
                        m_userId   = e.attribute("nsid");
                        username   = e.attribute("username");
                        m_username = username;
                        kdDebug() << "username=" << e.attribute("username") << endl; 
                        kdDebug() << "fullname=" << e.attribute("fullname") << endl; 
                    }
                }

                details = details.nextSibling();
            }

            m_authProgressDlg->hide();
            emit signalTokenObtained(m_token);
            success = true;
        }

        if (node.isElement() && node.nodeName() == "err")
        {
            kdDebug() << "Checking Error in response" << endl;
            errorString = node.toElement().attribute("code");
            kdDebug() << "Error code=" << errorString << endl;
            kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl;

            int valueOk = KMessageBox::questionYesNo(kapp->activeWindow(),
                                       i18n("Your token is invalid. Would you like to "
                                            "get a new token to proceed ?\n"));
            if(valueOk == KMessageBox::Yes)
            {
                getFrob();
                return;
            }
            else
            {
                m_authProgressDlg->hide(); //will popup the result for the checktoken failure below 
            }

        }

        node = node.nextSibling();
    }

    if(!success)
        emit signalError(errorString);

    kdDebug() << "CheckToken finished" << endl;
}

void FlickrTalker::parseResponseGetToken(const TQByteArray& data)
{
    bool success = false;
    TQString errorString;
    TQDomDocument doc("gettoken");
    if (!doc.setContent( data ))
        return;

    TQDomElement docElem = doc.documentElement();
    TQDomNode node       = docElem.firstChild();
    TQDomElement e;

    while(!node.isNull()) 
    {
        if (node.isElement() && node.nodeName() == "auth")
        {
            e                = node.toElement(); // try to convert the node to an element.
            TQDomNode details = e.firstChild();

            while(!details.isNull())
            {
                if(details.isElement())
                {
                    e = details.toElement();

                    if(details.nodeName() == "token")
                    {
                        kdDebug() << "Token=" << e.text() << endl;
                        m_token = e.text();      //this is what is obtained from data.
                    }

                    if(details.nodeName() == "perms")
                    {
                        kdDebug() << "Perms=" << e.text() << endl;
                    }

                    if(details.nodeName() == "user")
                    {
                        kdDebug() << "nsid=" << e.attribute("nsid") << endl;
                        kdDebug() << "username=" << e.attribute("username") << endl;
                        kdDebug() << "fullname=" << e.attribute("fullname") << endl;
                        m_username = e.attribute("username");
                        m_userId   = e.attribute("nsid");
                    }
                }

                details = details.nextSibling();
            }

            success = true;
        }
        else if (node.isElement() && node.nodeName() == "err")
        {
            kdDebug() << "Checking Error in response" << endl;
            errorString = node.toElement().attribute("code");
            kdDebug() << "Error code=" << errorString << endl;
            kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl;
            //emit signalError(code);
        }

        node = node.nextSibling();
    }

    kdDebug() << "GetToken finished" << endl;
    //emit signalBusy( false );
    m_authProgressDlg->hide();

    if(success)
        emit signalTokenObtained(m_token);
    else
        emit signalError(errorString);
}
void FlickrTalker::parseResponseListPhotoSets(const TQByteArray& data)
{
    bool success = false;
    TQDomDocument doc("getListPhotoSets");
    if (!doc.setContent(data)) 
        return;

    TQDomElement docElem = doc.documentElement();
    TQDomNode node       = docElem.firstChild();
    TQDomElement e;
    TQString photoSet_id, photoSet_title, photoSet_description;
    TQValueList <FPhotoSet> photoSetList;

    while(!node.isNull())
    {
        if (node.isElement() && node.nodeName() == "photosets")
        {
            e                = node.toElement();
            TQDomNode details = e.firstChild();
            FPhotoSet fps;
            TQDomNode detailsNode = details;

            while(!detailsNode.isNull())
            {
                if(detailsNode.isElement())
                {
                    e = detailsNode.toElement();
                    if(detailsNode.nodeName() == "photoset")
                    {
                        kdDebug() << "id=" << e.attribute("id") << endl;
                        photoSet_id              = e.attribute("id");           //this is what is obtained from data.
                        fps.id                   = photoSet_id;
                        TQDomNode photoSetDetails = detailsNode.firstChild();
                        TQDomElement e_detail;

                        while(!photoSetDetails.isNull())
                        {
                            e_detail = photoSetDetails.toElement();

                            if(photoSetDetails.nodeName() == "title")
                            {
                                kdDebug() << "Title=" << e_detail.text() << endl;
                                photoSet_title = e_detail.text();
                                fps.title      = photoSet_title;
                            }
                            else if(photoSetDetails.nodeName() == "description")
                            {
                                kdDebug() << "Description =" << e_detail.text() << endl;
                                photoSet_description = e_detail.text();
                                fps.description      = photoSet_description;
                            }

                            photoSetDetails = photoSetDetails.nextSibling();
                        }
                    }
                }

                detailsNode = detailsNode.nextSibling();
            }

            photoSetList.append(fps);
            details = details.nextSibling();
            success = true;
        }

        if (node.isElement() && node.nodeName() == "err")
        {
            kdDebug() << "Checking Error in response" << endl;
            TQString code = node.toElement().attribute("code");
            kdDebug() << "Error code=" << code << endl;
            kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl;
            emit signalError(code);
        }

        node = node.nextSibling();
    }

    kdDebug() << "GetPhotoList finished" << endl;

    if (!success)
    {
        emit signalListPhotoSetsFailed(i18n("Failed to fetch photoSets List"));
    }
    else
    {
        emit signalListPhotoSetsSucceeded(photoSetList);
    }
}

void FlickrTalker::parseResponseListPhotos(const TQByteArray& data)
{
    TQDomDocument doc("getPhotosList");
    if (!doc.setContent( data))
        return;

    TQDomElement docElem = doc.documentElement();
    TQDomNode node       = docElem.firstChild();
    //TQDomElement e;
    //TODO
}

void FlickrTalker::parseResponseCreateAlbum(const TQByteArray& data)
{
    TQDomDocument doc("getCreateAlbum");
    if (!doc.setContent(data)) 
        return;

    TQDomElement docElem = doc.documentElement();
    TQDomNode node       = docElem.firstChild();

    //TODO
}

void FlickrTalker::parseResponseAddPhoto(const TQByteArray& data)
{
    bool    success = false;
    TQString line;
    TQDomDocument doc("AddPhoto Response");
    if (!doc.setContent(data))
        return;

    TQDomElement docElem = doc.documentElement();
    TQDomNode node       = docElem.firstChild();
    TQDomElement e;

    while(!node.isNull())
    {
        if (node.isElement() && node.nodeName() == "photoid")
        {
            e                = node.toElement();           // try to convert the node to an element.
            TQDomNode details = e.firstChild();
            kdDebug() << "Photoid= " << e.text() << endl; 
            success = true;
        }

        if (node.isElement() && node.nodeName() == "err")
        {
            kdDebug() << "Checking Error in response" << endl;
            TQString code = node.toElement().attribute("code");
            kdDebug() << "Error code=" << code << endl;
            kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl;
            emit signalError(code);
        }

        node = node.nextSibling();
    }

    kdDebug() << "GetToken finished" << endl;

    if (!success)
    {
        emit signalAddPhotoFailed(i18n("Failed to upload photo"));
    }
    else
    {
        emit signalAddPhotoSucceeded();
    }

}
void FlickrTalker::parseResponsePhotoProperty(const TQByteArray& data)
{
    bool         success = false;
    TQString      line;
    TQDomDocument doc("Photos Properties");
    if (!doc.setContent(data))
        return;

    TQDomElement docElem = doc.documentElement();
    TQDomNode node       = docElem.firstChild();
    TQDomElement e;

    while(!node.isNull()) 
    {
        if (node.isElement() && node.nodeName() == "photoid")
        {
            e = node.toElement();                 // try to convert the node to an element.
            TQDomNode details = e.firstChild();
            kdDebug() << "Photoid=" << e.text() << endl;
            success = true;
        }

        if (node.isElement() && node.nodeName() == "err")
        {
            kdDebug() << "Checking Error in response" << endl;
            TQString code = node.toElement().attribute("code");
            kdDebug() << "Error code=" << code << endl;
            kdDebug() << "Msg=" << node.toElement().attribute("msg") << endl;
            emit signalError(code);
        }

        node = node.nextSibling();
    }

    kdDebug() << "GetToken finished" << endl;

    if (!success)
    {
        emit signalAddPhotoFailed(i18n("Failed to query photo information"));
    }
    else
    {
        emit signalAddPhotoSucceeded();
    }
}

} // namespace KIPIFlickrExportPlugin
