#include "fileop.h"
#include "ifapp.h"
#include "imageutils.h"
#include "imageheaders.h"
#include "catagorymgr.h"
#include <klocale.h>
#include <kurl.h>
#include <kmdcodec.h>
#include <kstandarddirs.h>
#include <qfileinfo.h>
#include <qdir.h>
#include <qpixmap.h>
#include <qimage.h>
#include <qlabel.h>
#include <qlayout.h>

#include <kiconloader.h>
#include <kmessagebox.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <unistd.h>
#include <utime.h>

KIFFileOpDialog::KIFFileOpDialog(const QString &src, const QString &dest,
                                 QWidget *parent, const char *name,
                                 bool singleFile)
    : QDialog(parent, name, true)
{
    QFileInfo srcInfo(src);
    QFileInfo destInfo(dest+"/"+srcInfo.fileName());

    setCaption(i18n("File already exists"));
    QLabel *descLbl = new QLabel(i18n("The file \'") + destInfo.absFilePath() + i18n("\' already exists!"), this);
    QLabel *srcIconLbl = new QLabel(this);
    QLabel *destIconLbl = new QLabel(this);
    QLabel *srcDescLbl = new QLabel(this);
    QLabel *destDescLbl = new QLabel(this);

    srcDescLbl->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);
    destDescLbl->setAlignment(Qt::AlignVCenter | Qt::AlignLeft);

    if(isImageType(srcInfo.fileName())){
        QImage image;
        loadImage(image, srcInfo.absFilePath());
        int iconSize = 90;
        if(!image.isNull()){
            if(image.width() > iconSize || image.height() > iconSize){
                if(image.width() > image.height()){
                    float percent = (((float)iconSize)/image.width());
                    int h = (int)(image.height()*percent);
                    image = image.smoothScale(iconSize, h);
                }
                else{
                    float percent = (((float)iconSize)/image.height());
                    int w = (int)(image.width()*percent);
                    image = image.smoothScale(w, iconSize);
                }
            }
            QPixmap pix;
            pix.convertFromImage(image);
            srcIconLbl->setPixmap(pix);
        }
        else{
            srcIconLbl->setPixmap(BarIcon("document", KIcon::SizeLarge));
        }
        loadImage(image, destInfo.absFilePath());
        if(!image.isNull()){
            if(image.width() > iconSize || image.height() > iconSize){
                if(image.width() > image.height()){
                    float percent = (((float)iconSize)/image.width());
                    int h = (int)(image.height()*percent);
                    image = image.smoothScale(iconSize, h);
                }
                else{
                    float percent = (((float)iconSize)/image.height());
                    int w = (int)(image.width()*percent);
                    image = image.smoothScale(w, iconSize);
                }
            }
            QPixmap pix;
            pix.convertFromImage(image);
            destIconLbl->setPixmap(pix);
        }
        else{
            destIconLbl->setPixmap(BarIcon("image", KIcon::SizeLarge));
        }
    }
    else{
        srcIconLbl->setPixmap(BarIcon("document", KIcon::SizeLarge));
        destIconLbl->setPixmap(BarIcon("document", KIcon::SizeLarge));
    }

    QString sizeStr;
    bool anyRights;
    QString srcStr(i18n("Source file\n"));
    float size;

    // Source file information
    if(!srcInfo.isDir()){
        size = srcInfo.size();
        if(size >= 1024){
            size /= 1024.0;
            if(size >= 1024){
                size /= 1024.0;
                sizeStr += i18n("Size: ")+QString::number(size, 'f', 2)+"M\n";
            }
            else{
                sizeStr += i18n("Size: ")+QString::number(size, 'f', 2)+"K\n";

            }
        }
        else{
            sizeStr += i18n("Size: ")+QString::number(((int)size))+"B\n";
        }
        srcStr += sizeStr;
    }
    srcStr += i18n("Owner: ") + srcInfo.owner() + ", ";
    srcStr += i18n("Group: ") + srcInfo.group() + "\n";
    srcStr += i18n("Your rights: ");
    anyRights = false;
    if(srcInfo.isReadable()){
        srcStr += i18n("Read ");
        anyRights = true;
    }
    if(srcInfo.isWritable()){
        srcStr += i18n("Write ");
        anyRights = true;
    }
    if(srcInfo.isExecutable()){
        srcStr += i18n("Execute ");
        anyRights = true;
    }
    if(!anyRights)
        srcStr += i18n("None");
    srcStr += "\n";
    srcStr += i18n("Last accessed: ") + srcInfo.lastRead().toString() + "\n";
    srcStr += i18n("Last modified: ") + srcInfo.lastModified().toString() + "\n";

    QString imageStr, cameraStr, commentStr;
    appendTooltipData(QFile::encodeName(srcInfo.absFilePath()),
                      imageStr, cameraStr, commentStr, false);
    if(!imageStr.isEmpty())
        srcStr += imageStr;

    // Dest file information
    QString destStr(i18n("Destination file\n"));
    sizeStr = "";

    if(!destInfo.isDir()){
        size = destInfo.size();
        if(size >= 1024){
            size /= 1024.0;
            if(size >= 1024){
                size /= 1024.0;
                sizeStr += i18n("Size: ")+QString::number(size, 'f', 2)+"M\n";
            }
            else{
                sizeStr += i18n("Size: ")+QString::number(size, 'f', 2)+"K\n";

            }
        }
        else{
            sizeStr += i18n("Size: ")+QString::number(((int)size))+"B\n";
        }
        destStr += sizeStr;
    }
    destStr += i18n("Owner: ") + destInfo.owner() + ", ";
    destStr += i18n("Group: ") + destInfo.group() + "\n";
    destStr += i18n("Your rights: ");
    anyRights = false;
    if(destInfo.isReadable()){
        destStr += i18n("Read ");
        anyRights = true;
    }
    if(destInfo.isWritable()){
        destStr += i18n("Write ");
        anyRights = true;
    }
    if(destInfo.isExecutable()){
        destStr += i18n("Execute ");
        anyRights = true;
    }
    if(!anyRights)
        destStr += i18n("None");
    destStr += "\n";
    destStr += i18n("Last accessed: ") + destInfo.lastRead().toString() + "\n";
    destStr += i18n("Last modified: ") + destInfo.lastModified().toString() + "\n";
    imageStr = ""; cameraStr = ""; commentStr = "";
    appendTooltipData(QFile::encodeName(destInfo.absFilePath()),
                      imageStr, cameraStr, commentStr, false);
    if(!imageStr.isEmpty())
        destStr += imageStr;

    srcDescLbl->setText(srcStr);
    destDescLbl->setText(destStr);

    renameEdit = new QLineEdit(this);
    renameEdit->setText(srcInfo.fileName());
    connect(renameEdit, SIGNAL(textChanged(const QString &)), this,
            SLOT(slotRenameEnabled(const QString &)));

    // Bug in KButtonBox means one button has to not be noexpand or there is no
    // sizehint height :P
    KButtonBox *bbox = new KButtonBox(this);
    renameBtn = bbox->addButton(i18n("Rename"), this, SLOT(slotRename()), true);
    renameBtn->setEnabled(false);
    if(!singleFile)
        bbox->addButton(i18n("AutoRename All"), this, SLOT(slotAutoRename()), true);
    else
        bbox->addButton(i18n("AutoRename"), this, SLOT(slotAutoRename()), true);
    bbox->addButton(i18n("Skip"), this, SLOT(slotSkip()), false);
    if(!singleFile)
        bbox->addButton(i18n("Skip All"), this, SLOT(slotSkipAll()), true);
    bbox->addButton(i18n("Overwrite"), this, SLOT(slotOverwrite()), true);
    if(!singleFile)
        bbox->addButton(i18n("Overwrite All"), this, SLOT(slotOverwriteAll()), true);
    QPushButton *cancelBtn = bbox->addButton(i18n("Cancel"), this, SLOT(reject()), true);
    cancelBtn->setDefault(true);
    bbox->layout();

    QGridLayout *layout = new QGridLayout(this, 0, 0, 15);
    layout->addMultiCellWidget(descLbl, 0, 0, 0, 3);
    layout->addMultiCellWidget(srcIconLbl, 1, 2, 0, 0);
    layout->addMultiCellWidget(destIconLbl, 3, 4, 0, 0);
    layout->addMultiCellWidget(srcDescLbl, 1, 2, 1, 1);
    layout->addMultiCellWidget(destDescLbl, 3, 4, 1, 1);
    layout->addMultiCellWidget(renameEdit, 6, 6, 0, 3);
    layout->addMultiCellWidget(bbox, 7, 7, 0, 3);
    layout->setColStretch(2, 1);
    layout->setRowStretch(5, 1);

}

