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

#include "GridLayout.h"
#include "GridLayoutItem.h"
#include "HistogramWidget.h"
#include "IconEngine.h"
#include "IconNames.h"
#include "Options.h"
#include "Singleton.h"

#include <QLayout>
#include <QShortcut>

//______________________________________________
JobInformationDialog::JobInformationDialog( QWidget* parent ):
    CustomDialog( parent, CloseButton )
{

    Debug::Throw( "JobInformationDialog::JobInformationDialog.\n" );
    setWindowTitle( "Job Information - Top" );
    setAttribute( Qt::WA_DeleteOnClose );
    setOptionName( "JOB_INFORMATION_DIALOG" );

    // customize layout
    layout()->setMargin(0);
    layout()->setSpacing(0);
    buttonLayout().setMargin(5);

    // tabwidget
    tabWidget_ = new QTabWidget( this );
    mainLayout().addWidget( tabWidget_ );

    // general information
    QWidget *box;
    tabWidget_->addTab( box = new QWidget, tr( "General" ) );

    QHBoxLayout* hLayout = new QHBoxLayout;
    hLayout->setMargin(5);
    hLayout->setSpacing(5);
    box->setLayout( hLayout );

    // icon
    iconLabel_ = new QLabel(box);
    iconLabel_->setPixmap( IconEngine::get( IconNames::DialogInformation ).pixmap( iconSize() ) );
    hLayout->addWidget( iconLabel_, 0, Qt::AlignTop );

    QVBoxLayout* layout = new QVBoxLayout;
    layout->setMargin(0);
    layout->setSpacing( 5 );
    hLayout->addLayout( layout, 1 );

    GridLayout* gridLayout = new GridLayout;
    gridLayout->setSpacing( 5 );
    gridLayout->setMaxCount( 2 );
    layout->addLayout( gridLayout );

    ( nameLabel_ = new GridLayoutItem( box, gridLayout, GridLayoutItem::Flag::Selectable ) )->setKey( tr( "Name:" ) );
    ( idLabel_ = new GridLayoutItem( box, gridLayout, GridLayoutItem::Flag::Selectable ) )->setKey( tr( "Process id:" ) );
    ( parentIdLabel_ = new GridLayoutItem( box, gridLayout, GridLayoutItem::Flag::Selectable ) )->setKey( tr( "Parent id:" ) );
    ( userLabel_ = new GridLayoutItem( box, gridLayout, GridLayoutItem::Flag::Selectable| GridLayoutItem::Flag::Elide ) )->setKey( tr( "User:" ) );
    ( commandLabel_ = new GridLayoutItem( box, gridLayout, GridLayoutItem::Flag::Selectable| GridLayoutItem::Flag::Elide ) )->setKey( tr( "Command:" ) );
    ( startTimeLabel_ = new GridLayoutItem( box, gridLayout ) )->setKey( tr( "Started:" ) );
    ( completionTimeLabel_ = new GridLayoutItem( box, gridLayout ) )->setKey( tr( "Completed:" ) );
    completionTimeLabel_->hide();

    gridLayout->setColumnStretch( 1, 1 );
    layout->addStretch( 1 );

    // statistics
    tabWidget_->addTab( box = new QWidget, tr( "Resources" ) );

    // create vbox layout
    box->setLayout( new QVBoxLayout );
    box->layout()->setSpacing(5);
    box->layout()->setMargin(5);

    box->layout()->addWidget( cpuHistogram_ = new RecordHistogram( box ) );
    box->layout()->addWidget( memoryHistogram_ = new RecordHistogram( box ) );

    // configuration
    connect( Base::Singleton::get().application(), SIGNAL(configurationChanged()), SLOT(_updateConfiguration()) );

    // close accelerator
    new QShortcut( QKeySequence::Close, this, SLOT(close()) );

    _updateConfiguration();

}

//_________________________________________________________________________
void JobInformationDialog::setJob( const Job& job, const JobRecord& record )
{

    Debug::Throw( "JobInformationDialog::setJob.\n" );

    // assign
    job_ = job;
    record_ = record;
    alive_ = true;
    _updateJobInformation();
    _updateHistograms();

}

