content: /*
   *  Licensed to the Apache Software Foundation (ASF) under one
   *  or more contributor license agreements.  See the NOTICE file
   *  distributed with this work for additional information
   *  regarding copyright ownership.  The ASF licenses this file
   *  to you 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
   *
   *        http://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 org.apache.causeway.commons.internal.memento;
  
  import java.io.ObjectInput;
  import java.io.ObjectOutput;
  import java.io.Serializable;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Map;
  import java.util.Set;
  
  import org.apache.causeway.commons.internal.base._Strings;
  import org.apache.causeway.commons.internal.exceptions._Exceptions;
  
  import org.jspecify.annotations.NonNull;
  
  /**
   * <h1>- internal use only -</h1>
   * <p>
   * Provides framework internal memento support.
   * </p>
   * <p>
   * <b>WARNING</b>: Do <b>NOT</b> use any of the classes provided by this package! <br/>
   * These may be changed or removed without notice!
   * </p>
   *
   * @since 2.0
   */
  public final class _Mementos {
  
      private _Mementos(){}
  
      // -- ENCODE-DECODER INTERFACE
  
      public static interface EncoderDecoder {
          public String encode(final byte[] bytes);
          public byte[] decode(String str);
      }
  
      // -- MEMENTO INTERFACE
  
      /**
       * Similar to a {@link Map}&lt;String, Object&gt; for key/value pairs,
       * but in addition allows to-String <em>serialization</em> and
       * from-String <em>de-serialization</em> of the entire map.
       */
      public static interface Memento {
  
          /**
           * Returns the Object associated with {@code name}
           * @param name
           * @param cls the expected type which to cast the retrieved value to (required)
           */
          public <T> T get(String name, Class<T> cls);
  
          /**
           * Behaves like a {@link HashMap}, but returns the Memento itself.
           * @param name
           * @param value
           * @return self
           */
          public Memento put(String name, Object value);
  
          /**
           * @return an unmodifiable key-set of this map
           */
          public Set<String> keySet();
  
          /**
           * @return to-String <em>serialization</em> of this map
           */
          public String asString();
      }
  
      // -- SERIALIZER INTERFACE
  
      /**
       * Coder/Decoder from {@link Object} to {@link Serializable}
       */
      public static interface SerializingAdapter {
  
          /**
           * Converts the value into a {@link Serializable} that is write-able to an {@link ObjectOutput}.<br/>
           * Note: write and read are complementary operators.
           * @param value
           */
          public Serializable write(@NonNull Object value);
  
          /**
           * Converts the {@link Serializable} {@code value} as read from an {@link ObjectInput} back into its
           * original (typically a Pojo).<br/>
           * Note: write and read are complementary operators.
           * @param cls the expected type which to cast the {@code value} to (required)
           * @param value
           */
          public <T> T read(@NonNull Class<T> cls, @NonNull Serializable value);
      }
  
      // -- MEMENTO CONSTRUCTION
  
      /**
       * Creates an empty {@link Memento}.
       *
       * <p>
       * Typically followed by {@link Memento#put(String, Object)} for each of the data values to
       * add to the {@link Memento}, then {@link Memento#asString()} to convert to a string format.
       * </p>
       *
       * @param codec (required)
       * @param serializer (required)
       * @return non-null
       */
      public static Memento create(final EncoderDecoder codec, final SerializingAdapter serializer) {
          return new _MementoDefault(codec, serializer);
      }
  
      /**
       * Parse string returned from {@link Memento#asString()}
       *
       * <p>
       * Typically followed by {@link Memento#get(String, Class)} for each of the data values held
       * in the {@link Memento}.
       * </p>
       *
       * @param codec (required)
       * @param serializer (required)
       * @param input
       * @return {@code empty()} if {@code input} is empty
       *
       * @throws IllegalArgumentException if parsing fails
       *
       */
      public static Memento parse(
              final EncoderDecoder codec,
              final SerializingAdapter serializer,
              final String input) {
  
          if(_Strings.isNullOrEmpty(input)) {
              return empty();
          }
          return _MementoDefault.parse(codec, serializer, input);
      }
  
      // -- EMPTY MEMENTO
  
      private static final class EmptyMemento implements Memento {
  
          @Override
          public <T> T get(final String name, final Class<T> cls) {
              return null;
          }
  
          @Override
          public Memento put(final String name, final Object value) {
              throw _Exceptions.notImplemented();
          }
  
          @Override
          public Set<String> keySet() {
              return Collections.emptySet();
          }
  
          @Override
          public String asString() {
              return "EmptyMemento";
          }
  
      }
  
      private static final Memento EMPTY_MEMENTO = new EmptyMemento();
  
      public static Memento empty() {
          return EMPTY_MEMENTO;
      }
  
  }
  