bool KIFFileTransfer::transferFile(const QString &src, const QString &dest,
                                   QDropEvent::Action action)
{
    QString destFile = dest;
    QFileInfo fi(dest);
    if(fi.isDir()){
        fi.setFile(src);
        destFile = dest + "/" + fi.fileName();
    }

    while(QFile::exists(destFile)){
        KIFFileOpDialog *dlg = new KIFFileOpDialog(src, destFile, NULL, NULL,
                                                   true);
        if(dlg->exec() == QDialog::Rejected){
            qWarning("Overwrite dialog rejected");
            delete dlg;
            return(false);
        }
        if(dlg->fileOpSelection() == Skip || dlg->fileOpSelection() == SkipAll){
            delete dlg;
            return(false);
        }
        else if(dlg->fileOpSelection() == Overwrite ||
                dlg->fileOpSelection() == OverwriteAll){
            delete dlg;
            break;
        }
        else if(dlg->fileOpSelection() == Rename){
            destFile = dlg->renameString();
            delete dlg;
        }
        else if(dlg->fileOpSelection() == AutoRename){
            int i = 0;
            QString newStr(destFile);
            while(QFile::exists(newStr)){
                newStr = destFile;
                QFileInfo autoFi(newStr);
                newStr = autoFi.dirPath() + "/"+ autoFi.baseName() +
                    QString::number(i) + "." + autoFi.extension();
                ++i;
            }
            destFile = newStr;
            delete dlg;
        }
        else
            delete dlg;
    }
    qWarning("Operation: %s to %s", (const char *)QFile::encodeName(src),
             (const char *)QFile::encodeName(destFile));
    if(action == QDropEvent::Move)
        return(move(src, destFile));
    else if(action == QDropEvent::Copy)
        return(copy(src, destFile));
    else if(action == QDropEvent::Link)
        return(makesymlink(src, destFile));
    return(true);
}


