1   /* Copyright 2002-2021 CS GROUP
2    * Licensed to CS GROUP (CS) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * CS licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.orekit.propagation.sampling;
18  
19  import java.util.ArrayList;
20  import java.util.Collections;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import org.hipparchus.CalculusFieldElement;
25  import org.orekit.propagation.FieldSpacecraftState;
26  import org.orekit.time.FieldAbsoluteDate;
27  
28  /** This class gathers several {@link OrekitStepHandler} instances into one.
29   *
30   * @author Luc Maisonobe
31   */
32  public class FieldStepHandlerMultiplexer<T extends CalculusFieldElement<T>> implements FieldOrekitStepHandler<T> {
33  
34      /** Underlying step handlers. */
35      private final List<FieldOrekitStepHandler<T>> handlers;
36  
37      /** Target time. */
38      private FieldAbsoluteDate<T> target;
39  
40      /** Last known state. */
41      private FieldSpacecraftState<T> last;
42  
43      /** Simple constructor.
44       */
45      public FieldStepHandlerMultiplexer() {
46          handlers = new ArrayList<>();
47      }
48  
49      /** Add a handler for variable size step.
50       * <p>
51       * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
52       * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
53       * yet), then the local {@link FieldOrekitStepHandler#init(FieldSpacecraftState, FieldAbsoluteDate)
54       * FieldOrekitStepHandler.init} method of the added handler will be called with the last
55       * known state, so the handler starts properly.
56       * </p>
57       * @param handler step handler to add
58       */
59      public void add(final FieldOrekitStepHandler<T> handler) {
60          handlers.add(handler);
61          if (last != null) {
62              // propagation is ongoing, we need to call init now for this handler
63              handler.init(last, target);
64          }
65      }
66  
67      /** Add a handler for fixed size step.
68       * <p>
69       * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
70       * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
71       * yet), then the local {@link FieldOrekitFixedStepHandler#init(FieldSpacecraftState, FieldAbsoluteDate,
72       * CalculusFieldElement) FieldOrekitStepHandler.init} method of the added handler will be
73       * called with the last known state, so the handler starts properly.
74       * </p>
75       * @param h fixed stepsize (s)
76       * @param handler handler called at the end of each finalized step
77       * @since 11.0
78       */
79      public void add(final T h, final FieldOrekitFixedStepHandler<T> handler) {
80          final FieldOrekitStepHandler<T> normalized = new FieldOrekitStepNormalizer<>(h, handler);
81          handlers.add(normalized);
82          if (last != null) {
83              // propagation is ongoing, we need to call init now for this handler
84              normalized.init(last, target);
85          }
86      }
87  
88      /** Get an unmodifiable view of all handlers.
89       * <p>
90       * Note that if {@link FieldOrekitFixedStepHandler fixed step handlers} have
91       * been {@link #add(CalculusFieldElement, FieldOrekitFixedStepHandler)}, then they will
92       * show up wrapped within {@link FieldOrekitStepNormalizer step normalizers}.
93       * </p>
94       * @return an unmodifiable view of all handlers
95       * @since 11.0
96       */
97      public List<FieldOrekitStepHandler<T>> getHandlers() {
98          return Collections.unmodifiableList(handlers);
99      }
100 
101     /** Remove a handler.
102      * <p>
103      * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
104      * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
105      * yet), then the local {@link FieldOrekitStepHandler#finish(FieldSpacecraftState)
106      * FieldOrekitStepHandler.finish} method of the removed handler will be called with the last
107      * known state, so the handler stops properly.
108      * </p>
109      * @param handler step handler to remove
110      * @since 11.0
111      */
112     public void remove(final FieldOrekitStepHandler<T> handler) {
113         final Iterator<FieldOrekitStepHandler<T>> iterator = handlers.iterator();
114         while (iterator.hasNext()) {
115             if (iterator.next() == handler) {
116                 if (last != null) {
117                     // propagation is ongoing, we need to call finish now for this handler
118                     handler.finish(last);
119                 }
120                 iterator.remove();
121                 return;
122             }
123         }
124     }
125 
126     /** Remove a handler.
127      * <p>
128      * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
129      * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
130      * yet), then the local {@link FieldOrekitFixedStepHandler#finish(FieldSpacecraftState)
131      * FieldOrekitFixedStepHandler.finish} method of the removed handler will be called with the last
132      * known state, so the handler stops properly.
133      * </p>
134      * @param handler step handler to remove
135      * @since 11.0
136      */
137     public void remove(final FieldOrekitFixedStepHandler<T> handler) {
138         final Iterator<FieldOrekitStepHandler<T>> iterator = handlers.iterator();
139         while (iterator.hasNext()) {
140             final FieldOrekitStepHandler<T> current = iterator.next();
141             if (current instanceof FieldOrekitStepNormalizer &&
142                 ((FieldOrekitStepNormalizer<T>) current).getFixedStepHandler() == handler) {
143                 if (last != null) {
144                     // propagation is ongoing, we need to call finish now for this handler
145                     current.finish(last);
146                 }
147                 iterator.remove();
148                 return;
149             }
150         }
151     }
152 
153     /** Remove all handlers managed by this multiplexer.
154      * <p>
155      * If propagation is ongoing (i.e. global {@link #init(FieldSpacecraftState, FieldAbsoluteDate)
156      * init} already called and global {@link #finish(FieldSpacecraftState) finish} not called
157      * yet), then the local {@link FieldOrekitStepHandler#finish(FieldSpacecraftState)
158      * FieldOrekitStepHandler.finish} and {@link FieldOrekitFixedStepHandler#finish(FieldSpacecraftState)
159      * FieldOrekitFixedStepHandler.finish} methods of the removed handlers will be called with the last
160      * known state, so the handlers stop properly.
161      * </p>
162      * @since 11.0
163      */
164     public void clear() {
165         if (last != null) {
166             // propagation is ongoing, we need to call finish now for all handlers
167             handlers.forEach(h -> h.finish(last));
168         }
169         handlers.clear();
170     }
171 
172     /** {@inheritDoc} */
173     public void init(final FieldSpacecraftState<T> s0, final FieldAbsoluteDate<T> t) {
174         this.target = t;
175         this.last   = s0;
176         for (final FieldOrekitStepHandler<T> handler : handlers) {
177             handler.init(s0, t);
178         }
179     }
180 
181     /** {@inheritDoc} */
182     public void handleStep(final FieldOrekitStepInterpolator<T> interpolator) {
183         this.last = interpolator.getCurrentState();
184         for (final FieldOrekitStepHandler<T> handler : handlers) {
185             handler.handleStep(interpolator);
186         }
187     }
188 
189     /** {@inheritDoc} */
190     public void finish(final FieldSpacecraftState<T> finalState) {
191         this.target = null;
192         this.last   = null;
193         for (final FieldOrekitStepHandler<T> handler : handlers) {
194             handler.finish(finalState);
195         }
196     }
197 
198 }