#ifndef Job_h
#define Job_h

/******************************************************************************
*
* Copyright (C) 2002 Hugo PEREIRA <mailto: hugo.pereira@free.fr>
*
* This 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.
*
* This software 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.
*
* You should have received a copy of the GNU General Public License along with
* this program.  If not, see <http://www.gnu.org/licenses/>.
*
*******************************************************************************/

#include "Counter.h"
#include "TimeStamp.h"

#include <QIcon>
#include <QList>
#include <QMap>
#include <QSet>
#include <QVector>

//! single process read from top command line output
class Job: public Counter
{
    public:

    //! list of jobs
    using List = QList<Job>;

    //! set of jobs
    using Set = QSet<Job>;

    //! constructor
    Job( void );

    //! constructor
    Job( long, long = 0 );

    //! lower than operator
    bool operator < ( const Job& other ) const
    {
        return
            (parentId() < other.parentId()) ||
            (parentId() == other.parentId() && id() < other.id() );
    }

    //! equal to operator
    bool operator == ( const Job& other ) const
    {
        return
            parentId() == other.parentId() &&
            id() == other.id();
    }

    //! changed flags
    enum Flag
    {
        Id = 1<<0,
        ParentId = 1<<1,
        TreeParentId = 1<<2,
        Name = 1<<3,
        LongName = 1<<4,
        Command = 1<<5,
        User = 1<<6,
        UserId = 1<<7,
        State = 1<<8,
        Cpu = 1<<9,
        Memory = 1<<10,
        Priority = 1<<11,
        Nice = 1<<12,
        VirtualMemory = 1<<13,
        ResidentMemory = 1<<14,
        SharedMemory = 1<<15,
        UserTime = 1<<16,
        SystemTime = 1<<16,
        ElapsedTime = 1<<17,
        Threads = 1<<18,
        StartTime = 1<<19,
        Icon = 1<<20
    };

    Q_DECLARE_FLAGS( Flags, Flag );

    //!@name accessors
    //@{

    //! valid
    bool isValid( void ) const
    { return mask_&Id && mask_&Name;  }

    //! mask
    Flags mask( void ) const
    { return mask_; }

    //! id
    long id( void ) const
    { return id_; }

    //! parent id
    long parentId( void ) const
    { return parentId_; }

    //! returns true if this job is a child of argument
    bool isChild( const Job& other ) const
    { return treeParentId_ == other.id_; }

    //! name
    QString name( void ) const
    { return name_; }

    //! long name
    QString longName( void ) const
    { return longName_; }

    //! command
    QString command( void ) const
    { return command_; }

    //! user
    QString user( void ) const
    { return user_; }

    //! user id
    qint64 userId( void ) const
    { return userId_; }

    //! state
    QChar state( void ) const
    { return state_; }

    //! returns true if job is running
    bool isRunning( void ) const
    { return state_ == 'R'; }

    //! returns true if job is paused
    bool isPaused( void ) const
    { return state_ == 'T'; }

    //! cpu percentage
    qreal cpu( void ) const
    { return cpu_; }

    //! memory percentage
    qreal memory( void ) const
    { return memory_; }

    //! priority
    int priority( void ) const
    { return priority_; }

    //! nice
    int nice( void ) const
    { return nice_; }

    //! virtual memory
    int virtualMemory( void ) const
    { return virtualMemory_; }

    //! resident memory
    int residentMemory( void ) const
    { return residentMemory_; }

    //! shared memory
    int sharedMemory( void ) const
    { return sharedMemory_; }

    //! time
    int userTime( void ) const
    { return userTime_; }

    //! time
    int systemTime( void ) const
    { return systemTime_; }

    //! time
    int cpuTime( void ) const
    { return userTime_ + systemTime_; }

    //! time
    QString userTimeString( void ) const
    { return _timeString( userTime_ ); }

    //! time
    QString systemTimeString( void ) const
    { return _timeString( systemTime_ ); }

    // time
    QString cpuTimeString( void ) const
    { return _timeString( userTime_ + systemTime_ ); }

    //! threads
    int threads( void ) const
    { return threads_; }

    //! start time
    const TimeStamp startTime( void ) const
    { return startTime_; }

    //!icon initialized
    bool iconInitialized( void ) const
    { return iconInitialized_; }

    //! icon
    QIcon icon( void ) const
    { return icon_; }

    //@}

    //!@name modifiers
    //@{

    //! clear mask
    void clearMask( void )
    { mask_ = 0; }

    //! update from other job
    void updateFrom( const Job& );

    //! read name from /proc/pid/cmdline
    void readFromCommandLine( void );

    //! read information from /proc/pid/status
    bool readFromStatus( void );

    //! read information from /proc/pid/stat
    bool readFromStat( void );

