From 75048390f3d5fc49f6c8f1c64c6312ed93d70773 Mon Sep 17 00:00:00 2001
From: Florian Prill <florian.prill@dwd.de>
Date: Fri, 21 Jun 2019 20:47:58 +0200
Subject: [PATCH] Implemented gettriggernextevent for hl interface (untested).

---
 include/mtime_eventHandling.h | 15 +++++++
 src/libmtime_hl.f90           |  2 +-
 src/mtime_c_bindings.f90      | 17 +++++++-
 src/mtime_eventHandling.c     | 78 ++++++++++++++++++++++-------------
 src/mtime_t_datetime.inc      |  1 -
 src/mtime_t_event.inc         | 61 ++++++++++++++++++++++++---
 src/mtime_t_timedelta.inc     |  4 +-
 7 files changed, 139 insertions(+), 39 deletions(-)

diff --git a/include/mtime_eventHandling.h b/include/mtime_eventHandling.h
index 21cfbbd0..393922df 100644
--- a/include/mtime_eventHandling.h
+++ b/include/mtime_eventHandling.h
@@ -153,6 +153,21 @@ iseventNextInNextYearRaw(struct _datetime* event_triggerNextEventDateTime,
 char*
 eventToString(struct _event* e, char* string);
 
+void
+getTriggerNextEventAtDateTimeRaw(struct _datetime* eventLastDateTime,
+				 bool nextEventIsFirst,
+				 struct _datetime* triggerNextEventDateTime,
+				 struct _timedelta* eventInterval, 
+				 struct _datetime* current_dt,
+				 struct _datetime* dt_return);
+
+struct _datetime*
+getTriggerNextEventAtDateTime(struct _datetime* eventLastDateTime,
+			      bool nextEventIsFirst,
+			      struct _datetime* triggerNextEventDateTime,
+			      struct _timedelta* eventInterval, 
+			      struct _datetime* current_dt);
+
 struct _datetime*
 getTriggerNextEventAtDateTime(struct _event* e, struct _datetime* dt_current, struct _datetime* dt_return);
 
diff --git a/src/libmtime_hl.f90 b/src/libmtime_hl.f90
index 6b40c518..4eb857c2 100644
--- a/src/libmtime_hl.f90
+++ b/src/libmtime_hl.f90
@@ -59,7 +59,7 @@ MODULE mtime_hl
   ! TODO: simply repeat the implementation of "divisionquotienttimespan" in order to disentangle the mtime_hl and the mtime Fortran modules.
   !
   PUBLIC :: divisionquotienttimespan
-
+  PUBLIC :: no_of_sec_in_a_day
 
 
   !> NOTE / TODO:
diff --git a/src/mtime_c_bindings.f90 b/src/mtime_c_bindings.f90
index eb5cd831..ffb102b2 100644
--- a/src/mtime_c_bindings.f90
+++ b/src/mtime_c_bindings.f90
@@ -652,6 +652,22 @@ MODULE mtime_c_bindings
       logical(c_bool) :: ret
     end function my_iseventnextinnextyear
     !
+    SUBROUTINE my_gettriggernexteventatdatetimeraw(eventLastDateTime,        &
+      &                                           nextEventIsFirst,          &
+      &                                           triggerNextEventDateTime,  &
+      &                                           eventInterval,             &
+      &                                           my_currentdatetime,        &
+      &                                           c_pointer)                 &
+      &   BIND(c, name='getTriggerNextEventAtDateTimeRaw')
+      IMPORT :: c_ptr, c_bool
+      TYPE(c_ptr),     VALUE :: eventLastDateTime
+      LOGICAL(c_bool)        :: nextEventIsFirst
+      TYPE(c_ptr),     VALUE :: triggerNextEventDateTime
+      TYPE(c_ptr),     VALUE :: eventInterval
+      TYPE(c_ptr),     VALUE :: my_currentdatetime
+      TYPE(c_ptr) :: c_pointer
+    END SUBROUTINE my_gettriggernexteventatdatetimeraw
+    !
     function my_gettriggernexteventatdatetime(my_event,my_currentdatetime,my_datetime) result(c_pointer) &
          & bind(c, name='getTriggerNextEventAtDateTime')
       import :: c_ptr
@@ -809,7 +825,6 @@ contains
     integer, intent(IN) :: lineno
 
     character(LEN=*), intent(IN) :: routine_str
-    character(len=max_mtime_error_str_len)     :: error_str
     if (lcond)  call handle_errno_base(errno, routine_str, lineno)
   end subroutine handle_errno_cond
 
diff --git a/src/mtime_eventHandling.c b/src/mtime_eventHandling.c
index c21f7f09..91651295 100644
--- a/src/mtime_eventHandling.c
+++ b/src/mtime_eventHandling.c
@@ -1511,53 +1511,75 @@ getEventFirstTriggerDateTime(struct _datetime* start_dt, struct _timedelta* time
 }
 
 
-/**
-  * @brief Get the Datetime when 'this' event will be triggered next.
-  *
-  * WARNING: The value returned is with-respect-to current_dt and not a true copy of triggerNextEventDateTime in the event data structure.
-  *
-  * @param  e
-  *         A pointer to struct _event. This is the event being queried.
-  *
-  * @param  dt_return
-  *         A pointer to struct _datetime. The next trigger datetime is copied here.
-  *
-  * @return dt_return
-  *         A pointer to DateTime with next-trigger datetime.
-  */
-
-struct _datetime*
-getTriggerNextEventAtDateTime(struct _event* e, struct _datetime* current_dt, struct _datetime* dt_return)
+void
+getTriggerNextEventAtDateTimeRaw(struct _datetime* eventLastDateTime,
+				 bool nextEventIsFirst,
+				 struct _datetime* triggerNextEventDateTime,
+				 struct _timedelta* eventInterval, 
+				 struct _datetime* current_dt,
+				 struct _datetime* dt_return)
 {
-  if ((e != NULL) && (current_dt != NULL) && (dt_return != NULL))
+  dt_return = NULL;
+  if ((eventLastDateTime != NULL)		&& 
+      (triggerNextEventDateTime != NULL)	&& 
+      (eventInterval != NULL)			&& 
+      (current_dt != NULL)			&& 
+      (dt_return != NULL))
     {
        /* If last date is defined, check if current_dt is ahead of event->eventLastDateTime.
           Return on NULL indicating no future trigger event scheduled.*/
-      if (e->eventLastDateTime && (compareDatetime(current_dt,e->eventLastDateTime) == greater_than))
-        return NULL;
+      if (eventLastDateTime && (compareDatetime(current_dt,eventLastDateTime) == greater_than))
+	{
+	  dt_return = NULL;
+	  return;
+	}
 
       /* This if should evaluate to false normally. The only occasion when it does not is if the
          current_dt > triggerNextEventDateTime and isCurrentEventActive(.) has never been called  */
       if (
-           (e->nextEventIsFirst)
+           (nextEventIsFirst)
            &&
-           (compareDatetime(current_dt,e->triggerNextEventDateTime) == greater_than)
+           (compareDatetime(current_dt,triggerNextEventDateTime) == greater_than)
          )
         {
               struct _timedelta* modulo_td = newTimeDelta("PT00.000S");
               // Get the first trigger time and return (WARNING: Do not update e->triggerNextEventDateTime here!).
-              moduloTimeDeltaFromDateTime(e->triggerNextEventDateTime, e->eventInterval, current_dt, modulo_td);
+              moduloTimeDeltaFromDateTime(triggerNextEventDateTime, eventInterval, current_dt, modulo_td);
               addTimeDeltaToDateTime(current_dt,modulo_td,dt_return);
               // Cleanup.
               deallocateTimeDelta(modulo_td);
-              return dt_return;
+              return;
         }
       // else ...
-      dt_return = replaceDatetime(e->triggerNextEventDateTime, dt_return);
-      return dt_return;
+      dt_return = replaceDatetime(triggerNextEventDateTime, dt_return);
     }
-  else
-    return NULL;
+}
+
+
+/**
+  * @brief Get the Datetime when 'this' event will be triggered next.
+  *
+  * WARNING: The value returned is with-respect-to current_dt and not a true copy of triggerNextEventDateTime in the event data structure.
+  *
+  * @param  e
+  *         A pointer to struct _event. This is the event being queried.
+  *
+  * @param  dt_return
+  *         A pointer to struct _datetime. The next trigger datetime is copied here.
+  *
+  * @return dt_return
+  *         A pointer to DateTime with next-trigger datetime.
+  */
+struct _datetime*
+getTriggerNextEventAtDateTime(struct _event* e, struct _datetime* current_dt, struct _datetime* dt_return)
+{
+  if ((e == NULL) || (current_dt == NULL) || (dt_return == NULL))  return NULL;
+
+  getTriggerNextEventAtDateTimeRaw(e->eventLastDateTime,
+				   e->nextEventIsFirst,
+				   e->triggerNextEventDateTime,
+				   e->eventInterval, current_dt,
+				   dt_return);
 }
 
 /**
diff --git a/src/mtime_t_datetime.inc b/src/mtime_t_datetime.inc
index 5f1ad0aa..49e1e8d6 100644
--- a/src/mtime_t_datetime.inc
+++ b/src/mtime_t_datetime.inc
@@ -9,7 +9,6 @@
     CHARACTER(len=*), INTENT(in) :: dt_string
     TYPE(c_ptr)             :: c_pointer
     TYPE(datetime), POINTER :: dt_tmp
-    INTEGER :: errno
     c_pointer = my_newdatetime(TRIM(ADJUSTL(dt_string))//c_null_char)
     CALL handle_errno(.NOT. c_ASSOCIATED(c_pointer), 4 *100 + 1, __FILE__, __LINE__)
     CALL c_f_pointer(c_pointer, dt_tmp)
diff --git a/src/mtime_t_event.inc b/src/mtime_t_event.inc
index b36a406a..521b32f9 100644
--- a/src/mtime_t_event.inc
+++ b/src/mtime_t_event.inc
@@ -151,17 +151,68 @@
     res = this%eventLastDateTime
   END FUNCTION t_event_getLastDatetime
 
-  FUNCTION t_event_getNextOccurrenceDatetime(this, my_currentdatetime) RESULT(res)
+  FUNCTION t_event_getNextOccurrenceDatetime(this, query_start_dt) RESULT(res)
     TYPE(t_datetime)             :: res
     CLASS(t_event)               :: this
-    TYPE(t_datetime), INTENT(IN) :: my_currentdatetime
-    res = this%triggerNextEventDateTime
+    TYPE(t_datetime), INTENT(IN), OPTIONAL :: query_start_dt
+    !
+    TYPE(datetime),  POINTER :: dt_tmp
+    TYPE(c_ptr)              :: tmp_dt, tmp_evLastDateTime, tmp_evInterval
+    TYPE(c_ptr)              :: event_triggerNextEventDateTime, c_pointer1
+    LOGICAL(c_bool)          :: event_nextEventIsFirst
+
+    IF (PRESENT(query_start_dt)) THEN
+      ! if a start for our query is given, invoke
+      ! "my_gettriggernexteventatdatetime":
+
+      ! --- copy-in:
+
+      c_pointer1 = res%get_c_pointer()	
+      tmp_dt                         = query_start_dt%get_c_pointer()
+      tmp_evLastDateTime             = this%eventLastDateTime%get_c_pointer()
+      tmp_evInterval                 = this%eventInterval%get_c_pointer()
+      event_nextEventIsFirst         = this%nextEventIsFirst
+      event_triggerNextEventDateTime = c_null_ptr
+      IF (ASSOCIATED(this%triggerNextEventDateTime      ))  &
+        &   event_triggerNextEventDateTime = this%triggerNextEventDateTime%get_c_pointer()
+
+      ! --- call C routine:
+
+      CALL my_gettriggernexteventatdatetimeraw(                       &
+        &             tmp_evLastDateTime, event_nextEventIsFirst,     &
+        &             event_triggerNextEventDateTime, tmp_evInterval, &
+        &             tmp_dt, c_pointer1)
+
+      ! --- copy-out:
+
+      CALL C_F_POINTER(c_pointer1, dt_tmp)
+      res%dt = dt_tmp
+
+      IF (C_ASSOCIATED(event_triggerNextEventDateTime)) THEN
+        IF (.NOT. ASSOCIATED(this%triggerNextEventDateTime)) ALLOCATE(this%triggerNextEventDateTime)
+        CALL C_F_POINTER(event_triggerNextEventDateTime, dt_tmp)
+        this%triggerNextEventDateTime%dt = dt_tmp
+      END IF
+
+      ! --- clean up:
+
+      CALL my_deallocatedatetime(tmp_dt)
+      IF (C_ASSOCIATED(tmp_evLastDateTime))  CALL my_deallocatedatetime(tmp_evLastDateTime)
+      IF (C_ASSOCIATED(tmp_evInterval))      CALL my_deallocatetimedelta(tmp_evInterval)
+
+      IF (C_ASSOCIATED(event_triggerNextEventDateTime      )) &
+        &     CALL my_deallocatedatetime(event_triggerNextEventDateTime      )
+
+      CALL my_deallocatedatetime(c_pointer1)
+
+    ELSE
+      res = this%triggerNextEventDateTime
+    END IF
   END FUNCTION t_event_getNextOccurrenceDatetime
 
-  FUNCTION t_event_getPrevOccurrenceDatetime(this, my_currentdatetime) RESULT(res)
+  FUNCTION t_event_getPrevOccurrenceDatetime(this) RESULT(res)
     TYPE(t_datetime)             :: res
     CLASS(t_event)               :: this
-    TYPE(t_datetime), INTENT(IN) :: my_currentdatetime
     res = this%triggeredPreviousEventDateTime
   END FUNCTION t_event_getPrevOccurrenceDatetime
 
diff --git a/src/mtime_t_timedelta.inc b/src/mtime_t_timedelta.inc
index b348412f..f1f1ec4c 100644
--- a/src/mtime_t_timedelta.inc
+++ b/src/mtime_t_timedelta.inc
@@ -151,8 +151,7 @@
     TYPE(t_timedelta), TARGET :: scaled_td
     INTEGER(c_int32_t),       INTENT(in) :: lambda
     CLASS(t_timedelta), TARGET, INTENT(in) :: this
-    TYPE(timedelta), POINTER             :: td_tmp
-    TYPE(c_ptr) :: c_pointer, dummy_ptr, c_ptr_result
+    TYPE(c_ptr) :: dummy_ptr
 
     ! cast into real since in mtime int implementation scalar
     ! multiplication can not give a value in excess of 24 hours
@@ -222,7 +221,6 @@
     TYPE(t_timedelta),  INTENT(in), target  :: divisor
     TYPE(t_datetime),   INTENT(IN), target  :: referenceDateTime
     TYPE(divisionquotienttimespan), target  :: quotient
-    TYPE(t_datetime), target                :: dt_tmp
     type(c_ptr)                             :: dummy_ptr
 
     dummy_ptr = my_divideTimeDelta(c_loc(this%td), c_loc(divisor%td), &
-- 
GitLab