bool KIFFileTransfer::transferFiles(QStringList &fileList, const QString &dest,
                                    QDropEvent::Action action)
{
    OpType op = None;
    struct utimbuf timeBuf;
    struct stat status;
    time_t modtime;
    CatInfo *srcCatInfo;
    long srcInode=0L;

    bool catSrcModified = false;
    bool catDestModified = false;
    QIntDict<CatInfo>srcCatagories;
    QIntDict<CatInfo>destCatagories;
    srcCatagories.setAutoDelete(true);
    destCatagories.setAutoDelete(true);
    modtime = QDateTime::currentDateTime().toTime_t();

    QString currentSrcStr, currentDestStr;
    for(QStringList::Iterator it = fileList.begin(); it != fileList.end(); ++it){
        if((*it).left(7) == "file://"){
            (*it) =  (*it).remove(0, 7);
        }
        qWarning("File operation for %s to %s",
                 (const char *)QFile::encodeName((*it)),
                 (const char *)QFile::encodeName(dest));
        // setup source catagories
        QFileInfo fi(*it);
        if(currentSrcStr.isEmpty() || currentSrcStr != fi.dirPath(true)){
            if(!currentSrcStr.isEmpty() && srcCatagories.count() != 0){
                qWarning("Source folder changed, saving old catagories");
                kifapp()->catagoryManager()->
                    saveFolderCatagories(currentSrcStr, &srcCatagories);
            }
            srcCatagories.clear();
            currentSrcStr = fi.dirPath(true);
            kifapp()->catagoryManager()->
                loadFolderCatagories(currentSrcStr, &srcCatagories);
            catSrcModified = false;
        }
        srcCatInfo = NULL;
        if(srcCatagories.count() != 0){
            if(stat(QFile::encodeName(fi.absFilePath()), &status) == 0){
                srcInode = (long)status.st_ino;
                srcCatInfo = srcCatagories.find(srcInode);
            }
            else
                qWarning("Could not stat source file %s for catagories!",
                        (const char *)QFile::encodeName(fi.absFilePath()));
        }

        // check for overwrite
        QString destStr;
        if(QFile::exists(dest+"/"+fi.fileName())){
            qWarning("Overwrite file %s",
                     (const char *)QFile::encodeName(fi.fileName()));
            if(op == None || op == Rename || op == Skip){
                KIFFileOpDialog *dlg = new KIFFileOpDialog(*it, dest,
                                                           NULL);
                if(dlg->exec() == QDialog::Rejected){
                    qWarning("Overwrite dialog rejected");
                    delete dlg;
                    return(false);
                }
                if(dlg->fileOpSelection() == Skip)
                    ;
                else if(dlg->fileOpSelection() == Overwrite){
                    destStr = dest;
                    if(action == QDropEvent::Move)
                        move(*it, dest);
                    else if(action == QDropEvent::Copy)
                        copy(*it, dest);
                    else if(action == QDropEvent::Link)
                        makesymlink(*it, dest);

                }
                else if(dlg->fileOpSelection() == Rename){
                    QFileInfo destFi(dest);
                    destStr = destFi.absFilePath() + "/" +
                        dlg->renameString();
                    if(action == QDropEvent::Move)
                        move(*it, destStr);
                    else if(action == QDropEvent::Copy)
                        copy(*it, destStr);
                    else if(action == QDropEvent::Link)
                        makesymlink(*it, destStr);
                }
                else
                    op = dlg->fileOpSelection();
                delete dlg;
            }
            if(op == AutoRename){
                int i = 0;
                destStr = dest+"/"+fi.fileName();
                while(QFile::exists(destStr)){
                    destStr = dest+"/"+fi.fileName();
                    QFileInfo autoFi(destStr);
                    destStr = autoFi.dirPath() + "/"+ autoFi.baseName() +
                        QString::number(i) + "." + autoFi.extension();
                    ++i;
                }
                if(action == QDropEvent::Move)
                    move(*it, destStr);
                else if(action == QDropEvent::Copy)
                    copy(*it, destStr);
                else if(action == QDropEvent::Link)
                    makesymlink(*it, destStr);
            }
            else if(op == SkipAll){
                ;
            }
            else if(op == OverwriteAll){
                destStr = dest;
                if(action == QDropEvent::Move)
                    move(*it, dest);
                else if(action == QDropEvent::Copy)
                    copy(*it, dest);
                else if(action == QDropEvent::Link)
                    makesymlink(*it, dest);
            }
        }
        else{
            destStr = dest;
            if(action == QDropEvent::Move)
                move(*it, dest);
            else if(action == QDropEvent::Copy)
                copy(*it, dest);
            else if(action == QDropEvent::Link)
                makesymlink(*it, dest);
        }
        // Preserve timestamp order for those who sort by date. Otherwise
        // since the first file is written first, the second file is
        // written second, etc... the order would be reversed after
        // copying because the first item becomes the oldest. We just worry
        // about order, not keeping the same time, since you probably want
        // copied files to be the newest.
        if(!destStr.isEmpty()){
            QFileInfo destInfo(destStr);
            if(destInfo.isDir())
                destInfo.setFile(destStr + "/" +  fi.fileName());
            if(destInfo.exists()){
                timeBuf.actime = destInfo.lastRead().toTime_t();
                timeBuf.modtime = modtime;
                if(utime(QFile::encodeName(destInfo.absFilePath()), &timeBuf)
                   == -1){
                    qWarning("Unable to update timestamp for %s", (const char *)
                             QFile::encodeName(destInfo.absFilePath()));
                }
                else{
                    // handle thumbnails
                    timeBuf.modtime = modtime+1;
                    if(QFile::exists(destInfo.dirPath(true) +"/.pics/large/"+
                                     destInfo.fileName()))
                        utime(QFile::encodeName(destInfo.dirPath(true)
                                                +"/.pics/large/"+
                                                destInfo.fileName()), &timeBuf);
                    if(QFile::exists(destInfo.dirPath(true) +"/.pics/med/"+
                                     destInfo.fileName()))
                        utime(QFile::encodeName(destInfo.dirPath(true)
                                                +"/.pics/med/"+
                                                destInfo.fileName()), &timeBuf);
                    if(QFile::exists(destInfo.dirPath(true) +"/.pics/small/"+
                                     destInfo.fileName()))
                        utime(QFile::encodeName(destInfo.dirPath(true)
                                                +"/.pics/small/"+
                                                destInfo.fileName()), &timeBuf);
                    if(QFile::exists(destInfo.dirPath(true) +"/.pics/huge/"+
                                     destInfo.fileName()))
                        utime(QFile::encodeName(destInfo.dirPath(true)
                                                +"/.pics/huge/"+
                                                destInfo.fileName()), &timeBuf);
                    --modtime;
                }
            }
            else
                qWarning("Unable to find destination %s to update timestamp!",
                         (const char *)QFile::encodeName(destInfo.absFilePath()));

            // Now do the destination catagories if any
            if(srcCatInfo){
                int i;
                if(currentDestStr.isEmpty() || currentDestStr !=
                   destInfo.dirPath(true)){
                    if(currentDestStr != destInfo.dirPath(true) &&
                       destCatagories.count() != 0){
                        qWarning("Dest folder changed, saving old catagories");
                        kifapp()->catagoryManager()->
                            saveFolderCatagories(currentDestStr, &destCatagories);
                    }
                    destCatagories.clear();
                    currentDestStr = destInfo.dirPath(true);
                    kifapp()->catagoryManager()->
                        loadFolderCatagories(currentDestStr, &destCatagories);
                    catDestModified = false;
                }

                if(stat(QFile::encodeName(destInfo.absFilePath()), &status)==0){
                    if(destCatagories.find((long)status.st_ino)){
                        // Could happen if overwriting
                        qWarning("Removing old catagory inode for %s!",
                                 (const char *)
                                 QFile::encodeName(destInfo.absFilePath()));
                        destCatagories.remove((long)status.st_ino);
                    }
                    CatInfo *data = new CatInfo;
                    for(i=0; i < 8; ++i)
                        data->catagories[i] = srcCatInfo->catagories[i];
                    destCatagories.insert((long)status.st_ino, data);
                    catDestModified = true;
                }
                else
                    qWarning("Could not stat dest file %s",
                             (const char *)
                             QFile::encodeName(destInfo.absFilePath()));

                if(action == QDropEvent::Move){
                    if(srcInode)
                        srcCatagories.remove(srcInode); // remove old catagory
                    catSrcModified = true;
                }
            }
        }
    }

    if(!currentDestStr.isEmpty() && catDestModified)
        kifapp()->catagoryManager()->
            saveFolderCatagories(currentDestStr, &destCatagories);
    if(!currentSrcStr.isEmpty() && catSrcModified)
        kifapp()->catagoryManager()->
            saveFolderCatagories(currentSrcStr, &srcCatagories);

    return(true);
}


