#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 final: private Base::Counter<JobRecord>
{

    public:

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

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

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

    //* storage
    class Record final: private Base::Counter<Record>
    {

        public:

        //* empty constructor
        explicit Record():
            Counter( "Record" )
        {}

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

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

        //* divide
        Record& operator /= ( int value )
        {
            virtualMemory_ /= value;
            residentMemory_ /= value;
            sharedMemory_ /= value;
            cpu_ /= value;
            memory_ /= value;
            return *this;
        }

        //* virtual memory
        int virtualMemory_ = 0;

        //* resident memory
        int residentMemory_ = 0;

        //* shared memory
        int sharedMemory_ = 0;

        //* cpu (%)
        double cpu_ = 0;

        //* mem (%)
        double memory_ = 0;

        //* 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 final: private Base::Counter<Samples>
    {

        public:

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

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

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

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

        //* retrieve data
        const RecordList& records() 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() const
    { return job_.id(); }

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

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

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

    //@}

    //*@name modifier
    //@{

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

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

    //@}

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

        //* constructor
        explicit SameIdFTor( 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_;

};

//* lower than operator
inline bool operator < ( const JobRecord& first, const JobRecord& second)
{ return first.id() < second.id(); }

//* equal to operator
inline bool operator == ( const JobRecord& first, const JobRecord& second)
{ return first.id() == second.id(); }


#endif
