/******************************************************************************
*
* 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 "JobThread.h"

#include <QDir>
#include <QFile>
#include <QMutexLocker>
#include <QTextStream>

#include <unistd.h>

//________________________________________________________________________
JobThread::JobThread( QObject* parent ):
    QThread( parent ),
    Counter( "JobThread" )
{ timer_.start(); }

//________________________________________________________________________
void JobThread::resetUserMap()
{
    QMutexLocker lock( &mutex_ );
    userMapInitialized_ = false;
    userMap_.clear();
}

//________________________________________________________________________
void JobThread::run()
{

    // initialize usermap
    if( !userMapInitialized_ )
    {
        _readUserMap();
        userMapInitialized_ = true;
    }

    // initialize total memory
    if( !totalMemoryInitialized_ )
    {
        _readTotalMemory();
        totalMemoryInitialized_ = true;
    }

    // prepare jobs
    jobs_.clear();

    // get list of jobs from /proc
    QDir dir( "/proc" );
    for( const auto& file:dir.entryList() )
    {

        bool ok( true );
        const long id( file.toLong( &ok ) );
        if( !ok ) continue;

        // create job
        Job job( id );

        // read everything
        if( !job.readFromStatus() ) continue;
        if( !job.readFromStatM() ) continue;
        if( !job.readFromStat() ) continue;

        // update elapsed time
        job.setElapsedTime( timer_.elapsed() );

        // assign user name
        UserMap::const_iterator iter = userMap_.find( job.userId() );
        job.setUser( iter == userMap_.end() ? QString( tr( "Unknown (%1)" ) ).arg( job.userId() ):iter.value() );

        // assign memory
        if( totalMemory_ > 0 )
        job.setMemory( 100.0*job.residentMemory()/totalMemory_ );

        // insert in list
        jobs_.insert( job );

    }

}

//________________________________________________________________________
void JobThread::_readUserMap()
{
    QFile file( "/etc/passwd" );
    if( !file.open(QIODevice::ReadOnly) ) return;

    // regular expression to read users
    QRegExp regExp( "(.+):.:(\\d+)" );

    QTextStream in(&file);
    while( !in.atEnd() )
    {
        QStringList values = in.readLine().split( ":" );
        if( values.size() > 3 ) userMap_.insert( values[2].toLongLong(), values[0] );
    }

    return;
}

//________________________________________________________________________
void JobThread::_readTotalMemory()
{

    #ifdef _SC_PHYS_PAGES
    totalMemory_ = ((qint64) sysconf(_SC_PHYS_PAGES)) * (sysconf(_SC_PAGESIZE)/1024);
    #else

    //This is backup code in case this is not defined.
    QFile file( "/proc/meminfo" );
    if( !file.open(QIODevice::ReadOnly) ) return;

    QString buffer( file.readAll() );
    while( !buffer.atEnd() )
    {
        const QString line( buffer.readLine() );
        if( line.startsWith( "MemTotal:" ) )
        {
            const QStringList values( line.split( QRegExp( "\\s+" ), QString::SkipEmptyParts ) );
            if( values.size() >= 2 ) totalMemory_ = values[1].toLongLong();
            break;
        }
    }

    #endif

}