//_____________________________________
void JobInformationDialog::update( Job::Set jobs )
{
    Debug::Throw( "JobInformationDialog::update.\n" );

    if( !alive_ ) return;

    auto iter( std::find_if( jobs.begin(), jobs.end(), Job::SameIdFTor( job_.id() ) ) );
    if( iter == jobs.end() ) {

        const QString buffer = QString( tr( "Process %1 (%2) (finished) - Top" ) ).arg( job_.id() ).arg( job_.longName().isEmpty() ? job_.name():job_.longName() );
        setWindowTitle( buffer );

        completionTimeLabel_->setText( TimeStamp::now().toString() );
        alive_ = false;

    } else {

        job_.updateFrom( *iter );
        record_.updateJob( job_ );
        _updateHistograms();

    }

    return;

}

//_______________________________________________________________
void JobInformationDialog::closeEvent( QCloseEvent* )
{ emit closed( record_ ); }

//_______________________________________________________________
void JobInformationDialog::resizeEvent( QResizeEvent* e )
{

    BaseDialog::resizeEvent( e );

    int maxWidth( qMax<int>( record_.samples().maxLength(), cpuHistogram_->scrollArea().width() - 5 ) );
    maxWidth = qMax<int>( maxWidth, memoryHistogram_->scrollArea().width() - 5 );

    record_.samples().setMaxLength( maxWidth );
    cpuHistogram_->histogram().resize( maxWidth, cpuHistogram_->histogram().height() );
    memoryHistogram_->histogram().resize( maxWidth, memoryHistogram_->histogram().height() );
    return;
}

//_______________________________________________________________
void JobInformationDialog::_updateConfiguration()
{

    Debug::Throw( "JobInformationDialog::_updateConfiguration.\n" );

    // record length and sample size
    record_.samples().setMaxLength( XmlOptions::get().get<int>( "RECORD_LENGTH" ) );
    record_.samples().setSampleSize( XmlOptions::get().get<int>( "SAMPLES" ) );

}

//_____________________________________________________________________________
void JobInformationDialog::_updateJobInformation()
{
    Debug::Throw( "JobInformationDialog::_updateJobInformation.\n" );

    // window title
    const QString buffer = QString( tr( "Process %1 (%2) - Top" ) ).arg( job_.id() ).arg( job_.longName().isEmpty() ? job_.name():job_.longName() );
    setWindowTitle( buffer );

    // update informations
    if( !job_.icon().isNull() )
    { iconLabel_->setPixmap( job_.icon().pixmap( iconSize() ) ); }

    nameLabel_->setText( job_.longName().isEmpty() ? job_.name():job_.longName() );
    idLabel_->setText( QString::number( job_.id() ) );
    parentIdLabel_->setText( QString::number( job_.parentId() ) );
    userLabel_->setText( QString( "%1 (%2)" ).arg( job_.user() ).arg( job_.userId() ) );
    commandLabel_->setText( job_.command() );
    startTimeLabel_->setText( job_.startTime().toString() );
}

//_____________________________________________________________________________
void JobInformationDialog::_updateHistograms()
{

    Debug::Throw( "JobInformationDialog::_updateHistograms.\n" );

    const JobRecord::RecordList& valueList( record_.samples().records() );

    {
        // cpu values
        cpuHistogram_->histogram().setText(
            QString( tr( "Cpu (%) max: %1 current: %2" ) )
            .arg( QString::number( record_.max().cpu_, 'f', 1 ) )
            .arg( QString::number( record_.current().cpu_, 'f', 1 ) ) );

        // update histograms
        HistogramWidget::DataSet::ValueList values;
        for( const auto& record:valueList ) values << record.cpu_;
        cpuHistogram_->setValues( values );

    }

    {
        // memory values
        memoryHistogram_->histogram().setText(
            QString( tr( "Memory (%) max: %1 current: %2" ) )
            .arg( QString::number( record_.max().memory_, 'f', 1 ) )
            .arg( QString::number( record_.current().memory_, 'f', 1 ) ) );

        HistogramWidget::DataSet::ValueList values;
        for( const auto& record:valueList ) values << record.memory_;
        memoryHistogram_->setValues( values );
    }

}
