/***************************************************************************
 *   Copyright (C) 2004 by Fred Schaettgen <kdebluetooth@schaettgen.de>*
 *                                                                         *
 *   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 of the License, or     *
 *   (at your option) any later version.                                   *
 ***************************************************************************/
#include "commandhandler.h"

#include <tdecmdlineargs.h>
#include <tdeapplication.h>
#include <tdelocale.h>
#include <iostream>
#include <kdebug.h>
#include <tqdatetime.h>
#include <tqtimer.h>
#include <tdeio/job.h>

CommandHandler::CommandHandler(TDECmdLineArgs *a)
{
    this->iterate = false;
    this->args = a;
    returnValue = 0;
    if (args->count() < 2)
    {
        exitPrintUsage(i18n("Arguments missing."));
    }
    origCommand = args->arg(0);
    for (int n = 1; n < args->count() - 1; ++n)
    {
        sources.append(args->arg(n));
    }
    target = args->arg(args->count() - 1);
    targets = sources;
    targets.append(target);

    if (args->isSet("outfile"))
    {
        outFile.setName(args->getOption("outfile"));
        outFile.open(IO_WriteOnly);
    }
    else
    {
        // Open stdout
        outFile.open(IO_WriteOnly, 1);
    }

    if (args->isSet("infile"))
    {
        inFile.setName(args->getOption("infile"));
        inFile.open(IO_ReadOnly);
    }
    else
    {
        // Open stdin
        inFile.open(IO_ReadOnly, 0);
    }

    showProgressWindow = args->isSet("progresswindow");
    overwrite = args->isSet("overwrite");
}

CommandHandler::~CommandHandler()
{
}

void CommandHandler::start()
{
    if (origCommand == "ls")
    {
        command = "ls";
        list(target);
    }
    else if (origCommand == "get" || origCommand == "cat" || origCommand == "read")
    {
        command = "get";
        get(target);
    }
    else if (origCommand == "put" || origCommand == "write")
    {
        command = "put";
        put(target);
    }
    else if (origCommand == "mkdir")
    {
        command = "mkdir";
        mkdir(target);
    }
    else if (origCommand == "rmdir")
    {
        command = "rmdir";
        rmdir(target);
    }
    else if (origCommand == "rm" || origCommand == "del")
    {
        command = "del";
        del(targets);
    }
    else if (origCommand == "cp" || origCommand == "copy")
    {
        command = "copy";
        copy(sources, target);
    }
    else
    {
        command = origCommand;
        exitPrintUsage(i18n("unknown command: %1").arg(command));
    }
}

void CommandHandler::commonConnect(TDEIO::Job* job)
{
    connect(job, TQ_SIGNAL(infoMessage(TDEIO::Job*,const TQString&)),
            this, TQ_SLOT(slotInfoMessage(TDEIO::Job*,const TQString&)));
    connect(job, TQ_SIGNAL(percent (TDEIO::Job*, unsigned long)),
            this, TQ_SLOT(slotPercent(TDEIO::Job*, unsigned long)));
    connect(job, TQ_SIGNAL(result(TDEIO::Job*)), this, TQ_SLOT(slotFinished(TDEIO::Job*)));
}

KURL::List CommandHandler::urlList(const TQStringList& sources)
{
    KURL::List ret;
    for (size_t n = 0; n < sources.size(); ++n)
    {
        ret.append(KURL(sources[n]));
    }
    return ret;
}

// Commands ---------------------------------------------------

void CommandHandler::list(const TQString& target)
{
    bool showHidden = true;
    TDEIO::ListJob* job = TDEIO::listDir(KURL(target), showProgressWindow, showHidden);
    this->job = job;
    commonConnect(job);
    connect(job, TQ_SIGNAL(entries(TDEIO::Job*, const TDEIO::UDSEntryList&)),
            this, TQ_SLOT(slotEntries(TDEIO::Job*, const TDEIO::UDSEntryList&)));
}