bool KIFFileTransfer::copy(const QString &src, const QString &dest,
                           bool handleThumbs)
{
    QFile srcFile(src);
    QFileInfo fi(src);
    QFile destFile;

    if(fi.isDir()){
        if(QFile::exists(dest)){
            QFileInfo destFi(dest);
            if(!copyFolder(src, destFi.absFilePath()+"/"+fi.fileName())){
                KMessageBox::sorry(NULL, i18n("Cannot copy folder!"),
                                   i18n("Pixie Copy Error!"));
                return(false);
            }
        }
        else{
            if(!copyFolder(src, dest)){
                KMessageBox::sorry(NULL,  i18n("Cannot copy folder!"),
                                   i18n("Pixie Copy Error!"));
                return(false);
            }
        }
        return(true);
    }

    fi.setFile(dest);
    if(fi.isDir()){
        fi.setFile(src);
        destFile.setName(dest + "/" + fi.fileName());
    }
    else
        destFile.setName(dest);
    qWarning("In copy of %s to %s",
             (const char *)QFile::encodeName(srcFile.name()),
             (const char *)QFile::encodeName(destFile.name()));

    // TODO: First try hard link

    if(!srcFile.open(IO_ReadOnly)){
        qWarning("Unable to open source file");
        // TODO: error message
        return(false);
    }
    if(!destFile.open(IO_WriteOnly)){
        qWarning("Unable to open dest file");
        // TODO: error message
        return(false);
    }
    char buffer[65536];
    int bytesRead;
    while(!srcFile.atEnd()){
        bytesRead = srcFile.readBlock(buffer, 65536);
        if(bytesRead == -1){
            srcFile.close();
            destFile.close();
            qWarning("File copy error");
            // TODO: error message
            return(false);
        }
        else if(bytesRead != 0){
            if(destFile.writeBlock(buffer, bytesRead) == -1){
                srcFile.close();
                destFile.close();
                qWarning("File copy error");
                // TODO: error message
                return(false);
            }
        }
    }
    srcFile.close();
    destFile.close();

    // do the thumnail
    if(handleThumbs)
        moveThumbnails(src, dest, false);

    return(true);
}

