package ru.simplex_software.wicket_springdata.kryo;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.springframework.data.domain.Persistable;

import java.io.Serializable;
import java.util.Optional;
import java.util.function.Function;

/**
 * Чтение и запись хранимых сущностей.
 */
public class PersistableSerializer<P extends Persistable<ID>, ID extends Serializable> extends Serializer<P> {

    private Function<ID, Optional<P>> findByIsFunction;
    private Class<ID> idClass;

    public PersistableSerializer(Function<ID, Optional<P>> findByIsFunction, Class<ID> idClass) {
        this.findByIsFunction = findByIsFunction;
        this.idClass = idClass;
    }

    @Override
    public void write(Kryo kryo, Output output, P entity) {
        output.writeBoolean(entity.isNew());
        if (entity.isNew()) {
            Serializer<P> defaultSerializer = kryo.getDefaultSerializer(entity.getClass());
            defaultSerializer.write(kryo, output, entity);
        } else {
            Serializer<Serializable> idSerializer = kryo.getSerializer(idClass);
            idSerializer.write(kryo, output, entity.getId());
        }
    }

    @Override
    public P read(Kryo kryo, Input input, Class<? extends P> type) {
        if (input.readBoolean()) {
            Serializer<P> defaultSerializer = kryo.getDefaultSerializer(type);
            return defaultSerializer.read(kryo, input, type);
        } else {
            Serializer<ID> idSerializer = kryo.getSerializer(idClass);
            ID id = idSerializer.read(kryo, input, idClass);
            return findByIsFunction.apply(id).get();
        }
    }
}