void CommandHandler::get(const TQString& target)
{
    bool reload = false;
    TDEIO::TransferJob* job = TDEIO::get(KURL(target), reload, showProgressWindow);
    this->job = job;
    commonConnect(job);
    connect(job, TQ_SIGNAL(data(TDEIO::Job*,const TQByteArray&)),
            this, TQ_SLOT(slotData(TDEIO::Job*,const TQByteArray&)));
}

void CommandHandler::put(const TQString& target)
{
    int permissions = -1;
    bool resume = false;
    TDEIO::TransferJob* job = TDEIO::put(KURL(target), permissions, 
            overwrite, resume, showProgressWindow);
    this->job = job;
    commonConnect(job);
    connect(job, TQ_SIGNAL(dataReq(TDEIO::Job*,TQByteArray&)),
            this, TQ_SLOT(slotDataReq(TDEIO::Job*,TQByteArray&)));
}

void CommandHandler::mkdir(const TQString& target)
{
    int permissions = -1;
    TDEIO::SimpleJob* job = TDEIO::mkdir(KURL(target), permissions);
    this->job = job;
    commonConnect(job);    
}

void CommandHandler::rmdir(const TQString& target)
{
    TDEIO::SimpleJob* job = TDEIO::rmdir(KURL(target));
    this->job = job;
    commonConnect(job);    
}

void CommandHandler::del(const TQStringList& targets)
{
    bool shred = false;
    TDEIO::DeleteJob* job = TDEIO::del(urlList(targets), shred, showProgressWindow);
    this->job = job;
    commonConnect(job);
}

void CommandHandler::copy(const TQStringList& sources, const TQString& target)
{
    TDEIO::CopyJob *job = TDEIO::copy(urlList(sources), KURL(target),
            showProgressWindow);
    this->job = job;
    commonConnect(job);
}

// Signal handlers --------------------------------------------

