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

#include "Command.h"
#include "Debug.h"
#include "File.h"
#include "Job.h"
#include "InformationDialog.h"
#include "Singleton.h"
#include "ToolTipWidget.h"
#include "TreeView.h"
#include "UserSet.h"
#include "Util.h"
#include "XcbInterface.h"
#include "XmlOptions.h"

#include <QApplication>
#include <QHeaderView>
#include <QTextStream>

//_______________________________________________
JobManager::JobManager( QWidget *parent ):
    QWidget( parent ),
    user_( Util::user() )
{
    Debug::Throw("JobManager::JobManager.\n");

    // layout
    setLayout( new QVBoxLayout( this ) );
    layout()->setSpacing(0);
    layout()->setMargin(0);

    // tooltip widget
    toolTipWidget_ = new ToolTipWidget( this );

    // list
    TreeView::Container* container = new TreeView::Container( this );
    layout()->addWidget( container );

    treeView_ = &container->treeView();
    treeView_->setMouseTracking( true );
    treeView_->setModel( &model_ );
    treeView_->setSortingEnabled( true );
    treeView_->setRootIsDecorated( false );
    treeView_->setSelectionMode( TreeView::ContiguousSelection );
    treeView_->setOptionName( "JOBLIST" );

    // column visibility
    treeView_->lockColumnVisibility( JobModel::Empty );
    treeView_->lockColumnVisibility( JobModel::User );
    treeView_->setColumnHidden( JobModel::Empty, false );
    treeView_->setColumnHidden( JobModel::User, true );

    connect( treeView_, SIGNAL(expanded(QModelIndex)), treeView_, SLOT(resizeColumns()) );
    connect( treeView_, SIGNAL(collapsed(QModelIndex)), treeView_, SLOT(resizeColumns()) );
    connect( treeView_, SIGNAL(hovered(QModelIndex)), SLOT(_showToolTip(QModelIndex)) );

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

}

//_______________________________________
bool JobManager::setUser( QString user )
{

    Debug::Throw() << "JobManager::setUser - " << user << endl;
    if( user.isEmpty() || user == user_ ) return false;
    user_ = user;
    model_.clear();
    treeView_->setColumnHidden( JobModel::User, !UserSet::isAllUsers( user ) );
    return true;

}

//____________________________________________________________
void JobManager::processJobList( Job::Set jobs )
{
    Debug::Throw( "JobManager::processJobList.\n" );

    QString localUser( user_.left(8) );

    // keep track of old jobs
    Job::List oldJobs;
    for( auto& job:jobs_ )
    {

        // find matching job in set
        Job::Set::iterator newJobIter = jobs.find( Job( job.id(), job.parentId() ) );
        if( newJobIter == jobs.end() ) {

            if( job.id() < 0 || job.user() != localUser ) oldJobs.append( job );
            else job.setId( -job.id() );

        } else {

            job.updateFrom( *newJobIter );
            jobs.erase( newJobIter );

        }

    }

    // remove jobs that have dissapear
    for( const auto& job:oldJobs )
    { jobs_.removeOne( job ); }

    // add new jobs
    for( const auto& job:jobs )
    {
        if( job.isValid() && ( user_.isEmpty() || UserSet::isAllUsers( user_ ) || localUser == job.user() ) )
        {
            jobs_.append( job );
            jobs_.back().readStartTime();
        }
    }

    // find pixmaps
    if( showIcons_ )
    {
        XcbInterface().findIcons( jobs_ );
        for( auto& job:jobs_ )
        { job.setIconInitialized( true ); }
    }

    // find full command names
    if( showFullNames_ )
    {
        for( auto& job:jobs_ )
        { job.readFromCommandLine(); }
    }

    // use parent id for tree view if enabled
    if( treeViewEnabled() )
    {
        for( auto& job:jobs_ )
        {
            const bool parentFound( std::find_if( jobs_.begin(), jobs_.end(), Job::SameIdFTor( job.parentId() ) ) != jobs_.end() );
            job.setTreeParentId( parentFound ? job.parentId():0 );
        }
    }

    // update model
    _updateModel();

    // update tooltip if visible
    if( toolTipWidget_->isVisible() )
    {
        const QModelIndex index( treeView_->indexAt( treeView_->viewport()->mapFromGlobal( QCursor::pos() ) ) );
        if( index.isValid() ) toolTipWidget_->setJob( model_.get( index ) );
        else toolTipWidget_->hide();
    }

    return;

}

//_______________________________________________
bool JobManager::toggleTreeView( bool state )
{

    Debug::Throw( "JobManager::toggleTreeView.\n" );
    if( treeViewEnabled_  == state ) return false;
    treeViewEnabled_ = state;
    treeView_->setRootIsDecorated( state );

    // explicitely reset job's parents when turning off
    if( !state )
    {
        for( auto& job:jobs_ )
        { job.setTreeParentId( 0 ); }
    }

    return true;

}

//________________________________________
Job::List JobManager::selectedJobs() const
{ return model_.get( treeView_->selectionModel()->selectedRows() ); }

//______________________________________________________
void JobManager::_showToolTip( const QModelIndex& index )
{

    Debug::Throw() << "JobManager::_showToolTip." << endl;

    if( !index.isValid() ) toolTipWidget_->hide();
    else {

        // fileInfo
        const Job job( model_.get( index ) );

        // rect
        QRect rect( treeView_->visualRect( index ) );
        rect.translate( treeView_->viewport()->mapToGlobal( QPoint( 0, 0 ) ) );
        toolTipWidget_->setIndexRect( rect );

        // assign to tooltip widget
        toolTipWidget_->setJob( job );

        // show
        toolTipWidget_->showDelayed();

    }

}

//_______________________________________
void JobManager::_updateModel()
{

    // store selected jobs in model
    treeView_->setUpdatesEnabled( false );
    treeView_->storeScrollBarPosition();
    treeView_->storeSelectedIndexes();

    // assign to list  and restart timer
    model_.setToday( TimeStamp::now() );
    model_.set( jobs_ );

    // restore selected jobs
    treeView_->resizeColumns();
    treeView_->restoreSelectedIndexes();
    treeView_->restoreScrollBarPosition();
    treeView_->setUpdatesEnabled( true );
}

//_______________________________________
void JobManager::_updateConfiguration()
{

    Debug::Throw( "JobManager::_updateConfiguration.\n" );
    showIcons_ = XmlOptions::get().get<bool>( "SHOW_ICONS" );
    showFullNames_ = XmlOptions::get().get<bool>( "SHOW_FULL_NAMES" );

}
