001/**
002 * Copyright (c) 2025-2026, Michael Yang 杨福海 (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the GNU Lesser General Public License (LGPL) ,Version 3.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.gnu.org/licenses/lgpl-3.0.txt
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package dev.tinyflow.core.chain;
017
018import dev.tinyflow.core.chain.listener.ChainErrorListener;
019import dev.tinyflow.core.chain.listener.ChainEventListener;
020import dev.tinyflow.core.chain.listener.ChainOutputListener;
021import dev.tinyflow.core.chain.listener.NodeErrorListener;
022import dev.tinyflow.core.util.MapUtil;
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025
026import java.util.List;
027import java.util.Map;
028import java.util.concurrent.ConcurrentHashMap;
029import java.util.concurrent.CopyOnWriteArrayList;
030
031public class EventManager {
032
033    private static final Logger log = LoggerFactory.getLogger(EventManager.class);
034
035    protected final Map<Class<?>, List<ChainEventListener>> eventListeners = new ConcurrentHashMap<>();
036    protected final List<ChainOutputListener> outputListeners = new CopyOnWriteArrayList<>();
037    protected final List<ChainErrorListener> chainErrorListeners = new CopyOnWriteArrayList<>();
038    protected final List<NodeErrorListener> nodeErrorListeners = new CopyOnWriteArrayList<>();
039    protected final Map<String, Object> otherListeners = new ConcurrentHashMap<>();
040
041    /**
042     * ---------- 通用事件监听器 ----------
043     */
044    public void addEventListener(Class<? extends Event> eventClass, ChainEventListener listener) {
045        MapUtil.computeIfAbsent(eventListeners, eventClass, k -> {
046            CopyOnWriteArrayList<ChainEventListener> objects = new CopyOnWriteArrayList<>();
047            objects.add(listener);
048            return objects;
049        });
050    }
051
052    public void addEventListener(ChainEventListener listener) {
053        addEventListener(Event.class, listener);
054    }
055
056    public void removeEventListener(Class<? extends Event> eventClass, ChainEventListener listener) {
057        List<ChainEventListener> list = eventListeners.get(eventClass);
058        if (list != null) list.remove(listener);
059    }
060
061    public void removeEventListener(ChainEventListener listener) {
062        for (List<ChainEventListener> list : eventListeners.values()) {
063            list.remove(listener);
064        }
065    }
066
067    public void notifyEvent(Event event, Chain chain) {
068        for (Map.Entry<Class<?>, List<ChainEventListener>> entry : eventListeners.entrySet()) {
069            if (entry.getKey().isInstance(event)) {
070                for (ChainEventListener listener : entry.getValue()) {
071                    try {
072                        listener.onEvent(event, chain);
073                    } catch (Exception e) {
074                        log.error("Error in event listener: {}", e, e);
075                    }
076                }
077            }
078        }
079    }
080
081    /**
082     * ---------- Output Listener ----------
083     */
084    public void addOutputListener(ChainOutputListener listener) {
085        outputListeners.add(listener);
086    }
087
088    public void removeOutputListener(ChainOutputListener listener) {
089        outputListeners.remove(listener);
090    }
091
092    public void notifyOutput(Chain chain, Node node, Object response) {
093        for (ChainOutputListener listener : outputListeners) {
094            try {
095                listener.onOutput(chain, node, response);
096            } catch (Exception e) {
097                log.error("Error in output listener: {}", e.toString(), e);
098            }
099        }
100    }
101
102    /**
103     * ---------- Chain Error Listener ----------
104     */
105    public void addChainErrorListener(ChainErrorListener listener) {
106        chainErrorListeners.add(listener);
107    }
108
109    public void removeChainErrorListener(ChainErrorListener listener) {
110        chainErrorListeners.remove(listener);
111    }
112
113    public void notifyChainError(Throwable error, Chain chain) {
114        for (ChainErrorListener listener : chainErrorListeners) {
115            try {
116                listener.onError(error, chain);
117            } catch (Exception e) {
118                log.error("Error in chain error listener: {}", e, e);
119            }
120        }
121    }
122
123    /**
124     * ---------- Node Error Listener ----------
125     */
126    public void addNodeErrorListener(NodeErrorListener listener) {
127        nodeErrorListeners.add(listener);
128    }
129
130    public void removeNodeErrorListener(NodeErrorListener listener) {
131        nodeErrorListeners.remove(listener);
132    }
133
134    public void notifyNodeError(Throwable error, Node node, Map<String, Object> result, Chain chain) {
135        for (NodeErrorListener listener : nodeErrorListeners) {
136            try {
137                listener.onError(error, node, result, chain);
138            } catch (Exception e) {
139                log.error("Error in node error listener: {}", e.toString(), e);
140            }
141        }
142    }
143
144    public void addOtherListener(String key, Object listener) {
145        otherListeners.put(key, listener);
146    }
147
148    public void removeOtherListener(String key) {
149        otherListeners.remove(key);
150    }
151
152    public <T> T getOtherListener(String key) {
153        //noinspection unchecked
154        return (T) otherListeners.get(key);
155    }
156}