void CommandHandler::slotEntries(TDEIO::Job* /*job*/, const TDEIO::UDSEntryList& list)
{
    if (command == "ls")
    {
        for (size_t n = 0; n < list.size(); ++n)
        {
            TDEIO::UDSEntry entry = list[n];

            TQDateTime date = TQDateTime::currentDateTime();
            TQString user = "n/a";
            TQString iconName = "unknown";
            TQString group = "n/a";
            TQString extra = "n/a";
            TQString name = "n/a";
            TQDateTime mTime = TQDateTime::currentDateTime();
            TQDateTime aTime = TQDateTime::currentDateTime();
            TQDateTime cTime = TQDateTime::currentDateTime();
            int fileType = 0;
            TQString linkDest = "n/a";
            TQString url = "n/a";
            TQString mimeType = "n/a";
            TQString guessedMimeType = "n/a";
            TQString xmlProperties = "n/a";
            long long size = -1;
            int access = 0;

            for (size_t m = 0; m < entry.size(); ++m)
            {
                TDEIO::UDSAtom atom = entry[m];
                switch (atom.m_uds)
                {
                case TDEIO::UDS_TIME:
                    date.setTime_t(atom.m_long);
                    break;
                case TDEIO::UDS_SIZE:
                    size = atom.m_long;
                    break;
                case TDEIO::UDS_USER:
                    user = atom.m_str;
                    break;
                case TDEIO::UDS_ICON_NAME:
                    iconName = atom.m_str;
                    break;
                case TDEIO::UDS_GROUP:
                    group = atom.m_str;
                    break;
                case TDEIO::UDS_EXTRA:
                    extra = atom.m_str;
                    break;
                case TDEIO::UDS_NAME:
                    name = atom.m_str;
                    break;
                case TDEIO::UDS_ACCESS:
                    access = atom.m_long;
                    break;
                case TDEIO::UDS_MODIFICATION_TIME:
                    mTime.setTime_t(atom.m_long);
                    break;
                case TDEIO::UDS_ACCESS_TIME:
                    aTime.setTime_t(atom.m_long);
                    break;
                case TDEIO::UDS_CREATION_TIME:
                    cTime.setTime_t(atom.m_long);
                    break;
                case TDEIO::UDS_FILE_TYPE:
                    fileType = atom.m_long;
                    break;
                case TDEIO::UDS_LINK_DEST:
                    linkDest = atom.m_str;
                    break;
                case TDEIO::UDS_URL:
                    url = atom.m_str;
                    break;
                case TDEIO::UDS_MIME_TYPE:
                    mimeType = atom.m_str;
                    break;
                case TDEIO::UDS_GUESSED_MIME_TYPE:
                    guessedMimeType = atom.m_str;
                    break;
                case TDEIO::UDS_XML_PROPERTIES:
                    xmlProperties = atom.m_str;
                    break;
                };
            }

            if (args->isSet("access"))
            {
                std::cout << TQString::number(access, 8).local8Bit() << " ";
            }
            if (args->isSet("filetype"))
            {
                std::cout << TQString::number(fileType).rightJustify(4).local8Bit() << " ";
            }
            if (args->isSet("user"))
            {
                std::cout << user.rightJustify(8).local8Bit() << " ";
            }
            if (args->isSet("group"))
            {
                std::cout << group.rightJustify(8).local8Bit() << " ";
            }
            if (args->isSet("size"))
            {
                std::cout << TQString::number(size).rightJustify(9).local8Bit() << " ";
            }
            if (args->isSet("date"))
            {
                std::cout << date.toString("yyyy-MM-dd hh:mm:ss").local8Bit() << " ";
            }
            if (args->isSet("mtime"))
            {
                std::cout << mTime.toString("yyyy-MM-dd hh:mm:ss").local8Bit() << " ";
            }
            if (args->isSet("atime"))
            {
                std::cout << aTime.toString("yyyy-MM-dd hh:mm:ss").local8Bit() << " ";
            }
            if (args->isSet("ctime"))
            {
                std::cout << cTime.toString("yyyy-MM-dd hh:mm:ss").local8Bit() << " ";
            }
            if (args->isSet("iconName"))
            {
                std::cout << iconName.local8Bit() << " ";
            }
            if (args->isSet("mimetype"))
            {
                std::cout << mimeType.local8Bit() << " ";
            }
            if (args->isSet("guessedmimetype"))
            {
                std::cout << guessedMimeType.local8Bit() << " ";
            }
            if (args->isSet("linkdest"))
            {
                std::cout << linkDest.local8Bit() << " ";
            }
            if (args->isSet("url"))
            {
                std::cout << url.local8Bit() << " ";
            }
            if (args->isSet("name"))
            {
                std::cout << name.local8Bit() << " ";
            }
            if (args->isSet("xmlproperties"))
            {
                std::cout << xmlProperties.local8Bit() << " ";
            }
            if (args->isSet("extra"))
            {
                std::cout << extra.local8Bit() << " ";
            }
            std::cout << std::endl;
        }
    }
}

void CommandHandler::slotData(TDEIO::Job* /*job*/, const TQByteArray &data)
{
    outFile.writeBlock(data);
}

void CommandHandler::slotDataReq(TDEIO::Job* /*job*/, TQByteArray &data)
{
    data.resize(65536);
    data.resize(inFile.readBlock(data.data(), data.size()));
}

void CommandHandler::slotInfoMessage(TDEIO::Job* /*job*/, const TQString& msg)
{
    if (msg != lastMessage && args->isSet("messages"))
    {
        std::cerr << " >" << msg.local8Bit() << std::endl;
        lastMessage = msg;
    }
}

void CommandHandler::slotPercent(TDEIO::Job* /*job*/, unsigned long /*percent*/)
{

}

void CommandHandler::slotFinished(TDEIO::Job* job)
{
    if (job->error() != 0)
    {
        std::cerr << job->errorString().local8Bit() << std::endl;
        iterate = false;
    }
    else
    {
        if (iterate)
        {
            start();
        }
    }

    if (!iterate)
    {
        TDEApplication::kApplication()->exit(job->error());
    }
}

void CommandHandler::exitPrintUsage(const TQString& message)
{
    std::cout << message.local8Bit() << std::endl;
    TDECmdLineArgs::usage();
}

#include "commandhandler.moc"