bool KIFFileTransfer::move(const QString &src, const QString &dest,
                           bool handleThumbs)
{
    QFileInfo fi(src);
    if(fi.isDir()){
        if(QFile::exists(dest)){
            QFileInfo destFi(dest);
            if(rename(QFile::encodeName(src),
                      QFile::encodeName(destFi.absFilePath()+"/"+
                                        fi.fileName())) != 0){
                if(!moveFolder(src, dest)){
                    KMessageBox::sorry(NULL, i18n("Cannot move folder!"),
                                       i18n("Pixie Move Error!"));
                    return(false);
                }
            }
        }
        else{
            if(rename(QFile::encodeName(src), QFile::encodeName(dest)) != 0){
                if(!moveFolder(src, dest)){
                    KMessageBox::sorry(NULL,  i18n("Cannot move folder!"),
                                       i18n("Pixie Move Error!"));
                    return(false);
                }
            }
        }
        return(true);
    }
    else{
        if(makelink(src, dest) || copy(src, dest)){
            qWarning("Unlinking file %s",
                     (const char *)QFile::encodeName(src));
            if(unlink(QFile::encodeName(src)) != 0){
                qWarning("Error unlinking file");
                // TODO: error message
                return(false);
            }
            // do the thumbnail
            if(handleThumbs)
                moveThumbnails(src, dest);
            return(true);
        }
    }
    return(false);
}

bool KIFFileTransfer::moveFolder(const QString &src, const QString &dest)
{
    // first make sure we have delete permissions on everything
    QStringList fileList;
    if(!recursiveParseDir(src, fileList, true, false, true, false))
        return(false);

    // then copy contents
    QFileInfo fi(src);
    if(!copyFolder(src, dest)){
        // see if anything was copied
        QString newDest;
        if(QFile::exists(dest)){
            QFileInfo destFi(dest);
            newDest = QString(destFi.absFilePath()+"/"+fi.fileName());
        }
        else
            newDest = dest;
        if(QFile::exists(newDest)){
            qWarning("Removing new directory %s",
                     (const char *)QFile::encodeName(newDest));
            QStringList delList;
            recursiveParseDir(newDest, delList, true, false, true, false);
            for(QStringList::Iterator dit = delList.begin(); dit != delList.end(); ++dit){
                qWarning("removing %s",
                         (const char *)QFile::encodeName((*dit)));
                fi.setFile(*dit);
                if(fi.isDir()){
                    if(rmdir(QFile::encodeName((*dit))) == -1){
                        // these errors shouldn't happen, since we just created
                        // it
                        qWarning("rmdir error");
                        KMessageBox::sorry(NULL, i18n("Could not remove folder ") +
                                           QString(QFile::encodeName((*dit))));
                        return(false);
                    }
                }
                else{
                    if(unlink(QFile::encodeName((*dit))) == -1){
                        qWarning("unlink error");
                        KMessageBox::sorry(NULL, i18n("Could not remove file ") +
                                           QString(QFile::encodeName((*dit))));
                        return(false);
                    }
                }
            }
        }
        return(false);
    }
    // then remove the old contents
    qWarning("Removing old directory %s",
             (const char *)QFile::encodeName(src));
    for(QStringList::Iterator dit = fileList.begin(); dit != fileList.end(); ++dit){
        qWarning("removing %s",
                 (const char *)QFile::encodeName((*dit)));
        fi.setFile(*dit);
        if(fi.isDir()){
            if(rmdir(QFile::encodeName((*dit))) == -1){
                qWarning("rmdir error");
                KMessageBox::sorry(NULL, i18n("Could not remove folder ") +
                                   QString(QFile::encodeName((*dit))));
                return(false);
            }
        }
        else{
            if(unlink(QFile::encodeName((*dit))) == -1){
                qWarning("unlink error");
                KMessageBox::sorry(NULL, i18n("Could not remove file ") +
                                   QString(QFile::encodeName((*dit))));
                return(false);
            }
        }
    }
    return(true);
}

