/*
 * Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
 *
 * 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 org.pkl.core;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
import org.jspecify.annotations.Nullable;

/** Visitor for data models generated by [Evaluator]. */
public interface ValueVisitor {
  default void visitDefault(@Nullable Object value) {}

  default void visitNull() {
    visitDefault(null);
  }

  default void visitString(String value) {
    visitDefault(value);
  }

  default void visitBoolean(Boolean value) {
    visitDefault(value);
  }

  default void visitInt(Long value) {
    visitDefault(value);
  }

  default void visitFloat(Double value) {
    visitDefault(value);
  }

  default void visitDuration(Duration value) {
    visitDefault(value);
  }

  default void visitDataSize(DataSize value) {
    visitDefault(value);
  }

  default void visitBytes(byte[] value) {
    visitDefault(value);
  }

  default void visitPair(Pair<?, ?> value) {
    visitDefault(value);
  }

  default void visitList(List<?> value) {
    visitDefault(value);
  }

  default void visitSet(Set<?> value) {
    visitDefault(value);
  }

  default void visitMap(Map<?, ?> value) {
    visitDefault(value);
  }

  default void visitObject(PObject value) {
    visitDefault(value);
  }

  default void visitModule(PModule value) {
    visitDefault(value);
  }

  default void visitClass(PClass value) {
    visitDefault(value);
  }

  default void visitTypeAlias(TypeAlias value) {
    visitDefault(value);
  }

  default void visitRegex(Pattern value) {
    visitDefault(value);
  }

  default void visitReference(Reference value) {
    visitDefault(value);
  }

  default void visit(Object value) {
    if (value instanceof Value v) {
      v.accept(this);
    } else if (value instanceof String string) {
      visitString(string);
    } else if (value instanceof Boolean b) {
      visitBoolean(b);
    } else if (value instanceof Long l) {
      visitInt(l);
    } else if (value instanceof Double d) {
      visitFloat(d);
    } else if (value instanceof List<?> list) {
      visitList(list);
    } else if (value instanceof Set<?> set) {
      visitSet(set);
    } else if (value instanceof Map<?, ?> map) {
      visitMap(map);
    } else if (value instanceof Pattern pattern) {
      visitRegex(pattern);
    } else if (value instanceof byte[] bytes) {
      visitBytes(bytes);
    } else {
      throw new IllegalArgumentException("Cannot visit value with unexpected type: " + value);
    }
  }
}
