content: /*
   * Copyright 2024-2025 the original author or authors.
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      https://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  package com.alibaba.cloud.ai.graph.state;
  
  import java.util.Optional;
  import java.util.function.Supplier;
  
  import static java.util.Optional.ofNullable;
  
  /**
   * @param <T>
   */
  class BaseChannel<T> implements Channel<T> {
  
  	final Supplier<T> defaultProvider;
  
  	final Reducer<T> reducer;
  
  	/**
  	 * Constructs a new BaseChannel with the specified {@code reducer} and
  	 * {@code defaultProvider}.
  	 * @param reducer the function to apply in the reduction process; must not be null
  	 * @param defaultProvider the supplier of default value for operations where no input
  	 * is provided; must not be null
  	 * @throws NullPointerException if either the {@code reducer} or
  	 * {@code defaultProvider} is null
  	 */
  	BaseChannel(Reducer<T> reducer, Supplier<T> defaultProvider) {
  		this.defaultProvider = defaultProvider;
  		this.reducer = reducer;
  	}
  
  	/**
  	 * Returns an {@link Optional} containing the default supplier if it is set;
  	 * otherwise, returns an empty {@link Optional}.
  	 * @return an {@link Optional} describing the default supplier or an empty
  	 * {@link Optional} if none is set
  	 */
  	public Optional<Supplier<T>> getDefault() {
  		return ofNullable(defaultProvider);
  	}
  
  	/**
  	 * Retrieves the {@link Reducer} instance wrapped in an {@link Optional}.
  	 * @return An {@link Optional} containing the {@code Reducer} object if it is
  	 * non-null, or an empty {@link Optional} if it is null.
  	 */
  	public Optional<Reducer<T>> getReducer() {
  		return ofNullable(reducer);
  	}
  
  }
  
  /**
   * A Channel is a mechanism used to maintain a state property.
   * <p>
   * A Channel is associated with a key and a value. The Channel is updated by calling the
   * {@link #update(String, Object, Object)} method. The update operation is applied to the
   * channel's value.
   * <p>
   * The Channel may be initialized with a default value. This default value is provided by
   * a {@link Supplier}. The {@link #getDefault()} method returns an optional containing the
   * default supplier.
   * <p>
   * The Channel may also be associated with a Reducer. The Reducer is a function that
   * combines the current value of the channel with a new value and returns the updated
   * value.
   * <p>
   * The {@link #update(String, Object, Object)} method updates the channel's value with the
   * provided key, old value and new value. The update operation is applied to the channel's
   * value. If the channel is not initialized, the default value is used. If the channel is
   * initialized, the reducer is used to compute the new value.
   *
   * @param <T> the type of the state property
   */
  public interface Channel<T> {
  
  	/**
  	 * Creates a channel with the specified default provider.
  	 * @param <T> the type of items produced by this channel
  	 * @param defaultProvider the supplier of the default item for the channel
  	 * @return a new channel with the specified default provider
  	 */
  	static <T> Channel<T> of(Supplier<T> defaultProvider) {
  		return new BaseChannel<T>(null, defaultProvider);
  	}
  
  	/**
  	 * Creates a channel with the specified {@code Reducer}.
  	 * @param <T> the type of elements in the channel
  	 * @param reducer the function to reduce values as they are added to the channel
  	 * @return a new channel instance
  	 */
  	static <T> Channel<T> of(Reducer<T> reducer) {
  		return new BaseChannel<T>(reducer, null);
  	}
  
  	/**
  	 * Creates a new channel instance with the specified {@code reducer} and
  	 * {@code defaultProvider}.
  	 * @param <T> the type of elements in this channel
  	 * @param reducer the function to reduce elements from multiple suppliers into one
  	 * value
  	 * @param defaultProvider the supplier to provide a default value when no other value
  	 * is available
  	 * @return a new channel instance with the specified parameters
  	 */
  	static <T> Channel<T> of(Reducer<T> reducer, Supplier<T> defaultProvider) {
  		return new BaseChannel<T>(reducer, defaultProvider);
  	}
  
  	/**
  	 * The Reducer, if provided, is invoked for each state property to compute value.
  	 * @return An optional containing the reducer, if it exists.
  	 */
  	Optional<Reducer<T>> getReducer();
  
  	/**
  	 * a Supplier that provide a default value. The result must be mutable.
  	 * @return an Optional containing the default Supplier
  	 */
  	Optional<Supplier<T>> getDefault();
  
  	/**
  	 * Update the state property with the given key and returns the new value.
  	 * @param key the key of the state property to be updated
  	 * @param oldValue the current value of the state property
  	 * @param newValue the new value to be set
  	 * @return the new value of the state property
  	 */
  	@SuppressWarnings("unchecked")
  	default Object update(String key, Object oldValue, Object newValue) {
  		T _new = (T) newValue;
  
  		final T _old = (oldValue == null) ? getDefault().map(Supplier::get).orElse(null) : (T) oldValue;
  
  		return getReducer().map(reducer -> reducer.apply(_old, _new)).orElse(_new);
  	}
  
  }
  