bool KIFFileTransfer::copyFolder(const QString &src, const QString &dest)
{
    QFileInfo fi(src);
    if(!fi.isDir()){
        qWarning("Copy folder called on a file that is not a folder!");
        return(false);
    }
    QString newDest;
    if(QFile::exists(dest)){
        QFileInfo destFi(dest);
        newDest = QString(destFi.absFilePath()+"/"+fi.fileName());
    }
    else
        newDest = dest;
    qWarning("Copying folder %s to %s", (const char *)QFile::encodeName(src),
             (const char *)QFile::encodeName(newDest));

    QStringList fileList;
    if(!recursiveParseDir(src, fileList, false, true, true, true))
        return(false);

    QString destFile;
    for(QStringList::Iterator it = fileList.begin(); it != fileList.end(); ++it){
        // convert src file to relative path
        destFile = (*it);
        destFile.remove(0, src.length());
        destFile = newDest+destFile;
        fi.setFile(*it);
        if(fi.isDir()){
            // get orignal folder permissions
            struct stat buffer;
            stat(QFile::encodeName((*it)), &buffer);
            if(mkdir(QFile::encodeName(destFile), buffer.st_mode) != 0){
                KMessageBox::sorry(NULL, i18n("Cannot create folder ") +
                                   destFile);
                return(false);
            }
        }
        else{
            if(!copy(*it, destFile, false)){
                KMessageBox::sorry(NULL, i18n("Cannot copy ") +
                                   QString(QFile::encodeName((*it))) + " to "
                                   + QString(QFile::encodeName(destFile)));
                return(false);
            }

        }
    }
    return(true);
}



