/***************************** LICENSE START ***********************************

 Copyright 2012 ECMWF and INPE. This software is distributed under the terms
 of the Apache License version 2.0. In applying this license, ECMWF does not
 waive the privileges and immunities granted to it by virtue of its status as
 an Intergovernmental Organization or submit itself to any jurisdiction.

 ***************************** LICENSE END *************************************/

//
// .NAME:
//  Task
//
// .AUTHOR:
//  Gilberto Camara, Baudouin Raoult and Fernando Ii
//
// .SUMMARY:
//  Provide support for handling a list of tasks.
//  The idea is that there are some lengthy tasks which should
//  better be delayed. Therefore, these tasks are placed in a queue
//  and are executed at a covenient moment.
//
//  A task consists of an object and a called procedure.
//  Executing a task is done by calling "object->Proc()"
// .CLIENTS:
//  Page, SubPage (which ask for a new drawing)
//
//
// .RESPONSABILITIES:
//
//  1. Put tasks in a task list
//
//  2. Execute all tasks in the list
//     when the "Flush" method is called
//
// .COLLABORATORS:
//
//
// .BASE CLASS:
//
//
// .DERIVED CLASSES:
//
//
// .REFERENCES:
//
//

#pragma once

#include <list>

class TaskBase;

using PendingTaskList = std::list<TaskBase*>;

class TaskBase
{
public:
    // Contructors
    TaskBase();

    // Destructor
    virtual ~TaskBase();  // Change to virtual if base class

    // Abstract method which should be supplied by the derived class
    virtual void Execute() = 0;

    // Execute all tasks in the list
    static void Flush();

    // Execute all pending tasks (called first)
    static void FlushPending();

    // Execute all clean up tasks (called in the end)
    static void FlushCleanUp();

    // Register a task on the pending list
    static void RegisterTask(TaskBase*);

    // Register a task on the cleanup list
    static void RegisterCleanUpTask(TaskBase*);

private:
    // List of tasks to be executed first
    static PendingTaskList pendingTaskList_;

    // List of tasks to be executed on cleanup
    static PendingTaskList cleanupTaskList_;

    // Method used when in multi_thread mode
    static void* Run(void*);
};

template <class T>
class Task : public TaskBase
{
    T& calledObject_;
    using Procedure = void (T::*)();
    Procedure calledProc_;

public:
    Task(T& object, Procedure proc) :
        calledObject_(object),
        calledProc_(proc) {}

    // Execute - calls object->procedure
    void Execute() override
    {
        (calledObject_.*calledProc_)();
    }
};

template <class T>
void AddTask(T& object, void (T::*proc)())
{
    TaskBase::RegisterTask(new Task<T>(object, proc));
}

template <class T>
void AddCleanUpTask(T& object, void (T::*proc)())
{
    TaskBase::RegisterCleanUpTask(new Task<T>(object, proc));
}
