#ifndef JobRecord_h
#define JobRecord_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 "Job.h"
#include "XmlOptions.h"

#include <QList>

//* keep track of job memory and usage
class JobRecord: public Counter
{

    public:

    //* list of records
    using List = QList<JobRecord>;

    //* constructor
    JobRecord( void ):
        Counter( "JobRecord" ),
        records_(
        XmlOptions::get().get<int>( "SAMPLES" ),
        XmlOptions::get().get<int>( "RECORD_LENGTH" ) )
    {}

    //* constructor
    JobRecord( const Job& job ):
        Counter( "JobRecord" ),
        job_( job ),
        records_(
        XmlOptions::get().get<int>( "SAMPLES" ),
        XmlOptions::get().get<int>( "RECORD_LENGTH" ) )
    { updateJob( job ); }

    //* lower than operator
    bool operator < ( const JobRecord& other ) const
    { return id() < other.id(); }


    //* equal to operator
    bool operator == ( const JobRecord& other ) const
    { return id() == other.id(); }

    //* storage
    class Record: public Counter
    {

        public:

        //* empty constructor
        Record( void ):
            Counter( "Record" ),
            virtualMemory_(0),
            residentMemory_(0),
            sharedMemory_(0),
            cpu_(0),
            memory_(0)
        {}

        //* constructo from job
        Record( const Job& job );

        //* sum operator
        Record& operator += ( const Record& record )
        {
            virtualMemory_ += record.virtualMemory_;
            residentMemory_ += record.residentMemory_;
            sharedMemory_ += record.sharedMemory_;
            cpu_ += record.cpu_;
            memory_ += record.memory_;
            return *this;
        }

        //* divide
        Record divide( const int& value )
        {
            Q_ASSERT( value > 0 );
            Record out( *this );
            out.virtualMemory_ /= value;
            out.residentMemory_ /= value;
            out.sharedMemory_ /= value;
            out.cpu_ /= value;
            out.memory_ /= value;
            return out;
        }

        //* virtual memory
        int virtualMemory_;

        //* resident memory
        int residentMemory_;

        //* shared memory
        int sharedMemory_;

        //* cpu (%)
        double cpu_;

        //* mem (%)
        double memory_;

        //* streamer
        friend QTextStream& operator << ( QTextStream& out, const Record& record )
        {
            out << record.cpu_ << " " << record.memory_;
            return out;
        }

    };

    //* Record List
    using RecordList = QList<Record>;

    //* data samples storage
    class Samples: public Counter
    {

        public:

        //* construtor
        Samples( int sampleSize = 0, int length = 0 ):
            Counter( "JobRecord::Samples" ),
            sampleSize_( sampleSize ),
            maxLength_( length )
        {}

        //* set sample size
        void setSampleSize( const int& sampleSize );

        //* set data point size
        void setMaxLength( const int length );

        //* max length
        int maxLength( void ) const
        { return maxLength_; }

        //* retrieve data
        const RecordList& records( void ) const
        { return recordList_; }

        //* add a data point
        void add( const Record& record );

        private:

        //* list of measurements
        RecordList sampleList_;

        //* list of differences
        RecordList recordList_;

        //* sample size
        int sampleSize_ = 0;

        //* number of data point to store
        int maxLength_ = 0;

    };

    //*@name accessor
    //@{

    //* id
    int id( void ) const
    { return job_.id(); }

    //* current record
    const Record& current( void ) const
    { return current_; }

    //* max record
    const Record& max( void ) const
    { return max_; }

    //* get records
    const Samples& samples( void ) const
    { return records_; }

    //@}

    //*@name modifier
    //@{

    //* update statistics from job informations
    bool updateJob( const Job& job );

    //* get records
    Samples& samples( void )
    { return records_; }

    //@}

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

        //* constructor
        SameIdFTor( const int& id ):
            id_( id )
        {}

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

        private:

        //* field index
        int id_;

    };

    private:

    //* job Id
    Job job_;

    //* current record
    Record current_;

    //* max
    Record max_;

    //* records
    Samples records_;

};

#endif
