/***************************** 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 *************************************/

#include "Task.h"

#ifdef PM_USE_THREADS
#include "Mutex.hpp"
#endif

// -- Lists for holding tasks
//    pendingTaskList: holds the tasks to be processed first
//    cleanupTaskList: holds the taks to be processed in the end

PendingTaskList TaskBase::pendingTaskList_;
PendingTaskList TaskBase::cleanupTaskList_;

TaskBase::TaskBase() = default;

TaskBase::~TaskBase() = default;

void TaskBase::RegisterTask(TaskBase* task)
{
#ifdef PM_USE_THREADS
    glMutex.Lock();
#endif
    pendingTaskList_.push_back(task);

#ifdef PM_USE_THREADS
    glMutex.Unlock();
#endif
}

// Register a task on the cleanup list
void TaskBase::RegisterCleanUpTask(TaskBase* task)
{
    cleanupTaskList_.push_back(task);
}

void* TaskBase::Run(void*)
{
    PendingTaskList::iterator t;

    for (t = pendingTaskList_.begin();
         t != pendingTaskList_.end(); ++t) {
        // Execute the tasks
        (*t)->Execute();

        // delete the task element
        TaskBase* pt = *t;
        delete pt;

        // make the element of the list point to zero
        (*t) = nullptr;
    }

    return nullptr;
}

void TaskBase::Flush()
{
    TaskBase::FlushPending();
    TaskBase::FlushCleanUp();
}

// -- Flush Pending
//    execute all pending tasks (called first)
void TaskBase::FlushPending()
{
#ifdef PM_USE_THREADS
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
    pthread_t thread;
    pthread_create(&thread, &attr, TaskBase::Run, 0);
    pthread_attr_destroy(&attr);
#else

    PendingTaskList::iterator t;

    for (t = pendingTaskList_.begin();
         t != pendingTaskList_.end(); ++t) {
        // Execute the tasks
        (*t)->Execute();

        // delete the task element
        TaskBase* pt = *t;
        delete pt;

        // make the element of the list point to zero
        (*t) = nullptr;
    }

    pendingTaskList_.clear();
#endif
}

// -- Flush CleanUp
//
// Execute all clean up tasks (called in the end)
void TaskBase::FlushCleanUp()
{
    PendingTaskList::iterator t;

    for (t = cleanupTaskList_.begin();
         t != cleanupTaskList_.end(); ++t) {
        // Execute the tasks
        (*t)->Execute();

        // delete the task element
        TaskBase* pt = *t;
        delete pt;

        // make the element of the list point to zero
        (*t) = nullptr;
    }

    cleanupTaskList_.clear();
}
