/* This file is part of the KDE project

   Copyright (C) 2005 Dario Massarin <nekkar@libero.it>
   Copyright (C) 2009 Lukas Appelhans <l.appelhans@gmx.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.
*/

#ifndef JOB_H
#define JOB_H

/**
 *  @brief Job class
 *
 *  We want to abstract this common interface in order to simplify the
 *  Scheduler code. A Job can be either a Transfer or a search through the net.
 *  It is basically something you execute in background and that the scheduler
 *  can decide to start, stop or cancel. In this way we don't expose the complex
 *  API of a Transfer (or a Search), to the scheduler.
 *  By definition a job must always belong to a JobQueue (see jobqueue.h).
 **/

#include "kget_export.h"
#include <QObject>
#include <QPixmap>

class QDomNode;

class Scheduler;
class JobQueue;

class KGET_EXPORT Job : public QObject
{
    Q_OBJECT
public:
    /**
     * The status property describes the current job status
     */
    enum Status {
        Running = 0, /// The job is being executed
        Stopped = 2, /// The job is stopped
        Aborted = 3, /// The job is stopped, but this also indicates that it
                     /// stopped because an error occurred
        Finished = 4, /// The job exited from its Running state successfully
        FinishedKeepAlive = 5, /// The job exited from its Running state successfully
                               /// but wants to be restarted by the scheduler
        Moving = 6 /// The associated files to that job (e.g. Download) are
                   /// moved to a different location
    };

    /**
     * The policy property describes how the scheduler should manage this job.
     */
    enum Policy {
        Start, /// The scheduler should start this job even if its queue
               /// isn't in a Running status
        Stop, /// The scheduler shouldn't never start this job, even if
              /// if its queue is in a Running status
        None /// The scheduler should start this job depending on its
             /// queue status
    };
    /**
     * Describes different types of errors and how the scheduler should manage them.
     */
    enum ErrorType {
        AutomaticRetry,
        ManualSolve,
        NotSolveable
    };
    struct Error {
        int id;
        QString text;
        QString iconName;
        ErrorType type;
    };
    Job(Scheduler *scheduler, JobQueue *parent);
    ~Job() override;

    // Job commands
    virtual void start() = 0;
    virtual void stop() = 0;

    JobQueue *jobQueue()
    {
        return m_jobQueue;
    }

    // Job properties
    void setStatus(Status jobStatus);
    void setPolicy(Policy jobPolicy);
    void setError(const QString &text, const QString &iconName, ErrorType type = AutomaticRetry, int errorId = -1);

    Status status() const
    {
        return m_status;
    }
    Status startStatus() const
    {
        return m_startStatus;
    }
    Policy policy() const
    {
        return m_policy;
    }
    Error error() const
    {
        return m_error;
    }

    virtual int elapsedTime() const = 0;
    virtual int remainingTime() const = 0;
    virtual bool isStalled() const = 0;
    virtual bool isWorking() const = 0;

    virtual void resolveError(int errorId);

protected:
    Scheduler *scheduler() const
    {
        return m_scheduler;
    }

    void read(QDomNode *n);
    void write(QDomNode *n);

    void setStartStatus(Status jobStatus);

    /**
     * This one posts a job event to the scheduler
     */
    void postJobEvent(Status); // do we need a JobEvent instead of JobStatus?

    JobQueue *m_jobQueue;
    Scheduler *m_scheduler;

private:
    Status m_status;
    // our status when KGet is started
    Status m_startStatus;
    Policy m_policy;
    Error m_error;
};

#endif