bool KIFFileTransfer::moveThumbnails(const QString &src, const QString &dest,
                                     bool move)
{
    qWarning("In moveThumbnails");
    QFileInfo fi(src);
    QString srcDirStr = fi.dirPath(true);
    QString srcFile = fi.fileName();

    // Pixie Thumbnails
    QString destDirStr;
    QString destFile;
    fi.setFile(dest);
    if(!fi.isDir()){
        destDirStr = fi.dirPath(true);
        destFile = fi.fileName();
    }
    else{
        destDirStr = fi.absFilePath();
        destFile = srcFile;
    }

    qWarning("Source directory: %s",
             (const char *)QFile::encodeName(srcDirStr));
    qWarning("Target directory: %s",
             (const char *)QFile::encodeName(destDirStr));

    if(QFile::exists(srcDirStr+"/.pics/xxl/"+srcFile)){
        qWarning("Found xxl thumbnail");
        if(!QFile::exists(destDirStr+"/.pics")){
            if(mkdir(QFile::encodeName(destDirStr+"/.pics"), 0777) == -1){
                qWarning("Couldn't make .pics dir!");
                return(false);
            }
        }
        if(!QFile::exists(destDirStr+"/.pics/xxl")){
            if(mkdir(QFile::encodeName(destDirStr+"/.pics/xxl"), 0777) == -1){
                qWarning("Couldn't make .pics/xxl dir!");
                return(false);
            }
        }
        if(move){
            if(makelink(srcDirStr+"/.pics/xxl/"+srcFile,
                        destDirStr+"/.pics/xxl/"+destFile) ||
               copy(srcDirStr+"/.pics/xxl/"+srcFile,
                    destDirStr+"/.pics/xxl/"+destFile)){
                qWarning("Unlinking file %s",
                         (const char *)QFile::encodeName(srcDirStr+
                                                         "/.pics/xxl/"+srcFile));
                if(unlink(QFile::encodeName(srcDirStr+"/.pics/xxl/"+srcFile)) != 0){
                    qWarning("Error unlinking file");
                }
            }
        }
        else{
            copy(srcDirStr+"/.pics/xxl/"+srcFile,
                 destDirStr+"/.pics/xxl/"+destFile);
        }
    }
    if(QFile::exists(srcDirStr+"/.pics/large/"+srcFile)){
        qWarning("Found large thumbnail");
        if(!QFile::exists(destDirStr+"/.pics")){
            if(mkdir(QFile::encodeName(destDirStr+"/.pics"), 0777) == -1){
                qWarning("Couldn't make .pics dir!");
                return(false);
            }
        }
        if(!QFile::exists(destDirStr+"/.pics/large")){
            if(mkdir(QFile::encodeName(destDirStr+"/.pics/large"), 0777) == -1){
                qWarning("Couldn't make .pics/large dir!");
                return(false);
            }
        }
        if(move){
            if(makelink(srcDirStr+"/.pics/large/"+srcFile,
                        destDirStr+"/.pics/large/"+destFile) ||
               copy(srcDirStr+"/.pics/large/"+srcFile,
                    destDirStr+"/.pics/large/"+destFile)){
                qWarning("Unlinking file %s",
                         (const char *)QFile::encodeName(srcDirStr+
                                                         "/.pics/large/"+
                                                         srcFile));
                if(unlink(QFile::encodeName(srcDirStr+"/.pics/large/"+srcFile)) != 0){
                    qWarning("Error unlinking file" );
                }
            }
        }
        else{
            copy(srcDirStr+"/.pics/large/"+srcFile,
                 destDirStr+"/.pics/large/"+destFile);
        }

    }
    if(QFile::exists(srcDirStr+"/.pics/med/"+srcFile)){
        qWarning("Found medium thumbnail");
        if(!QFile::exists(destDirStr+"/.pics")){
            if(mkdir(QFile::encodeName(destDirStr+"/.pics"), 0777) == -1){
                qWarning("Couldn't make .pics dir!");
                return(false);
            }
        }
        if(!QFile::exists(destDirStr+"/.pics/large")){
            if(mkdir(QFile::encodeName(destDirStr+"/.pics/med"), 0777) == -1){
                qWarning("Couldn't make .pics/med dir!");
                return(false);
            }
        }
        if(move){
            if(makelink(srcDirStr+"/.pics/med/"+srcFile,
                        destDirStr+"/.pics/med/"+destFile) ||
               copy(srcDirStr+"/.pics/med/"+srcFile,
                    destDirStr+"/.pics/med/"+destFile)){
                qWarning("Unlinking file %s",
                         (const char *)QFile::encodeName(srcDirStr+
                                                         "/.pics/med/"+
                                                         srcFile));
                if(unlink(QFile::encodeName(srcDirStr+"/.pics/med/"+srcFile)) != 0){
                    qWarning("Error unlinking file");
                }
            }
        }
        else{
            copy(srcDirStr+"/.pics/med/"+srcFile,
                 destDirStr+"/.pics/med/"+destFile);
        }

    }
    if(QFile::exists(srcDirStr+"/.pics/small/"+srcFile)){
        qWarning("Found small thumbnail");
        if(!QFile::exists(destDirStr+"/.pics")){
            if(mkdir(QFile::encodeName(destDirStr+"/.pics"), 0777) == -1){
                qWarning("Couldn't make .pics dir!");
                return(false);
            }
        }
        if(!QFile::exists(destDirStr+"/.pics/small")){
            if(mkdir(QFile::encodeName(destDirStr+"/.pics/small"), 0777) == -1){
                qWarning("Couldn't make .pics/small dir!");
                return(false);
            }
        }
        if(move){
            if(makelink(srcDirStr+"/.pics/small/"+srcFile,
                        destDirStr+"/.pics/small/"+destFile) ||
               copy(srcDirStr+"/.pics/small/"+srcFile,
                    destDirStr+"/.pics/med/"+destFile)){
                qWarning("Unlinking file %s",
                         (const char *)QFile::encodeName(srcDirStr+
                                                         "/.pics/small/"+
                                                         srcFile));
                if(unlink(QFile::encodeName(srcDirStr+"/.pics/small/"+srcFile)) != 0){
                    qWarning("Error unlinking file");
                }
            }
        }
        else{
            copy(srcDirStr+"/.pics/small/"+srcFile,
                 destDirStr+"/.pics/small/"+destFile);
        }
    }

    // Konq thumbnails
    KURL srcURL;

    srcURL.setPath(QDir::cleanDirPath(srcDirStr));
    KMD5 srcMD5(QFile::encodeName(srcURL.url()));
    QCString srcHash = srcMD5.hexDigest();

    srcDirStr = KGlobal::dirs()->localkdedir() + "/share/thumbnails/" +
        QString::fromLatin1(srcHash.data(), 4) + "/" +
        QString::fromLatin1(srcHash.data()+4, 4) + "/" +
        QString::fromLatin1(srcHash.data()+8) + "/";

    if(QFile::exists(srcDirStr)){
        KURL destURL;
        destURL.setPath(QDir::cleanDirPath(destDirStr));
        KMD5 destMD5(QFile::encodeName(destURL.url()));
        QCString destHash = destMD5.hexDigest();

        destDirStr = KGlobal::dirs()->localkdedir() + "/share/thumbnails/" +
            QString::fromLatin1(destHash.data(), 4) + "/";
        if(!QFile::exists(destDirStr)){
            if(mkdir(QFile::encodeName(destDirStr), 0777) == -1){
                qWarning("Couldn't make Konq thumbnail dir!");
                return(false);
            }
        }
        destDirStr += QString::fromLatin1(destHash.data()+4, 4) + "/";
        if(!QFile::exists(destDirStr)){
            if(mkdir(QFile::encodeName(destDirStr), 0777) == -1){
                qWarning("Couldn't make Konq thumbnail dir!");
                return(false);
            }
        }
        destDirStr += QString::fromLatin1(destHash.data()+8) + "/"; 
        if(!QFile::exists(destDirStr)){
            if(mkdir(QFile::encodeName(destDirStr), 0777) == -1){
                qWarning("Couldn't make Konq thumbnail dir!");
                return(false);
            }
        }

        if(QFile::exists(srcDirStr+"xxl/"+srcFile)){
            if(!QFile::exists(destDirStr+"xxl/")){
                if(mkdir(QFile::encodeName(destDirStr+"xxl/"), 0777) == -1){
                    qWarning("Couldn't make Konq xxl dir!");
                    return(false);
                }

            }
            if(move){
                if(makelink(srcDirStr+"xxl/"+srcFile,
                            destDirStr+"xxl/"+destFile) ||
                   copy(srcDirStr+"xxl/"+srcFile,
                        destDirStr+"xxl/"+destFile)){
                    qWarning("Unlinking file %s",
                             (const char *)QFile::encodeName(srcDirStr+"xxl/"+
                                                             srcFile));
                    if(unlink(QFile::encodeName(srcDirStr+"xxl/"+srcFile)) != 0){
                        qWarning("Error unlinking file");
                    }
                }
            }
            else{
                copy(srcDirStr+"xxl/"+srcFile,
                     destDirStr+"xxl/"+destFile);
            }
        }
        if(QFile::exists(srcDirStr+"large/"+srcFile)){
            if(!QFile::exists(destDirStr+"large/")){
                if(mkdir(QFile::encodeName(destDirStr+"large/"), 0777) == -1){
                    qWarning("Couldn't make Konq large dir!");
                    return(false);
                }

            }
            if(move){
                if(makelink(srcDirStr+"large/"+srcFile,
                            destDirStr+"large/"+destFile) ||
                   copy(srcDirStr+"large/"+srcFile,
                        destDirStr+"large/"+destFile)){
                    qWarning("Unlinking file %s",
                             (const char *)QFile::encodeName(srcDirStr+
                                                             "large/"+
                                                             srcFile));
                    if(unlink(QFile::encodeName(srcDirStr+"large/"+srcFile)) != 0){
                        qWarning("Error unlinking file");
                    }
                }
            }
            else{
                copy(srcDirStr+"large/"+srcFile,
                     destDirStr+"large/"+destFile);
            }
        }
        if(QFile::exists(srcDirStr+"med/"+srcFile)){
            if(!QFile::exists(destDirStr+"med/")){
                if(mkdir(QFile::encodeName(destDirStr+"med/"), 0777) == -1){
                    qWarning("Couldn't make Konq med dir!");
                    return(false);
                }

            }
            if(move){
                if(makelink(srcDirStr+"med/"+srcFile,
                            destDirStr+"med/"+destFile) ||
                   copy(srcDirStr+"med/"+srcFile,
                        destDirStr+"med/"+destFile)){
                    qWarning("Unlinking file %s",
                             (const char *)QFile::encodeName(srcDirStr+
                                                             "med/"+
                                                             srcFile));
                    if(unlink(QFile::encodeName(srcDirStr+"med/"+srcFile)) != 0){
                        qWarning("Error unlinking file");
                    }
                }
            }
            else{
                copy(srcDirStr+"med/"+srcFile,
                     destDirStr+"med/"+destFile);
            }
        }
        if(QFile::exists(srcDirStr+"small/"+srcFile)){
            if(!QFile::exists(destDirStr+"small/")){
                if(mkdir(QFile::encodeName(destDirStr+"small/"), 0777) == -1){
                    qWarning("Couldn't make Konq small dir!");
                    return(false);
                }

            }
            if(move){
                if(makelink(srcDirStr+"small/"+srcFile,
                            destDirStr+"small/"+destFile) ||
                   copy(srcDirStr+"small/"+srcFile,
                        destDirStr+"small/"+destFile)){
                    qWarning("Unlinking file %s",
                             (const char *)QFile::encodeName(srcDirStr+
                                                             "small/"+
                                                             srcFile));
                    if(unlink(QFile::encodeName(srcDirStr+"small/"+srcFile)) != 0){
                        qWarning("Error unlinking file");
                    }
                }
            }
            else{
                copy(srcDirStr+"small/"+srcFile,
                     destDirStr+"small/"+destFile);
            }
        }
    }
    return(true);
}


