/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 
 *
 *    Copyright 2017, 2018, 2021 (c) Fraunhofer IOSB (Author: Julius Pfrommer)
 *    Copyright 2017 (c) Stefan Profanter, fortiss GmbH
 */

#ifndef UA_TIMER_H_
#define UA_TIMER_H_

#include "ua_util_internal.h"
#include "aa_tree.h"

_UA_BEGIN_DECLS

/* The timer is protected by its own mutex. The mutex is released before calling
 * into the callbacks. So the timer can be modified from the callbacks it is
 * executing. Also, the timer mutex can never lead to locking. Because the timer
 * mutex will be left without acquiring another mutex.
 *
 * Obviously, the timer must not be deleted from within one of its
 * callbacks. */

/* Callback where the application is either a client or a server */
typedef void (*UA_ApplicationCallback)(void *application, void *data);

typedef struct UA_TimerEntry {
    struct aa_entry treeEntry;
    UA_TimerPolicy timerPolicy;              /* Timer policy to handle cycle misses */
    UA_DateTime nextTime;                    /* The next time when the callback
                                              * is to be executed */
    UA_UInt64 interval;                      /* Interval in 100ns resolution. If
                                                the interval is zero, the
                                                callback is not repeated and
                                                removed after execution. */
    UA_ApplicationCallback callback;
    void *application;
    void *data;

    struct aa_entry idTreeEntry;
    UA_UInt64 id;                            /* Id of the entry */
} UA_TimerEntry;

typedef struct {
    struct aa_head root;   /* The root of the time-sorted tree */
    struct aa_head idRoot; /* The root of the id-sorted tree */
    UA_UInt64 idCounter;   /* Generate unique identifiers. Identifiers are
                            * always above zero. */
#if UA_MULTITHREADING >= 100
    UA_Lock timerMutex;
#endif
} UA_Timer;

void
UA_Timer_init(UA_Timer *t);

UA_StatusCode
UA_Timer_addTimedCallback(UA_Timer *t, UA_ApplicationCallback callback,
                          void *application, void *data, UA_DateTime date,
                          UA_UInt64 *callbackId);

/* Add a pre-allocated and pre-filled UA_TimerEntry. This cannot fail. It is
 * used, for example, for delayed memory reclamation where the data structure
 * begins with a UA_TimerEntry. */
void
UA_Timer_addTimerEntry(UA_Timer *t, UA_TimerEntry *te, UA_UInt64 *callbackId);

UA_StatusCode
UA_Timer_addRepeatedCallback(UA_Timer *t, UA_ApplicationCallback callback,
                             void *application, void *data, UA_Double interval_ms,
                             UA_DateTime *baseTime, UA_TimerPolicy timerPolicy,
                             UA_UInt64 *callbackId);

UA_StatusCode
UA_Timer_changeRepeatedCallback(UA_Timer *t, UA_UInt64 callbackId,
                                UA_Double interval_ms, UA_DateTime *baseTime,
                                UA_TimerPolicy timerPolicy);

void
UA_Timer_removeCallback(UA_Timer *t, UA_UInt64 callbackId);

/* Process (dispatch) the repeated callbacks that have timed out. Returns the
 * timestamp of the next scheduled repeated callback. Not thread-safe.
 * Application is a pointer to the client / server environment for the callback.
 * Dispatched is set to true when at least one callback was run / dispatched. */
typedef void
(*UA_TimerExecutionCallback)(void *executionApplication, UA_ApplicationCallback cb,
                             void *callbackApplication, void *data);

UA_DateTime
UA_Timer_process(UA_Timer *t, UA_DateTime nowMonotonic,
                 UA_TimerExecutionCallback executionCallback,
                 void *executionApplication);

void
UA_Timer_clear(UA_Timer *t);

_UA_END_DECLS

#endif /* UA_TIMER_H_ */