    //! read information from /proc/pid/statM
    bool readFromStatM( void );

    //! read start time
    bool readStartTime( void );

    //! id
    void setId( long value )
    {
        id_ = value;
        mask_ |= Id;
    }

    //! parent id
    void setParentId( long value )
    {
        parentId_ = value;
        mask_ |= ParentId;
    }

    //! parent id
    void setTreeParentId( long value )
    {
        treeParentId_ = value;
        mask_ |= TreeParentId;
    }

    //! name
    void setName( const QString& value )
    {
        name_ = value;
        mask_ |= Name;
    }

    //! long name
    void setLongName( const QString& value )
    {
        longName_ = value;
        mask_ |= LongName;
    }

    //! command
    void setCommand( const QString& value )
    {
        command_ = value;
        mask_ |= Command;
    }

    //! user
    void setUser( const QString& value )
    {
        user_ = value;
        mask_ |= User;
    }

    //! user
    void setUserId( qint64 value )
    {
        userId_ = value;
        mask_ |= UserId;
    }

    //! state
    void setState( QChar value )
    {
        state_ = value;
        mask_ |= State;
    }

    //! cpu
    void setCpu( qreal value )
    {
        cpu_ = value;
        mask_ |= Cpu;
    }

    void setMemory( qreal value )
    {
        memory_ = value;
        mask_ |= Memory;
    }

    //! priority
    void setPriority( int value )
    {
        priority_ = value;
        mask_ |= Priority;
    }

    //! nice
    void setNice( int value )
    {
        nice_ = value;
        mask_ |= Nice;
    }

    //! virtual memory
    void setVirtualMemory( qint64 value )
    {
        virtualMemory_ = value;
        mask_ |= VirtualMemory;
    }

    //! resident memory
    void setResidentMemory( qint64 value )
    {
        residentMemory_ = value;
        mask_ |= ResidentMemory;
    }

    //! shared memory
    void setSharedMemory( qint64 value )
    {
        sharedMemory_ = value;
        mask_ |= SharedMemory;
    }

    //! user time
    void setUserTime( qint64 value )
    {
        userTime_ = value;
        mask_ |= UserTime;
    }

    //! system time
    void setSystemTime( qint64 value )
    {
        systemTime_ = value;
        mask_ |= SystemTime;
    }

    //! up time
    void setElapsedTime( qint64 value )
    {
        elapsedTime_ = value;
        mask_ |= ElapsedTime;
    }

    //! threads
    void setThreads( int value )
    {
        threads_ = value;
        mask_ |= Threads;
    }

    //! start time
    void setStartTime( const TimeStamp& value )
    {
        startTime_ = value;
        mask_ |= StartTime;
    }

    //! icon initialized
    void setIconInitialized( bool value )
    { iconInitialized_ = value; }

    //! icon
    void setIcon( QIcon icon )
    {
        icon_ = icon;
        mask_ |= Icon;
    }

    //@}

    //! used to cound running jobs
    class IsRunningFTor
    {
        public:

        bool operator() (const Job& job ) const
        { return job.isRunning(); }

    };

    //! used to select with Id matching an integer
    class SameIdFTor
    {
        public:

        //! constructor
        SameIdFTor( long id ):
            id_( id )
        {}

        //! predicate
        bool operator() (const Job& job ) const
        {  return job.id() == id_; }

        private:

        //! field index
        long id_;

    };

    protected:

    //! convert time integer to string
    static QString _timeString( int );

    private:

    //! mask
    Flags mask_;

    //! id
    long id_;

    //! parent id
    long parentId_;

    //! parent id (for tree)
    long treeParentId_;

    //! name
    QString name_;

    //! long command
    QString longName_;

    //! full command
    QString command_;

    //! user
    QString user_;

    //! user id
    qint64 userId_;

    //! state
    QChar state_;

    //! cpu percentage
    qreal cpu_;

    //! memory percentage
    qreal memory_;

    //! priority
    int priority_;

    //! nice
    int nice_;

    //! virtual memory
    qint64 virtualMemory_;

    //! resident memory
    qint64 residentMemory_;

    //! shared memory
    qint64 sharedMemory_;

    //! user time (milliseconds)
    qint64 userTime_;

    //! system time (milliseconds)
    qint64 systemTime_;

    //! up time (milliseconds)
    qint64 elapsedTime_;

    //! start time
    TimeStamp startTime_;

    //! number of threads
    int threads_;

    //! true if icon is set (or absent)
    bool iconInitialized_;

    //! icon
    QIcon icon_;

};

// hash (this is utterly wrong
inline uint qHash( const Job& job )
{ return job.parentId() << 8 | job.id(); }

Q_DECLARE_OPERATORS_FOR_FLAGS( Job::Flags );

#endif
