content: /*
   * DazzleConf
   * Copyright © 2025 Anand Beh
   *
   * DazzleConf is free software: you can redistribute it and/or modify
   * it under the terms of the GNU Lesser General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * DazzleConf is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
   * GNU Lesser General Public License for more details.
   *
   * You should have received a copy of the GNU Lesser General Public License
   * along with DazzleConf. If not, see <https://www.gnu.org/licenses/>
   * and navigate to version 3 of the GNU Lesser General Public License.
   */
  
  package space.arim.dazzleconf;
  
  import org.checkerframework.checker.nullness.qual.NonNull;
  import space.arim.dazzleconf.backend.Printable;
  import space.arim.dazzleconf.internals.lang.LibraryLang;
  
  import java.io.IOException;
  import java.util.LinkedHashMap;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Objects;
  import java.util.Set;
  
  final class LoadError implements ErrorContext, LibraryLang.Accessor {
  
      private final Printable message;
      private final LibraryLang libraryLang;
      private final Map<Key<?>, Object> contexts = new LinkedHashMap<>();
  
      LoadError(Printable message, LibraryLang libraryLang) {
          this.message = Objects.requireNonNull(message, "message");
          this.libraryLang = Objects.requireNonNull(libraryLang, "libraryLang");
      }
  
      @Override
      public @NonNull LibraryLang getLibraryLang() {
          return libraryLang;
      }
  
      @Override
      public @NonNull Locale getLocale() {
          return libraryLang.getLocale();
      }
  
      @Override
      public @NonNull Printable mainMessage() {
          return message;
      }
  
      @Override
      public @NonNull Printable display() {
          return new Printable.Abstract() {
              @Override
              public void printTo(@NonNull Appendable output) throws IOException {
  
                  // Append the main message
                  output.append(libraryLang.failed());
                  output.append(':');
                  output.append(' ');
                  message.printTo(output);
  
                  // Append each of the detail values
                  for (Key<?> key : allKeys()) {
                      output.append("\n  ");
                      formatKeyData(output, key);
                  }
              }
          };
      }
  
      private <V> void formatKeyData(Appendable output, Key<V> key) throws IOException {
          output.append(key.langKey.getMessage(libraryLang));
          output.append(": ");
          key.formatData.format(output, query(key));
      }
  
      @Override
      public <V> V query(@NonNull Key<V> key) {
          Objects.requireNonNull(key, "key");
          @SuppressWarnings("unchecked")
          V value = (V) contexts.get(key);
          return value;
      }
  
      @Override
      public <V> void addDetail(@NonNull Key<V> key, @NonNull V context) {
          Objects.requireNonNull(key, "key");
          Objects.requireNonNull(context, "context");
          contexts.put(key, context);
      }
  
      @Override
      public void clearDetail(@NonNull Key<?> key) {
          contexts.remove(key);
      }
  
      @Override
      public void copyDetailsInto(@NonNull ErrorContext target) {
          for (Key<?> key :  contexts.keySet()) {
              copyContextInto(key, target);
          }
      }
  
      private <V> void copyContextInto(Key<V> key, ErrorContext target) {
          V val = query(key);
          assert val != null;
          target.addDetail(key, val);
      }
  
      @Override
      public @NonNull Set<@NonNull Key<?>> allKeys() {
          return contexts.keySet();
      }
  
      abstract static class Factory implements Source, LibraryLang.Accessor {
  
          @Override
          public @NonNull Locale getLocale() {
              return getLibraryLang().getLocale();
          }
  
          @Override
          public @NonNull <R> LoadResult<R> throwError(@NonNull CharSequence message) {
              return LoadResult.failure(buildError(Printable.preBuilt(message)));
          }
  
          @Override
          public @NonNull <R> LoadResult<R> throwError(@NonNull Printable message) {
              return LoadResult.failure(buildError(message));
          }
      }
  }
  