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.node;
017
018import com.agentsflex.core.chain.Chain;
019import com.agentsflex.core.chain.Parameter;
020import com.agentsflex.core.chain.RefType;
021import com.agentsflex.core.chain.node.BaseNode;
022import com.agentsflex.core.util.Maps;
023
024import java.util.*;
025
026public class LoopNode extends BaseNode {
027
028    private Parameter loopVar;
029    private Chain loopChain;
030
031    public Parameter getLoopVar() {
032        return loopVar;
033    }
034
035    public void setLoopVar(Parameter loopVar) {
036        this.loopVar = loopVar;
037    }
038
039    public Chain getLoopChain() {
040        return loopChain;
041    }
042
043    public void setLoopChain(Chain loopChain) {
044        this.loopChain = loopChain;
045    }
046
047    @Override
048    protected Map<String, Object> execute(Chain chain) {
049        loopChain.setParent(chain);
050        Map<String, Object> loopVars = getChainParameters(chain, Collections.singletonList(loopVar));
051        Maps result = Maps.of();
052        Object value = loopVars.get(loopVar.getName());
053        if (value instanceof Iterable) {
054            Iterable<?> iterable = (Iterable<?>) value;
055            int index = 0;
056            for (Object o : iterable) {
057                Map<String, Object> loopParams = new HashMap<>();
058                loopParams.put("loopItem", o);
059                loopParams.put("index", index++);
060                loopParams.putAll(loopVars);
061                loopParams.putAll(chain.getMemory().getAll());
062                loopChain.execute(loopParams);
063                fillResult(result, loopChain.getMemory().getAll());
064            }
065        } else if (value instanceof Number) {
066            int count = ((Number) value).intValue();
067            for (int i = 0; i < count; i++) {
068                Map<String, Object> loopParams = new HashMap<>();
069                loopParams.put("loopItem", i);
070                loopParams.put("index", i);
071                loopParams.putAll(loopVars);
072                loopParams.putAll(chain.getMemory().getAll());
073                loopChain.execute(loopParams);
074                fillResult(result, loopChain.getMemory().getAll());
075            }
076        }
077
078        List<Parameter> outputDefs = getOutputDefs();
079        if (outputDefs != null) {
080            for (Parameter outputDef : outputDefs) {
081                if (outputDef.getRefType() == RefType.INPUT) {
082                    result.put(outputDef.getName(), outputDef.getRef());
083                }
084            }
085        }
086        return result;
087    }
088
089    /**
090     * 把子流程执行的结果填充到主流程的输出参数中
091     *
092     * @param result        主流程的输出参数
093     * @param executeResult 子流程的执行结果
094     */
095    private void fillResult(Maps result, Map<String, Object> executeResult) {
096        List<Parameter> outputDefs = getOutputDefs();
097        if (outputDefs != null) {
098            for (Parameter outputDef : outputDefs) {
099                if (outputDef.getRefType() == RefType.REF) {
100                    Object value = executeResult.get(outputDef.getRef());
101                    @SuppressWarnings("unchecked") List<Object> list = (List<Object>) result.get(outputDef.getName());
102                    if (list == null) list = new ArrayList<>();
103                    list.add(value);
104                    result.put(outputDef.getName(), list);
105                }
106            }
107        }
108    }
109}