/*
 * Copyright © 2023 by Data Virtuality GmbH
 */
package com.datavirtuality.dv.core.services;

import java.util.HashMap;
import java.util.Map;

/**
 * @author Roman Pedchenko
 * @date 2023.04.12
 */
public class DVServices {
    public static class SingletonHolder {
        public static final DVServices HOLDER_INSTANCE = new DVServices();
    }

    public static DVServices getInstance() {
        return SingletonHolder.HOLDER_INSTANCE;
    }

    private final Map<Class<? extends DVService>, DVService> registry = new HashMap<>();

    public static <T extends DVService> void register(Class<T> key, T instance) {
        getInstance().registry.put(key, instance);
    }

    public static <T extends DVService, V> V call(Class<T> clazz, Code<T, V> code) throws Exception {
        @SuppressWarnings("unchecked")
        final T s = (T) getInstance().registry.get(clazz);
        if (s == null)
            throw new DVNoServiceException(clazz);
        return code.call(s);
    }

    public static <T extends DVService, V> V callne(Class<T> clazz, NeCode<T, V> code) {
        @SuppressWarnings("unchecked")
        final T s = (T) getInstance().registry.get(clazz);
        if (s == null)
            throw new DVNoServiceException(clazz);
        return code.call(s);
    }

    public static <T extends DVService, V> V callne(Class<T> clazz, NeCode<T, V> code, V defaultValue) {
        @SuppressWarnings("unchecked")
        final T s = (T) getInstance().registry.get(clazz);
        if (s == null)
            return defaultValue;
        return code.call(s);
    }

    @FunctionalInterface
    public interface Code<T, V> {
        V call(T instance) throws Exception;
    }

    @FunctionalInterface
    public interface NeCode<T, V> {
        V call(T instance);
    }
}