bool KIFFileTransfer::makelink(const QString &src, const QString &dest)
{
    QString destFile = dest;
    QFileInfo fi(dest);
    if(fi.isDir()){
        fi.setFile(src);
        destFile = dest + "/" + fi.fileName();
    }
    if(link(QFile::encodeName(src), QFile::encodeName(destFile)) == 0){
        qWarning("Link %s -> %s", (const char *)QFile::encodeName(src),
                 (const char *)QFile::encodeName(destFile));
        return(true);
    }
    qWarning("Unable to create hard link");
    return(false);
}

bool KIFFileTransfer::makesymlink(const QString &src, const QString &dest)
{
    QString destFile = dest;
    QFileInfo fi(dest);
    if(fi.isDir()){
        fi.setFile(src);
        destFile = dest + "/" + fi.fileName();
    }
    if(symlink(QFile::encodeName(src), QFile::encodeName(destFile)) == 0)
        return(true);
    KMessageBox::sorry(NULL, i18n("Unable to create symlink"));
    return(false);
}

bool KIFFileTransfer::recursiveParseDir(const QString &path,
                                        QStringList &fileList,
                                        bool requireDeletePerms,
                                        bool requireReadPerms,
                                        bool processPicsDir,
                                        bool folderNameBeforeContents)
{
    QDir dir(path);
    dir.setFilter(QDir::All | QDir::Hidden);

    const QFileInfoList *list = dir.entryInfoList();
    QFileInfoListIterator it(*list);
    QFileInfo *fi;
    if(folderNameBeforeContents)
        fileList.append(path);
    while((fi = it.current())){
        if(fi->isDir()){
            if(!fi->isReadable()){
                KMessageBox::sorry(NULL, i18n("Cannot read folder ") +
                                   fi->absFilePath());
                return(false);
            }
            else if(!fi->isWritable() && requireDeletePerms){
                KMessageBox::sorry(NULL, i18n("You do not have permission for folder ") +
                                   fi->absFilePath());
                return(false);
            }
            else if(fi->fileName() == ".pics" && !processPicsDir){
                qWarning("Skipping .pics dir");
            }
            else if(fi->fileName() == "." || fi->fileName() == ".."){
                ;
            }
            else{
                if(!recursiveParseDir(fi->absFilePath(), fileList,
                                      requireDeletePerms, requireReadPerms,
                                      processPicsDir, folderNameBeforeContents))
                    return(false);
            }
        }
        else{
            if(!fi->isReadable() && requireReadPerms){
                KMessageBox::sorry(NULL, i18n("Cannot read file ") + fi->fileName());
                return(false);
            }
            fileList.append(fi->absFilePath());
        }
        ++it;
    }
    if(!folderNameBeforeContents)
        fileList.append(path);
    return(true);
}











